Source Code

;; title: swap-pair
;; version:
;; summary:
;; description:

;; EternalLegacy: Multi-Tiered Endowment Fund with Succession Planning
;; A comprehensive smart contract that enables users to create endowment funds with:
;; - Multi-tiered succession planning (up to 3 levels of successors)
;; - Time-locked inheritance triggers based on inactivity periods
;; - Percentage-based fund distribution to successors
;; - Endowment support voting system
;; - Returns calculation and distribution mechanisms

;; Error Constants
(define-constant ERR-UNAUTHORIZED-ACCESS (err u100))
(define-constant ERR-INSUFFICIENT-FUNDS (err u101))
(define-constant ERR-INVALID-ENDOWMENT-DATA (err u102))
(define-constant ERR-ALREADY-VOTED (err u103))
(define-constant ERR-TRANSACTION-FAILED (err u104))
(define-constant ERR-INVALID-TIER-LEVEL (err u105))
(define-constant ERR-SUCCESSOR-NOT-REGISTERED (err u106))
(define-constant ERR-NOT-DESIGNATED-SUCCESSOR (err u107))
(define-constant ERR-TIMELOCK-ACTIVE (err u108))
(define-constant ERR-INVALID-PARAMETER (err u109))
(define-constant ERR-INVALID-ADDRESS (err u110))
(define-constant ERR-INVALID-NAME (err u111))

