Source Code

;; YieldForge Strategy Router Contract
;; Routes capital to optimal yield sources with gas-optimized execution

;; Constants
(define-constant CONTRACT-OWNER tx-sender)
(define-constant ERR-NOT-AUTHORIZED (err u200))
(define-constant ERR-INVALID-PROTOCOL (err u201))
(define-constant ERR-INSUFFICIENT-LIQUIDITY (err u202))
(define-constant ERR-ROUTE-NOT-FOUND (err u203))
(define-constant ERR-REBALANCE-FAILED (err u204))
(define-constant ERR-EMERGENCY-ONLY (err u205))
(define-constant ERR-INVALID-VOTE (err u206))
(define-constant ERR-STAKE-REQUIRED (err u207))

;; Fee constants (in basis points)
(define-constant REBALANCING-FEE-BP u10)     ;; 0.1%
(define-constant KEEPER-REWARD-BP u5)        ;; 0.05%
(define-constant FLASH-LOAN-FEE-BP u30)      ;; 0.3%
(define-constant STRATEGY-PROPOSAL-STAKE u10000000) ;; 10 STX

;; Data Variables
(define-data-var emergency-mode bool false)
(define-data-var total-routes uint u0)
(define-data-var keeper-rewards-pool uint u0)
(define-data-var last-keeper-claim-block uint u0)

;; Data Maps

;; Protocol registry for validation (Clarity 4: principal-destruct?)
(define-map registered-protocols
    { protocol-address: principal }
    {
        name: (string-ascii 50),
        active: bool,
        total-routed: uint,
        last-interaction-block: uint,
        risk-rating: uint  ;; 1-10 scale
    }
)

;; Route optimization data (Clarity 4: slice? for efficient parsing)
(define-map routes
    { route-id: uint }
    {
        source-protocol: principal,
        target-protocol: principal,
        estimated-apy: uint,
        gas-cost: uint,
        active: bool,
        success-count: uint,
        failure-count: uint
    }
)

;; Capital allocation tracking
(define-map protocol-allocations
    { protocol-address: principal }
    {
        allocated-amount: uint,
        last-rebalance-block: uint,
        pending-withdrawal: uint
    }
)

;; Strategy proposals (governance)
(define-map strategy-proposals
    { proposal-id: uint }
    {
        proposer: principal,
        target-protocol: principal,
        description: (string-utf8 500),
        stake-amount: uint,
        votes-for: uint,
        votes-against: uint,
        status: (string-ascii 20),  ;; "pending", "active", "rejected"
        created-block: uint
    }
)

;; User votes on strategies
(define-map strategy-votes
    { proposal-id: uint, voter: principal }
    {
        vote-weight: uint,
        vote-type: bool  ;; true = for, false = against
    }
)

;; Keeper registry
(define-map keepers
    { keeper-address: principal }
    {
        total-rebalances: uint,
        earned-rewards: uint,
        last-action-block: uint,
        active: bool
    }
)

;; Emergency withdrawal requests
(define-map emergency-withdrawals
    { user: principal, protocol: principal }
    {
        amount: uint,
        requested-block: uint,
        processed: bool
    }
)

;; Route execution history for optimization
(define-map route-history
    { route-id: uint, execution-block: uint }
    {
        amount-routed: uint,
        gas-used: uint,
        apy-achieved: uint,
        executor: principal
    }
)

;; Data variables for IDs
(define-data-var next-route-id uint u1)
(define-data-var next-proposal-id uint u1)

;; Private Functions

;; Clarity 4: Using principal-destruct? for protocol validation
(define-private (validate-protocol-address (protocol principal))
    (is-ok (principal-destruct? protocol))
)

;; Calculate rebalancing fee
(define-private (calculate-rebalancing-fee (amount uint))
    (/ (* amount REBALANCING-FEE-BP) u10000)
)

;; Calculate keeper reward based on TVL
(define-private (calculate-keeper-reward (tvl uint))
    (/ (* tvl KEEPER-REWARD-BP) u10000)
)

;; Optimize route selection (Clarity 4: slice? for data parsing)
(define-private (find-optimal-route (amount uint) (source principal) (target principal))
    (let (
        (route-data (unwrap! (map-get? routes { route-id: u1 }) 
                            (err ERR-ROUTE-NOT-FOUND)))
    )
        ;; Simple implementation - in production would iterate through routes
        (ok u1)
    )
)

