Source Code

;; SPDX-License-Identifier: BUSL-1.1

;; TRAITS
(use-trait token-trait 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.sip-010-trait)

;; CONSTANTS

;; Action to update governance in State Contract
(define-constant ACTION_UPDATE_GOVERNANCE u0)

;; Action to freeze upgrades on State contract
(define-constant ACTION_FREEZE_UPGRADES u1)

;; Action to set depositing assets
(define-constant ACTION_SET_DEPOSIT_ASSET_FLAG u2)

;; Action to set withdrawing assets
(define-constant ACTION_SET_WITHDRAW_ASSET_FLAG u3)

;; Action to set adding collateral to market
(define-constant ACTION_SET_ADD_COLLATERAL_FLAG u4)

;; Action to set removing collateral from market
(define-constant ACTION_SET_REMOVE_COLLATERAL_FLAG u5)

;; Action to set Borrow
(define-constant ACTION_SET_BORROW_FLAG u6)

;; Action to set Repay
(define-constant ACTION_SET_REPAY_FLAG u7)

;; Action to set Liquidation
(define-constant ACTION_SET_LIQUIDATION_FLAG u8)

;; Action to set market pause
(define-constant ACTION_SET_MARKET_PAUSE_FLAG u9)

;; Action to set market unpause
(define-constant ACTION_SET_MARKET_UNPAUSE_FLAG u10)

;; Action to update collateral settings
(define-constant ACTION_UPDATE_COLLATERAL_SETTINGS u11)

;; Action to deposit to Market reserve balance
(define-constant ACTION_DEPOSIT_TO_RESERVE u12)

;; Action to withdraw from Market reserve
(define-constant ACTION_WITHDRAW_FROM_RESERVE u13)

;; Action to update Allowed contract list
(define-constant ACTION_SET_ALLOWED_CONTRACT u14)

;; Action to remove allowed contract list
(define-constant ACTION_REMOVE_ALLOWED_CONTRACT u15)

;; Action to add new principal to guardians
(define-constant ACTION_ADD_GUARDIAN u16)

;; Action to remove principal from guardians
(define-constant ACTION_REMOVE_GUARDIAN u17)

;; Action to update interest rate parameters
(define-constant ACTION_UPDATE_INTEREST_RATE_PARAMS u18)

;; Action to update protocol reserve percentage
(define-constant ACTION_UPDATE_PROTOCOL_RESERVE_PERCENTAGE u19)

;; Action to update asset cap
(define-constant ACTION_UPDATE_ASSET_CAP u20)

;; Action to transfer out funds from governance contract
(define-constant ACTION_TRANSFER_FUNDS u21)

;; Action to remove collateral
(define-constant ACTION_REMOVE_COLLATERAL u22)

;; Action to pause interest accrual
(define-constant ACTION_SET_INTEREST_ACCRUAL_FLAG u23)

;; Action to update staking reward rate
(define-constant ACTION_UPDATE_REWARD_RATE_PARAMS u24)

;; Action to update the staking module withdrawal window
(define-constant ACTION_UPDATE_WITHDRAWAL_FINALIZATION_PERIOD u25)

;; Action to update a token feed to the Pyth oracle contract
(define-constant ACTION_UPDATE_PYTH_TOKEN_FEED u26)

;; Action to reconcile staking balance
(define-constant ACTION_RECONCILE_STAKING_LP_BALANCE u27)

;; Action to set staking flag
(define-constant ACTION_SET_STAKING_FLAG u28)

;; Action to update pyth time delta
(define-constant ACTION_UPDATE_TIME_DELTA u29)

;; Action to set lp cap
(define-constant ACTION_SET_LP_CAP u30)

;; Action to set debt cap
(define-constant ACTION_SET_DEBT_CAP u31)

;; action to set collateral cap
(define-constant ACTION_SET_COLLATERAL_CAP u32)

;; action to set refill time window
(define-constant ACTION_SET_REFILL_TIME_WINDOW u33)

;; action to set decay time window
(define-constant ACTION_SET_DECAY_TIME_WINDOW u34)

;; action to update flash loan fee
(define-constant ACTION_UPDATE_FLASH_LOAN_FEE u35)

;; action to add contract to allow list in flash loan
(define-constant ACTION_ADD_CONTRACT_FLASH_LOAN u36)

;; action to remove contract from allow list in flash loan
(define-constant ACTION_REMOVE_CONTRACT_FLASH_LOAN u37)

;; action to allow or disable any contract
(define-constant ACTION_ALLOW_ANY_CONTRACT_FLASH_LOAN u38)

;; Threshold to either execute or remove proposal
;; 60% and above
;; 1 & 2 Account Multisig will require all of them to execute or deny proposal
(define-constant THRESHOLD u60)

;; Time lock period before executing approved proposal
;; approximately 24 hours assuming 4 second block time
(define-constant TIME_LOCKED_PERIOD u21600)

;; Time lock expiration period
;; approved time lock proposal expires after expiration block
;; approximately 1 week assuming 4 second block time
(define-constant TIME_LOCK_EXECUTE_EXPIRATION_PERIOD u151200)

;; Success response
(define-constant SUCCESS (ok true))

;; ERRORS
(define-constant ERR-INVALID-ACTION (err u40000))
(define-constant ERR-NOT-GUARDIAN (err u40001))
(define-constant ERR-UNKNOWN-PROPOSAL (err u40002))
(define-constant ERR-SUBMITTED-VOTE (err u40003))
(define-constant ERR-PROPOSAL-CLOSED (err u40004))
(define-constant ERR-CONTRACT-ALREADY-INITIALIZED (err u40005))
(define-constant ERR-CONTRACT-NOT-INITIALIZED (err u40006))
(define-constant ERR-NOT-CONTRACT-DEPLOYER (err u40007))
(define-constant ERR-INTEREST-RATE-PARAMS (err u40008))
(define-constant ERR-PROPOSAL-ALREADY-EXISTS (err u40009))
(define-constant ERR-FAILED-TO-GENERATE-PROPOSAL-ID (err u40010))
(define-constant ERR-PROPOSAL-VOTING-INCOMPLETE (err u40011))
(define-constant ERR-PROPOSAL-CANNOT-CLOSE (err u40012))
(define-constant ERR-PROPOSAL-EXPIRED (err u40013))
(define-constant ERR-MINIMUM-PYTH-PRICE-DELTA (err u40014))
(define-constant ERR-PROPOSAL-NOT-CLOSED (err u40015))
(define-constant ERR-PROPOSAL-ALREADY-EXECUTED (err u40016))
(define-constant ERR-PROPOSAL-TIME-LOCKED (err u40017))
(define-constant ERR-PROPOSAL-NOT-TIME-LOCKED (err u40018))
(define-constant ERR-CANNOT-VOTE (err u40019))
(define-constant ERR-ALREADY-GUARDIAN (err u40020))

;; DATA VARS

