Source Code

;; Title: Burn Swap Router - Fixed Version
;; Version: 1.1.0
;; Description: 
;;   Executes a strategy by burning LP tokens, swapping the underlying assets
;;   through multiple hops. Fixed to properly handle multihop return types.

;; Use Traits
(use-trait pool-trait .dexterity-traits-v0.liquidity-pool-trait)
(use-trait ft-trait .charisma-traits-v1.sip010-ft-trait)

;; Constants
(define-constant CONTRACT (as-contract tx-sender))
(define-constant ERR_UNAUTHORIZED (err u403))
(define-constant ERR_INVALID_OPERATION (err u401))
(define-constant ERR_TRANSFER_FAILED (err u402))
(define-constant ERR_MULTIHOP_RESULT (err u404))

;; Opcodes for pool operations
(define-constant OP_SWAP_A_TO_B 0x00)
(define-constant OP_SWAP_B_TO_A 0x01)
(define-constant OP_ADD_LIQUIDITY 0x02)
(define-constant OP_REMOVE_LIQUIDITY 0x03)

;; Helper function to extract final amount from multihop result
(define-private (get-final-amount (multihop-result (list 10 {dx: uint, dy: uint, dk: uint})))
  (get dy (unwrap-panic (element-at multihop-result (- (len multihop-result) u1)))))

;; @desc Execute 0-hop/1-hop burn-swap (Token A no swap, Token B 1-hop)
(define-public (execute-burn-swap-0-1
    (lp-pool <pool-trait>)
    (lp-token <ft-trait>)
    (lp-amount uint)
    (token-a <ft-trait>)
    (token-b-final <ft-trait>)
    (token-b-hop {pool: <pool-trait>, opcode: (optional (buff 16))}))
  (let (
    (sender tx-sender))
    
    ;; Step 1: Transfer LP tokens to contract
    (try! (contract-call? lp-token transfer lp-amount sender CONTRACT none))
    
    ;; Step 2: Burn LP tokens to get underlying assets (dx = token A, dy = token B)
    (let ((burn-result (try! (as-contract (contract-call? lp-pool execute lp-amount (some OP_REMOVE_LIQUIDITY))))))
      
      ;; Step 3: Token A stays as-is, Token B gets swapped via 1-hop
      (let ((token-b-result (try! (as-contract (contract-call? .multihop swap-1 
                                                (get dy burn-result) 
                                                token-b-hop)))))
        
        ;; Step 4: Transfer tokens back to sender using provided token contracts
        (let ((token-a-amount (get dx burn-result))
              (token-b-amount (get-final-amount token-b-result)))
          
          (try! (as-contract (contract-call? token-a transfer token-a-amount CONTRACT sender none)))
          (try! (as-contract (contract-call? token-b-final transfer token-b-amount CONTRACT sender none)))
          
          ;; Return the execution details
          (ok {
            burn-result: burn-result,
            token-a-amount: token-a-amount,
            token-b-multihop: token-b-result
          }))))))

;; @desc Execute 0-hop/2-hop burn-swap (Token A no swap, Token B 2-hop)
(define-public (execute-burn-swap-0-2
    (lp-pool <pool-trait>)
    (lp-token <ft-trait>)
    (lp-amount uint)
    (token-a <ft-trait>)
    (token-b-final <ft-trait>)
    (token-b-hops {hop-1: {pool: <pool-trait>, opcode: (optional (buff 16))}, hop-2: {pool: <pool-trait>, opcode: (optional (buff 16))}}))
  (let (
    (sender tx-sender))
    
    ;; Step 1: Transfer LP tokens to contract
    (try! (contract-call? lp-token transfer lp-amount sender CONTRACT none))
    
    ;; Step 2: Burn LP tokens to get underlying assets (dx = token A, dy = token B)
    (let ((burn-result (try! (as-contract (contract-call? lp-pool execute lp-amount (some OP_REMOVE_LIQUIDITY))))))
      
      ;; Step 3: Token A stays as-is, Token B gets swapped via 2-hop
      (let ((token-b-result (try! (as-contract (contract-call? .multihop swap-2 
                                                (get dy burn-result) 
                                                (get hop-1 token-b-hops) 
                                                (get hop-2 token-b-hops))))))
        
        ;; Step 4: Transfer tokens back to sender using provided token contracts
        (let ((token-a-amount (get dx burn-result))
              (token-b-amount (get-final-amount token-b-result)))
          
          (try! (as-contract (contract-call? token-a transfer token-a-amount CONTRACT sender none)))
          (try! (as-contract (contract-call? token-b-final transfer token-b-amount CONTRACT sender none)))
          
          ;; Return the execution details
          (ok {
            burn-result: burn-result,
            token-a-amount: token-a-amount,
            token-b-multihop: token-b-result
          }))))))

