Source Code

;; STX Allowance Contract
;; Allows users to approve others to spend STX on their behalf

;; Constants
(define-constant err-insufficient-allowance (err u100))
(define-constant err-insufficient-balance (err u101))
(define-constant err-transfer-failed (err u102))
(define-constant err-invalid-amount (err u103))
(define-constant err-self-approval (err u104))
(define-constant err-self-transfer (err u105))

;; Data maps
;; Maps owner -> spender -> amount
(define-map allowances 
    {owner: principal, spender: principal}
    {amount: uint}
)

;; Events (using print for event-like functionality)
(define-private (log-approval (owner principal) (spender principal) (amount uint))
    (print {
        event: "approval",
        owner: owner,
        spender: spender,
        amount: amount
    })
)

(define-private (log-transfer (from principal) (to principal) (amount uint))
    (print {
        event: "transfer",
        from: from,
        to: to,
        amount: amount
    })
)

;; Read-only functions

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

;; Get STX balance
(define-read-only (get-balance (wallet principal))
    (ok (stx-get-balance wallet))
)

;; Check if spender can spend a specific amount
(define-read-only (can-spend (owner principal) (spender principal) (amount uint))
    (let
        (
            (current-allowance (get amount (default-to {amount: u0} 
                (map-get? allowances {owner: owner, spender: spender}))))
        )
        (ok (>= current-allowance amount))
    )
)

;; Public functions

;; Approve a spender to spend tokens on behalf of the caller
(define-public (approve (spender principal) (amount uint))
    (begin
        (asserts! (not (is-eq tx-sender spender)) err-self-approval)
        (map-set allowances 
            {owner: tx-sender, spender: spender}
            {amount: amount}
        )
        (log-approval tx-sender spender amount)
        (ok true)
    )
)

;; Increase allowance
(define-public (increase-allowance (spender principal) (increment uint))
    (let
        (
            (current-allowance (get amount (default-to {amount: u0} 
                (map-get? allowances {owner: tx-sender, spender: spender}))))
            (new-allowance (+ current-allowance increment))
        )
        (begin
            (asserts! (not (is-eq tx-sender spender)) err-self-approval)
            (map-set allowances 
                {owner: tx-sender, spender: spender}
                {amount: new-allowance}
            )
            (log-approval tx-sender spender new-allowance)
            (ok new-allowance)
        )
    )
)

;; Decrease allowance
(define-public (decrease-allowance (spender principal) (decrement uint))
    (let
        (
            (current-allowance (get amount (default-to {amount: u0} 
                (map-get? allowances {owner: tx-sender, spender: spender}))))
            (new-allowance (if (>= current-allowance decrement)
                (- current-allowance decrement)
                u0))
        )
        (begin
            (asserts! (not (is-eq tx-sender spender)) err-self-approval)
            (map-set allowances 
                {owner: tx-sender, spender: spender}
                {amount: new-allowance}
            )
            (log-approval tx-sender spender new-allowance)
            (ok new-allowance)
        )
    )
)

;; Transfer tokens directly from sender
(define-public (transfer (amount uint) (recipient principal))
    (begin
        (asserts! (> amount u0) err-invalid-amount)
        (asserts! (not (is-eq tx-sender recipient)) err-self-transfer)
        (asserts! (>= (stx-get-balance tx-sender) amount) err-insufficient-balance)
        
        (match (stx-transfer? amount tx-sender recipient)
            success (begin
                (log-transfer tx-sender recipient amount)
                (ok true)
            )
            error err-transfer-failed
        )
    )
)

;; Transfer tokens from another account using allowance
(define-public (transfer-from (owner principal) (recipient principal) (amount uint))
    (let
        (
            (current-allowance (get amount (default-to {amount: u0} 
                (map-get? allowances {owner: owner, spender: tx-sender}))))
        )
        (begin
            ;; Validation checks
            (asserts! (> amount u0) err-invalid-amount)
            (asserts! (not (is-eq owner recipient)) err-self-transfer)
            (asserts! (>= current-allowance amount) err-insufficient-allowance)
            (asserts! (>= (stx-get-balance owner) amount) err-insufficient-balance)
            
            ;; Execute transfer
            (match (as-contract (stx-transfer? amount owner recipient))
                success (begin
                    ;; Decrease allowance
                    (map-set allowances 
                        {owner: owner, spender: tx-sender}
                        {amount: (- current-allowance amount)}
                    )
                    (log-transfer owner recipient amount)
                    (ok true)
                )
                error err-transfer-failed
            )
        )
    )
)

;; Revoke all allowance for a spender
(define-public (revoke-allowance (spender principal))
    (begin
        (map-delete allowances {owner: tx-sender, spender: spender})
        (log-approval tx-sender spender u0)
        (ok true)
    )
)

Functions (11)

FunctionAccessArgs
log-approvalprivateowner: principal, spender: principal, amount: uint
log-transferprivatefrom: principal, to: principal, amount: uint
get-allowanceread-onlyowner: principal, spender: principal
get-balanceread-onlywallet: principal
can-spendread-onlyowner: principal, spender: principal, amount: uint
approvepublicspender: principal, amount: uint
increase-allowancepublicspender: principal, increment: uint
decrease-allowancepublicspender: principal, decrement: uint
transferpublicamount: uint, recipient: principal
transfer-frompublicowner: principal, recipient: principal, amount: uint
revoke-allowancepublicspender: principal