;; Contract Constants
(define-constant contract-admin tx-sender)
(define-constant ZERO_ADDRESS 'SP000000000000000000002Q6VF78)
(define-constant MIN-INACTIVITY-PERIOD u1)
(define-constant MAX-ALLOCATION-PERCENTAGE u100)
(define-constant MIN-TIER-LEVEL u1)
(define-constant MAX-TIER-LEVEL u3)
(define-constant MIN-NAME-LENGTH u1)
(define-constant MAX-NAME-LENGTH u64)

;; Fund Data Variables
(define-data-var fund-total-balance uint u0)
(define-data-var fund-generated-returns uint u0)
(define-data-var fund-last-activity-timestamp uint u0)

;; Data Maps
(define-map user-deposits principal uint)
(define-map registered-endowments 
  {endowment-name: (string-ascii 64)} 
  {beneficiary-address: principal, vote-count: uint}
)
(define-map endowment-voter-registry 
  {endowment-name: (string-ascii 64), voter-address: principal} 
  bool
)
(define-map inheritance-configuration 
  {owner-address: principal, tier-level: uint} 
  {inactivity-period: uint, heir-address: principal, allocation-percentage: uint, notification-timestamp: uint}
)
(define-map heir-notification-registry 
  {heir-address: principal, owner-address: principal} 
  {tier-level: uint, inheritance-activation-time: uint, notification-sent: bool}
)



(define-private (update-activity-timestamp)
  (var-set fund-last-activity-timestamp stacks-block-height)
)

(define-private (is-valid-principal (address principal))
  ;; Simply check if the address is not the zero address
  ;; We don't need principal-destruct? for basic validation
  (not (is-eq address ZERO_ADDRESS))
)

(define-private (is-valid-endowment-name (name (string-ascii 64)))
  (and 
    (>= (len name) MIN-NAME-LENGTH)
    (<= (len name) MAX-NAME-LENGTH)
    (not (is-eq name ""))
  )
)

(define-private (is-valid-tier-level (tier uint))
  (and (>= tier MIN-TIER-LEVEL) (<= tier MAX-TIER-LEVEL))
)

(define-private (is-valid-allocation-percentage (percentage uint))
  (<= percentage MAX-ALLOCATION-PERCENTAGE)
)

(define-private (is-valid-inactivity-period (period uint))
  (> period MIN-INACTIVITY-PERIOD)
)



(define-public (compute-fund-returns)
  (let (
    (periodic-returns (/ (* (var-get fund-total-balance) u5) u100)) ;; 5% return simulation
  )
    (var-set fund-generated-returns (+ (var-get fund-generated-returns) periodic-returns))
    (update-activity-timestamp)
    (ok periodic-returns)
  )
)


;; Fund Information Functions
(define-read-only (get-fund-status)
  (ok {
    total-assets: (var-get fund-total-balance),
    undistributed-returns: (var-get fund-generated-returns)
  })
)

;; Endowment Management Functions
(define-public (create-endowment (endowment-name (string-ascii 64)) (beneficiary-address principal))
  ;; Validate all inputs first
  (if (not (is-eq tx-sender contract-admin))
      (err ERR-UNAUTHORIZED-ACCESS)
      (if (not (is-valid-endowment-name endowment-name))
          (err ERR-INVALID-NAME)
          (if (not (is-valid-principal beneficiary-address))
              (err ERR-INVALID-ADDRESS)
              (begin
                (map-set registered-endowments {endowment-name: endowment-name} 
                         {beneficiary-address: beneficiary-address, vote-count: u0})
                (update-activity-timestamp)
                (ok true)
              )
          )
      )
  )
)

(define-public (vote-for-endowment (endowment-name (string-ascii 64)))
  ;; Validate input first
  (if (not (is-valid-endowment-name endowment-name))
      (err ERR-INVALID-NAME)
      ;; Check if endowment exists
      (match (map-get? registered-endowments {endowment-name: endowment-name})
        endowment-record
          (let (
            (has-voted-before (default-to false (map-get? endowment-voter-registry 
                                                {endowment-name: endowment-name, voter-address: tx-sender})))
            (current-votes (get vote-count endowment-record))
          )
            (if has-voted-before
                (err ERR-ALREADY-VOTED)
                (begin
                  (map-set endowment-voter-registry {endowment-name: endowment-name, voter-address: tx-sender} true)
                  (map-set registered-endowments {endowment-name: endowment-name} 
                    (merge endowment-record {vote-count: (+ u1 current-votes)}))
                  (update-activity-timestamp)
                  (ok true)
                )
            )
          )
        (err ERR-INVALID-ENDOWMENT-DATA)
      )
  )
)

;; Succession Planning Functions
(define-public (configure-succession-tier (tier-level uint) (inactivity-period uint) 
                                         (heir-address principal) (allocation-percentage uint))
  ;; Validate all inputs first
  (if (not (is-valid-tier-level tier-level))
      (err ERR-INVALID-TIER-LEVEL)
      (if (not (is-valid-inactivity-period inactivity-period))
          (err ERR-INVALID-PARAMETER)
          (if (not (is-valid-principal heir-address))
              (err ERR-INVALID-ADDRESS)
              (if (not (is-valid-allocation-percentage allocation-percentage))
                  (err ERR-INVALID-PARAMETER)
                  (begin
                    (map-set inheritance-configuration {owner-address: tx-sender, tier-level: tier-level} 
                      {inactivity-period: inactivity-period, heir-address: heir-address, 
                       allocation-percentage: allocation-percentage, notification-timestamp: u0})
                    (update-activity-timestamp)
                    (ok true)
                  )
              )
          )
      )
  )
)

(define-public (delete-succession-tier (tier-level uint))
  ;; Validate input first
  (if (not (is-valid-tier-level tier-level))
      (err ERR-INVALID-TIER-LEVEL)
      (begin
        (map-delete inheritance-configuration {owner-address: tx-sender, tier-level: tier-level})
        (update-activity-timestamp)
        (ok true)
      )
  )
)

(define-read-only (view-succession-tier (owner-address principal) (tier-level uint))
  ;; Validate all inputs first
  (if (not (is-valid-principal owner-address))
      (err ERR-INVALID-ADDRESS)
      (if (not (is-valid-tier-level tier-level))
          (err ERR-INVALID-TIER-LEVEL)
          (match (map-get? inheritance-configuration {owner-address: owner-address, tier-level: tier-level})
            tier-details (ok tier-details)
            (err ERR-SUCCESSOR-NOT-REGISTERED)
          )
      )
  )
)



;; Succession Alert Functions
(define-public (verify-succession-eligibility)
  (let (
    (current-block-height stacks-block-height)
    (last-user-activity (var-get fund-last-activity-timestamp))
  )
    (map-set heir-notification-registry 
      {heir-address: tx-sender, owner-address: contract-admin}
      (merge 
        (default-to 
          {tier-level: u0, inheritance-activation-time: u0, notification-sent: false}
          (map-get? heir-notification-registry {heir-address: tx-sender, owner-address: contract-admin})
        )
        {
          tier-level: (determine-eligible-tier-level tx-sender contract-admin current-block-height last-user-activity),
          inheritance-activation-time: (+ last-user-activity (get-tier-inactivity-period tx-sender contract-admin)),
          notification-sent: true
        }
      )
    )
    (ok true)
  )
)

(define-private (determine-eligible-tier-level (heir-address principal) (owner-address principal) 
                                              (current-time uint) (last-activity uint))
  ;; Validate inputs first
  (if (not (is-valid-principal heir-address))
      u0
      (if (not (is-valid-principal owner-address))
          u0
          (let (
            (tier-one (default-to {inactivity-period: u0, heir-address: ZERO_ADDRESS, 
                                   allocation-percentage: u0, notification-timestamp: u0} 
                        (map-get? inheritance-configuration {owner-address: owner-address, tier-level: u1})))
            (tier-two (default-to {inactivity-period: u0, heir-address: ZERO_ADDRESS, 
                                  allocation-percentage: u0, notification-timestamp: u0} 
                        (map-get? inheritance-configuration {owner-address: owner-address, tier-level: u2})))
            (tier-three (default-to {inactivity-period: u0, heir-address: ZERO_ADDRESS, 
                                    allocation-percentage: u0, notification-timestamp: u0} 
                          (map-get? inheritance-configuration {owner-address: owner-address, tier-level: u3})))
          )
            (if (and (is-eq heir-address (get heir-address tier-three)) 
                     (>= (- current-time last-activity) (get inactivity-period tier-three)))
              u3
              (if (and (is-eq heir-address (get heir-address tier-two)) 
                       (>= (- current-time last-activity) (get inactivity-period tier-two)))
                u2
                (if (and (is-eq heir-address (get heir-address tier-one)) 
                         (>= (- current-time last-activity) (get inactivity-period tier-one)))
                  u1
                  u0
                )
              )
            )
          )
      )
  )
)

(define-private (get-tier-inactivity-period (heir-address principal) (owner-address principal))
  ;; Validate inputs first
  (if (not (is-valid-principal heir-address))
      u0
      (if (not (is-valid-principal owner-address))
          u0
          (let (
            (tier-one (default-to {inactivity-period: u0, heir-address: ZERO_ADDRESS, 
                                  allocation-percentage: u0, notification-timestamp: u0} 
                        (map-get? inheritance-configuration {owner-address: owner-address, tier-level: u1})))
            (tier-two (default-to {inactivity-period: u0, heir-address: ZERO_ADDRESS, 
                                  allocation-percentage: u0, notification-timestamp: u0} 
                        (map-get? inheritance-configuration {owner-address: owner-address, tier-level: u2})))
            (tier-three (default-to {inactivity-period: u0, heir-address: ZERO_ADDRESS, 
                                    allocation-percentage: u0, notification-timestamp: u0} 
                          (map-get? inheritance-configuration {owner-address: owner-address, tier-level: u3})))
          )
            (if (is-eq heir-address (get heir-address tier-three))
              (get inactivity-period tier-three)
              (if (is-eq heir-address (get heir-address tier-two))
                (get inactivity-period tier-two)
                (if (is-eq heir-address (get heir-address tier-one))
                  (get inactivity-period tier-one)
                  u0
                )
              )
            )
          )
      )
  )
)

;; Read-only Information Functions
(define-read-only (get-user-deposit (user-address principal))
  ;; Validate input first
  (if (not (is-valid-principal user-address))
      (err ERR-INVALID-ADDRESS)
      (ok (default-to u0 (map-get? user-deposits user-address)))
  )
)

(define-read-only (get-endowment-details (endowment-name (string-ascii 64)))
  ;; Validate input first
  (if (not (is-valid-endowment-name endowment-name))
      (err ERR-INVALID-NAME)
      (match (map-get? registered-endowments {endowment-name: endowment-name})
        endowment-record (ok endowment-record)
        (err ERR-INVALID-ENDOWMENT-DATA)
      )
  )
)

(define-read-only (get-total-fund-assets)
  (ok (var-get fund-total-balance))
)

(define-read-only (get-undistributed-returns)
  (ok (var-get fund-generated-returns))
)

(define-read-only (get-last-activity-timestamp)
  (ok (var-get fund-last-activity-timestamp))
)

(define-read-only (get-heir-notification-status (heir-address principal) (owner-address principal))
  ;; Validate inputs first
  (if (not (is-valid-principal heir-address))
      (err ERR-INVALID-ADDRESS)
      (if (not (is-valid-principal owner-address))
          (err ERR-INVALID-ADDRESS)
          (match (map-get? heir-notification-registry {heir-address: heir-address, owner-address: owner-address})
            notification-record (ok notification-record)
            (err ERR-NOT-DESIGNATED-SUCCESSOR)
          )
      )
  )
)

Functions (22)

FunctionAccessArgs
update-activity-timestampprivate
is-valid-principalprivateaddress: principal
is-valid-endowment-nameprivatename: (string-ascii 64
is-valid-tier-levelprivatetier: uint
is-valid-allocation-percentageprivatepercentage: uint
is-valid-inactivity-periodprivateperiod: uint
compute-fund-returnspublic
get-fund-statusread-only
create-endowmentpublicendowment-name: (string-ascii 64
vote-for-endowmentpublicendowment-name: (string-ascii 64
configure-succession-tierpublictier-level: uint, inactivity-period: uint, heir-address: principal, allocation-percentage: uint
delete-succession-tierpublictier-level: uint
view-succession-tierread-onlyowner-address: principal, tier-level: uint
verify-succession-eligibilitypublic
determine-eligible-tier-levelprivateheir-address: principal, owner-address: principal, current-time: uint, last-activity: uint
get-tier-inactivity-periodprivateheir-address: principal, owner-address: principal
get-user-depositread-onlyuser-address: principal
get-endowment-detailsread-onlyendowment-name: (string-ascii 64
get-total-fund-assetsread-only
get-undistributed-returnsread-only
get-last-activity-timestampread-only
get-heir-notification-statusread-onlyheir-address: principal, owner-address: principal