;; @desc Execute 1-hop/0-hop burn-swap (Token A 1-hop, Token B no swap)
(define-public (execute-burn-swap-1-0
    (lp-pool <pool-trait>)
    (lp-token <ft-trait>)
    (lp-amount uint)
    (token-a-final <ft-trait>)
    (token-b <ft-trait>)
    (token-a-hop {pool: <pool-trait>, opcode: (optional (buff 16))}))
  (let (
    (sender tx-sender))
    
    ;; Step 1: Transfer LP tokens to contract
    (try! (contract-call? lp-token transfer lp-amount sender CONTRACT none))
    
    ;; Step 2: Burn LP tokens to get underlying assets (dx = token A, dy = token B)
    (let ((burn-result (try! (as-contract (contract-call? lp-pool execute lp-amount (some OP_REMOVE_LIQUIDITY))))))
      
      ;; Step 3: Token A gets swapped via 1-hop, Token B stays as-is
      (let ((token-a-result (try! (as-contract (contract-call? .multihop swap-1 
                                                (get dx burn-result) 
                                                token-a-hop)))))
        
        ;; Step 4: Transfer tokens back to sender using provided token contracts
        (let ((token-a-amount (get-final-amount token-a-result))
              (token-b-amount (get dy burn-result)))
          
          (try! (as-contract (contract-call? token-a-final transfer token-a-amount CONTRACT sender none)))
          (try! (as-contract (contract-call? token-b transfer token-b-amount CONTRACT sender none)))
          
          ;; Return the execution details
          (ok {
            burn-result: burn-result,
            token-a-multihop: token-a-result,
            token-b-amount: token-b-amount
          }))))))

;; @desc Execute 2-hop/0-hop burn-swap (Token A 2-hop, Token B no swap)
(define-public (execute-burn-swap-2-0
    (lp-pool <pool-trait>)
    (lp-token <ft-trait>)
    (lp-amount uint)
    (token-a-final <ft-trait>)
    (token-b <ft-trait>)
    (token-a-hops {hop-1: {pool: <pool-trait>, opcode: (optional (buff 16))}, hop-2: {pool: <pool-trait>, opcode: (optional (buff 16))}}))
  (let (
    (sender tx-sender))
    
    ;; Step 1: Transfer LP tokens to contract
    (try! (contract-call? lp-token transfer lp-amount sender CONTRACT none))
    
    ;; Step 2: Burn LP tokens to get underlying assets (dx = token A, dy = token B)
    (let ((burn-result (try! (as-contract (contract-call? lp-pool execute lp-amount (some OP_REMOVE_LIQUIDITY))))))
      
      ;; Step 3: Token A gets swapped via 2-hop, Token B stays as-is
      (let ((token-a-result (try! (as-contract (contract-call? .multihop swap-2 
                                                (get dx burn-result) 
                                                (get hop-1 token-a-hops) 
                                                (get hop-2 token-a-hops))))))
        
        ;; Step 4: Transfer tokens back to sender using provided token contracts
        (let ((token-a-amount (get-final-amount token-a-result))
              (token-b-amount (get dy burn-result)))
          
          (try! (as-contract (contract-call? token-a-final transfer token-a-amount CONTRACT sender none)))
          (try! (as-contract (contract-call? token-b transfer token-b-amount CONTRACT sender none)))
          
          ;; Return the execution details
          (ok {
            burn-result: burn-result,
            token-a-multihop: token-a-result,
            token-b-amount: token-b-amount
          }))))))

;; @desc Execute 1-hop/1-hop burn-swap
(define-public (execute-burn-swap-1-1
    (lp-pool <pool-trait>)
    (lp-token <ft-trait>)
    (lp-amount uint)
    (token-a-final <ft-trait>)
    (token-b-final <ft-trait>)
    (token-a-hop {pool: <pool-trait>, opcode: (optional (buff 16))})
    (token-b-hop {pool: <pool-trait>, opcode: (optional (buff 16))}))
  (let (
    (sender tx-sender))
    
    ;; Step 1: Transfer LP tokens to contract
    (try! (contract-call? lp-token transfer lp-amount sender CONTRACT none))
    
    ;; Step 2: Burn LP tokens to get underlying assets (dx = token A, dy = token B)
    (let ((burn-result (try! (as-contract (contract-call? lp-pool execute lp-amount (some OP_REMOVE_LIQUIDITY))))))
      
      ;; Step 3: Execute 1-hop swaps for both tokens using .multihop
      (let ((token-a-result (try! (as-contract (contract-call? .multihop swap-1 
                                                (get dx burn-result) 
                                                token-a-hop))))
            (token-b-result (try! (as-contract (contract-call? .multihop swap-1 
                                                (get dy burn-result) 
                                                token-b-hop)))))
        
        ;; Step 4: Transfer tokens back to sender using provided token contracts
        (let ((token-a-amount (get-final-amount token-a-result))
              (token-b-amount (get-final-amount token-b-result)))
          
          (try! (as-contract (contract-call? token-a-final transfer token-a-amount CONTRACT sender none)))
          (try! (as-contract (contract-call? token-b-final transfer token-b-amount CONTRACT sender none)))
          
          ;; Return the execution details
          (ok {
            burn-result: burn-result,
            token-a-multihop: token-a-result,
            token-b-multihop: token-b-result
          }))))))