;; Calculate gas efficiency score
(define-private (calculate-gas-efficiency (route-id uint))
    (match (map-get? routes { route-id: route-id })
        route (let (
            (total-executions (+ (get success-count route) (get failure-count route)))
            (success-rate (if (> total-executions u0)
                            (/ (* (get success-count route) u100) total-executions)
                            u0))
        )
            (ok success-rate)
        )
        (err ERR-ROUTE-NOT-FOUND)
    )
)

;; Public Functions

;; Register a new DeFi protocol
(define-public (register-protocol (protocol-address principal) (name (string-ascii 50)) 
                                  (risk-rating uint))
    (begin
        (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
        (asserts! (validate-protocol-address protocol-address) ERR-INVALID-PROTOCOL)
        
        (map-set registered-protocols
            { protocol-address: protocol-address }
            {
                name: name,
                active: true,
                total-routed: u0,
                last-interaction-block: stacks-block-height,
                risk-rating: risk-rating
            }
        )
        
        (ok true)
    )
)

;; Create a route between protocols
(define-public (create-route (source-protocol principal) (target-protocol principal) 
                            (estimated-apy uint) (gas-cost uint))
    (let (
        (route-id (var-get next-route-id))
    )
        (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
        (asserts! (is-some (map-get? registered-protocols { protocol-address: source-protocol }))
                  ERR-INVALID-PROTOCOL)
        (asserts! (is-some (map-get? registered-protocols { protocol-address: target-protocol }))
                  ERR-INVALID-PROTOCOL)
        
        (map-set routes
            { route-id: route-id }
            {
                source-protocol: source-protocol,
                target-protocol: target-protocol,
                estimated-apy: estimated-apy,
                gas-cost: gas-cost,
                active: true,
                success-count: u0,
                failure-count: u0
            }
        )
        
        (var-set next-route-id (+ route-id u1))
        (var-set total-routes (+ (var-get total-routes) u1))
        
        (ok route-id)
    )
)

;; Execute capital routing (gas-optimized)
(define-public (route-capital (route-id uint) (amount uint))
    (let (
        (route (unwrap! (map-get? routes { route-id: route-id }) ERR-ROUTE-NOT-FOUND))
        (rebalancing-fee (calculate-rebalancing-fee amount))
        (net-amount (- amount rebalancing-fee))
        (source-alloc (default-to 
            { allocated-amount: u0, last-rebalance-block: stacks-block-height, pending-withdrawal: u0 }
            (map-get? protocol-allocations { protocol-address: (get source-protocol route) })))
        (target-alloc (default-to 
            { allocated-amount: u0, last-rebalance-block: stacks-block-height, pending-withdrawal: u0 }
            (map-get? protocol-allocations { protocol-address: (get target-protocol route) })))
    )
        (asserts! (not (var-get emergency-mode)) ERR-EMERGENCY-ONLY)
        (asserts! (get active route) ERR-ROUTE-NOT-FOUND)
        (asserts! (>= (get allocated-amount source-alloc) amount) ERR-INSUFFICIENT-LIQUIDITY)
        
        ;; Update source protocol allocation
        (map-set protocol-allocations
            { protocol-address: (get source-protocol route) }
            (merge source-alloc {
                allocated-amount: (- (get allocated-amount source-alloc) amount),
                last-rebalance-block: stacks-block-height
            })
        )
        
        ;; Update target protocol allocation
        (map-set protocol-allocations
            { protocol-address: (get target-protocol route) }
            (merge target-alloc {
                allocated-amount: (+ (get allocated-amount target-alloc) net-amount),
                last-rebalance-block: stacks-block-height
            })
        )
        
        ;; Update route success count
        (map-set routes
            { route-id: route-id }
            (merge route {
                success-count: (+ (get success-count route) u1)
            })
        )
        
        ;; Add to keeper rewards pool
        (var-set keeper-rewards-pool (+ (var-get keeper-rewards-pool) rebalancing-fee))
        
        ;; Record execution history
        (map-set route-history
            { route-id: route-id, execution-block: stacks-block-height }
            {
                amount-routed: amount,
                gas-used: (get gas-cost route),
                apy-achieved: (get estimated-apy route),
                executor: tx-sender
            }
        )
        
        (ok net-amount)
    )
)

;; Propose new strategy (requires 10 STX stake)
(define-public (propose-strategy (target-protocol principal) 
                                (description (string-utf8 500)))
    (let (
        (proposal-id (var-get next-proposal-id))
    )
        (asserts! (is-some (map-get? registered-protocols { protocol-address: target-protocol }))
                  ERR-INVALID-PROTOCOL)
        
        ;; Require stake
        (try! (stx-transfer? STRATEGY-PROPOSAL-STAKE tx-sender (as-contract tx-sender)))
        
        (map-set strategy-proposals
            { proposal-id: proposal-id }
            {
                proposer: tx-sender,
                target-protocol: target-protocol,
                description: description,
                stake-amount: STRATEGY-PROPOSAL-STAKE,
                votes-for: u0,
                votes-against: u0,
                status: "pending",
                created-block: stacks-block-height
            }
        )
        
        (var-set next-proposal-id (+ proposal-id u1))
        
        (ok proposal-id)
    )
)

;; Vote on strategy proposal (requires vault tokens - simplified for demo)
(define-public (vote-on-strategy (proposal-id uint) (vote-for bool) (vote-weight uint))
    (let (
        (proposal (unwrap! (map-get? strategy-proposals { proposal-id: proposal-id }) 
                          ERR-INVALID-VOTE))
    )
        (asserts! (is-eq (get status proposal) "pending") ERR-INVALID-VOTE)
        
        (map-set strategy-votes
            { proposal-id: proposal-id, voter: tx-sender }
            {
                vote-weight: vote-weight,
                vote-type: vote-for
            }
        )
        
        ;; Update proposal votes
        (map-set strategy-proposals
            { proposal-id: proposal-id }
            (merge proposal {
                votes-for: (if vote-for 
                             (+ (get votes-for proposal) vote-weight)
                             (get votes-for proposal)),
                votes-against: (if (not vote-for) 
                                 (+ (get votes-against proposal) vote-weight)
                                 (get votes-against proposal))
            })
        )
        
        (ok true)
    )
)

;; Emergency withdrawal mechanism
(define-public (request-emergency-withdrawal (protocol principal) (amount uint))
    (let (
        (allocation (unwrap! (map-get? protocol-allocations { protocol-address: protocol })
                            ERR-INVALID-PROTOCOL))
    )
        (asserts! (var-get emergency-mode) ERR-EMERGENCY-ONLY)
        
        (map-set emergency-withdrawals
            { user: tx-sender, protocol: protocol }
            {
                amount: amount,
                requested-block: stacks-block-height,
                processed: false
            }
        )
        
        (ok true)
    )
)

;; Process emergency withdrawal (keeper/admin only)
(define-public (process-emergency-withdrawal (user principal) (protocol principal))
    (let (
        (withdrawal (unwrap! (map-get? emergency-withdrawals { user: user, protocol: protocol })
                            ERR-ROUTE-NOT-FOUND))
    )
        (asserts! (var-get emergency-mode) ERR-EMERGENCY-ONLY)
        (asserts! (not (get processed withdrawal)) ERR-REBALANCE-FAILED)
        
        (map-set emergency-withdrawals
            { user: user, protocol: protocol }
            (merge withdrawal {
                processed: true
            })
        )
        
        (ok true)
    )
)

;; Register as keeper
(define-public (register-keeper)
    (begin
        (map-set keepers
            { keeper-address: tx-sender }
            {
                total-rebalances: u0,
                earned-rewards: u0,
                last-action-block: stacks-block-height,
                active: true
            }
        )
        (ok true)
    )
)

;; Claim keeper rewards
(define-public (claim-keeper-rewards)
    (let (
        (keeper (unwrap! (map-get? keepers { keeper-address: tx-sender }) 
                        ERR-NOT-AUTHORIZED))
        (reward-amount (get earned-rewards keeper))
    )
        (asserts! (get active keeper) ERR-NOT-AUTHORIZED)
        (asserts! (> reward-amount u0) ERR-INSUFFICIENT-LIQUIDITY)
        
        ;; Transfer rewards
        (try! (as-contract (stx-transfer? reward-amount tx-sender tx-sender)))
        
        ;; Update keeper record
        (map-set keepers
            { keeper-address: tx-sender }
            (merge keeper {
                earned-rewards: u0,
                last-action-block: stacks-block-height
            })
        )
        
        (ok reward-amount)
    )
)

;; Toggle emergency mode
(define-public (toggle-emergency-mode)
    (begin
        (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
        (var-set emergency-mode (not (var-get emergency-mode)))
        (ok (var-get emergency-mode))
    )
)

;; Update route APY estimate
(define-public (update-route-apy (route-id uint) (new-apy uint))
    (let (
        (route (unwrap! (map-get? routes { route-id: route-id }) ERR-ROUTE-NOT-FOUND))
    )
        (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
        
        (map-set routes
            { route-id: route-id }
            (merge route {
                estimated-apy: new-apy
            })
        )
        
        (ok true)
    )
)

;; Deactivate route
(define-public (deactivate-route (route-id uint))
    (let (
        (route (unwrap! (map-get? routes { route-id: route-id }) ERR-ROUTE-NOT-FOUND))
    )
        (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-AUTHORIZED)
        
        (map-set routes
            { route-id: route-id }
            (merge route {
                active: false
            })
        )
        
        (ok true)
    )
)

;; Read-only Functions

(define-read-only (get-protocol-info (protocol-address principal))
    (map-get? registered-protocols { protocol-address: protocol-address })
)

(define-read-only (get-route-info (route-id uint))
    (map-get? routes { route-id: route-id })
)

(define-read-only (get-protocol-allocation (protocol-address principal))
    (map-get? protocol-allocations { protocol-address: protocol-address })
)

(define-read-only (get-strategy-proposal (proposal-id uint))
    (map-get? strategy-proposals { proposal-id: proposal-id })
)

(define-read-only (get-keeper-info (keeper-address principal))
    (map-get? keepers { keeper-address: keeper-address })
)

(define-read-only (get-route-history (route-id uint) (execution-block uint))
    (map-get? route-history { route-id: route-id, execution-block: execution-block })
)

(define-read-only (is-emergency-mode)
    (ok (var-get emergency-mode))
)

(define-read-only (get-total-routes)
    (ok (var-get total-routes))
)

(define-read-only (get-keeper-rewards-pool)
    (ok (var-get keeper-rewards-pool))
)

;; Calculate optimal route (read-only simulation)
(define-read-only (simulate-route (source principal) (target principal) (amount uint))
    (let (
        (source-protocol (map-get? registered-protocols { protocol-address: source }))
        (target-protocol (map-get? registered-protocols { protocol-address: target }))
    )
        (if (and (is-some source-protocol) (is-some target-protocol))
            (ok {
                estimated-fee: (calculate-rebalancing-fee amount),
                net-amount: (- amount (calculate-rebalancing-fee amount))
            })
            (err ERR-INVALID-PROTOCOL)
        )
    )
)

Functions (27)

FunctionAccessArgs
validate-protocol-addressprivateprotocol: principal
calculate-rebalancing-feeprivateamount: uint
calculate-keeper-rewardprivatetvl: uint
find-optimal-routeprivateamount: uint, source: principal, target: principal
calculate-gas-efficiencyprivateroute-id: uint
register-protocolpublicprotocol-address: principal, name: (string-ascii 50
create-routepublicsource-protocol: principal, target-protocol: principal, estimated-apy: uint, gas-cost: uint
route-capitalpublicroute-id: uint, amount: uint
propose-strategypublictarget-protocol: principal, description: (string-utf8 500
vote-on-strategypublicproposal-id: uint, vote-for: bool, vote-weight: uint
request-emergency-withdrawalpublicprotocol: principal, amount: uint
process-emergency-withdrawalpublicuser: principal, protocol: principal
register-keeperpublic
claim-keeper-rewardspublic
toggle-emergency-modepublic
update-route-apypublicroute-id: uint, new-apy: uint
deactivate-routepublicroute-id: uint
get-protocol-inforead-onlyprotocol-address: principal
get-route-inforead-onlyroute-id: uint
get-protocol-allocationread-onlyprotocol-address: principal
get-strategy-proposalread-onlyproposal-id: uint
get-keeper-inforead-onlykeeper-address: principal
get-route-historyread-onlyroute-id: uint, execution-block: uint
is-emergency-moderead-only
get-total-routesread-only
get-keeper-rewards-poolread-only
simulate-routeread-onlysource: principal, target: principal, amount: uint