Source Code


(define-constant CONTRACT_OWNER tx-sender)
(define-constant ERR_NOT_AUTHORIZED (err u100))
(define-constant ERR_INVALID_TIME (err u101))
(define-constant ERR_INSUFFICIENT_BALANCE (err u102))
(define-constant ERR_INVALID_RECIPIENT (err u103))
(define-constant ERR_INVALID_AMOUNT (err u104))
(define-constant ERR_EMERGENCY_NOT_ACTIVE (err u105))
(define-constant ERR_ALLOWANCE_EXCEEDED (err u106))
(define-constant ERR_INSUFFICIENT_SIGNATURES (err u107))
(define-constant ERR_ALREADY_EXECUTED (err u108))
(define-constant ERR_PAYMENT_INACTIVE (err u109))
(define-constant ERR_INVALID_FREQUENCY (err u110))

;; Data variables
(define-data-var minimum-lock-period uint u1440) ;; minimum lock period in blocks (approximately 10 days)
(define-data-var emergency-withdrawal-fee uint u5) ;; 5% fee for emergency withdrawals
(define-data-var current-block-height uint u0)
(define-data-var transaction-counter uint u0)

(define-map time-locked-savings 
    principal 
    {
        amount: uint,
        unlock-height: uint,
        is-active: bool,
        emergency-contact: (optional principal)
    }
)

(define-map split-payment-settings
    principal
    {
        recipients: (list 10 principal),
        percentages: (list 10 uint),
        is-active: bool
    }
)

;; NEW: Recurring payment map
(define-map recurring-payments
    { owner: principal, payment-id: uint }
    {
        recipient: principal,
        amount: uint,
        frequency: uint, ;; in blocks
        last-payment-height: uint,
        end-height: (optional uint),
        is-active: bool
    }
)

;; NEW: Allowance system map
(define-map allowances
    { owner: principal, spender: principal }
    {
        amount: uint,
        expiry-height: (optional uint)
    }
)

;; NEW: Multi-signature transaction map
(define-map multi-sig-transactions
    { tx-id: uint }
    {
        owner: principal,
        required-signatures: uint,
        signers: (list 10 principal),
        signatures: (list 10 principal),
        recipient: principal,
        amount: uint,
        memo: (optional (buff 34)),
        expiry-height: uint,
        executed: bool
    }
)

;; NEW: Multi-signature settings map
(define-map multi-sig-settings
    principal
    {
        signers: (list 10 principal),
        required-signatures: uint,
        is-active: bool
    }
)

;; Read-only functions
(define-read-only (get-balance (user principal))
    (default-to u0 
        (get amount (map-get? time-locked-savings user))))

(define-read-only (get-unlock-height (user principal))
    (default-to u0 
        (get unlock-height (map-get? time-locked-savings user))))

(define-read-only (get-split-payment-info (user principal))
    (map-get? split-payment-settings user))

(define-read-only (get-emergency-contact (user principal))
    (get emergency-contact (default-to 
        { amount: u0, unlock-height: u0, is-active: false, emergency-contact: none }
        (map-get? time-locked-savings user))))

(define-read-only (get-current-block-height)
    (var-get current-block-height))

;; NEW: Recurring payment read-only functions
(define-read-only (get-recurring-payment (owner principal) (payment-id uint))
    (map-get? recurring-payments { owner: owner, payment-id: payment-id }))

(define-read-only (get-allowance (owner principal) (spender principal))
    (default-to u0 
        (get amount (map-get? allowances { owner: owner, spender: spender }))))

(define-read-only (get-multi-sig-transaction (tx-id uint))
    (map-get? multi-sig-transactions { tx-id: tx-id }))

(define-read-only (get-multi-sig-settings (owner principal))
    (map-get? multi-sig-settings owner))

;; Time-locked savings functions
(define-public (create-time-lock (amount uint) (lock-blocks uint) (emergency-contact (optional principal)))
    (let
        (
            (unlock-at (+ (var-get current-block-height) lock-blocks))
        )
        (asserts! (> amount u0) ERR_INVALID_AMOUNT)
        (asserts! (>= lock-blocks (var-get minimum-lock-period)) ERR_INVALID_TIME)
        (asserts! (>= (stx-get-balance tx-sender) amount) ERR_INSUFFICIENT_BALANCE)
        (try! (stx-transfer? amount tx-sender (as-contract tx-sender)))
        (ok (map-set time-locked-savings tx-sender
            {
                amount: amount,
                unlock-height: unlock-at,
                is-active: true,
                emergency-contact: emergency-contact
            }))))

(define-public (withdraw)
    (let
        (
            (savings-data (unwrap! (map-get? time-locked-savings tx-sender) ERR_NOT_AUTHORIZED))
            (amount (get amount savings-data))
            (unlock-height (get unlock-height savings-data))
        )
        (asserts! (get is-active savings-data) ERR_NOT_AUTHORIZED)
        (asserts! (>= (var-get current-block-height) unlock-height) ERR_INVALID_TIME)
        (map-delete time-locked-savings tx-sender)
        (as-contract (stx-transfer? amount tx-sender tx-sender))))

(define-public (emergency-withdraw)
    (let
        (
            (savings-data (unwrap! (map-get? time-locked-savings tx-sender) ERR_NOT_AUTHORIZED))
            (amount (get amount savings-data))
            (fee-amount (/ (* amount (var-get emergency-withdrawal-fee)) u100))
            (withdrawal-amount (- amount fee-amount))
        )
        (asserts! (get is-active savings-data) ERR_NOT_AUTHORIZED)
        (asserts! (< (var-get current-block-height) (get unlock-height savings-data)) ERR_EMERGENCY_NOT_ACTIVE)
        (map-delete time-locked-savings tx-sender)
        (as-contract (begin
            (try! (stx-transfer? withdrawal-amount tx-sender tx-sender))
            (stx-transfer? fee-amount tx-sender CONTRACT_OWNER)))))

Functions (12)

FunctionAccessArgs
get-balanceread-onlyuser: principal
get-unlock-heightread-onlyuser: principal
get-split-payment-inforead-onlyuser: principal
get-emergency-contactread-onlyuser: principal
get-current-block-heightread-only
get-recurring-paymentread-onlyowner: principal, payment-id: uint
get-allowanceread-onlyowner: principal, spender: principal
get-multi-sig-transactionread-onlytx-id: uint
get-multi-sig-settingsread-onlyowner: principal
create-time-lockpublicamount: uint, lock-blocks: uint, emergency-contact: (optional principal
withdrawpublic
emergency-withdrawpublic