Source Code

;; ============================================================================
;;  Inspired Hook-Enabled Fungible Token Contract with Clarity v4
;; ============================================================================
;; 
;; This contract implements an  style token with:
;; - Send/Receive Hooks for token holders to control token flow
;; - Operators system for delegated token operations
;; - Default operators for pre-approved contracts
;; - Granularity for token divisibility
;; - Data fields for rich transfer context
;;
;; Clarity v4 Functions Used:
;; - contract-hash?: Verify contract integrity
;; - restrict-assets?: Asset restriction management (simulated)
;; - to-ascii?: String conversion for hook data
;; - stacks-block-time: Timestamp for operations
;; - secp256r1-verify: Signature verification for operators
;; ============================================================================

;; ============================================================================
;; CONSTANTS
;; ============================================================================

;; Error codes
(define-constant ERR_UNAUTHORIZED (err u1001))
(define-constant ERR_NOT_OWNER (err u1002))
(define-constant ERR_INSUFFICIENT_BALANCE (err u1003))
(define-constant ERR_INVALID_AMOUNT (err u1004))
(define-constant ERR_ASSETS_RESTRICTED (err u1005))
(define-constant ERR_SIGNATURE_VERIFICATION_FAILED (err u1006))
(define-constant ERR_INVALID_RECIPIENT (err u1007))
(define-constant ERR_INVALID_SENDER (err u1008))
(define-constant ERR_NOT_OPERATOR (err u1009))
(define-constant ERR_CANNOT_REVOKE_SELF (err u1010))
(define-constant ERR_HOOK_REJECTED (err u1011))
(define-constant ERR_GRANULARITY_VIOLATION (err u1012))
(define-constant ERR_INVALID_GRANULARITY (err u1013))
(define-constant ERR_PAUSED (err u1014))
(define-constant ERR_ALREADY_OPERATOR (err u1015))
(define-constant ERR_NOT_AUTHORIZED_OPERATOR (err u1016))
(define-constant ERR_HOOK_NOT_REGISTERED (err u1017))
(define-constant ERR_INVALID_HOOK_CONTRACT (err u1018))
(define-constant ERR_CONVERSION_FAILED (err u1019))
(define-constant ERR_OPERATOR_ALREADY_DEFAULT (err u1020))

;; Token constants
(define-constant TOKEN_NAME u"Hook-Enabled Token")
(define-constant TOKEN_SYMBOL u"HOOK")
(define-constant TOKEN_DECIMALS u18) ;;  requires 18 decimals
(define-constant TOTAL_SUPPLY u1000000000000000000000000) ;; 1 million tokens with 18 decimals
(define-constant TOKEN_GRANULARITY u1) ;; Smallest divisible unit (1 wei equivalent)

;; Contract owner (deployer)
(define-constant CONTRACT_OWNER tx-sender)

;; Default operators list (max 5 for this implementation)
;; These are pre-approved operators for all holders
(define-constant DEFAULT_OPERATORS_COUNT u0) ;; Initially no default operators

;; ============================================================================
;; DATA VARIABLES
;; ============================================================================

;; Contract state
(define-data-var contract-paused bool false)
(define-data-var assets-restricted bool false)
(define-data-var total-minted uint TOTAL_SUPPLY)
(define-data-var total-burned uint u0)

;; Operation tracking
(define-data-var operation-nonce uint u0)
(define-data-var event-nonce uint u0)

;; ============================================================================
;; DATA MAPS
;; ============================================================================

;; Token balances ( balanceOf)
(define-map balances principal uint)

;; Operators mapping: holder -> (operator -> authorized)
;;  authorizeOperator, revokeOperator
(define-map operators { holder: principal, operator: principal } bool)

;; Revoked default operators: holder -> (operator -> revoked)
;; Allows holders to revoke default operators
(define-map revoked-default-operators { holder: principal, operator: principal } bool)

;; Default operators list
(define-map default-operators uint principal)

;; Hook registrations: address -> hook-implementer-contract
;;  ERC1820 registry simulation for tokensToSend and tokensReceived hooks
(define-map tokens-to-send-hooks principal principal)
(define-map tokens-received-hooks principal principal)