;; @desc Execute 1-hop/2-hop burn-swap
(define-public (execute-burn-swap-1-2
    (lp-pool <pool-trait>)
    (lp-token <ft-trait>)
    (lp-amount uint)
    (token-a-final <ft-trait>)
    (token-b-final <ft-trait>)
    (token-a-hop {pool: <pool-trait>, opcode: (optional (buff 16))})
    (token-b-hops {hop-1: {pool: <pool-trait>, opcode: (optional (buff 16))}, hop-2: {pool: <pool-trait>, opcode: (optional (buff 16))}}))
  (let (
    (sender tx-sender))
    
    ;; Step 1: Transfer LP tokens to contract
    (try! (contract-call? lp-token transfer lp-amount sender CONTRACT none))
    
    ;; Step 2: Burn LP tokens to get underlying assets (dx = token A, dy = token B)
    (let ((burn-result (try! (as-contract (contract-call? lp-pool execute lp-amount (some OP_REMOVE_LIQUIDITY))))))
      
      ;; Step 3: Execute swaps using .multihop
      (let ((token-a-result (try! (as-contract (contract-call? .multihop swap-1 
                                                (get dx burn-result) 
                                                token-a-hop))))
            (token-b-result (try! (as-contract (contract-call? .multihop swap-2 
                                                (get dy burn-result) 
                                                (get hop-1 token-b-hops) 
                                                (get hop-2 token-b-hops))))))
        
        ;; Step 4: Transfer tokens back to sender using provided token contracts
        (let ((token-a-amount (get-final-amount token-a-result))
              (token-b-amount (get-final-amount token-b-result)))
          
          (try! (as-contract (contract-call? token-a-final transfer token-a-amount CONTRACT sender none)))
          (try! (as-contract (contract-call? token-b-final transfer token-b-amount CONTRACT sender none)))
          
          ;; Return the execution details
          (ok {
            burn-result: burn-result,
            token-a-multihop: token-a-result,
            token-b-multihop: token-b-result
          }))))))

;; @desc Execute 2-hop/1-hop burn-swap
(define-public (execute-burn-swap-2-1
    (lp-pool <pool-trait>)
    (lp-token <ft-trait>)
    (lp-amount uint)
    (token-a-final <ft-trait>)
    (token-b-final <ft-trait>)
    (token-a-hops {hop-1: {pool: <pool-trait>, opcode: (optional (buff 16))}, hop-2: {pool: <pool-trait>, opcode: (optional (buff 16))}})
    (token-b-hop {pool: <pool-trait>, opcode: (optional (buff 16))}))
  (let (
    (sender tx-sender))
    
    ;; Step 1: Transfer LP tokens to contract
    (try! (contract-call? lp-token transfer lp-amount sender CONTRACT none))
    
    ;; Step 2: Burn LP tokens to get underlying assets (dx = token A, dy = token B)
    (let ((burn-result (try! (as-contract (contract-call? lp-pool execute lp-amount (some OP_REMOVE_LIQUIDITY))))))
      
      ;; Step 3: Execute swaps using .multihop
      (let ((token-a-result (try! (as-contract (contract-call? .multihop swap-2 
                                                (get dx burn-result) 
                                                (get hop-1 token-a-hops) 
                                                (get hop-2 token-a-hops)))))
            (token-b-result (try! (as-contract (contract-call? .multihop swap-1 
                                                (get dy burn-result) 
                                                token-b-hop)))))
        
        ;; Step 4: Transfer tokens back to sender using provided token contracts
        (let ((token-a-amount (get-final-amount token-a-result))
              (token-b-amount (get-final-amount token-b-result)))
          
          (try! (as-contract (contract-call? token-a-final transfer token-a-amount CONTRACT sender none)))
          (try! (as-contract (contract-call? token-b-final transfer token-b-amount CONTRACT sender none)))
          
          ;; Return the execution details
          (ok {
            burn-result: burn-result,
            token-a-multihop: token-a-result,
            token-b-multihop: token-b-result
          }))))))