;; Next proposal nonce
(define-data-var next-proposal-nonce uint u0)

;; Guardians with specific permissions
(define-map guardians principal bool)

;; Governance proposal
(define-map governance-proposal (buff 32) {
  action: uint,
  approve-count: uint,
  deny-count: uint,
  closed: bool,
  expires-at: uint,
  executed: bool,
  execute-at: (optional uint)
})

;; approved multisigs for given proposal
(define-map proposal-approved-members { proposal-id: (buff 32), member: principal} bool)

;; denied multisigs for given proposal
(define-map proposal-denied-members { proposal-id: (buff 32), member: principal} bool)

;; Update governance proposal data
(define-map update-governance-proposal-data (buff 32) principal)

;; Set market feature proposal data
(define-map set-market-feature-proposal-data (buff 32) {
  flag: bool,
  cooldown: uint
})

;; Collateral settings proposal data
(define-map collateral-settings-proposal-data (buff 32) {
    collateral: principal,
    max-ltv: uint, 
    liquidation-ltv: uint, 
    liquidation-premium: uint,
    decimals: uint
  }
)

;; Reserve proposal data
(define-map reserve-proposal-data (buff 32) uint)

;; Market unpausing data
(define-map unpause-market-data (buff 32) uint)

;; Allowed contracts data
(define-map allowed-contract-data (buff 32) principal)

;; Update guardians proposal data
(define-map update-guardians-proposal-data (buff 32) principal)

;; Proposal's state contract address
(define-map state-contract-address (buff 32) principal)

;; Proposal's interest rate contract address
(define-map update-interest-rate-params (buff 32) {
  ir-slope-1-val: uint,
  ir-slope-2-val: uint,
  utilization-kink-val: uint,
  base-ir-val: uint,
})

;; Reserve token feed data
(define-map update-pyth-feed (buff 32) {
  token: principal,
  feed: (buff 32),
  max-confidence-ratio: uint,
})

;; Staking status flag
(define-map staking-flag (buff 32) bool)

;; contract deployer. No permissions except to initialize the contract
(define-constant contract-deployer contract-caller)

;; flag to check if the contract is initialized
(define-data-var governance-initialized bool false)

;; storage value for protocol reserve percentage.
(define-map protocol-reserve-percentage (buff 32) uint)

;; storage value for asset cap update
(define-map asset-cap-update (buff 32) uint)

;; storage value for funds transfer
(define-map transfer-funds (buff 32) {
  account: principal,
  amount: uint
})

;; storage value for remove collateral
(define-map remove-collateral (buff 32) principal)

;; storage value for reward rate
(define-map update-reward-rate-params (buff 32) {
  slope-1-val: int,
  slope-2-val: int,
  staked-kink-val: uint,
  base-reward-val: uint,
})

;; staking module withdrawal window data storage
(define-map withdrawal-finalization-period (buff 32) uint)

;; pyth time delta update value storage
(define-map update-time-delta-params (buff 32) uint)

;; time-locked actions
(define-map time-locked uint bool)

;; cap update data
(define-map cap-data (buff 32) {
    collateral: (optional principal),
    factor: uint
  }
)

;; flash loan fee update
(define-map flash-loan-fee-update (buff 32) uint)

;; flash loan add or remove contract
(define-map flash-loan-contract-update (buff 32) principal)

;; flash loan allow or disable any contract
(define-map flash-allow-disable-contract-update (buff 32) bool)

;; PRIVATE FUNCTIONS
(define-private (create-proposal (proposal-id (buff 32)) (action uint) (expires-in uint))
  (begin
    (try! (is-governance-member contract-caller))
    (asserts! (not (is-some (map-get? governance-proposal proposal-id))) ERR-PROPOSAL-ALREADY-EXISTS)
    (asserts! (var-get governance-initialized) ERR-CONTRACT-NOT-INITIALIZED)
    (var-set next-proposal-nonce (+ (var-get next-proposal-nonce) u1))
    (map-set governance-proposal proposal-id {
      action: action,
      approve-count: u1,
      deny-count: u0,
      expires-at: (+ stacks-block-height expires-in),
      closed: false,
      executed: false,
      execute-at: none,
    })
    (map-set proposal-approved-members {proposal-id: proposal-id, member: contract-caller} true)
    (print {
      action: "proposal-initiated",
      proposal-id: proposal-id
    })
    (print {
      action: "proposal-voted-approved",
      voter: contract-caller,
      proposal-id: proposal-id
    })
    (ok proposal-id)
))

(define-private (has-submitted-vote (proposal-id (buff 32)))
  (or 
    (default-to false (map-get? proposal-approved-members {proposal-id: proposal-id, member: contract-caller}))
    (default-to false (map-get? proposal-denied-members {proposal-id: proposal-id, member: contract-caller}))
))

(define-private (execute-update-pyth-token-price-feed (proposal-id (buff 32)))
  (let ((pyth-data (unwrap-panic (map-get? update-pyth-feed proposal-id))))
    (contract-call? .pyth-adapter-v1 update-price-feed-id (get token pyth-data) (get feed pyth-data) (get max-confidence-ratio pyth-data))
))

(define-private (execute-state-governance-update (proposal-id (buff 32)))
  (contract-call? .state-v1 update-governance (unwrap-panic (map-get? update-governance-proposal-data proposal-id)))
)

(define-private (execute-state-set-feature-flag (proposal-id (buff 32)) (action uint))
  (let (
      (data (unwrap-panic (map-get? set-market-feature-proposal-data proposal-id)))
      (flag (get flag data))
      (cooldown (get cooldown data))
    )
    (asserts! (not (is-eq action ACTION_SET_DEPOSIT_ASSET_FLAG)) (contract-call? .state-v1 set-deposit-asset-flag flag))
    (asserts! (not (is-eq action ACTION_SET_WITHDRAW_ASSET_FLAG)) (contract-call? .state-v1 set-withdraw-asset-flag flag))
    (asserts! (not (is-eq action ACTION_SET_ADD_COLLATERAL_FLAG)) (contract-call? .state-v1 set-add-collateral-flag flag))
    (asserts! (not (is-eq action ACTION_SET_REMOVE_COLLATERAL_FLAG)) (contract-call? .state-v1 set-remove-collateral-flag flag))
    (asserts! (not (is-eq action ACTION_SET_BORROW_FLAG)) (contract-call? .state-v1 set-borrow-flag flag))
    (asserts! (not (is-eq action ACTION_SET_REPAY_FLAG)) (contract-call? .state-v1 set-repay-flag flag))
    (asserts! (not (is-eq action ACTION_SET_LIQUIDATION_FLAG)) (contract-call? .state-v1 set-liquidation-flag flag cooldown))
    (asserts! (not (is-eq action ACTION_SET_INTEREST_ACCRUAL_FLAG)) (contract-call? .state-v1 set-interest-accrual-flag flag))
    ERR-INVALID-ACTION
))