;; Hook data storage for verification
(define-map hook-data uint {
  operator: principal,
  from: principal,
  to: principal,
  amount: uint,
  user-data: (buff 256),
  operator-data: (buff 256),
  timestamp: uint,
  hook-type: (string-ascii 20)
})

;; Signature nonces for replay protection
(define-map signature-nonces principal uint)

;; Transfer operations log
(define-map transfer-operations uint {
  operator: principal,
  from: principal,
  to: principal,
  amount: uint,
  user-data: (buff 256),
  operator-data: (buff 256),
  timestamp: uint,
  hooks-called: bool,
  signature-verified: bool
})

;; Event log for comprehensive audit trail
(define-map event-log uint {
  event-type: (string-ascii 32),
  operator: principal,
  holder: principal,
  amount: uint,
  timestamp: uint,
  data-hash: (optional (buff 32))
})

;; ============================================================================
;; INITIALIZATION
;; ============================================================================

;; Initialize contract with total supply to deployer
(map-set balances CONTRACT_OWNER TOTAL_SUPPLY)

;; Log deployment event
(map-set event-log u1 {
  event-type: "contract-deployed",
  operator: CONTRACT_OWNER,
  holder: CONTRACT_OWNER,
  amount: TOTAL_SUPPLY,
  timestamp: stacks-block-time,
  data-hash: none
})
(var-set event-nonce u1)

;; ============================================================================
;; CLARITY V4 FUNCTIONS INTEGRATION
;; ============================================================================

;; Get contract hash using Clarity v4 contract-hash? function
;; Used for verifying contract integrity and security
(define-read-only (get-contract-hash)
  (contract-hash? contract-caller)
)

;; Get specific contract hash for verification
(define-read-only (get-contract-hash-for (contract principal))
  (contract-hash? contract)
)

;; Check if assets are currently restricted
;; Simulates the restrict-assets? functionality
(define-read-only (are-assets-restricted)
  (var-get assets-restricted)
)

;; Convert token name to ASCII using Clarity v4 to-ascii?
(define-read-only (get-token-name-ascii)
  (to-ascii? TOKEN_NAME)
)

;; Convert token symbol to ASCII
(define-read-only (get-token-symbol-ascii)
  (to-ascii? TOKEN_SYMBOL)
)

;; Get current block time using Clarity v4 stacks-block-time
(define-read-only (get-current-block-time)
  stacks-block-time
)

;; Verify secp256r1 signature using Clarity v4 function
(define-private (verify-secp256r1-signature 
  (message-hash (buff 32)) 
  (signature (buff 64)) 
  (public-key (buff 33)))
  (secp256r1-verify message-hash signature public-key)
)

;; ============================================================================
;;  VIEW FUNCTIONS
;; ============================================================================

;; Get token name ( name)
(define-read-only (get-name)
  (ok TOKEN_NAME)
)

;; Get token symbol ( symbol)
(define-read-only (get-symbol)
  (ok TOKEN_SYMBOL)
)

;; Get token granularity ( granularity)
;; Returns the smallest part of the token that's not divisible
(define-read-only (get-granularity)
  (ok TOKEN_GRANULARITY)
)

;; Get total supply ( totalSupply)
(define-read-only (get-total-supply)
  (ok (- (var-get total-minted) (var-get total-burned)))
)

;; Get balance of account ( balanceOf)
(define-read-only (get-balance (holder principal))
  (ok (default-to u0 (map-get? balances holder)))
)

;; Get decimals (ERC-20 compatibility)
(define-read-only (get-decimals)
  (ok TOKEN_DECIMALS)
)

;; ============================================================================
;;  OPERATOR FUNCTIONS
;; ============================================================================

;; Get default operators list ( defaultOperators)
(define-read-only (get-default-operators)
  (ok (list))
)

;; Check if an address is an operator for a holder ( isOperatorFor)
(define-read-only (is-operator-for (operator principal) (holder principal))
  (if (is-eq operator holder)
    ;; A holder is always an operator for itself
    true
    (if (is-default-operator-for operator holder)
      ;; Check if it's a default operator that hasn't been revoked
      true
      ;; Check if explicitly authorized
      (default-to false (map-get? operators { holder: holder, operator: operator }))
    )
  )
)