;; @desc Execute 2-hop/2-hop burn-swap
(define-public (execute-burn-swap-2-2
    (lp-pool <pool-trait>)
    (lp-token <ft-trait>)
    (lp-amount uint)
    (token-a-final <ft-trait>)
    (token-b-final <ft-trait>)
    (token-a-hops {hop-1: {pool: <pool-trait>, opcode: (optional (buff 16))}, hop-2: {pool: <pool-trait>, opcode: (optional (buff 16))}})
    (token-b-hops {hop-1: {pool: <pool-trait>, opcode: (optional (buff 16))}, hop-2: {pool: <pool-trait>, opcode: (optional (buff 16))}}))
  (let (
    (sender tx-sender))
    
    ;; Step 1: Transfer LP tokens to contract
    (try! (contract-call? lp-token transfer lp-amount sender CONTRACT none))
    
    ;; Step 2: Burn LP tokens to get underlying assets (dx = token A, dy = token B)
    (let ((burn-result (try! (as-contract (contract-call? lp-pool execute lp-amount (some OP_REMOVE_LIQUIDITY))))))
      
      ;; Step 3: Execute 2-hop swaps for both tokens using .multihop
      (let ((token-a-result (try! (as-contract (contract-call? .multihop swap-2 
                                                (get dx burn-result) 
                                                (get hop-1 token-a-hops) 
                                                (get hop-2 token-a-hops)))))
            (token-b-result (try! (as-contract (contract-call? .multihop swap-2 
                                                (get dy burn-result) 
                                                (get hop-1 token-b-hops) 
                                                (get hop-2 token-b-hops))))))
        
        ;; Step 4: Transfer tokens back to sender using provided token contracts
        (let ((token-a-amount (get-final-amount token-a-result))
              (token-b-amount (get-final-amount token-b-result)))
          
          (try! (as-contract (contract-call? token-a-final transfer token-a-amount CONTRACT sender none)))
          (try! (as-contract (contract-call? token-b-final transfer token-b-amount CONTRACT sender none)))
          
          ;; Return the execution details
          (ok {
            burn-result: burn-result,
            token-a-multihop: token-a-result,
            token-b-multihop: token-b-result
          }))))))

Functions (9)

FunctionAccessArgs
get-final-amountprivatemultihop-result: (list 10 {dx: uint, dy: uint, dk: uint}
execute-burn-swap-0-1publiclp-pool: <pool-trait>, lp-token: <ft-trait>, lp-amount: uint, token-a: <ft-trait>, token-b-final: <ft-trait>, token-b-hop: {pool: <pool-trait>, opcode: (optional (buff 16
execute-burn-swap-0-2publiclp-pool: <pool-trait>, lp-token: <ft-trait>, lp-amount: uint, token-a: <ft-trait>, token-b-final: <ft-trait>, token-b-hops: {hop-1: {pool: <pool-trait>, opcode: (optional (buff 16
execute-burn-swap-1-0publiclp-pool: <pool-trait>, lp-token: <ft-trait>, lp-amount: uint, token-a-final: <ft-trait>, token-b: <ft-trait>, token-a-hop: {pool: <pool-trait>, opcode: (optional (buff 16
execute-burn-swap-2-0publiclp-pool: <pool-trait>, lp-token: <ft-trait>, lp-amount: uint, token-a-final: <ft-trait>, token-b: <ft-trait>, token-a-hops: {hop-1: {pool: <pool-trait>, opcode: (optional (buff 16
execute-burn-swap-1-1publiclp-pool: <pool-trait>, lp-token: <ft-trait>, lp-amount: uint, token-a-final: <ft-trait>, token-b-final: <ft-trait>, token-a-hop: {pool: <pool-trait>, opcode: (optional (buff 16
execute-burn-swap-1-2publiclp-pool: <pool-trait>, lp-token: <ft-trait>, lp-amount: uint, token-a-final: <ft-trait>, token-b-final: <ft-trait>, token-a-hop: {pool: <pool-trait>, opcode: (optional (buff 16
execute-burn-swap-2-1publiclp-pool: <pool-trait>, lp-token: <ft-trait>, lp-amount: uint, token-a-final: <ft-trait>, token-b-final: <ft-trait>, token-a-hops: {hop-1: {pool: <pool-trait>, opcode: (optional (buff 16
execute-burn-swap-2-2publiclp-pool: <pool-trait>, lp-token: <ft-trait>, lp-amount: uint, token-a-final: <ft-trait>, token-b-final: <ft-trait>, token-a-hops: {hop-1: {pool: <pool-trait>, opcode: (optional (buff 16