(define-private (execute-state-set-market-flag (proposal-id (buff 32)) (action uint))
  (let ((cooldown (unwrap-panic (map-get? unpause-market-data proposal-id))))
    (asserts! (not (is-eq action ACTION_SET_MARKET_PAUSE_FLAG)) (begin 
      (try! (contract-call? .state-v1 pause-market)) 
      (contract-call? .state-v1 set-staking-flag false)))
    (asserts! (not (is-eq action ACTION_SET_MARKET_UNPAUSE_FLAG)) (begin 
      (try! (contract-call? .state-v1 unpause-market cooldown))
      (contract-call? .state-v1 set-staking-flag true)))
    ERR-INVALID-ACTION
))

(define-private (execute-state-update-collateral-settings (proposal-id (buff 32)))
  (let ((settings (unwrap-panic (map-get? collateral-settings-proposal-data proposal-id))))
    (contract-call? .state-v1 update-collateral-settings
      (get collateral settings)
      (get max-ltv settings)
      (get liquidation-ltv settings)
      (get liquidation-premium settings)
      (get decimals settings)
    )
))

(define-private (execute-state-reserve-action (proposal-id (buff 32)) (action uint))
  (let ((amount (unwrap-panic (map-get? reserve-proposal-data proposal-id))))
    (asserts! (not (is-eq action ACTION_DEPOSIT_TO_RESERVE)) (as-contract (contract-call? .state-v1 deposit-to-reserve amount)))
    (asserts! (not (is-eq action ACTION_WITHDRAW_FROM_RESERVE)) (contract-call? .state-v1 withdraw-from-reserve amount))
    ERR-INVALID-ACTION
))

(define-private (execute-state-set-allowed-contract (proposal-id (buff 32)) (action uint))
  (let ((allowed-contract (unwrap-panic (map-get? allowed-contract-data proposal-id))))
    (asserts! (not (is-eq action ACTION_SET_ALLOWED_CONTRACT)) (contract-call? .state-v1 set-allowed-contract allowed-contract))
    (asserts! (not (is-eq action ACTION_REMOVE_ALLOWED_CONTRACT)) (contract-call? .state-v1 remove-allowed-contract allowed-contract))
    ERR-INVALID-ACTION
))

(define-private (is-already-guardian (account principal))
  (default-to false (map-get? guardians account))
)

(define-private (add-guardian (guardian principal))
  (begin
    (asserts! (not (is-already-guardian guardian)) ERR-ALREADY-GUARDIAN)
    (map-set guardians guardian true)
    (print {
      action: "add-guardian",
      guardian: guardian
    })
    SUCCESS
))

(define-private (remove-guardian (guardian principal))
  (begin
    (asserts! (is-already-guardian guardian) ERR-NOT-GUARDIAN)
    (map-delete guardians guardian)
    (print {
      action: "remove-guardian",
      guardian: guardian
    })
    SUCCESS
))

(define-private (execute-update-guardian (proposal-id (buff 32)) (action uint))
  (let ((guardian (unwrap-panic (map-get? update-guardians-proposal-data proposal-id))))
    (asserts! (not (is-eq action ACTION_ADD_GUARDIAN)) (add-guardian guardian))
    (asserts! (not (is-eq action ACTION_REMOVE_GUARDIAN)) (remove-guardian guardian))
    ERR-INVALID-ACTION
))

(define-private (execute-update-interest-rate-params (proposal-id (buff 32)))
  (let ((ir-data (unwrap-panic (map-get? update-interest-rate-params proposal-id))))
    (try! (accrue-interest))
    (contract-call? .linear-kinked-ir-v1 update-ir-params
      (get ir-slope-1-val ir-data)
      (get ir-slope-2-val ir-data)
      (get utilization-kink-val ir-data)
      (get base-ir-val ir-data)
    )
))

(define-private (execute-protocol-reserve-percentage (proposal-id (buff 32)))
  (let ((reserve-value (unwrap-panic (map-get? protocol-reserve-percentage proposal-id))))
    (try! (accrue-interest))
    (contract-call? .state-v1 set-protocol-reserve-percentage reserve-value)
))

(define-private (execute-update-asset-cap (proposal-id (buff 32)))
  (let ((asset-cap (unwrap-panic (map-get? asset-cap-update proposal-id))))
    (contract-call? .state-v1 update-asset-cap asset-cap)
))

(define-private (execute-update-reward-rate-params (proposal-id (buff 32)))
  (let ((reward-data (unwrap-panic (map-get? update-reward-rate-params proposal-id))))
    (try! (accrue-interest))
    (contract-call? .staking-reward-v1 update-reward-params
      (get slope-1-val reward-data)
      (get slope-2-val reward-data)
      (get staked-kink-val reward-data)
      (get base-reward-val reward-data)
    )
))

(define-private (execute-update-withdrawal-finalization-period (proposal-id (buff 32)))
  (let ((new-value (unwrap-panic (map-get? withdrawal-finalization-period proposal-id))))
    (contract-call? .staking-v1 update-withdrawal-finalization-period new-value)
))