;; Check if operator is a default operator for holder
(define-private (is-default-operator-for (operator principal) (holder principal))
  (and
    (is-default-operator operator)
    (not (default-to false (map-get? revoked-default-operators { holder: holder, operator: operator })))
  )
)

;; Check if address is a default operator
(define-private (is-default-operator (operator principal))
  false ;; Initially no default operators
)

;; Authorize an operator ( authorizeOperator)
;; Allows a holder to authorize another address to send tokens on their behalf
(define-public (authorize-operator (operator principal))
  (let ((holder tx-sender))
    ;; Cannot authorize self as operator (you're always your own operator)
    (asserts! (not (is-eq operator holder)) ERR_CANNOT_REVOKE_SELF)
    
    ;; Check if contract is paused
    (asserts! (not (var-get contract-paused)) ERR_PAUSED)
    
    ;; Set operator authorization
    (map-set operators { holder: holder, operator: operator } true)
    
    ;; If this was a revoked default operator, remove the revocation
    (map-delete revoked-default-operators { holder: holder, operator: operator })
    
    ;; Emit AuthorizedOperator event
    (log-operator-event "authorized-operator" operator holder)
    
    ;; Print event for indexers
    (print {
      event: "AuthorizedOperator",
      operator: operator,
      holder: holder,
      timestamp: stacks-block-time,
      contract-hash: (get-contract-hash)
    })
    
    (ok true)
  )
)

;; Revoke an operator ( revokeOperator)
(define-public (revoke-operator (operator principal))
  (let ((holder tx-sender))
    ;; Cannot revoke self as operator (you're always your own operator)
    (asserts! (not (is-eq operator holder)) ERR_CANNOT_REVOKE_SELF)
    
    ;; Check if contract is paused
    (asserts! (not (var-get contract-paused)) ERR_PAUSED)
    
    ;; Remove operator authorization
    (map-delete operators { holder: holder, operator: operator })
    
    ;; If this is a default operator, mark as revoked for this holder
    (if (is-default-operator operator)
      (map-set revoked-default-operators { holder: holder, operator: operator } true)
      true
    )
    
    ;; Emit RevokedOperator event
    (log-operator-event "revoked-operator" operator holder)
    
    ;; Print event for indexers
    (print {
      event: "RevokedOperator",
      operator: operator,
      holder: holder,
      timestamp: stacks-block-time
    })
    
    (ok true)
  )
)

;; ============================================================================
;; HOOK REGISTRATION (Registry Simulation)
;; ============================================================================

;; Register tokensToSend hook implementer
;; Register TokensSender implementation
(define-public (register-tokens-to-send-hook (implementer principal))
  (let ((holder tx-sender))
    ;; Verify the implementer contract exists using Clarity v4 contract-hash?
    (asserts! (is-ok (contract-hash? implementer)) ERR_INVALID_HOOK_CONTRACT)
    
    ;; Register the hook implementer
    (map-set tokens-to-send-hooks holder implementer)
    
    ;; Log registration
    (print {
      event: "TokensToSendHookRegistered",
      holder: holder,
      implementer: implementer,
      timestamp: stacks-block-time
    })
    
    (ok true)
  )
)

;; Register tokensReceived hook implementer
;; Register TokensRecipient implementation
(define-public (register-tokens-received-hook (implementer principal))
  (let ((recipient tx-sender))
    ;; Verify the implementer contract exists using Clarity v4 contract-hash?
    (asserts! (is-ok (contract-hash? implementer)) ERR_INVALID_HOOK_CONTRACT)
    
    ;; Register the hook implementer
    (map-set tokens-received-hooks recipient implementer)
    
    ;; Log registration
    (print {
      event: "TokensReceivedHookRegistered",
      recipient: recipient,
      implementer: implementer,
      timestamp: stacks-block-time
    })
    
    (ok true)
  )
)

;; Unregister tokensToSend hook
(define-public (unregister-tokens-to-send-hook)
  (begin
    (map-delete tokens-to-send-hooks tx-sender)
    (ok true)
  )
)

;; Unregister tokensReceived hook
(define-public (unregister-tokens-received-hook)
  (begin
    (map-delete tokens-received-hooks tx-sender)
    (ok true)
  )
)

;; Get tokens-to-send hook implementer for an address
(define-read-only (get-tokens-to-send-hook (holder principal))
  (map-get? tokens-to-send-hooks holder)
)

;; Get tokens-received hook implementer for an address
(define-read-only (get-tokens-received-hook (recipient principal))
  (map-get? tokens-received-hooks recipient)
)

;; ============================================================================
;;  SENDING TOKENS
;; ============================================================================

;; Send tokens ( send)
;; The operator and holder are both msg.sender
(define-public (send-tokens 
  (to principal) 
  (amount uint) 
  (user-data (buff 256)))
  (internal-send tx-sender tx-sender to amount user-data 0x)
)

;; Operator send ( operatorSend)
;; Send tokens on behalf of a holder
(define-public (operator-send 
  (from principal) 
  (to principal) 
  (amount uint) 
  (user-data (buff 256)) 
  (operator-data (buff 256)))
  (let ((operator tx-sender))
    ;; Verify operator is authorized
    (asserts! (is-operator-for operator from) ERR_NOT_OPERATOR)
    
    (internal-send operator from to amount user-data operator-data)
  )
)

;; Operator send with signature verification (Clarity v4 secp256r1-verify)
(define-public (operator-send-with-signature
  (from principal)
  (to principal)
  (amount uint)
  (user-data (buff 256))
  (operator-data (buff 256))
  (nonce uint)
  (signature (buff 64))
  (public-key (buff 33)))
  (let ((operator tx-sender)
        (message-hash (keccak256 (concat 
          (concat (unwrap-panic (to-consensus-buff? from)) (unwrap-panic (to-consensus-buff? to)))
          (concat (unwrap-panic (to-consensus-buff? amount)) (unwrap-panic (to-consensus-buff? nonce)))
        )))
        (current-nonce (default-to u0 (map-get? signature-nonces from))))
    
    ;; Verify nonce for replay protection
    (asserts! (is-eq nonce (+ current-nonce u1)) ERR_SIGNATURE_VERIFICATION_FAILED)
    
    ;; Verify signature using Clarity v4 secp256r1-verify
    (asserts! (verify-secp256r1-signature message-hash signature public-key) ERR_SIGNATURE_VERIFICATION_FAILED)
    
    ;; Verify operator is authorized
    (asserts! (is-operator-for operator from) ERR_NOT_OPERATOR)
    
    ;; Update nonce
    (map-set signature-nonces from nonce)
    
    ;; Perform the send
    (internal-send operator from to amount user-data operator-data)
  )
)

;; Internal send function implementing  rules
(define-private (internal-send 
  (operator principal) 
  (from principal) 
  (to principal) 
  (amount uint) 
  (user-data (buff 256)) 
  (operator-data (buff 256)))
  (let ((from-balance (default-to u0 (map-get? balances from)))
        (to-balance (default-to u0 (map-get? balances to))))
    
    ;; Check if contract is paused
    (asserts! (not (var-get contract-paused)) ERR_PAUSED)
    
    ;; Check if assets are restricted using Clarity v4 function
    (asserts! (not (are-assets-restricted)) ERR_ASSETS_RESTRICTED)
    
    ;; Validate granularity (amount must be multiple of granularity)
    (asserts! (is-eq (mod amount TOKEN_GRANULARITY) u0) ERR_GRANULARITY_VIOLATION)
    
    ;; Check sufficient balance
    (asserts! (>= from-balance amount) ERR_INSUFFICIENT_BALANCE)
    
    ;; Call tokensToSend hook BEFORE updating state
    (try! (call-tokens-to-send-hook operator from to amount user-data operator-data))
    
    ;; Update balances
    (map-set balances from (- from-balance amount))
    (map-set balances to (+ to-balance amount))
    
    ;; Call tokensReceived hook AFTER updating state
    (try! (call-tokens-received-hook operator from to amount user-data operator-data))
    
    ;; Record transfer operation
    (record-transfer-operation operator from to amount user-data operator-data)
    
    ;; Emit Sent event
    (print {
      event: "Sent",
      operator: operator,
      from: from,
      to: to,
      amount: amount,
      user-data: user-data,
      operator-data: operator-data,
      timestamp: stacks-block-time,
      block-height: stacks-block-height
    })
    
    (ok amount)
  )
)

;; ============================================================================
;;  MINTING TOKENS
;; ============================================================================

;; Mint tokens (only owner)
(define-public (mint 
  (to principal) 
  (amount uint) 
  (operator-data (buff 256)))
  (let ((operator tx-sender)
        (to-balance (default-to u0 (map-get? balances to))))
    
    ;; Only owner can mint
    (asserts! (is-eq operator CONTRACT_OWNER) ERR_NOT_OWNER)
    
    ;; Check if contract is paused
    (asserts! (not (var-get contract-paused)) ERR_PAUSED)
    
    ;; Validate granularity
    (asserts! (is-eq (mod amount TOKEN_GRANULARITY) u0) ERR_GRANULARITY_VIOLATION)
    
    ;; Validate amount
    (asserts! (> amount u0) ERR_INVALID_AMOUNT)
    
    ;; Update balance
    (map-set balances to (+ to-balance amount))
    
    ;; Update total minted
    (var-set total-minted (+ (var-get total-minted) amount))
    
    ;; Call tokensReceived hook for the recipient (from is "zero address" for mint)
    (try! (call-tokens-received-hook-for-mint operator to amount operator-data))
    
    ;; Emit Minted event
    (print {
      event: "Minted",
      operator: operator,
      to: to,
      amount: amount,
      operator-data: operator-data,
      timestamp: stacks-block-time
    })
    
    (ok amount)
  )
)

;; ============================================================================
;;  BURNING TOKENS
;; ============================================================================

;; Burn tokens ( burn)
(define-public (burn 
  (amount uint) 
  (user-data (buff 256)))
  (internal-burn tx-sender tx-sender amount user-data 0x)
)

;; Operator burn ( operatorBurn)
(define-public (operator-burn 
  (from principal) 
  (amount uint) 
  (user-data (buff 256)) 
  (operator-data (buff 256)))
  (let ((operator tx-sender))
    ;; Verify operator is authorized
    (asserts! (is-operator-for operator from) ERR_NOT_OPERATOR)
    
    (internal-burn operator from amount user-data operator-data)
  )
)

;; Internal burn function
(define-private (internal-burn 
  (operator principal) 
  (from principal) 
  (amount uint) 
  (user-data (buff 256)) 
  (operator-data (buff 256)))
  (let ((from-balance (default-to u0 (map-get? balances from))))
    
    ;; Check if contract is paused
    (asserts! (not (var-get contract-paused)) ERR_PAUSED)
    
    ;; Validate granularity
    (asserts! (is-eq (mod amount TOKEN_GRANULARITY) u0) ERR_GRANULARITY_VIOLATION)
    
    ;; Check sufficient balance
    (asserts! (>= from-balance amount) ERR_INSUFFICIENT_BALANCE)
    
    ;; Call tokensToSend hook BEFORE updating state (to is "zero address" for burn)
    (try! (call-tokens-to-send-hook-for-burn operator from amount user-data operator-data))
    
    ;; Update balance
    (map-set balances from (- from-balance amount))
    
    ;; Update total burned
    (var-set total-burned (+ (var-get total-burned) amount))
    
    ;; Emit Burned event
    (print {
      event: "Burned",
      operator: operator,
      from: from,
      amount: amount,
      user-data: user-data,
      operator-data: operator-data,
      timestamp: stacks-block-time
    })
    
    (ok amount)
  )
)

;; ============================================================================
;; HOOK CALL FUNCTIONS
;; ============================================================================

;; Call tokensToSend hook for registered holders
;; Returns (response uint (response uint uint)) to match calling context
(define-private (call-tokens-to-send-hook 
  (operator principal) 
  (from principal) 
  (to principal) 
  (amount uint) 
  (user-data (buff 256)) 
  (operator-data (buff 256)))
  (begin
    (match (map-get? tokens-to-send-hooks from)
      hook-implementer (begin
        ;; Store hook call data for verification
        (let ((hook-id (+ (var-get operation-nonce) u1)))
          (map-set hook-data hook-id {
            operator: operator,
            from: from,
            to: to,
            amount: amount,
            user-data: user-data,
            operator-data: operator-data,
            timestamp: stacks-block-time,
            hook-type: "tokens-to-send"
          })
          
          ;; Print hook call for off-chain processing
          (print {
            event: "TokensToSendHookCalled",
            hook-id: hook-id,
            implementer: hook-implementer,
            operator: operator,
            from: from,
            to: to,
            amount: amount,
            timestamp: stacks-block-time
          })
          
          ;; In a real implementation, this would call the hook contract
          ;; Return with explicit error type matching parent context
          (if true (ok u1) ERR_HOOK_REJECTED)
        )
      )
      ;; No hook registered, continue with explicit error type
      (if true (ok u0) ERR_HOOK_REJECTED)
    )
  )
)

;; Call tokensReceived hook for registered recipients
;; Returns (response uint (response uint uint)) to match calling context
(define-private (call-tokens-received-hook 
  (operator principal) 
  (from principal) 
  (to principal) 
  (amount uint) 
  (user-data (buff 256)) 
  (operator-data (buff 256)))
  (begin
    (match (map-get? tokens-received-hooks to)
      hook-implementer (begin
        ;; Store hook call data for verification
        (let ((hook-id (+ (var-get operation-nonce) u1)))
          (map-set hook-data hook-id {
            operator: operator,
            from: from,
            to: to,
            amount: amount,
            user-data: user-data,
            operator-data: operator-data,
            timestamp: stacks-block-time,
            hook-type: "tokens-received"
          })
          
          ;; Print hook call for off-chain processing
          (print {
            event: "TokensReceivedHookCalled",
            hook-id: hook-id,
            implementer: hook-implementer,
            operator: operator,
            from: from,
            to: to,
            amount: amount,
            timestamp: stacks-block-time
          })
          
          ;; Return with explicit error type matching parent context
          (if true (ok u1) ERR_HOOK_REJECTED)
        )
      )
      ;; No hook registered, continue with explicit error type
      (if true (ok u0) ERR_HOOK_REJECTED)
    )
  )
)

;; Call tokensToSend hook for burn (to is conceptually "zero address")
(define-private (call-tokens-to-send-hook-for-burn 
  (operator principal) 
  (from principal) 
  (amount uint) 
  (user-data (buff 256)) 
  (operator-data (buff 256)))
  (call-tokens-to-send-hook operator from CONTRACT_OWNER amount user-data operator-data)
)

;; Call tokensReceived hook for mint (from is conceptually "zero address")
(define-private (call-tokens-received-hook-for-mint 
  (operator principal) 
  (to principal) 
  (amount uint) 
  (operator-data (buff 256)))
  (call-tokens-received-hook operator CONTRACT_OWNER to amount 0x operator-data)
)

;; ============================================================================
;; ADMINISTRATIVE FUNCTIONS
;; ============================================================================

;; Check if contract is paused
(define-read-only (is-paused)
  (var-get contract-paused)
)

;; Pause contract (only owner)
(define-public (pause-contract)
  (begin
    (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_NOT_OWNER)
    (var-set contract-paused true)
    (print {
      event: "ContractPaused",
      by: tx-sender,
      timestamp: stacks-block-time
    })
    (ok true)
  )
)

;; Unpause contract (only owner)
(define-public (unpause-contract)
  (begin
    (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_NOT_OWNER)
    (var-set contract-paused false)
    (print {
      event: "ContractUnpaused",
      by: tx-sender,
      timestamp: stacks-block-time
    })
    (ok true)
  )
)

;; Set asset restrictions (only owner)
;; Demonstrates Clarity v4 restrict-assets? concept
(define-public (set-asset-restrictions (restricted bool))
  (begin
    (asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_NOT_OWNER)
    (var-set assets-restricted restricted)
    (print {
      event: "AssetRestrictionsUpdated",
      restricted: restricted,
      by: tx-sender,
      timestamp: stacks-block-time
    })
    (ok true)
  )
)

;; ============================================================================
;; LOGGING AND UTILITY FUNCTIONS
;; ============================================================================

;; Log operator events
(define-private (log-operator-event 
  (event-type (string-ascii 32)) 
  (operator principal) 
  (holder principal))
  (let ((new-nonce (+ (var-get event-nonce) u1)))
    (map-set event-log new-nonce {
      event-type: event-type,
      operator: operator,
      holder: holder,
      amount: u0,
      timestamp: stacks-block-time,
      data-hash: none
    })
    (var-set event-nonce new-nonce)
  )
)

;; Record transfer operation
(define-private (record-transfer-operation 
  (operator principal) 
  (from principal) 
  (to principal) 
  (amount uint) 
  (user-data (buff 256)) 
  (operator-data (buff 256)))
  (let ((new-nonce (+ (var-get operation-nonce) u1)))
    (map-set transfer-operations new-nonce {
      operator: operator,
      from: from,
      to: to,
      amount: amount,
      user-data: user-data,
      operator-data: operator-data,
      timestamp: stacks-block-time,
      hooks-called: true,
      signature-verified: false
    })
    (var-set operation-nonce new-nonce)
  )
)

;; ============================================================================
;; READ-ONLY QUERY FUNCTIONS
;; ============================================================================

;; Get transfer operation details
(define-read-only (get-transfer-operation (operation-id uint))
  (map-get? transfer-operations operation-id)
)

;; Get hook data
(define-read-only (get-hook-data (hook-id uint))
  (map-get? hook-data hook-id)
)

;; Get event log entry
(define-read-only (get-event-log (event-id uint))
  (map-get? event-log event-id)
)

;; Get signature nonce for address
(define-read-only (get-signature-nonce (address principal))
  (default-to u0 (map-get? signature-nonces address))
)

;; Get contract status with Clarity v4 features
(define-read-only (get-contract-status)
  {
    paused: (var-get contract-paused),
    assets-restricted: (are-assets-restricted),
    total-supply: (- (var-get total-minted) (var-get total-burned)),
    total-minted: (var-get total-minted),
    total-burned: (var-get total-burned),
    granularity: TOKEN_GRANULARITY,
    operation-nonce: (var-get operation-nonce),
    event-nonce: (var-get event-nonce),
    current-block-time: stacks-block-time,
    contract-hash: (get-contract-hash),
    token-name-ascii: (get-token-name-ascii),
    token-symbol-ascii: (get-token-symbol-ascii)
  }
)

;; Get comprehensive token info
(define-read-only (get-token-info)
  {
    name: TOKEN_NAME,
    symbol: TOKEN_SYMBOL,
    decimals: TOKEN_DECIMALS,
    granularity: TOKEN_GRANULARITY,
    total-supply: (- (var-get total-minted) (var-get total-burned)),
    owner: CONTRACT_OWNER
  }
)

;; ============================================================================
;; ERC-20 COMPATIBILITY FUNCTIONS (Optional for )
;; ============================================================================

;; ERC-20 compatible transfer (calls send internally)
(define-public (transfer (to principal) (amount uint) (memo (optional (buff 34))))
  (let ((user-data (default-to 0x memo)))
    ;; Convert memo to buff 256 for send-tokens
    (send-tokens to amount (unwrap-panic (as-max-len? user-data u256)))
  )
)

;; ERC-20 compatible transfer-from (using operator system)
(define-public (transfer-from (from principal) (to principal) (amount uint) (memo (optional (buff 34))))
  (let ((user-data (default-to 0x memo)))
    (operator-send from to amount (unwrap-panic (as-max-len? user-data u256)) 0x)
  )
)

;; ============================================================================
;; CLARITY V4 INTEGRATION SHOWCASE
;; ============================================================================

;; Enhanced send with all Clarity v4 features demonstration
(define-public (send-with-v4-features
  (to principal)
  (amount uint)
  (user-data (buff 256))
  (signature (buff 64))
  (public-key (buff 33))
  (message-hash (buff 32)))
  (let ((from tx-sender))
    
    ;; 1. Check contract hash using Clarity v4 contract-hash?
    (asserts! (is-ok (get-contract-hash)) ERR_UNAUTHORIZED)
    
    ;; 2. Check asset restrictions (simulates restrict-assets?)
    (asserts! (not (are-assets-restricted)) ERR_ASSETS_RESTRICTED)
    
    ;; 3. Verify signature using Clarity v4 secp256r1-verify
    (asserts! (verify-secp256r1-signature message-hash signature public-key) ERR_SIGNATURE_VERIFICATION_FAILED)
    
    ;; 4. Record operation with stacks-block-time timestamp
    (match (internal-send from from to amount user-data 0x)
      success (begin
        ;; 5. Log with ASCII conversion using Clarity v4 to-ascii?
        (print {
          event: "V4EnhancedSend",
          token-name: (get-token-name-ascii),
          token-symbol: (get-token-symbol-ascii),
          amount: amount,
          timestamp: stacks-block-time,
          signature-verified: true
        })
        (ok success)
      )
      error (err error)
    )
  )
)

;; Verify operator authorization with signature (Clarity v4)
(define-public (verify-and-authorize-operator
  (operator principal)
  (signature (buff 64))
  (public-key (buff 33))
  (message-hash (buff 32)))
  (begin
    ;; Verify signature using Clarity v4 secp256r1-verify
    (asserts! (verify-secp256r1-signature message-hash signature public-key) ERR_SIGNATURE_VERIFICATION_FAILED)
    
    ;; Authorize the operator
    (authorize-operator operator)
  )
)

;; ============================================================================
;; SIP-010 COMPATIBILITY (Stacks Fungible Token Standard)
;; ============================================================================

;; Get token URI
(define-read-only (get-token-uri)
  (ok (some u"https://api.hook-token.io/metadata"))
)

;; Get balance (SIP-010 compatible)
(define-read-only (get-balance-of (account principal))
  (get-balance account)
)

Functions (55)

FunctionAccessArgs
get-contract-hashread-only
get-contract-hash-forread-onlycontract: principal
are-assets-restrictedread-only
get-token-name-asciiread-only
get-token-symbol-asciiread-only
get-current-block-timeread-only
verify-secp256r1-signatureprivatemessage-hash: (buff 32
get-nameread-only
get-symbolread-only
get-granularityread-only
get-total-supplyread-only
get-balanceread-onlyholder: principal
get-decimalsread-only
get-default-operatorsread-only
is-operator-forread-onlyoperator: principal, holder: principal
is-default-operator-forprivateoperator: principal, holder: principal
is-default-operatorprivateoperator: principal
authorize-operatorpublicoperator: principal
revoke-operatorpublicoperator: principal
register-tokens-to-send-hookpublicimplementer: principal
register-tokens-received-hookpublicimplementer: principal
unregister-tokens-to-send-hookpublic
unregister-tokens-received-hookpublic
get-tokens-to-send-hookread-onlyholder: principal
get-tokens-received-hookread-onlyrecipient: principal
send-tokenspublicto: principal, amount: uint, user-data: (buff 256
operator-sendpublicfrom: principal, to: principal, amount: uint, user-data: (buff 256
operator-send-with-signaturepublicfrom: principal, to: principal, amount: uint, user-data: (buff 256
internal-sendprivateoperator: principal, from: principal, to: principal, amount: uint, user-data: (buff 256
mintpublicto: principal, amount: uint, operator-data: (buff 256
burnpublicamount: uint, user-data: (buff 256
operator-burnpublicfrom: principal, amount: uint, user-data: (buff 256
internal-burnprivateoperator: principal, from: principal, amount: uint, user-data: (buff 256
call-tokens-to-send-hookprivateoperator: principal, from: principal, to: principal, amount: uint, user-data: (buff 256
call-tokens-received-hookprivateoperator: principal, from: principal, to: principal, amount: uint, user-data: (buff 256
call-tokens-to-send-hook-for-burnprivateoperator: principal, from: principal, amount: uint, user-data: (buff 256
call-tokens-received-hook-for-mintprivateoperator: principal, to: principal, amount: uint, operator-data: (buff 256
is-pausedread-only
pause-contractpublic
unpause-contractpublic
set-asset-restrictionspublicrestricted: bool
log-operator-eventprivateevent-type: (string-ascii 32
record-transfer-operationprivateoperator: principal, from: principal, to: principal, amount: uint, user-data: (buff 256
get-transfer-operationread-onlyoperation-id: uint
get-hook-dataread-onlyhook-id: uint
get-event-logread-onlyevent-id: uint
get-signature-nonceread-onlyaddress: principal
get-contract-statusread-only
get-token-inforead-only
transferpublicto: principal, amount: uint, memo: (optional (buff 34
transfer-frompublicfrom: principal, to: principal, amount: uint, memo: (optional (buff 34
send-with-v4-featurespublicto: principal, amount: uint, user-data: (buff 256
verify-and-authorize-operatorpublicoperator: principal, signature: (buff 64
get-token-uriread-only
get-balance-ofread-onlyaccount: principal