;; title: intent-filler-impl
;; version: 1.0.0
;; summary: Intent Filler Implementation
;; description: Implements a cross-chain intent filler by facilitating token transfers between chains.
;; Traits:
;; - ft-trait: SIP-010 fungible token interface for token operations.
;; - connection-contract: connection interface for cross-chain message verification.
(use-trait ft-trait .sip-010-trait.sip-010-trait)
(use-trait connection-contract .connection-trait.connection-trait)
;; Constants:
;; - Defined error codes for clear revert reasons.
(define-constant err-not-admin (err u3100))
(define-constant err-not-connection-contract (err u3101))
(define-constant err-amount-invalid (err u3102))
(define-constant err-already-initialized (err u3103))
(define-constant err-signature-verification-failed (err u3104))
(define-constant err-token-mismatch (err u3105))
(define-constant err-withdraw-failed (err u3106))
(define-constant err-not-sent-from-hub (err u3107))
(define-constant err-not-hub-intent (err u3108))
(define-constant err-fill-already-exists (err u3109))
(define-constant err-receiver-address-invalid (err u3110))
(define-constant err-fill-not-found (err u3111))
(define-constant err-not-filler (err u3112))
(define-constant err-invalid-chain-id (err u3113))
;; - NATIVE_TOKEN constant representing the native token principal.
(define-constant NATIVE_TOKEN 'ST000000000000000000002AMW42H.nativetoken)
;; Public Functions:
;; - init: Initialize contract with connection, hub chain ID, and hub intent contract.
;; - set-intent-filler-impl: Admin function to update intent filler implementation address.
;; - set-connection-impl: Admin function to update connection implementation address.
;; - set-admin: Admin function to update admin principal.
;; - fill-intent: Create and store a fill intent; deposits tokens.
;; - cancel-fill: Cancel an existing fill and withdraw tokens.
;; - recv-message: Receive and verify cross-chain messages; execute fills.
;; - get-remaining: Read-only function to decode payload and retrieve remaining params for recv-message.
;; - is-admin: Read-only function that asserts the caller is admin.
;; - is-not-initialized: Read-only function that asserts contract is not initialized.
;; Private Functions:
;; - are-token-matched: Validate the token trait passed matches the expected token.
;; - decode-fill: Decode a fill message from raw bytes.
;; - encode-fill-response: Encode a fill response message for sending.
;; --- Initialization ---
;; Initializes the contract with the connection contract, hub chain ID, and hub intent contract.
;; Only callable by admin and if contract not already initialized.
(define-public (init (connection principal) (hub-chain-id uint) (hub-intent (buff 256)))
(begin
(try! (is-admin))
(try! (is-not-initialized))
(asserts! (> hub-chain-id u0) err-invalid-chain-id)
(try! (contract-call? .intent-filler-state set-connection-impl connection))
(try! (contract-call? .intent-filler-state set-hub-chain-id hub-chain-id))
(try! (contract-call? .intent-filler-state set-hub-intent hub-intent))
(ok true)
)
)
;; --- Admin Setter Functions ---
;; All require caller to be admin.
;;
;; Updates the intent filler implementation contract principal.
(define-public (set-intent-filler-impl (who principal))
(begin
(try! (is-admin))
(contract-call? .intent-filler-state set-intent-filler-impl who)
)
)
;; Updates the connection implementation contract principal.
(define-public (set-connection-impl (who principal))
(begin
(try! (is-admin))
(contract-call? .intent-filler-state set-connection-impl who)
)
)
;; --- Fill Management ---
;; Creates a fill intent by storing its hash and depositing the specified amount of tokens.
;; Requires the fill not to already exist and valid token matching.
;; Emits "FillCreated" event on success.
(define-public (fill-intent
(intent-data
{ fill-id: uint,
intent-hash: (buff 32),
solver: (buff 100),
receiver: (buff 100),
token: (buff 100),
amount: uint})
(token (optional <ft-trait>))
)
(let (
(amount (get amount intent-data))
(receiver (get receiver intent-data))
(fill-hash (keccak256 (unwrap-panic (to-consensus-buff? intent-data))))
(filled (contract-call? .intent-filler-state is-hash-filled fill-hash))
)
(try! (are-token-matched token (get token intent-data)))
(asserts! (> amount u0) err-amount-invalid)
(asserts! (> (len receiver) u0) err-receiver-address-invalid)
(asserts! (not filled) err-fill-already-exists)
(try! (contract-call? .intent-filler-state deposit token amount))
(try! (contract-call? .intent-filler-state set-fill fill-hash true))
(try! (contract-call? .intent-filler-state set-filler fill-hash contract-caller))
(ok (print {
event: "FillCreated",
creator: contract-caller,
fill-hash: fill-hash,
amount: amount
}))
)
)
;; Cancels a previously created fill if the caller is the filler.
;; Removes stored fill and filler records, withdraws tokens to caller.
;; Emits "FillCancelled" event on success.
(define-public (cancel-fill
(intent-data
{ fill-id: uint,
intent-hash: (buff 32),
solver: (buff 100),
receiver: (buff 100),
token: (buff 100),
amount: uint})
(token (optional <ft-trait>))
)
(let (
(amount (get amount intent-data))
(fill-hash (keccak256 (unwrap-panic (to-consensus-buff? intent-data))))
(filled (contract-call? .intent-filler-state is-hash-filled fill-hash))
(filler (unwrap! (contract-call? .intent-filler-state get-filler fill-hash) err-not-filler))
)
(try! (are-token-matched token (get token intent-data)))
(asserts! filled err-fill-not-found)
(asserts! (is-eq contract-caller filler) err-not-filler)
(try! (contract-call? .intent-filler-state delete-fill fill-hash))
(try! (contract-call? .intent-filler-state delete-filler fill-hash))
(try! (contract-call? .intent-filler-state withdraw token amount contract-caller))
(ok (print {
event: "FillCancelled",
canceller: contract-caller,
fill-hash: fill-hash,
amount: amount
}))
)
)
;; --- Cross-Chain Message Receiver ---
;; Verifies and processes cross-chain fill messages.
;; Checks that the connection contract matches the stored approved contract.
;; Verifies message signatures via connection contract.
;; Confirms message is from authorized hub chain and hub intent contract.
;; Decodes fill message and, if a fill exists, executes withdrawal to the receiver and deletes fill record.
;; Sends a fill-response message back to the hub.
(define-public (recv-message
(src-chain-id uint)
(src-address (buff 256))
(conn-sn uint)
(payload (buff 4096))
(signatures (list 50 (buff 65)))
(connection <connection-contract>)
(token (optional <ft-trait>))
)
(let (
(current-connection-contract (contract-call? .intent-filler-state get-connection-impl))
)
;; Ensure the connection contract is correct
(asserts!
(is-eq (contract-of connection) current-connection-contract)
err-not-connection-contract
)
;; Ensure the message is sent from the hub chain and the hub intent contract
(asserts!
(is-eq src-chain-id (contract-call? .intent-filler-state get-hub-chain-id))
err-not-sent-from-hub
)
(asserts!
(is-eq src-address (unwrap-panic (contract-call? .intent-filler-state get-hub-intent)))
err-not-hub-intent
)
;; Verify message signature
(try!
(contract-call? .intent-filler-state verify-message src-chain-id src-address conn-sn payload signatures connection)
)
(let (
(message (unwrap-panic (decode-fill payload)))
(fill-id (get fill-id message))
(intent-hash (get intent-hash message))
(solver (get solver message))
(receiver (unwrap-panic (from-consensus-buff? principal (get receiver message))))
(amount (get amount message))
(fill-hash (keccak256 (unwrap-panic (to-consensus-buff? message))))
(has-fill (contract-call? .intent-filler-state is-hash-filled fill-hash))
(fill-response (encode-fill-response fill-id (if has-fill u1 u0)))
)
;; Ensure token matches the one expected
(try! (are-token-matched token (get token message)))
;; Execute fill if it exists
(if has-fill
(begin
(try! (contract-call? .intent-filler-state delete-fill fill-hash))
(try! (contract-call? .intent-filler-state delete-filler fill-hash))
(try! (contract-call? .intent-filler-state withdraw token amount receiver))
(print {
event: "FillExecuted",
fill-hash: fill-hash,
receiver: receiver,
amount: amount
})
true
)
true
)
;; Send the fill-response back to the hub
(ok (try!
(contract-call? .intent-filler-state send-message src-chain-id src-address fill-response connection)
))
;; (ok true)
)
)
)
;; --- Utility Functions ---
;; Checks that the token matches the one expected
(define-private (are-token-matched (token (optional <ft-trait>)) (token-buff (buff 4096)))
(let (
(token-addr (unwrap-panic (from-consensus-buff? principal token-buff)))
(token-trait (match token ft-token (contract-of ft-token) NATIVE_TOKEN))
)
(ok (asserts! (is-eq token-trait token-addr) err-token-mismatch))
)
)
;; Encode and Decode
(define-private (decode-fill (raw (buff 4096)))
(let (
(rlp-list (contract-call? .rlp-decode rlp-to-list raw))
(fill-id (contract-call? .rlp-decode rlp-decode-uint rlp-list u0))
(intent-hash (unwrap-panic (element-at? rlp-list u1)))
(solver (unwrap-panic (element-at? rlp-list u2)))
(receiver (unwrap-panic (element-at? rlp-list u3)))
(token (unwrap-panic (element-at? rlp-list u4)))
(amount (contract-call? .rlp-decode rlp-decode-uint rlp-list u5))
)
(ok {
fill-id: fill-id,
intent-hash: intent-hash,
solver: solver,
receiver: receiver,
token: token,
amount: amount
})
)
)
;; Encodes a fill response message (fill ID and filled flag) into RLP bytes.
(define-private (encode-fill-response (fill-id uint) (filled uint))
(contract-call? .rlp-encode encode-arr
(list
(contract-call? .rlp-encode encode-uint fill-id)
(contract-call? .rlp-encode encode-uint filled)
)
)
)
;; read only functions
(define-read-only (get-remaining (payload (buff 4096)))
(let (
(message (unwrap-panic (decode-fill payload)))
(token-addr (unwrap-panic (from-consensus-buff? principal (get token message))))
(token-trait (if (is-eq token-addr NATIVE_TOKEN) none (some token-addr)))
)
{token: token-trait}
))
;; guard read only functions
(define-read-only (is-admin)
(ok (asserts! (is-eq contract-caller (contract-call? .intent-filler-state get-admin)) err-not-admin))
)
(define-read-only (is-not-initialized)
(ok (asserts! (is-eq (contract-call? .intent-filler-state get-hub-chain-id) u0) err-already-initialized))
)