(define-private (execute-transfer-funds (proposal-id (buff 32)))
  (let ((transfer-funds-data (unwrap-panic (map-get? transfer-funds proposal-id))))
    (as-contract (try! (contract-call? 'SP120SBRBQJ00MCWS7TM5R8WJNTTKD5K0HFRC2CNE.usdcx transfer (get amount transfer-funds-data) (as-contract contract-caller) (get account transfer-funds-data) none)))
    SUCCESS
))

(define-private (execute-freeze-upgrades)
  (contract-call? .state-v1 freeze-upgrades)
)

(define-private (execute-remove-collateral (proposal-id (buff 32)))
  (let ((collateral (unwrap-panic (map-get? remove-collateral proposal-id))))
    (try! (contract-call? .state-v1 remove-collateral collateral))
    SUCCESS
))

(define-private (execute-reconcile-staking-lp-balance)
  (contract-call? .staking-v1 reconcile-lp-token-balance)
)

(define-private (execute-set-staking-flag (proposal-id (buff 32)))
  (let ((status (unwrap-panic (map-get? staking-flag proposal-id))))
    (contract-call? .state-v1 set-staking-flag status)
))

(define-private (execute-update-time-delta (proposal-id (buff 32)))
  (let ((time-delta (unwrap-panic (map-get? update-time-delta-params proposal-id))))
    (contract-call? .pyth-adapter-v1 update-time-delta time-delta)
))

(define-private (execute-set-lp-cap (proposal-id (buff 32)))
  (let ((data (unwrap-panic (map-get? cap-data proposal-id))))
    (contract-call? .withdrawal-caps-v1 set-lp-cap (get factor data))
))

(define-private (execute-set-debt-cap (proposal-id (buff 32)))
  (let ((data (unwrap-panic (map-get? cap-data proposal-id))))
    (contract-call? .withdrawal-caps-v1 set-debt-cap (get factor data))
))

(define-private (execute-set-collateral-cap (proposal-id (buff 32)))
  (let (
      (data (unwrap-panic (map-get? cap-data proposal-id)))
      (collateral (unwrap-panic (get collateral data)))
      (factor (get factor data))
    )
    (contract-call? .withdrawal-caps-v1 set-collateral-cap collateral factor)
))

(define-private (execute-set-refill-time-window (proposal-id (buff 32)))
  (let ((data (unwrap-panic (map-get? cap-data proposal-id))))
    (contract-call? .withdrawal-caps-v1 set-refill-time-window (get factor data))
))

(define-private (execute-set-decay-time-window (proposal-id (buff 32)))
  (let ((data (unwrap-panic (map-get? cap-data proposal-id))))
    (contract-call? .withdrawal-caps-v1 set-decay-time-window (get factor data))
))

(define-private (execute-update-flash-loan-fee (proposal-id (buff 32)))
  (let ((data (unwrap-panic (map-get? flash-loan-fee-update proposal-id))))
    (contract-call? .flash-loan-v1 update-fee data)
))

(define-private (execute-add-flash-loan-contract (proposal-id (buff 32)))
  (let ((data (unwrap-panic (map-get? flash-loan-contract-update proposal-id))))
    (contract-call? .flash-loan-v1 set-allowed-contract data)
))

(define-private (execute-remove-flash-loan-contract (proposal-id (buff 32)))
  (let ((data (unwrap-panic (map-get? flash-loan-contract-update proposal-id))))
    (contract-call? .flash-loan-v1 remove-allowed-contract data)
))

(define-private (execute-allow-any-contract-flash-loan (proposal-id (buff 32)))
  (let ((data (unwrap-panic (map-get? flash-allow-disable-contract-update proposal-id))))
    (contract-call? .flash-loan-v1 update-allow-any-contract data)
))

(define-private (approve-threshold-met (proposal-id (buff 32)))
  (let (
      (proposal (unwrap! (map-get? governance-proposal proposal-id) ERR-UNKNOWN-PROPOSAL))
      (approve-count (get approve-count proposal))
      (total-count (contract-call? .meta-governance-v1 governance-multisig-count))
      (percentage (/ (* approve-count u100) total-count))
    )
    (ok (>= percentage THRESHOLD))
))

(define-private (deny-threshold-met (proposal-id (buff 32)))
  (let (
      (proposal (unwrap! (map-get? governance-proposal proposal-id) ERR-UNKNOWN-PROPOSAL))
      (deny-count (get deny-count proposal))
      (total-count (contract-call? .meta-governance-v1 governance-multisig-count))
      (percentage (/ (* deny-count u100) total-count))
    )
    (ok (>= percentage THRESHOLD))
))

(define-private (execute-proposal (proposal-id (buff 32)) (action uint))
  (begin
    (asserts! (not (is-eq action ACTION_UPDATE_GOVERNANCE)) (execute-state-governance-update proposal-id))
    (asserts! (not (is-eq action ACTION_FREEZE_UPGRADES)) (execute-freeze-upgrades))
    (asserts! (not (and (>= action ACTION_SET_DEPOSIT_ASSET_FLAG) (<= action ACTION_SET_LIQUIDATION_FLAG))) (execute-state-set-feature-flag proposal-id action))
    (asserts! (not (and (>= action ACTION_SET_MARKET_PAUSE_FLAG) (<= action ACTION_SET_MARKET_UNPAUSE_FLAG))) (execute-state-set-market-flag proposal-id action))
    (asserts! (not (and (>= action ACTION_DEPOSIT_TO_RESERVE) (<= action ACTION_WITHDRAW_FROM_RESERVE))) (execute-state-reserve-action proposal-id action))
    (asserts! (not (is-eq action ACTION_UPDATE_COLLATERAL_SETTINGS)) (execute-state-update-collateral-settings proposal-id))
    (asserts! (not (and (>= action ACTION_SET_ALLOWED_CONTRACT) (<= action ACTION_REMOVE_ALLOWED_CONTRACT))) (execute-state-set-allowed-contract proposal-id action))
    (asserts! (not (and (>= action ACTION_ADD_GUARDIAN) (<= action ACTION_REMOVE_GUARDIAN))) (execute-update-guardian proposal-id action))
    (asserts! (not (is-eq action ACTION_UPDATE_INTEREST_RATE_PARAMS)) (execute-update-interest-rate-params proposal-id))
    (asserts! (not (is-eq action ACTION_UPDATE_REWARD_RATE_PARAMS)) (execute-update-reward-rate-params proposal-id))
    (asserts! (not (is-eq action ACTION_UPDATE_PROTOCOL_RESERVE_PERCENTAGE)) (execute-protocol-reserve-percentage proposal-id))
    (asserts! (not (is-eq action ACTION_UPDATE_ASSET_CAP)) (execute-update-asset-cap proposal-id))
    (asserts! (not (is-eq action ACTION_TRANSFER_FUNDS)) (execute-transfer-funds proposal-id))
    (asserts! (not (is-eq action ACTION_UPDATE_PYTH_TOKEN_FEED)) (execute-update-pyth-token-price-feed proposal-id))
    (asserts! (not (is-eq action ACTION_REMOVE_COLLATERAL)) (execute-remove-collateral proposal-id))
    (asserts! (not (is-eq action ACTION_SET_INTEREST_ACCRUAL_FLAG)) (execute-state-set-feature-flag proposal-id action))
    (asserts! (not (is-eq action ACTION_RECONCILE_STAKING_LP_BALANCE)) (execute-reconcile-staking-lp-balance))
    (asserts! (not (is-eq action ACTION_UPDATE_WITHDRAWAL_FINALIZATION_PERIOD)) (execute-update-withdrawal-finalization-period proposal-id))
    (asserts! (not (is-eq action ACTION_SET_STAKING_FLAG)) (execute-set-staking-flag proposal-id))
    (asserts! (not (is-eq action ACTION_UPDATE_TIME_DELTA)) (execute-update-time-delta proposal-id))
    (asserts! (not (is-eq action ACTION_SET_LP_CAP)) (execute-set-lp-cap proposal-id))
    (asserts! (not (is-eq action ACTION_SET_DEBT_CAP)) (execute-set-debt-cap proposal-id))
    (asserts! (not (is-eq action ACTION_SET_COLLATERAL_CAP)) (execute-set-collateral-cap proposal-id))
    (asserts! (not (is-eq action ACTION_SET_REFILL_TIME_WINDOW)) (execute-set-refill-time-window proposal-id))
    (asserts! (not (is-eq action ACTION_SET_DECAY_TIME_WINDOW)) (execute-set-decay-time-window proposal-id))
    (asserts! (not (is-eq action ACTION_UPDATE_FLASH_LOAN_FEE)) (execute-update-flash-loan-fee proposal-id))
    (asserts! (not (is-eq action ACTION_ADD_CONTRACT_FLASH_LOAN)) (execute-add-flash-loan-contract proposal-id))
    (asserts! (not (is-eq action ACTION_REMOVE_CONTRACT_FLASH_LOAN)) (execute-remove-flash-loan-contract proposal-id))
    (asserts! (not (is-eq action ACTION_ALLOW_ANY_CONTRACT_FLASH_LOAN)) (execute-allow-any-contract-flash-loan proposal-id))
    ERR-INVALID-ACTION
))

(define-private (execute-if-approve-threshold-met (proposal-id (buff 32)))
  (let (
      (proposal (unwrap! (map-get? governance-proposal proposal-id) ERR-UNKNOWN-PROPOSAL))
      (threshold (try! (approve-threshold-met proposal-id)))
      (action (get action proposal))
      (execute-at (get-proposal-execution-time proposal-id))
    )
    (if threshold
      (if (<= execute-at stacks-block-height)
        ;; proposal can be executed immediately
        (begin 
          (try! (execute-proposal proposal-id action))
          (map-set governance-proposal proposal-id (merge proposal {
            closed: true,
            executed: true,
            execute-at: (some stacks-block-height),
          }))
          (print {
            action: "proposal-executed",
            proposal-id: proposal-id
          })
          SUCCESS
        )

        ;; proposal will be executed after time-lock
        (begin
          (map-set governance-proposal proposal-id (merge proposal {
            ;; bump expires at for time locked proposals
            expires-at: (+ TIME_LOCK_EXECUTE_EXPIRATION_PERIOD execute-at),
            closed: false,
            executed: false,
            execute-at: (some execute-at),
          }))
          (print {
            action: "proposal-execution-time-locked",
            proposal-id: proposal-id,
            execute-at: execute-at
          })
          SUCCESS
        )
      )
      SUCCESS
    )
))

(define-private (deny-proposal-if-deny-threshold-met (proposal-id (buff 32)))
  (let (
      (proposal (unwrap! (map-get? governance-proposal proposal-id) ERR-UNKNOWN-PROPOSAL))
      (threshold (try! (deny-threshold-met proposal-id)))
      (action (get action proposal))
    )
    (if threshold
      (begin
        (map-set governance-proposal proposal-id (merge proposal {
          closed: true,
          executed: false,
          execute-at: none,
        }))
        (print {
          action: "proposal-denied",
          proposal-id: proposal-id
        })
        SUCCESS
      )
      SUCCESS
    )
))

(define-private (set-guardians (maybe-account (optional principal)) (res (response bool uint)))
  (if (is-err res) 
    res
    (match maybe-account account (add-guardian account) res)
))

(define-private (accrue-interest)
  (let (
      (accrue-interest-params (unwrap! (contract-call? .state-v1 get-accrue-interest-params) ERR-INTEREST-RATE-PARAMS))
      (accrued-interest (try! (contract-call? .linear-kinked-ir-v1 accrue-interest
        (get last-accrued-block-time accrue-interest-params)
        (get lp-interest accrue-interest-params)
        (get staked-interest accrue-interest-params)
        (try! (contract-call? .staking-reward-v1 calculate-staking-reward-percentage (contract-call? .staking-v1 get-active-staked-lp-tokens)))
        (get protocol-interest accrue-interest-params)
        (get protocol-reserve-percentage accrue-interest-params)
        (get total-assets accrue-interest-params)))
      )
    )
    (contract-call? .state-v1 set-accrued-interest accrued-interest)
))

(define-private (get-proposal-execution-time (proposal-id (buff 32)))
  (let (
    (proposal (unwrap-panic (map-get? governance-proposal proposal-id)))
    (action (get action proposal))
    (is-time-locked (default-to false (map-get? time-locked action)))
    (current-execute-at (get execute-at proposal))
    (execute-at (if is-time-locked (+ stacks-block-height TIME_LOCKED_PERIOD) stacks-block-height))
  )
    (if (is-some current-execute-at) (unwrap-panic current-execute-at) execute-at)
  )
)

;; READ ONLY FUNCTIONS
(define-read-only (is-governance-member (member principal))
  (contract-call? .meta-governance-v1 is-governance-member member)
)

(define-read-only (is-guardian (member principal))
  (begin
    (unwrap! (map-get? guardians member) ERR-NOT-GUARDIAN)
    SUCCESS
))

(define-read-only (get-proposal (proposal-id (buff 32)))
  (map-get? governance-proposal proposal-id)
)
  
;; PUBLIC FUNCTIONS

(define-public (initiate-proposal-to-set-market-feature (action uint) (feature bool) (expires-in uint) (cooldown uint))
  (let (
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        data: feature,
        expires-in: expires-in
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (asserts! (and (>= action ACTION_SET_DEPOSIT_ASSET_FLAG) (<= action ACTION_SET_INTEREST_ACCRUAL_FLAG)) ERR-INVALID-ACTION)
    (try! (create-proposal proposal-id action expires-in))
    (map-set set-market-feature-proposal-data proposal-id {
      flag: feature,
      cooldown: cooldown
    })
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-set-market-state (action uint) (expires-in uint) (cooldown uint))
  (let (
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (asserts! (and (>= action ACTION_SET_MARKET_PAUSE_FLAG) (<= action ACTION_REMOVE_COLLATERAL)) ERR-INVALID-ACTION)
    (map-set unpause-market-data proposal-id cooldown)
    (try! (create-proposal proposal-id action expires-in))
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-freeze-upgrades (expires-in uint))
  (let (
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: ACTION_FREEZE_UPGRADES,
        expires-in: expires-in
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id ACTION_FREEZE_UPGRADES expires-in))
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-governance (new-governance principal) (expires-in uint))
  (let (
      (action ACTION_UPDATE_GOVERNANCE)
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        data: new-governance,
        expires-in: expires-in
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id action expires-in))
    (map-set update-governance-proposal-data proposal-id new-governance)
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-collateral-settings (token <token-trait>) (max-ltv uint) (liquidation-ltv uint) (liquidation-premium uint) (expires-in uint))
  (let (
      (collateral (contract-of token))
      (decimals (unwrap-panic (contract-call? token get-decimals)))
      (action ACTION_UPDATE_COLLATERAL_SETTINGS)
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        data: {
          collateral: collateral,
          max-ltv: max-ltv,
          liquidation-ltv: liquidation-ltv,
          liquidation-premium: liquidation-premium,
          decimals: decimals
        }
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id action expires-in))
    (map-set collateral-settings-proposal-data proposal-id {
      collateral: collateral,
      max-ltv: max-ltv,
      liquidation-ltv: liquidation-ltv,
      liquidation-premium: liquidation-premium,
      decimals: decimals
    })
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-remove-collateral (collateral principal) (expires-in uint))
  (let (
      (action ACTION_REMOVE_COLLATERAL)
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        data: collateral
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id action expires-in))
    (map-set remove-collateral proposal-id collateral)
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-for-reserve-balance (action uint) (amount uint) (expires-in uint))
  (let (
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        data: amount
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (asserts! (and (>= action ACTION_DEPOSIT_TO_RESERVE) (<= action ACTION_WITHDRAW_FROM_RESERVE)) ERR-INVALID-ACTION)
    (try! (create-proposal proposal-id action expires-in))
    (map-set reserve-proposal-data proposal-id amount)
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-allowed-contract (action uint) (allowed-contract principal) (expires-in uint))
  (let (
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        data: allowed-contract
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (asserts! (and (>= action ACTION_SET_ALLOWED_CONTRACT) (<= action ACTION_REMOVE_ALLOWED_CONTRACT)) ERR-INVALID-ACTION)
    (try! (create-proposal proposal-id action expires-in))
    (map-set allowed-contract-data proposal-id allowed-contract)
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-guardians (action uint) (guardian principal) (expires-in uint))
  (let (
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        data: guardian
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (asserts! (and (>= action ACTION_ADD_GUARDIAN) (<= action ACTION_REMOVE_GUARDIAN)) ERR-INVALID-ACTION)
    (if (is-eq action ACTION_ADD_GUARDIAN)
      (asserts! (not (is-already-guardian guardian)) ERR-ALREADY-GUARDIAN)
      (asserts! (is-already-guardian guardian) ERR-NOT-GUARDIAN)
    )
    (try! (create-proposal proposal-id action expires-in))
    (map-set update-guardians-proposal-data proposal-id guardian)
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-interest-params (ir-slope-1-val uint) (ir-slope-2-val uint) (utilization-kink-val uint) (base-ir-val uint) (expires-in uint))
  (let (
      (action ACTION_UPDATE_INTEREST_RATE_PARAMS)
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        data: {
          ir-slope-1-val: ir-slope-1-val,
          ir-slope-2-val: ir-slope-2-val,
          utilization-kink-val: utilization-kink-val,
          base-ir-val: base-ir-val,
        }
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id action expires-in))
    (map-set update-interest-rate-params proposal-id {
      ir-slope-1-val: ir-slope-1-val,
      ir-slope-2-val: ir-slope-2-val,
      utilization-kink-val: utilization-kink-val,
      base-ir-val: base-ir-val,
    })
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-reward-params (slope-1-val int) (slope-2-val int) (staked-kink-val uint) (base-reward-val uint) (expires-in uint))
  (let (
      (action ACTION_UPDATE_REWARD_RATE_PARAMS)
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        data: {
          slope-1-val: slope-1-val,
          slope-2-val: slope-2-val,
          staked-kink-val: staked-kink-val,
          base-reward-val: base-reward-val,
        }
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id action expires-in))
    (map-set update-reward-rate-params proposal-id {
      slope-1-val: slope-1-val,
      slope-2-val: slope-2-val,
      staked-kink-val: staked-kink-val,
      base-reward-val: base-reward-val,
    })
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-withdrawal-finalization-period (withdrawal-period uint) (expires-in uint))
  (let (
      (action ACTION_UPDATE_WITHDRAWAL_FINALIZATION_PERIOD)
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        data: withdrawal-period
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id action expires-in))
    (map-set withdrawal-finalization-period proposal-id withdrawal-period)
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-protocol-reserve-percentage (reserve-percentage uint) (expires-in uint))
  (let (
      (action ACTION_UPDATE_PROTOCOL_RESERVE_PERCENTAGE)
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        data: reserve-percentage
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id action expires-in))
    (map-set protocol-reserve-percentage proposal-id reserve-percentage)
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-asset-cap (asset-cap uint) (expires-in uint))
  (let (
      (action ACTION_UPDATE_ASSET_CAP)
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        data: asset-cap
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id action expires-in))
    (map-set asset-cap-update proposal-id asset-cap)
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-transfer-funds (account principal) (amount uint) (expires-in uint))
  (let (
      (action ACTION_TRANSFER_FUNDS)
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        data: {
          account: account,
          amount: amount
        }
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id action expires-in))
    (map-set transfer-funds proposal-id {account: account, amount: amount})
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-reconcile-staking-lp-balance (expires-in uint))
  (let (
      (action ACTION_RECONCILE_STAKING_LP_BALANCE)
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id action expires-in))
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-set-staking-flag (expires-in uint) (status bool))
  (let (
      (action ACTION_SET_STAKING_FLAG)
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        status: status,
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id action expires-in))
    (map-set staking-flag proposal-id status)
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-pyth-time-delta (expires-in uint) (time-delta uint))
  (let (
      (action ACTION_UPDATE_TIME_DELTA)
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        time-delta: time-delta,
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (asserts! (>= time-delta (contract-call? .pyth-adapter-v1 get-pyth-minimum-time-delta)) ERR-MINIMUM-PYTH-PRICE-DELTA)
    (try! (create-proposal proposal-id action expires-in))
    (map-set update-time-delta-params proposal-id time-delta)
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-withdrawal-caps-param (action uint) (data { collateral: (optional principal), factor: uint }) (expires-in uint))
  (let (
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        data: data,
        expires-in: expires-in
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (asserts! (and (>= action ACTION_SET_LP_CAP) (<= action ACTION_SET_DECAY_TIME_WINDOW)) ERR-INVALID-ACTION)
    (try! (create-proposal proposal-id action expires-in))
    (asserts! (if (is-eq action ACTION_SET_COLLATERAL_CAP)
      (is-some (get collateral data))
      true
    ) ERR-INVALID-ACTION)
    (map-set cap-data proposal-id data)
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-flash-loan-fee (new-fee uint) (expires-in uint))
  (let (
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: ACTION_UPDATE_FLASH_LOAN_FEE,
        new-fee: new-fee,
        expires-in: expires-in
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id ACTION_UPDATE_FLASH_LOAN_FEE expires-in))
    (map-set flash-loan-fee-update proposal-id new-fee)
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-flash-loan-contract (action uint) (contract principal) (expires-in uint))
  (let (
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: action,
        expires-in: expires-in,
        contract: contract,
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (asserts! (and (>= action ACTION_ADD_CONTRACT_FLASH_LOAN) (<= action ACTION_REMOVE_CONTRACT_FLASH_LOAN)) ERR-INVALID-ACTION)
    (try! (create-proposal proposal-id action expires-in))
    (map-set flash-loan-contract-update proposal-id contract)
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initiate-proposal-to-update-allow-any-flash-loan (value bool) (expires-in uint))
  (let (
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: ACTION_ALLOW_ANY_CONTRACT_FLASH_LOAN,
        value: value,
        expires-in: expires-in
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id ACTION_ALLOW_ANY_CONTRACT_FLASH_LOAN expires-in))
    (map-set flash-allow-disable-contract-update proposal-id value)
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))



