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

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
delete-succession-tierpublictier-level: uint
verify-succession-eligibilitypublic
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