(define-public (approve (proposal-id (buff 32)))
  (let ((proposal (unwrap! (map-get? governance-proposal proposal-id) ERR-UNKNOWN-PROPOSAL)))
    (try! (is-governance-member contract-caller))
    (asserts! (not (get closed proposal)) ERR-PROPOSAL-CLOSED)
    (asserts! (< stacks-block-height (get expires-at proposal)) ERR-PROPOSAL-EXPIRED)
    (asserts! (not (has-submitted-vote proposal-id)) ERR-SUBMITTED-VOTE)
    (asserts! (is-none (get execute-at proposal)) ERR-CANNOT-VOTE)
    (map-set proposal-approved-members {proposal-id: proposal-id, member: contract-caller} true)
    (map-set governance-proposal proposal-id (merge proposal { approve-count: (+ (get approve-count proposal) u1) }))

    (print {
      action: "proposal-voted-approved",
      voter: contract-caller,
      proposal-id: proposal-id
    })
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    SUCCESS
))

(define-public (deny (proposal-id (buff 32)))
  (let ((proposal (unwrap! (map-get? governance-proposal proposal-id) ERR-UNKNOWN-PROPOSAL)))
    (try! (is-governance-member contract-caller))
    (asserts! (not (get closed proposal)) ERR-PROPOSAL-CLOSED)
    (asserts! (< stacks-block-height (get expires-at proposal)) ERR-PROPOSAL-EXPIRED)
    (asserts! (not (has-submitted-vote proposal-id)) ERR-SUBMITTED-VOTE)
    (asserts! (is-none (get execute-at proposal)) ERR-CANNOT-VOTE)
    (map-set proposal-denied-members {proposal-id: proposal-id, member: contract-caller} true)
    (map-set governance-proposal proposal-id (merge proposal { deny-count: (+ (get deny-count proposal) u1) }))

    (print {
      action: "proposal-voted-denied",
      voter: contract-caller,
      proposal-id: proposal-id
    })
    ;; deny proposal if the deny threshold is met
    (try! (deny-proposal-if-deny-threshold-met proposal-id))
    SUCCESS
))

;; Close the proposal when
;; - Every one voted
;; - But all the votes does not meet neither approve or deny threshold. Proposal is locked.
;; or proposal is expired
(define-public (close (proposal-id (buff 32)))
  (let (
      (proposal (unwrap! (map-get? governance-proposal proposal-id) ERR-UNKNOWN-PROPOSAL))
      (total-voted (+ (get approve-count proposal) (get deny-count proposal)))
      (total-count (contract-call? .meta-governance-v1 governance-multisig-count))
      (deny-threshold (try! (deny-threshold-met proposal-id)))
      (approve-threshold (try! (approve-threshold-met proposal-id)))
      (has-threshold-met (or deny-threshold approve-threshold))
    )
    (try! (is-governance-member contract-caller))
    (asserts! (not (get closed proposal)) ERR-PROPOSAL-CLOSED)
    (if (>= stacks-block-height (get expires-at proposal))
      (begin 
        (print {
          action: "proposal-expired",
          proposal-id: proposal-id
        })
        true
      )
      (begin
        (asserts! (is-eq total-count total-voted) ERR-PROPOSAL-VOTING-INCOMPLETE)
        (asserts! (not has-threshold-met) ERR-PROPOSAL-CANNOT-CLOSE)
      )
    )
    (map-set governance-proposal proposal-id (merge proposal { 
      closed: true,
      executed: false,
      execute-at: none
    }))
    (print {
      action: "proposal-closed",
      proposal-id: proposal-id
    })
    SUCCESS
))

(define-public (execute (proposal-id (buff 32)))
  (let ((proposal (unwrap! (map-get? governance-proposal proposal-id) ERR-UNKNOWN-PROPOSAL)))
    (try! (is-governance-member contract-caller))
    (asserts! (not (get closed proposal)) ERR-PROPOSAL-CLOSED)
    (asserts! (not (get executed proposal)) ERR-PROPOSAL-ALREADY-EXECUTED)
    (asserts! (<= (unwrap! (get execute-at proposal) ERR-PROPOSAL-NOT-TIME-LOCKED) stacks-block-height) ERR-PROPOSAL-TIME-LOCKED)
    (asserts! (< stacks-block-height (get expires-at proposal)) ERR-PROPOSAL-EXPIRED)
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    SUCCESS
))

(define-public (initiate-proposal-to-update-pyth-feed (token principal) (feed (buff 32)) (max-confidence-ratio uint) (expires-in uint))
    (let (
      (proposal-nonce (var-get next-proposal-nonce))
      (proposal-id (keccak256 (unwrap! (to-consensus-buff? {
        sender: contract-caller,
        nonce: proposal-nonce,
        action: ACTION_UPDATE_PYTH_TOKEN_FEED,
        expires-in: expires-in,
        data: {
          feed: feed,
          max-confidence-ratio: max-confidence-ratio
        }
      }) ERR-FAILED-TO-GENERATE-PROPOSAL-ID)))
    )
    (try! (create-proposal proposal-id ACTION_UPDATE_PYTH_TOKEN_FEED expires-in))  
    (map-set update-pyth-feed proposal-id {token: token, feed: feed, max-confidence-ratio: max-confidence-ratio})
    ;; try to execute the proposal if threshold is met
    (try! (execute-if-approve-threshold-met proposal-id))
    (ok proposal-id)
))

(define-public (initialize-governance (guardians-addrs (list 5 (optional principal))))
  (begin
    (asserts! (not (var-get governance-initialized)) ERR-CONTRACT-ALREADY-INITIALIZED)
    (asserts! (is-eq contract-caller contract-deployer) ERR-NOT-CONTRACT-DEPLOYER)
    (var-set governance-initialized true)
    (try! (fold set-guardians guardians-addrs SUCCESS))
    (print {
      action: "initialize-governance",
      meta-governance: .meta-governance-v1,
      guardians: guardians-addrs
    })
    SUCCESS
))

(define-public (guardian-pause-market)
  (begin
    (try! (is-guardian contract-caller))
    (try! (contract-call? .state-v1 pause-market))
    (try! (contract-call? .state-v1 set-staking-flag false))
    SUCCESS
))

(map-set time-locked ACTION_UPDATE_GOVERNANCE true)
(map-set time-locked ACTION_FREEZE_UPGRADES true)
(map-set time-locked ACTION_UPDATE_COLLATERAL_SETTINGS true)
(map-set time-locked ACTION_WITHDRAW_FROM_RESERVE true)
(map-set time-locked ACTION_ADD_GUARDIAN true)
(map-set time-locked ACTION_UPDATE_INTEREST_RATE_PARAMS true)
(map-set time-locked ACTION_UPDATE_PROTOCOL_RESERVE_PERCENTAGE true)
(map-set time-locked ACTION_REMOVE_COLLATERAL true)
(map-set time-locked ACTION_UPDATE_REWARD_RATE_PARAMS true)
(map-set time-locked ACTION_UPDATE_WITHDRAWAL_FINALIZATION_PERIOD true)
(map-set time-locked ACTION_SET_LP_CAP true)
(map-set time-locked ACTION_SET_DEBT_CAP true)
(map-set time-locked ACTION_SET_COLLATERAL_CAP true)
(map-set time-locked ACTION_SET_REFILL_TIME_WINDOW true)
(map-set time-locked ACTION_SET_DECAY_TIME_WINDOW true)
(map-set time-locked ACTION_SET_WITHDRAW_ASSET_FLAG true)
(map-set time-locked ACTION_SET_REMOVE_COLLATERAL_FLAG true)
(map-set time-locked ACTION_SET_REPAY_FLAG true)
(map-set time-locked ACTION_SET_MARKET_PAUSE_FLAG true)
(map-set time-locked ACTION_SET_ALLOWED_CONTRACT true)
(map-set time-locked ACTION_REMOVE_ALLOWED_CONTRACT true)
(map-set time-locked ACTION_SET_STAKING_FLAG true)
(map-set time-locked ACTION_UPDATE_FLASH_LOAN_FEE true)
(map-set time-locked ACTION_ADD_CONTRACT_FLASH_LOAN true)
(map-set time-locked ACTION_REMOVE_CONTRACT_FLASH_LOAN true)
(map-set time-locked ACTION_ALLOW_ANY_CONTRACT_FLASH_LOAN true)

Functions (72)

FunctionAccessArgs
create-proposalprivateproposal-id: (buff 32
has-submitted-voteprivateproposal-id: (buff 32
execute-update-pyth-token-price-feedprivateproposal-id: (buff 32
execute-state-governance-updateprivateproposal-id: (buff 32
execute-state-set-feature-flagprivateproposal-id: (buff 32
execute-state-set-market-flagprivateproposal-id: (buff 32
execute-state-update-collateral-settingsprivateproposal-id: (buff 32
execute-state-reserve-actionprivateproposal-id: (buff 32
execute-state-set-allowed-contractprivateproposal-id: (buff 32
is-already-guardianprivateaccount: principal
add-guardianprivateguardian: principal
remove-guardianprivateguardian: principal
execute-update-guardianprivateproposal-id: (buff 32
execute-update-interest-rate-paramsprivateproposal-id: (buff 32
execute-protocol-reserve-percentageprivateproposal-id: (buff 32
execute-update-asset-capprivateproposal-id: (buff 32
execute-update-reward-rate-paramsprivateproposal-id: (buff 32
execute-update-withdrawal-finalization-periodprivateproposal-id: (buff 32
execute-transfer-fundsprivateproposal-id: (buff 32
execute-freeze-upgradesprivate
execute-remove-collateralprivateproposal-id: (buff 32
execute-reconcile-staking-lp-balanceprivate
execute-set-staking-flagprivateproposal-id: (buff 32
execute-update-time-deltaprivateproposal-id: (buff 32
execute-set-lp-capprivateproposal-id: (buff 32
execute-set-debt-capprivateproposal-id: (buff 32
execute-set-collateral-capprivateproposal-id: (buff 32
execute-set-refill-time-windowprivateproposal-id: (buff 32
execute-set-decay-time-windowprivateproposal-id: (buff 32
execute-update-flash-loan-feeprivateproposal-id: (buff 32
execute-add-flash-loan-contractprivateproposal-id: (buff 32
execute-remove-flash-loan-contractprivateproposal-id: (buff 32
execute-allow-any-contract-flash-loanprivateproposal-id: (buff 32
approve-threshold-metprivateproposal-id: (buff 32
deny-threshold-metprivateproposal-id: (buff 32
execute-proposalprivateproposal-id: (buff 32
execute-if-approve-threshold-metprivateproposal-id: (buff 32
deny-proposal-if-deny-threshold-metprivateproposal-id: (buff 32
set-guardiansprivatemaybe-account: (optional principal
accrue-interestprivate
get-proposal-execution-timeprivateproposal-id: (buff 32
is-governance-memberread-onlymember: principal
is-guardianread-onlymember: principal
get-proposalread-onlyproposal-id: (buff 32
initiate-proposal-to-set-market-featurepublicaction: uint, feature: bool, expires-in: uint, cooldown: uint
initiate-proposal-to-set-market-statepublicaction: uint, expires-in: uint, cooldown: uint
initiate-proposal-to-freeze-upgradespublicexpires-in: uint
initiate-proposal-to-update-governancepublicnew-governance: principal, expires-in: uint
initiate-proposal-to-update-collateral-settingspublictoken: <token-trait>, max-ltv: uint, liquidation-ltv: uint, liquidation-premium: uint, expires-in: uint
initiate-proposal-to-remove-collateralpubliccollateral: principal, expires-in: uint
initiate-proposal-for-reserve-balancepublicaction: uint, amount: uint, expires-in: uint
initiate-proposal-to-update-allowed-contractpublicaction: uint, allowed-contract: principal, expires-in: uint
initiate-proposal-to-update-guardianspublicaction: uint, guardian: principal, expires-in: uint
initiate-proposal-to-update-interest-paramspublicir-slope-1-val: uint, ir-slope-2-val: uint, utilization-kink-val: uint, base-ir-val: uint, expires-in: uint
initiate-proposal-to-update-reward-paramspublicslope-1-val: int, slope-2-val: int, staked-kink-val: uint, base-reward-val: uint, expires-in: uint
initiate-proposal-to-update-withdrawal-finalization-periodpublicwithdrawal-period: uint, expires-in: uint
initiate-proposal-to-update-protocol-reserve-percentagepublicreserve-percentage: uint, expires-in: uint
initiate-proposal-to-update-asset-cappublicasset-cap: uint, expires-in: uint
initiate-proposal-to-transfer-fundspublicaccount: principal, amount: uint, expires-in: uint
initiate-proposal-to-reconcile-staking-lp-balancepublicexpires-in: uint
initiate-proposal-to-set-staking-flagpublicexpires-in: uint, status: bool
initiate-proposal-to-update-pyth-time-deltapublicexpires-in: uint, time-delta: uint
initiate-proposal-to-update-flash-loan-feepublicnew-fee: uint, expires-in: uint
initiate-proposal-to-update-flash-loan-contractpublicaction: uint, contract: principal, expires-in: uint
initiate-proposal-to-update-allow-any-flash-loanpublicvalue: bool, expires-in: uint
approvepublicproposal-id: (buff 32
denypublicproposal-id: (buff 32
closepublicproposal-id: (buff 32
executepublicproposal-id: (buff 32
initiate-proposal-to-update-pyth-feedpublictoken: principal, feed: (buff 32
initialize-governancepublicguardians-addrs: (list 5 (optional principal
guardian-pause-marketpublic