diff --git a/contracts/stacks/.gitattributes b/contracts/stacks/.gitattributes new file mode 100644 index 000000000..da6a0655a --- /dev/null +++ b/contracts/stacks/.gitattributes @@ -0,0 +1,3 @@ +tests/** linguist-vendored +vitest.config.js linguist-vendored +* text=lf diff --git a/contracts/stacks/.gitignore b/contracts/stacks/.gitignore new file mode 100644 index 000000000..76c2842b1 --- /dev/null +++ b/contracts/stacks/.gitignore @@ -0,0 +1,13 @@ + +**/settings/Mainnet.toml +**/settings/Testnet.toml +.cache/** +history.txt + +logs +*.log +npm-debug.log* +coverage +*.info +costs-reports.json +node_modules diff --git a/contracts/stacks/Clarinet.toml b/contracts/stacks/Clarinet.toml new file mode 100644 index 000000000..5ccb72249 --- /dev/null +++ b/contracts/stacks/Clarinet.toml @@ -0,0 +1,74 @@ +[project] +name = 'stacks' +description = '' +authors = [] +telemetry = true +cache_dir = './.cache' +requirements = [] +[contracts.centralized-connection] +path = 'contracts/connections/centralized-connection.clar' +clarity_version = 2 +epoch = 2.5 + +[contracts.debug] +path = 'contracts/debug.clar' +clarity_version = 3 +epoch = 3.0 + +[contracts.mock-dapp] +path = 'tests/mocks/mock-dapp.clar' +clarity_version = 2 +epoch = 2.5 + +[contracts.rlp-decode] +path = 'lib/rlp/rlp-decode.clar' +clarity_version = 2 +epoch = 2.5 + +[contracts.rlp-encode] +path = 'lib/rlp/rlp-encode.clar' +clarity_version = 2 +epoch = 2.5 + +[contracts.util] +path = 'contracts/util.clar' +clarity_version = 2 +epoch = 2.5 + +[contracts.xcall-common-trait] +path = 'contracts/xcall/xcall-common-trait.clar' +clarity_version = 2 +epoch = 2.5 + +[contracts.xcall-impl] +path = 'contracts/xcall/xcall-impl.clar' +clarity_version = 2 +epoch = 2.5 + +[contracts.xcall-impl-trait] +path = 'contracts/xcall/xcall-impl-trait.clar' +clarity_version = 2 +epoch = 2.5 + +[contracts.xcall-proxy] +path = 'contracts/xcall/xcall-proxy.clar' +clarity_version = 2 +epoch = 2.5 + +[contracts.xcall-proxy-trait] +path = 'contracts/xcall/xcall-proxy-trait.clar' +clarity_version = 2 +epoch = 2.5 + +[contracts.xcall-receiver-trait] +path = 'contracts/xcall/xcall-receiver-trait.clar' +clarity_version = 2 +epoch = 2.5 +[repl.analysis] +passes = ['check_checker'] + +[repl.analysis.check_checker] +strict = false +trusted_sender = false +trusted_caller = false +callee_filter = false diff --git a/contracts/stacks/contracts/connections/centralized-connection.clar b/contracts/stacks/contracts/connections/centralized-connection.clar new file mode 100644 index 000000000..09aa29d16 --- /dev/null +++ b/contracts/stacks/contracts/connections/centralized-connection.clar @@ -0,0 +1,102 @@ +(use-trait xcall-impl-trait .xcall-impl-trait.xcall-impl-trait) + +(define-constant ERR_UNAUTHORIZED (err u900)) +(define-constant ERR_INVALID_FEE (err u901)) +(define-constant ERR_DUPLICATE_MESSAGE (err u902)) +(define-constant ERR_XCALL_NOT_SET (err u903)) + +(define-data-var xcall (optional principal) none) +(define-data-var admin principal tx-sender) +(define-data-var conn-sn int 0) + +(define-map message-fees {network-id: (string-ascii 128)} uint) +(define-map response-fees {network-id: (string-ascii 128)} uint) +(define-map receipts {network-id: (string-ascii 128), conn-sn: int} bool) + +(define-read-only (get-xcall) + (ok (var-get xcall))) + +(define-read-only (get-admin) + (ok (var-get admin))) + +(define-read-only (get-conn-sn) + (ok (var-get conn-sn))) + +(define-read-only (get-fee (to (string-ascii 128)) (response bool)) + (let + ((message-fee (default-to u0 (map-get? message-fees {network-id: to})))) + (if response + (let + ((response-fee (default-to u0 (map-get? response-fees {network-id: to})))) + (ok (+ message-fee response-fee))) + (ok message-fee)))) + +(define-read-only (get-receipt (src-network (string-ascii 128)) (conn-sn-in int)) + (ok (default-to false (map-get? receipts {network-id: src-network, conn-sn: conn-sn-in})))) + +(define-private (is-admin) + (is-eq tx-sender (var-get admin))) + +(define-private (is-xcall) + (match (var-get xcall) + xcall-contract (is-eq tx-sender xcall-contract) + false + )) + +(define-private (is-authorized) + (or + (is-xcall) + (is-admin))) + +(define-public (initialize (xcall-contract principal) (admin-address principal)) + (begin + (asserts! (is-admin) ERR_UNAUTHORIZED) + (var-set xcall (some xcall-contract)) + (var-set admin admin-address) + (ok true))) + +(define-public (set-fee (network-id (string-ascii 128)) (message-fee uint) (response-fee uint)) + (begin + (asserts! (is-admin) ERR_UNAUTHORIZED) + (map-set message-fees {network-id: network-id} message-fee) + (map-set response-fees {network-id: network-id} response-fee) + (ok true))) + +(define-public (claim-fees) + (begin + (asserts! (is-admin) ERR_UNAUTHORIZED) + (as-contract (stx-transfer? (stx-get-balance (as-contract tx-sender)) tx-sender (var-get admin))))) + +(define-public (set-admin (new-admin principal)) + (begin + (asserts! (is-admin) ERR_UNAUTHORIZED) + (var-set admin new-admin) + (ok true))) + +(define-private (emit-message-event (to (string-ascii 128)) (sn int) (msg (buff 2048))) + (print + { + event: "Message", + to: to, + sn: sn, + msg: msg + } + ) +) + +(define-public (send-message (to (string-ascii 128)) (svc (string-ascii 128)) (sn int) (msg (buff 2048))) + (begin + (asserts! (is-authorized) ERR_UNAUTHORIZED) + (let + ((fee (unwrap! (get-fee to (> sn 0)) ERR_INVALID_FEE))) + (asserts! (>= (stx-get-balance tx-sender) fee) ERR_INVALID_FEE) + (var-set conn-sn (+ (var-get conn-sn) 1)) + (emit-message-event to (var-get conn-sn) msg) + (ok (var-get conn-sn))))) + +(define-public (recv-message (src-network-id (string-ascii 128)) (conn-sn-in int) (msg (buff 2048)) (implementation )) + (begin + (asserts! (is-authorized) ERR_UNAUTHORIZED) + (asserts! (is-none (map-get? receipts {network-id: src-network-id, conn-sn: conn-sn-in})) ERR_DUPLICATE_MESSAGE) + (map-set receipts {network-id: src-network-id, conn-sn: conn-sn-in} true) + (as-contract (contract-call? .xcall-proxy handle-message src-network-id msg implementation)))) \ No newline at end of file diff --git a/contracts/stacks/contracts/debug.clar b/contracts/stacks/contracts/debug.clar new file mode 100644 index 000000000..2e6f30e53 --- /dev/null +++ b/contracts/stacks/contracts/debug.clar @@ -0,0 +1,118 @@ +(define-public (debug-execute-call-failure) + (let + ( + ;; Initialize xcall-impl + (init-impl-result (unwrap! (contract-call? .xcall-impl init "stacks" "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.xcall-impl") (err u800))) + + ;; Set admin for xcall-impl + (set-admin-result (unwrap! (contract-call? .xcall-impl set-admin tx-sender) (err u800))) + + ;; Initialize mock-dapp + (init-result (unwrap! (contract-call? .mock-dapp initialize .xcall-proxy) (err u800))) + + ;; Upgrade proxy to implementation + (upgrade-result (unwrap! (contract-call? .xcall-proxy upgrade .xcall-impl none) (err u800))) + + ;; Initialize centralized connection + (init-connection-result (unwrap! (contract-call? .centralized-connection initialize .xcall-proxy tx-sender) (err u800))) + + ;; Set default connections + (set-default-connection-stacks (unwrap! (contract-call? .xcall-proxy set-default-connection + "stacks" + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.centralized-connection" + .xcall-impl) + (err u800))) + + (set-default-connection-test (unwrap! (contract-call? .xcall-proxy set-default-connection + "test" + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.centralized-connection" + .xcall-impl) + (err u800))) + + ;; Set protocol fee handler + (set-protocol-fee-handler-result (unwrap! (contract-call? .xcall-proxy set-protocol-fee-handler + .centralized-connection + .xcall-impl) + (err u800))) + + ;; Set fees for both networks + (set-fee-stacks-result (unwrap! (contract-call? .centralized-connection set-fee + "stacks" + u500000 + u250000) + (err u800))) + + (set-fee-icon-result (unwrap! (contract-call? .centralized-connection set-fee + "test" + u1000000 + u500000) + (err u800))) + + ;; Set protocol fee + (set-protocol-fee-result (unwrap! (contract-call? .xcall-proxy set-protocol-fee + u100000 + .xcall-impl) + (err u800))) + + ;; Set up mock-dapp connections + (add-dapp-connection-stacks (unwrap! (contract-call? .mock-dapp add-connection + "stacks" + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.centralized-connection" + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.centralized-connection") + (err u800))) + + (add-dapp-connection-icon (unwrap! (contract-call? .mock-dapp add-connection + "test" + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.centralized-connection" + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.centralized-connection") + (err u800))) + + ;; Rest of the original code... + (encoded-result (contract-call? .rlp-encode encode-string "rollback")) + (test-protocols (list)) + (from-address "stacks/ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM") + (req-id u1) + (from "stacks/ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM") + (to "test/ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM") + (sn u1) + (messageData (contract-call? .rlp-encode encode-arr + (list + (contract-call? .rlp-encode encode-string from) + (contract-call? .rlp-encode encode-string to) + (contract-call? .rlp-encode encode-uint sn) + (contract-call? .rlp-encode encode-uint req-id) + encoded-result + (contract-call? .rlp-encode encode-arr (list)) + ))) + (messageData-prefix (unwrap-panic (element-at? messageData u0))) + (csMessageRequest (contract-call? .rlp-encode encode-arr + (list + (contract-call? .rlp-encode encode-uint u1) ;; CS_MESSAGE_TYPE_REQUEST + messageData + ))) + (csMessageRequest-prefix (unwrap-panic (element-at? csMessageRequest u0))) + (prefixes { + message-prefix: messageData-prefix, + request-prefix: csMessageRequest-prefix + }) + (handle-result (unwrap-panic (contract-call? .xcall-proxy handle-message "stacks" csMessageRequest .xcall-impl))) + ) + (contract-call? + .xcall-proxy + execute-call + req-id + encoded-result + .mock-dapp + .xcall-impl + .xcall-impl + ) + ) +) + +(define-public (debug-address-conversion) + (contract-call? + .util + address-string-to-principal + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.centralized-connection" + ) +) \ No newline at end of file diff --git a/contracts/stacks/contracts/util.clar b/contracts/stacks/contracts/util.clar new file mode 100644 index 000000000..1ae116f03 --- /dev/null +++ b/contracts/stacks/contracts/util.clar @@ -0,0 +1,71 @@ +(define-constant C32SET "0123456789ABCDEFGHJKMNPQRSTVWXYZ") + +(define-constant ERR_INVALID_ADDRESS (err u1000)) +(define-constant ERR_INVALID_CONTRACT_NAME (err u1001)) + +(define-data-var addr-var (buff 400) 0x) + +(define-public (address-string-to-principal (address (string-ascii 128))) + (let ( + (period-index (index-of address ".")) + ) + (if (is-some period-index) + (let ( + (address-part (unwrap-panic (slice? address u0 (unwrap-panic period-index)))) + (contract-name-part (unwrap-panic (slice? address u42 (len address)))) + ) + (begin + (asserts! (is-eq (unwrap-panic period-index) u41) ERR_INVALID_ADDRESS) + (asserts! (is-valid-c32 address-part) ERR_INVALID_ADDRESS) + (ok (unwrap-panic (c32-decode address-part (as-max-len? contract-name-part u40)))) + ) + ) + (begin + (asserts! (is-eq (len address) u41) ERR_INVALID_ADDRESS) + (asserts! (is-valid-c32 address) ERR_INVALID_ADDRESS) + (ok (unwrap-panic (c32-decode address none))) + ) + ) + ) +) + +(define-private (c32-decode-aux (input (string-ascii 1)) (res {bit-buff: uint, bits-remaining: uint})) + (let ((index (unwrap-panic (index-of? C32SET input))) + (bit-buff (bit-or (bit-shift-left (get bit-buff res) u5) index)) + (bits-remaining (+ (get bits-remaining res) u5))) + (if (>= bits-remaining u8) + (let ((char (to-buff (bit-and (bit-shift-right bit-buff (- bits-remaining u8)) u255))) + (bits-remaining1 (- bits-remaining u8)) + (bit-buff1 (bit-and bit-buff (- (bit-shift-left u1 bits-remaining1) u1)))) + (set (unwrap-panic (as-max-len? (var-get addr-var) u399)) char) + (tuple (bit-buff bit-buff1) (bits-remaining bits-remaining1))) + (tuple (bit-buff bit-buff) (bits-remaining bits-remaining))))) + +(define-private (c32-decode (address (string-ascii 128)) (contract-name (optional (string-ascii 40)))) + (begin + (var-set addr-var 0x) + (fold c32-decode-aux (unwrap-panic (slice? address u1 (- (len address) u5))) (tuple (bit-buff u0) (bits-remaining u0))) + (let ((version (to-buff (unwrap-panic (index-of? C32SET (unwrap-panic (element-at? address u1)))))) + (pub-key-hash (unwrap-panic (slice? (var-get addr-var) u1 u21)))) + (if (is-some contract-name) + (principal-construct? version (unwrap-panic (as-max-len? pub-key-hash u20)) (unwrap-panic contract-name)) + (principal-construct? version (unwrap-panic (as-max-len? pub-key-hash u20))) + ) + ) + ) +) + +(define-private (set (address (buff 399)) (char (buff 1))) + (var-set addr-var (concat address char))) + +(define-private (to-buff (data uint)) + (begin + (let ((encoded (unwrap-panic (to-consensus-buff? data)))) + (unwrap-panic (element-at? encoded (- (len encoded) u1)))))) + + +(define-private (is-valid-c32 (address (string-ascii 128))) + (fold is-c32-char address true)) + +(define-private (is-c32-char (char (string-ascii 1)) (valid bool)) + (and valid (is-some (index-of C32SET char)))) diff --git a/contracts/stacks/contracts/xcall/xcall-common-trait.clar b/contracts/stacks/contracts/xcall/xcall-common-trait.clar new file mode 100644 index 000000000..8d44a8a0d --- /dev/null +++ b/contracts/stacks/contracts/xcall/xcall-common-trait.clar @@ -0,0 +1,6 @@ +(define-trait xcall-common-trait + ( + (get-network-address () (response (string-ascii 128) uint)) + (send-call-message ((string-ascii 128) (buff 2048) (optional (buff 1024)) (optional (list 10 (string-ascii 128))) (optional (list 10 (string-ascii 128)))) (response uint uint)) + ) +) \ No newline at end of file diff --git a/contracts/stacks/contracts/xcall/xcall-impl-trait.clar b/contracts/stacks/contracts/xcall/xcall-impl-trait.clar new file mode 100644 index 000000000..0ac8eba3c --- /dev/null +++ b/contracts/stacks/contracts/xcall/xcall-impl-trait.clar @@ -0,0 +1,26 @@ +(use-trait xcall-receiver-trait .xcall-receiver-trait.xcall-receiver-trait) +(use-trait xcall-common-trait .xcall-common-trait.xcall-common-trait) + +(define-trait xcall-impl-trait + ( + (send-call ((string-ascii 128) (buff 2048)) (response uint uint)) + + (execute-call (uint (buff 2048) ) (response bool uint)) + (execute-rollback (uint ) (response bool uint)) + + (verify-success (uint) (response bool uint)) + + (handle-message ((string-ascii 128) (buff 2048)) (response bool uint)) + (handle-error (uint) (response bool uint)) + + (set-admin (principal) (response bool uint)) + (set-protocol-fee-handler (principal) (response bool uint)) + (set-protocol-fee (uint) (response bool uint)) + (set-default-connection ((string-ascii 128) (string-ascii 128)) (response bool uint)) + (set-trusted-protocols ((string-ascii 128) (list 10 (string-ascii 128))) (response bool uint)) + + (get-network-id () (response (string-ascii 128) uint)) + (get-protocol-fee () (response uint uint)) + (get-fee ((string-ascii 128) bool (optional (list 10 (string-ascii 128)))) (response uint uint)) + ) +) \ No newline at end of file diff --git a/contracts/stacks/contracts/xcall/xcall-impl.clar b/contracts/stacks/contracts/xcall/xcall-impl.clar new file mode 100644 index 000000000..6aae2a61b --- /dev/null +++ b/contracts/stacks/contracts/xcall/xcall-impl.clar @@ -0,0 +1,759 @@ +(impl-trait .xcall-impl-trait.xcall-impl-trait) +(use-trait xcall-common-trait .xcall-common-trait.xcall-common-trait) +(use-trait xcall-receiver-trait .xcall-receiver-trait.xcall-receiver-trait) + +(define-constant ERR_INVALID_NETWORK_ADDRESS (err u200)) +(define-constant ERR_INVALID_NETWORK_ID (err u201)) +(define-constant ERR_INVALID_ACCOUNT (err u202)) +(define-constant ERR_MESSAGE_NOT_FOUND (err u203)) +(define-constant ERR_NOT_ADMIN (err u204)) +(define-constant ERR_ALREADY_INITIALIZED (err u205)) +(define-constant ERR_NOT_INITIALIZED (err u206)) +(define-constant ERR_INVALID_MESSAGE_TYPE (err u207)) +(define-constant ERR_INVALID_RESPONSE (err u208)) +(define-constant ERR_NO_ROLLBACK_DATA (err u209)) +(define-constant ERR_INVALID_REPLY (err u210)) +(define-constant ERR_NO_DEFAULT_CONNECTION (err u211)) +(define-constant ERR_UNVERIFIED_PROTOCOL (err u212)) +(define-constant ERR_INVALID_MESSAGE (err u213)) +(define-constant ERR_INVALID_RECEIVER (err u214)) +(define-constant ERR_ADDRESS_TO_PRINCIPAL_FAILED (err u215)) + +(define-constant CS_MESSAGE_RESULT_FAILURE u0) +(define-constant CS_MESSAGE_RESULT_SUCCESS u1) +(define-constant CS_MESSAGE_TYPE_REQUEST u1) +(define-constant CS_MESSAGE_TYPE_RESULT u2) + +(define-data-var admin principal tx-sender) +(define-data-var protocol-fee uint u0) +(define-data-var protocol-fee-handler principal tx-sender) +(define-data-var current-network-id (string-ascii 128) "") +(define-data-var current-rollback bool false) +(define-data-var sn-counter uint u0) +(define-data-var req-id-counter uint u0) +(define-data-var reply-state + (optional { + from-nid: (string-ascii 128), + protocols: (list 10 (string-ascii 128)) + }) + none +) +(define-data-var call-reply (optional (buff 2048)) none) +(define-data-var network-id (optional (string-ascii 128)) none) +(define-data-var contract-address (optional (string-ascii 128)) none) + +(define-map default-connections + { nid: (string-ascii 128) } + { address: (string-ascii 128) } +) + +(define-map trusted-protocols + { nid: (string-ascii 128) } + { protocols: (list 10 (string-ascii 128)) } +) + +(define-map pending-messages + { msg-hash: (buff 32), protocol: principal } + { confirmed: bool } +) + +(define-map outgoing-messages + { sn: uint } + { + to: (string-ascii 128), + data: (buff 2048), + rollback: (optional (buff 1024)), + sources: (optional (list 10 (string-ascii 128))), + destinations: (optional (list 10 (string-ascii 128))), + } +) + +(define-map incoming-messages + { req-id: uint } + { + from: (string-ascii 128), + to: (string-ascii 128), + sn: uint, + type: uint, + data-hash: (buff 32), + protocols: (list 10 (string-ascii 128)) + } +) + +(define-map successful-responses + { sn: uint } + { value: bool } +) + +(define-public (init (nid (string-ascii 128)) (addr (string-ascii 128))) + (begin + (asserts! (is-none (var-get network-id)) ERR_ALREADY_INITIALIZED) + (asserts! (is-eq (var-get admin) tx-sender) ERR_NOT_ADMIN) + + (var-set network-id (some nid)) + (var-set contract-address (some addr)) + + (ok true) + ) +) + +(define-read-only (get-network-id) + (match (var-get network-id) + some-network-id (ok some-network-id) + ERR_NOT_INITIALIZED + ) +) + +(define-read-only (get-network-address) + (match (var-get network-id) + some-network-id + (match (var-get contract-address) + some-network-addr + (ok (unwrap! + (as-max-len? (concat (concat some-network-id "/") some-network-addr) u128) + ERR_INVALID_NETWORK_ADDRESS)) + ERR_NOT_INITIALIZED + ) + ERR_NOT_INITIALIZED + ) +) + +(define-read-only (get-outgoing-message (sn uint)) + (map-get? outgoing-messages { sn: sn }) +) + +(define-read-only (is-reply (network-id-in (string-ascii 128)) (sources (optional (list 10 (string-ascii 128))))) + (match (var-get reply-state) + state (and + (is-eq (get from-nid state) network-id-in) + (is-eq (get protocols state) (default-to (list) sources))) + false) +) + +(define-private (is-admin) + (is-eq (var-get admin) tx-sender) +) + +(define-private (get-next-sn) + (let + ((current-sn (var-get sn-counter))) + (var-set sn-counter (+ current-sn u1)) + (ok (+ current-sn u1)) + ) +) + +(define-private (get-next-req-id) + (let ( + (current-id (var-get req-id-counter)) + ) + (var-set req-id-counter (+ current-id u1)) + (ok (+ current-id u1)) + ) +) + +(define-private (validate-network-address (address (string-ascii 257))) + (match (index-of? address "/") + index + (let + ( + (network-id-in (slice? address u0 index)) + (account (slice? address (+ index u1) (len address))) + ) + (and + (is-some network-id-in) + (is-some account) + (> (len (unwrap! network-id-in false)) u0) + (> (len (unwrap! account false)) u0) + ) + ) + false + ) +) + +(define-private (parse-network-address (address (string-ascii 257))) + (if (validate-network-address address) + (match (index-of? address "/") + index + (let + ( + (network-id-in (unwrap-panic (as-max-len? (unwrap-panic (slice? address u0 index)) u128))) + (account (unwrap-panic (slice? address (+ index u1) (len address)))) + ) + (ok {network-id: network-id-in, account: account}) + ) + ERR_INVALID_NETWORK_ADDRESS + ) + ERR_INVALID_NETWORK_ADDRESS + ) +) + +(define-public (set-trusted-protocols (nid (string-ascii 128)) (protocols (list 10 (string-ascii 128)))) + (begin + (asserts! (is-admin) ERR_NOT_ADMIN) + (ok (map-set trusted-protocols { nid: nid } { protocols: protocols })) + ) +) + +(define-private (emit-call-message-received-event (from (string-ascii 128)) (to (string-ascii 128)) (sn uint) (req-id uint) (data (buff 2048))) + (print + { + event: "CallMessage", + from: from, + to: to, + sn: sn, + req-id: req-id, + data: data, + } + ) +) + +(define-private (emit-call-executed-event (req-id uint) (code uint) (message (string-ascii 128))) + (print + { + event: "CallExecuted", + req-id: req-id, + code: code, + msg: message + } + ) +) + +(define-private (emit-call-message-sent-event (from principal) (to (string-ascii 128)) (sn uint) (data (buff 2048)) (sources (optional (list 10 (string-ascii 128)))) (destinations (optional (list 10 (string-ascii 128))))) + (print + { + event: "CallMessageSent", + from: tx-sender, + to: to, + sn: sn, + data: data, + sources: (default-to (list) sources), + destinations: (default-to (list) destinations) + } + ) +) + + +(define-private (emit-response-message-event (sn uint) (code uint)) + (print + { + event: "ResponseMessage", + sn: sn, + code: code + } + ) +) + +(define-private (emit-rollback-message-received-event (sn uint)) + (print + { + event: "RollbackMessage", + sn: sn, + } + ) +) + +(define-private (emit-rollback-executed-event (sn uint)) + (print + { + event: "RollbackExecuted", + sn: sn + } + ) +) + +(define-read-only (get-default-connection (nid (string-ascii 128))) + (match (map-get? default-connections { nid: nid }) + connection (ok (some connection)) + ERR_NO_DEFAULT_CONNECTION) +) + +(define-public (send-call + (to (string-ascii 128)) + (data (buff 2048)) +) + (begin + (send-call-message to data none none none) + ) +) + +(define-private (encode-protocol-string (protocol (string-ascii 128))) + (contract-call? .rlp-encode encode-string protocol)) + +(define-public (send-call-message + (to (string-ascii 128)) + (data (buff 2048)) + (rollback (optional (buff 1024))) + (sources (optional (list 10 (string-ascii 128)))) + (destinations (optional (list 10 (string-ascii 128)))) +) + (let + ( + (fee (var-get protocol-fee)) + (fee-to (var-get protocol-fee-handler)) + (next-sn (unwrap-panic (get-next-sn))) + (parsed-address (try! (parse-network-address to))) + (dst-network-id (get network-id parsed-address)) + (connection-result (unwrap-panic (get-default-connection dst-network-id))) + (from-address (unwrap! (get-network-address) ERR_NOT_INITIALIZED)) + + (source-contract (contract-call? .rlp-encode encode-string from-address)) + (dest-address (contract-call? .rlp-encode encode-string (get account parsed-address))) + (sn (contract-call? .rlp-encode encode-uint next-sn)) + (msg-type (contract-call? .rlp-encode encode-uint CS_MESSAGE_TYPE_REQUEST)) + (message-data (contract-call? .rlp-encode encode-buff + (unwrap! (as-max-len? data u1024) ERR_INVALID_MESSAGE))) + + (protocol-list-raw (map encode-protocol-string + (default-to (list) destinations))) + (protocol-list (contract-call? .rlp-encode encode-arr protocol-list-raw)) + + (inner-message-raw (list + source-contract + dest-address + sn + msg-type + message-data + protocol-list)) + (inner-message (contract-call? .rlp-encode encode-arr inner-message-raw)) + + (final-list-raw (list + (contract-call? .rlp-encode encode-uint CS_MESSAGE_TYPE_REQUEST) + inner-message)) + (cs-message-request (contract-call? .rlp-encode encode-arr final-list-raw)) + ) + (asserts! (is-some connection-result) ERR_INVALID_NETWORK_ADDRESS) + + (emit-call-message-sent-event tx-sender to next-sn cs-message-request sources destinations) + + (if (is-some rollback) + (map-set outgoing-messages + { sn: next-sn } + { + to: to, + data: cs-message-request, + rollback: rollback, + sources: sources, + destinations: destinations + } + ) + true + ) + + (if (and (is-reply dst-network-id sources) (is-none rollback)) + (begin + (var-set reply-state none) + (var-set call-reply (some cs-message-request)) + ) + true + ) + + (try! (stx-transfer? fee tx-sender fee-to)) + (ok next-sn) + ) +) + +(define-public (handle-message (src-network-id (string-ascii 128)) (msg (buff 2048))) + (let ( + (cs-message (unwrap-panic (parse-cs-message msg))) + (msg-type (get type cs-message)) + (msg-data (get data cs-message)) + ) + (if (is-eq msg-type CS_MESSAGE_TYPE_REQUEST) + (handle-request src-network-id msg-data) + (if (is-eq msg-type CS_MESSAGE_TYPE_RESULT) + (handle-result msg-data) + ERR_INVALID_MESSAGE_TYPE + ) + ) + ) +) + +(define-private (handle-request (src-network-id (string-ascii 128)) (data (buff 2048))) + (let ( + (msg-req (unwrap-panic (parse-cs-message-request data))) + (hash (keccak256 data)) + ) + (asserts! (is-eq (get network-id (unwrap-panic (parse-network-address (get from msg-req)))) src-network-id) ERR_INVALID_NETWORK_ADDRESS) + (asserts! (verify-protocols src-network-id (get protocols msg-req) hash) ERR_UNVERIFIED_PROTOCOL) + + (let ( + (req-id (unwrap-panic (get-next-req-id))) + (data-hash (keccak256 (get data msg-req))) + ) + (emit-call-message-received-event (get from msg-req) (get to msg-req) (get sn msg-req) req-id (get data msg-req)) + (map-set incoming-messages + { req-id: req-id } + { + from: (get from msg-req), + to: (get to msg-req), + sn: (get sn msg-req), + type: (get type msg-req), + data-hash: data-hash, + protocols: (get protocols msg-req) + } + ) + (ok true) + ) + ) +) + +(define-private (handle-result (data (buff 2048))) + (let ( + (msg-res (unwrap-panic (parse-cs-message-result data))) + (res-sn (get sn msg-res)) + (rollback (unwrap! (map-get? outgoing-messages { sn: res-sn }) ERR_MESSAGE_NOT_FOUND)) + (dst-network-id (get network-id (unwrap-panic (parse-network-address (get to rollback))))) + (code (get code msg-res)) + ) + (asserts! (verify-protocols dst-network-id (default-to (list) (get sources rollback)) (keccak256 data)) ERR_UNVERIFIED_PROTOCOL) + + (emit-response-message-event res-sn (get code msg-res)) + (if (is-eq code CS_MESSAGE_RESULT_SUCCESS) + (handle-success res-sn msg-res rollback) + (if (is-eq code CS_MESSAGE_RESULT_FAILURE) + (handle-failure res-sn rollback) + ERR_INVALID_RESPONSE + ) + ) + ) +) + +(define-public (handle-error (sn uint)) + (let ( + (error-result (create-cs-message-result sn CS_MESSAGE_RESULT_FAILURE none)) + (encoded-result (unwrap-panic (encode-cs-message-result error-result))) + ) + (handle-result encoded-result) + ) +) + +(define-private (create-cs-message-result (sn uint) (code uint) (msg (optional (buff 2048)))) + { + sn: sn, + code: code, + msg: msg + } +) + +(define-private (encode-cs-message-result (result {sn: uint, code: uint, msg: (optional (buff 2048))})) + (ok (concat + (contract-call? .rlp-encode encode-uint (get sn result)) + (contract-call? .rlp-encode encode-uint (get code result)))) +) + +(define-private (handle-success (sn uint) (msg-res { sn: uint, code: uint, msg: (optional (buff 2048)) }) (rollback { to: (string-ascii 128), data: (buff 2048), rollback: (optional (buff 1024)), sources: (optional (list 10 (string-ascii 128))), destinations: (optional (list 10 (string-ascii 128))) })) +(begin + (map-delete outgoing-messages { sn: sn }) + (map-set successful-responses { sn: sn } { value: true }) + (if (is-some (get msg msg-res)) + (let ( + (reply-data (unwrap-panic (get msg msg-res))) + (parsed-reply-data (unwrap-panic (parse-cs-message-request reply-data))) + ) + (handle-reply rollback parsed-reply-data) + ) + (ok true) + ) +) +) + +(define-private (handle-reply (rollback { to: (string-ascii 128), data: (buff 2048), rollback: (optional (buff 1024)), sources: (optional (list 10 (string-ascii 128))), destinations: (optional (list 10 (string-ascii 128))) }) + (reply { from: (string-ascii 128), to: (string-ascii 128), sn: uint, type: uint, data: (buff 2048), protocols: (list 10 (string-ascii 128)) })) + (let ( + (rollback-to (try! (parse-network-address (get to rollback)))) + (reply-from (try! (parse-network-address (get from reply)))) + ) + (asserts! (is-eq (get network-id rollback-to) (get network-id reply-from)) ERR_INVALID_REPLY) + + (let ( + (updated-reply (merge reply { protocols: (default-to (list) (get sources rollback)) })) + (req-id (unwrap-panic (get-next-req-id))) + (data-hash (keccak256 (get data updated-reply))) + ) + (emit-call-message-received-event (get from updated-reply) (get to updated-reply) (get sn updated-reply) req-id (get data updated-reply)) + + (map-set incoming-messages + { req-id: req-id } + { + from: (get from updated-reply), + to: (get to updated-reply), + sn: (get sn updated-reply), + type: (get type updated-reply), + data-hash: data-hash, + protocols: (get protocols updated-reply) + } + ) + (ok true) + ) + ) +) + +(define-private (handle-failure (sn uint) (rollback { to: (string-ascii 128), data: (buff 2048), rollback: (optional (buff 1024)), sources: (optional (list 10 (string-ascii 128))), destinations: (optional (list 10 (string-ascii 128))) })) + (match (get rollback rollback) + rollback-data (begin + (map-set outgoing-messages { sn: sn } (merge rollback { data: rollback-data })) + (emit-rollback-message-received-event sn) + (ok true) + ) + ERR_NO_ROLLBACK_DATA + ) +) + +(define-private (parse-cs-message (msg (buff 2048))) + (let ( + (decoded (contract-call? .rlp-decode rlp-to-list msg)) + (type (contract-call? .rlp-decode rlp-decode-uint decoded u0)) + (data (unwrap-panic (element-at decoded u1))) + ) + (ok { + type: type, + data: data + }) + ) +) + +(define-private (parse-protocol (protocol (buff 2048))) + (unwrap-panic (as-max-len? (unwrap-panic (contract-call? .rlp-decode decode-string protocol)) u128)) +) + +(define-public (parse-cs-message-request (data (buff 2048))) + (let ( + (decoded (contract-call? .rlp-decode rlp-to-list data)) + (from (unwrap-panic (as-max-len? (unwrap-panic (contract-call? .rlp-decode rlp-decode-string decoded u0)) u128))) + (to (unwrap-panic (as-max-len? (unwrap-panic (contract-call? .rlp-decode rlp-decode-string decoded u1)) u128))) + (sn (contract-call? .rlp-decode rlp-decode-uint decoded u2)) + (type (contract-call? .rlp-decode rlp-decode-uint decoded u3)) + (msg-data (contract-call? .rlp-decode rlp-decode-buff decoded u4)) + (protocols-list (contract-call? .rlp-decode rlp-decode-list decoded u5)) + (protocols (map parse-protocol protocols-list)) + ) + (ok { + from: from, + to: to, + sn: sn, + type: type, + data: msg-data, + protocols: protocols + }) + ) +) + +(define-private (parse-cs-message-result (data (buff 2048))) + (let ( + (decoded (contract-call? .rlp-decode rlp-to-list data)) + ) + (ok { + sn: (contract-call? .rlp-decode rlp-decode-uint decoded u0), + code: (contract-call? .rlp-decode rlp-decode-uint decoded u1), + msg: (if (> (len decoded) u2) + (some (contract-call? .rlp-decode rlp-decode-buff decoded u2)) + none + ) + }) + ) +) + +(define-read-only (verify-success (sn uint)) + (match (map-get? successful-responses { sn: sn }) + success-response (ok (get value success-response)) + (ok false) + ) +) + +(define-public (execute-call (req-id uint) (data (buff 2048)) (receiver ) (common )) + (let + ( + (req (unwrap! (map-get? incoming-messages { req-id: req-id }) ERR_MESSAGE_NOT_FOUND)) + (from (get from req)) + (to (get to req)) + (sn (get sn req)) + (msg-type (get type req)) + (stored-data-hash (get data-hash req)) + (protocols (get protocols req)) + (parsed-to (unwrap! (parse-network-address to) ERR_INVALID_NETWORK_ADDRESS)) + (to-account (unwrap! (as-max-len? (get account parsed-to) u128) ERR_INVALID_ACCOUNT)) + (to-principal (unwrap! (contract-call? .util address-string-to-principal to-account) ERR_ADDRESS_TO_PRINCIPAL_FAILED)) + (receiver-principal (contract-of receiver)) + ) + (asserts! (is-eq (keccak256 data) stored-data-hash) ERR_MESSAGE_NOT_FOUND) + (asserts! (is-eq to-principal receiver-principal) ERR_INVALID_RECEIVER) + + (match (contract-call? receiver handle-call-message from data protocols common) + success-response (begin + (emit-call-executed-event req-id CS_MESSAGE_RESULT_SUCCESS "") + (map-delete incoming-messages { req-id: req-id }) + (ok true)) + error-value (begin + (emit-call-executed-event req-id CS_MESSAGE_RESULT_FAILURE (int-to-ascii error-value)) + (match (map-get? outgoing-messages { sn: sn }) + msg (match (get rollback msg) + rb (begin + (emit-rollback-message-received-event sn) + (err error-value)) + (err error-value)) + (err error-value))))) +) + +(define-public (execute-rollback (sn uint) (receiver ) (common )) + (let + ( + (message (unwrap! (map-get? outgoing-messages { sn: sn }) ERR_MESSAGE_NOT_FOUND)) + (to (get to message)) + (parsed-to (unwrap! (parse-network-address to) ERR_INVALID_NETWORK_ADDRESS)) + (to-account (unwrap! (as-max-len? (get account parsed-to) u128) ERR_INVALID_ACCOUNT)) + (to-principal (unwrap! (contract-call? .util address-string-to-principal to-account) ERR_ADDRESS_TO_PRINCIPAL_FAILED)) + (receiver-principal (contract-of receiver)) + (from (unwrap! (as-max-len? (unwrap! (get-network-address) ERR_NOT_INITIALIZED) u128) ERR_ADDRESS_TO_PRINCIPAL_FAILED)) + (protocols (default-to (list) (get sources message))) + (rollback (unwrap! (get rollback message) ERR_NO_ROLLBACK_DATA)) + ) + (asserts! (is-eq to-principal receiver-principal) ERR_INVALID_RECEIVER) + (try! (contract-call? receiver handle-call-message from rollback protocols common)) + (emit-rollback-executed-event sn) + (map-delete outgoing-messages { sn: sn }) + (ok true) + ) +) + +(define-public (set-admin (new-admin principal)) + (begin + (asserts! (is-admin) ERR_NOT_ADMIN) + (var-set admin new-admin) + (ok true) + ) +) + +(define-public (set-protocol-fee-handler (new-handler principal)) + (begin + (asserts! (is-admin) ERR_NOT_ADMIN) + (var-set protocol-fee-handler new-handler) + (ok true) + ) +) + +(define-public (set-protocol-fee (new-fee uint)) + (begin + (asserts! (is-admin) ERR_NOT_ADMIN) + (var-set protocol-fee new-fee) + (ok true) + ) +) + +(define-public (set-default-connection (nid (string-ascii 128)) (connection (string-ascii 128))) + (begin + (asserts! (is-admin) ERR_NOT_ADMIN) + (map-set default-connections + { nid: nid } + { address: connection } + ) + (ok true) + ) +) + +(define-read-only (get-protocol-fee) + (ok (var-get protocol-fee)) +) + +(define-public (get-fee (network-id-in (string-ascii 128)) (rollback bool) (sources (optional (list 10 (string-ascii 128))))) + (let + ( + (cumulative-fee (var-get protocol-fee)) + ) + (var-set current-network-id network-id-in) + (var-set current-rollback rollback) + (if (and (is-reply network-id-in sources) (not rollback)) + (ok u0) + (ok (+ cumulative-fee (get-connection-fee network-id-in rollback sources))) + ) + ) +) + +(define-private (sum-fees (source (string-ascii 128)) (acc uint)) + (+ acc (get-fee-from-source source)) +) + +(define-private (get-connection-fee (network-id-in (string-ascii 128)) (rollback bool) (sources (optional (list 10 (string-ascii 128))))) + (match sources + some-sources (fold sum-fees some-sources u0) + (let + ( + (default-connection (unwrap-panic (get-default-connection network-id-in))) + ) + (match default-connection + some-connection (get-fee-from-source (get address some-connection)) + u0 + ) + ) + ) +) + +(define-private (get-fee-from-source (source (string-ascii 128))) + (unwrap-panic (contract-call? .centralized-connection get-fee (var-get current-network-id) (var-get current-rollback))) +) + +(define-read-only (get-incoming-message (req-id uint)) + (match (map-get? incoming-messages { req-id: req-id }) + message (ok message) + (err ERR_MESSAGE_NOT_FOUND) + ) +) + +(define-private (verify-protocols (src-network-id (string-ascii 128)) (protocols (list 10 (string-ascii 128))) (data (buff 2048))) + (let + ( + (source tx-sender) + (msg-hash (keccak256 data)) + ) + (if (> (len protocols) u0) + (if (> (len protocols) u1) + (let + ( + (set-confirmation (map-set pending-messages { msg-hash: msg-hash, protocol: source } { confirmed: true })) + (all-confirmed (fold check-protocol protocols { msg-hash: msg-hash, all-valid: true })) + ) + (and + (get all-valid all-confirmed) + (begin + (map clear-pending-message msg-hash protocols) + true + ) + ) + ) + (is-eq source (unwrap! (contract-call? .util address-string-to-principal (unwrap-panic (element-at protocols u0))) false)) + ) + (match (map-get? default-connections { nid: src-network-id }) + default-connection + (is-eq + source + (unwrap! (contract-call? .util address-string-to-principal (get address default-connection)) false) + ) + false + ) + ) + ) +) + +(define-private (check-protocol (protocol (string-ascii 128)) (accumulator { msg-hash: (buff 32), all-valid: bool })) + (let + ( + (protocol-principal (unwrap! (contract-call? .util address-string-to-principal protocol) accumulator)) + (is-confirmed (default-to false (get confirmed (map-get? pending-messages { msg-hash: (get msg-hash accumulator), protocol: protocol-principal })))) + ) + { + msg-hash: (get msg-hash accumulator), + all-valid: (and (get all-valid accumulator) is-confirmed) + } + ) +) + +(define-private (clear-pending-message (msg-hash (buff 32)) (protocol (string-ascii 128))) + (let + ( + (protocol-principal (unwrap! (contract-call? .util address-string-to-principal protocol) false)) + ) + (map-delete pending-messages { + msg-hash: msg-hash, + protocol: protocol-principal + }) + ) +) \ No newline at end of file diff --git a/contracts/stacks/contracts/xcall/xcall-proxy-trait.clar b/contracts/stacks/contracts/xcall/xcall-proxy-trait.clar new file mode 100644 index 000000000..02dc6edd7 --- /dev/null +++ b/contracts/stacks/contracts/xcall/xcall-proxy-trait.clar @@ -0,0 +1,44 @@ +(use-trait xcall-impl-trait .xcall-impl-trait.xcall-impl-trait) +(use-trait xcall-common-trait .xcall-common-trait.xcall-common-trait) +(use-trait xcall-receiver-trait .xcall-receiver-trait.xcall-receiver-trait) + +(define-trait xcall-proxy-trait + ( + (get-current-implementation () (response principal bool)) + (get-current-proxy () (response (optional principal) uint)) + + (is-current-implementation (principal) (response bool uint)) + + (send-call ((string-ascii 128) (buff 2048) ) (response uint uint)) + + (send-call-message ((string-ascii 128) (buff 2048) (optional (buff 1024)) (optional (list 10 (string-ascii 128))) (optional (list 10 (string-ascii 128))) ) (response uint uint)) + + (execute-call (uint (buff 2048) ) (response bool uint)) + + (execute-rollback (uint ) (response bool uint)) + + (verify-success (uint ) (response bool uint)) + + (handle-message ((string-ascii 128) (buff 2048) ) (response bool uint)) + + (handle-error (uint ) (response bool uint)) + + (set-admin (principal ) (response bool uint)) + + (set-protocol-fee-handler (principal ) (response bool uint)) + + (set-protocol-fee (uint ) (response bool uint)) + + (set-default-connection ((string-ascii 128) (string-ascii 128) ) (response bool uint)) + + (set-trusted-protocols ((string-ascii 128) (list 10 (string-ascii 128)) ) (response bool uint)) + + (get-network-address () (response (string-ascii 257) uint)) + + (get-network-id () (response (string-ascii 128) uint)) + + (get-protocol-fee () (response uint uint)) + + (get-fee ((string-ascii 128) bool (optional (list 10 (string-ascii 128))) ) (response uint uint)) + ) +) \ No newline at end of file diff --git a/contracts/stacks/contracts/xcall/xcall-proxy.clar b/contracts/stacks/contracts/xcall/xcall-proxy.clar new file mode 100644 index 000000000..ca2cf1331 --- /dev/null +++ b/contracts/stacks/contracts/xcall/xcall-proxy.clar @@ -0,0 +1,183 @@ +(impl-trait .xcall-proxy-trait.xcall-proxy-trait) +(use-trait xcall-impl-trait .xcall-impl-trait.xcall-impl-trait) +(use-trait xcall-common-trait .xcall-common-trait.xcall-common-trait) +(use-trait xcall-receiver-trait .xcall-receiver-trait.xcall-receiver-trait) + +(define-constant CONTRACT_NAME "xcall-proxy") + +(define-data-var contract-owner principal tx-sender) +(define-data-var current-logic-implementation principal tx-sender) +(define-data-var current-proxy (optional principal) none) + +(define-constant err-not-current-implementation (err u100)) +(define-constant err-not-owner (err u101)) + +(define-map data-storage (string-ascii 16) (buff 2048)) + +;; xcall-proxy-trait implementation + +(define-read-only (get-current-implementation) + (ok (var-get current-logic-implementation)) +) + +(define-read-only (get-current-proxy) + (ok (var-get current-proxy)) +) + +(define-read-only (is-current-implementation (implementation principal)) + (ok (is-eq implementation (var-get current-logic-implementation))) +) + +(define-public (set-trusted-protocols (nid (string-ascii 128)) (protocols (list 10 (string-ascii 128))) (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation set-trusted-protocols nid protocols) + ) +) + +(define-public (send-call (to (string-ascii 128)) (data (buff 2048)) (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation send-call to data) + ) +) + +(define-public (send-call-message (to (string-ascii 128)) (data (buff 2048)) (rollback (optional (buff 1024))) (sources (optional (list 10 (string-ascii 128)))) (destinations (optional (list 10 (string-ascii 128)))) (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation send-call-message to data rollback sources destinations) + ) +) + +(define-public (execute-call (req-id uint) (data (buff 2048)) (receiver ) (common ) (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (as-contract (contract-call? implementation execute-call req-id data receiver common)) + ) +) + +(define-public (execute-rollback (sn uint) (receiver ) (common ) (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (as-contract (contract-call? implementation execute-rollback sn receiver common)) + ) +) + +(define-public (verify-success (sn uint) (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation verify-success sn) + ) +) + +(define-public (handle-message (source-network (string-ascii 128)) (message (buff 2048)) (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation handle-message source-network message) + ) +) + +(define-public (handle-error (sn uint) (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation handle-error sn) + ) +) + +;; Admin methods + +(define-public (set-admin (new-admin principal) (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation set-admin new-admin) + ) +) + +(define-public (set-protocol-fee-handler (handler principal) (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation set-protocol-fee-handler handler) + ) +) + +(define-public (set-protocol-fee (fee uint) (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation set-protocol-fee fee) + ) +) + +(define-public (set-default-connection (nid (string-ascii 128)) (connection (string-ascii 128)) (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation set-default-connection nid connection) + ) +) + +;; Read-only methods + +(define-public (get-network-address (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation get-network-address) + ) +) + +(define-public (get-network-id (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation get-network-id) + ) +) + +(define-public (get-protocol-fee (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation get-protocol-fee) + ) +) + +(define-public (get-fee (net (string-ascii 128)) (rollback bool) (sources (optional (list 10 (string-ascii 128)))) (implementation )) + (begin + (asserts! (is-eq (contract-of implementation) (var-get current-logic-implementation)) err-not-current-implementation) + (contract-call? implementation get-fee net rollback sources) + ) +) + +;; Governance functions + +(define-read-only (get-contract-owner) + (var-get contract-owner) +) + +(define-read-only (is-contract-owner (who principal)) + (is-eq who (var-get contract-owner)) +) + +(define-public (set-contract-owner (new-owner principal)) + (begin + (asserts! (is-contract-owner contract-caller) err-not-owner) + (ok (var-set contract-owner new-owner)) + ) +) + +(define-public (upgrade (new-implementation ) (new-proxy (optional principal))) + (begin + ;; (asserts! (is-contract-owner contract-caller) err-not-owner) + (var-set current-proxy new-proxy) + (ok (var-set current-logic-implementation (contract-of new-implementation))) + ) +) + +;; Implementation functions to affect contract storage + +(define-read-only (get-data (key (string-ascii 16))) + (map-get? data-storage key) +) + +(define-public (set-data (key (string-ascii 16)) (value (buff 2048))) + (begin + (asserts! (is-eq contract-caller (var-get current-logic-implementation)) err-not-current-implementation) + (ok (map-set data-storage key value)) + ) +) \ No newline at end of file diff --git a/contracts/stacks/contracts/xcall/xcall-receiver-trait.clar b/contracts/stacks/contracts/xcall/xcall-receiver-trait.clar new file mode 100644 index 000000000..053fee640 --- /dev/null +++ b/contracts/stacks/contracts/xcall/xcall-receiver-trait.clar @@ -0,0 +1,7 @@ +(use-trait xcall-common-trait .xcall-common-trait.xcall-common-trait) + +(define-trait xcall-receiver-trait + ( + (handle-call-message ((string-ascii 128) (buff 2048) (list 10 (string-ascii 128)) ) (response bool uint)) + ) +) \ No newline at end of file diff --git a/contracts/stacks/deployments/default.devnet-plan.yaml b/contracts/stacks/deployments/default.devnet-plan.yaml new file mode 100644 index 000000000..330216a81 --- /dev/null +++ b/contracts/stacks/deployments/default.devnet-plan.yaml @@ -0,0 +1,98 @@ +--- +id: 0 +name: Devnet deployment +network: devnet +stacks-node: "http://localhost:20443" +bitcoin-node: "http://devnet:devnet@localhost:18443" +plan: + batches: + - id: 0 + transactions: + - contract-publish: + contract-name: xcall-common-trait + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 2870 + path: contracts/xcall/xcall-common-trait.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: xcall-receiver-trait + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 2450 + path: contracts/xcall/xcall-receiver-trait.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: xcall-impl-trait + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 12050 + path: contracts/xcall/xcall-impl-trait.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: xcall-proxy-trait + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 20130 + path: contracts/xcall/xcall-proxy-trait.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: xcall-proxy + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 74480 + path: contracts/xcall/xcall-proxy.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: centralized-connection + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 34840 + path: contracts/connections/centralized-connection.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: rlp-decode + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 53600 + path: lib/rlp/rlp-decode.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: mock-dapp + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 35090 + path: tests/mocks/mock-dapp.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: rlp-encode + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 76210 + path: lib/rlp/rlp-encode.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: util + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 30570 + path: contracts/util.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: xcall-impl + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 241910 + path: contracts/xcall/xcall-impl.clar + anchor-block-only: true + clarity-version: 2 + epoch: "2.5" + - id: 1 + transactions: + - contract-publish: + contract-name: debug + expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + cost: 48920 + path: contracts/debug.clar + anchor-block-only: true + clarity-version: 3 + epoch: "3.0" diff --git a/contracts/stacks/deployments/default.simnet-plan.yaml b/contracts/stacks/deployments/default.simnet-plan.yaml new file mode 100644 index 000000000..39f1cf530 --- /dev/null +++ b/contracts/stacks/deployments/default.simnet-plan.yaml @@ -0,0 +1,3313 @@ +--- +id: 0 +name: "Simulated deployment, used as a default for `clarinet console`, `clarinet test` and `clarinet check`" +network: simnet +genesis: + wallets: + - name: deployer + address: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + balance: "100000000000000" + - name: faucet + address: STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 + balance: "100000000000000" + - name: wallet_1 + address: ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5 + balance: "100000000000000" + - name: wallet_2 + address: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG + balance: "100000000000000" + - name: wallet_3 + address: ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC + balance: "100000000000000" + - name: wallet_4 + address: ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND + balance: "100000000000000" + - name: wallet_5 + address: ST2REHHS5J3CERCRBEPMGH7921Q6PYKAADT7JP2VB + balance: "100000000000000" + - name: wallet_6 + address: ST3AM1A56AK2C1XAFJ4115ZSV26EB49BVQ10MGCS0 + balance: "100000000000000" + - name: wallet_7 + address: ST3PF13W7Z0RRM42A8VZRVFQ75SV1K26RXEP8YGKJ + balance: "100000000000000" + - name: wallet_8 + address: ST3NBRSFKX28FQ2ZJ1MAKX58HKHSDGNV5N7R21XCP + balance: "100000000000000" + contracts: + - costs + - pox + - pox-2 + - pox-3 + - pox-4 + - lockup + - costs-2 + - costs-3 + - cost-voting + - bns +plan: + batches: + - id: 0 + transactions: [] + epoch: "2.1" + - id: 1 + transactions: + - emulated-contract-publish: + contract-name: xcall-common-trait + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/xcall/xcall-common-trait.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: xcall-receiver-trait + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/xcall/xcall-receiver-trait.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: xcall-impl-trait + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/xcall/xcall-impl-trait.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: xcall-proxy-trait + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/xcall/xcall-proxy-trait.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: xcall-proxy + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/xcall/xcall-proxy.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: centralized-connection + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/connections/centralized-connection.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: rlp-decode + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: lib/rlp/rlp-decode.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: mock-dapp + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: tests/mocks/mock-dapp.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: rlp-encode + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: lib/rlp/rlp-encode.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: util + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/util.clar + clarity-version: 2 + - emulated-contract-publish: + contract-name: xcall-impl + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/xcall/xcall-impl.clar + clarity-version: 2 + epoch: "2.5" + - id: 2 + transactions: [] + epoch: "2.5" + - id: 3 + transactions: [] + epoch: "2.5" + - id: 4 + transactions: [] + epoch: "2.5" + - id: 5 + transactions: [] + epoch: "2.5" + - id: 6 + transactions: [] + epoch: "2.5" + - id: 7 + transactions: [] + epoch: "2.5" + - id: 8 + transactions: [] + epoch: "2.5" + - id: 9 + transactions: [] + epoch: "2.5" + - id: 10 + transactions: [] + epoch: "2.5" + - id: 11 + transactions: [] + epoch: "2.5" + - id: 12 + transactions: [] + epoch: "2.5" + - id: 13 + transactions: [] + epoch: "2.5" + - id: 14 + transactions: [] + epoch: "2.5" + - id: 15 + transactions: [] + epoch: "2.5" + - id: 16 + transactions: [] + epoch: "2.5" + - id: 17 + transactions: [] + epoch: "2.5" + - id: 18 + transactions: [] + epoch: "2.5" + - id: 19 + transactions: [] + epoch: "2.5" + - id: 20 + transactions: [] + epoch: "2.5" + - id: 21 + transactions: [] + epoch: "2.5" + - id: 22 + transactions: [] + epoch: "2.5" + - id: 23 + transactions: [] + epoch: "2.5" + - id: 24 + transactions: [] + epoch: "2.5" + - id: 25 + transactions: [] + epoch: "2.5" + - id: 26 + transactions: [] + epoch: "2.5" + - id: 27 + transactions: [] + epoch: "2.5" + - id: 28 + transactions: [] + epoch: "2.5" + - id: 29 + transactions: [] + epoch: "2.5" + - id: 30 + transactions: [] + epoch: "2.5" + - id: 31 + transactions: [] + epoch: "2.5" + - id: 32 + transactions: [] + epoch: "2.5" + - id: 33 + transactions: [] + epoch: "2.5" + - id: 34 + transactions: [] + epoch: "2.5" + - id: 35 + transactions: [] + epoch: "2.5" + - id: 36 + transactions: [] + epoch: "2.5" + - id: 37 + transactions: [] + epoch: "2.5" + - id: 38 + transactions: [] + epoch: "2.5" + - id: 39 + transactions: [] + epoch: "2.5" + - id: 40 + transactions: [] + epoch: "2.5" + - id: 41 + transactions: [] + epoch: "2.5" + - id: 42 + transactions: [] + epoch: "2.5" + - id: 43 + transactions: [] + epoch: "2.5" + - id: 44 + transactions: [] + epoch: "2.5" + - id: 45 + transactions: [] + epoch: "2.5" + - id: 46 + transactions: [] + epoch: "2.5" + - id: 47 + transactions: [] + epoch: "2.5" + - id: 48 + transactions: [] + epoch: "2.5" + - id: 49 + transactions: [] + epoch: "2.5" + - id: 50 + transactions: [] + epoch: "2.5" + - id: 51 + transactions: [] + epoch: "2.5" + - id: 52 + transactions: [] + epoch: "2.5" + - id: 53 + transactions: [] + epoch: "2.5" + - id: 54 + transactions: [] + epoch: "2.5" + - id: 55 + transactions: [] + epoch: "2.5" + - id: 56 + transactions: [] + epoch: "2.5" + - id: 57 + transactions: [] + epoch: "2.5" + - id: 58 + transactions: [] + epoch: "2.5" + - id: 59 + transactions: [] + epoch: "2.5" + - id: 60 + transactions: [] + epoch: "2.5" + - id: 61 + transactions: [] + epoch: "2.5" + - id: 62 + transactions: [] + epoch: "2.5" + - id: 63 + transactions: [] + epoch: "2.5" + - id: 64 + transactions: [] + epoch: "2.5" + - id: 65 + transactions: [] + epoch: "2.5" + - id: 66 + transactions: [] + epoch: "2.5" + - id: 67 + transactions: [] + epoch: "2.5" + - id: 68 + transactions: [] + epoch: "2.5" + - id: 69 + transactions: [] + epoch: "2.5" + - id: 70 + transactions: [] + epoch: "2.5" + - id: 71 + transactions: [] + epoch: "2.5" + - id: 72 + transactions: [] + epoch: "2.5" + - id: 73 + transactions: [] + epoch: "2.5" + - id: 74 + transactions: [] + epoch: "2.5" + - id: 75 + transactions: [] + epoch: "2.5" + - id: 76 + transactions: [] + epoch: "2.5" + - id: 77 + transactions: [] + epoch: "2.5" + - id: 78 + transactions: [] + epoch: "2.5" + - id: 79 + transactions: [] + epoch: "2.5" + - id: 80 + transactions: [] + epoch: "2.5" + - id: 81 + transactions: [] + epoch: "2.5" + - id: 82 + transactions: [] + epoch: "2.5" + - id: 83 + transactions: [] + epoch: "2.5" + - id: 84 + transactions: [] + epoch: "2.5" + - id: 85 + transactions: [] + epoch: "2.5" + - id: 86 + transactions: [] + epoch: "2.5" + - id: 87 + transactions: [] + epoch: "2.5" + - id: 88 + transactions: [] + epoch: "2.5" + - id: 89 + transactions: [] + epoch: "2.5" + - id: 90 + transactions: [] + epoch: "2.5" + - id: 91 + transactions: [] + epoch: "2.5" + - id: 92 + transactions: [] + epoch: "2.5" + - id: 93 + transactions: [] + epoch: "2.5" + - id: 94 + transactions: [] + epoch: "2.5" + - id: 95 + transactions: [] + epoch: "2.5" + - id: 96 + transactions: [] + epoch: "2.5" + - id: 97 + transactions: [] + epoch: "2.5" + - id: 98 + transactions: [] + epoch: "2.5" + - id: 99 + transactions: [] + epoch: "2.5" + - id: 100 + transactions: [] + epoch: "2.5" + - id: 101 + transactions: [] + epoch: "2.5" + - id: 102 + transactions: [] + epoch: "2.5" + - id: 103 + transactions: [] + epoch: "2.5" + - id: 104 + transactions: [] + epoch: "2.5" + - id: 105 + transactions: [] + epoch: "2.5" + - id: 106 + transactions: [] + epoch: "2.5" + - id: 107 + transactions: [] + epoch: "2.5" + - id: 108 + transactions: [] + epoch: "2.5" + - id: 109 + transactions: [] + epoch: "2.5" + - id: 110 + transactions: [] + epoch: "2.5" + - id: 111 + transactions: [] + epoch: "2.5" + - id: 112 + transactions: [] + epoch: "2.5" + - id: 113 + transactions: [] + epoch: "2.5" + - id: 114 + transactions: [] + epoch: "2.5" + - id: 115 + transactions: [] + epoch: "2.5" + - id: 116 + transactions: [] + epoch: "2.5" + - id: 117 + transactions: [] + epoch: "2.5" + - id: 118 + transactions: [] + epoch: "2.5" + - id: 119 + transactions: [] + epoch: "2.5" + - id: 120 + transactions: [] + epoch: "2.5" + - id: 121 + transactions: [] + epoch: "2.5" + - id: 122 + transactions: [] + epoch: "2.5" + - id: 123 + transactions: [] + epoch: "2.5" + - id: 124 + transactions: [] + epoch: "2.5" + - id: 125 + transactions: [] + epoch: "2.5" + - id: 126 + transactions: [] + epoch: "2.5" + - id: 127 + transactions: [] + epoch: "2.5" + - id: 128 + transactions: [] + epoch: "2.5" + - id: 129 + transactions: [] + epoch: "2.5" + - id: 130 + transactions: [] + epoch: "2.5" + - id: 131 + transactions: [] + epoch: "2.5" + - id: 132 + transactions: [] + epoch: "2.5" + - id: 133 + transactions: [] + epoch: "2.5" + - id: 134 + transactions: [] + epoch: "2.5" + - id: 135 + transactions: [] + epoch: "2.5" + - id: 136 + transactions: [] + epoch: "2.5" + - id: 137 + transactions: [] + epoch: "2.5" + - id: 138 + transactions: [] + epoch: "2.5" + - id: 139 + transactions: [] + epoch: "2.5" + - id: 140 + transactions: [] + epoch: "2.5" + - id: 141 + transactions: [] + epoch: "2.5" + - id: 142 + transactions: [] + epoch: "2.5" + - id: 143 + transactions: [] + epoch: "2.5" + - id: 144 + transactions: [] + epoch: "2.5" + - id: 145 + transactions: [] + epoch: "2.5" + - id: 146 + transactions: [] + epoch: "2.5" + - id: 147 + transactions: [] + epoch: "2.5" + - id: 148 + transactions: [] + epoch: "2.5" + - id: 149 + transactions: [] + epoch: "2.5" + - id: 150 + transactions: [] + epoch: "2.5" + - id: 151 + transactions: [] + epoch: "2.5" + - id: 152 + transactions: [] + epoch: "2.5" + - id: 153 + transactions: [] + epoch: "2.5" + - id: 154 + transactions: [] + epoch: "2.5" + - id: 155 + transactions: [] + epoch: "2.5" + - id: 156 + transactions: [] + epoch: "2.5" + - id: 157 + transactions: [] + epoch: "2.5" + - id: 158 + transactions: [] + epoch: "2.5" + - id: 159 + transactions: [] + epoch: "2.5" + - id: 160 + transactions: [] + epoch: "2.5" + - id: 161 + transactions: [] + epoch: "2.5" + - id: 162 + transactions: [] + epoch: "2.5" + - id: 163 + transactions: [] + epoch: "2.5" + - id: 164 + transactions: [] + epoch: "2.5" + - id: 165 + transactions: [] + epoch: "2.5" + - id: 166 + transactions: [] + epoch: "2.5" + - id: 167 + transactions: [] + epoch: "2.5" + - id: 168 + transactions: [] + epoch: "2.5" + - id: 169 + transactions: [] + epoch: "2.5" + - id: 170 + transactions: [] + epoch: "2.5" + - id: 171 + transactions: [] + epoch: "2.5" + - id: 172 + transactions: [] + epoch: "2.5" + - id: 173 + transactions: [] + epoch: "2.5" + - id: 174 + transactions: [] + epoch: "2.5" + - id: 175 + transactions: [] + epoch: "2.5" + - id: 176 + transactions: [] + epoch: "2.5" + - id: 177 + transactions: [] + epoch: "2.5" + - id: 178 + transactions: [] + epoch: "2.5" + - id: 179 + transactions: [] + epoch: "2.5" + - id: 180 + transactions: [] + epoch: "2.5" + - id: 181 + transactions: [] + epoch: "2.5" + - id: 182 + transactions: [] + epoch: "2.5" + - id: 183 + transactions: [] + epoch: "2.5" + - id: 184 + transactions: [] + epoch: "2.5" + - id: 185 + transactions: [] + epoch: "2.5" + - id: 186 + transactions: [] + epoch: "2.5" + - id: 187 + transactions: [] + epoch: "2.5" + - id: 188 + transactions: [] + epoch: "2.5" + - id: 189 + transactions: [] + epoch: "2.5" + - id: 190 + transactions: [] + epoch: "2.5" + - id: 191 + transactions: [] + epoch: "2.5" + - id: 192 + transactions: [] + epoch: "2.5" + - id: 193 + transactions: [] + epoch: "2.5" + - id: 194 + transactions: [] + epoch: "2.5" + - id: 195 + transactions: [] + epoch: "2.5" + - id: 196 + transactions: [] + epoch: "2.5" + - id: 197 + transactions: [] + epoch: "2.5" + - id: 198 + transactions: [] + epoch: "2.5" + - id: 199 + transactions: [] + epoch: "2.5" + - id: 200 + transactions: [] + epoch: "2.5" + - id: 201 + transactions: [] + epoch: "2.5" + - id: 202 + transactions: [] + epoch: "2.5" + - id: 203 + transactions: [] + epoch: "2.5" + - id: 204 + transactions: [] + epoch: "2.5" + - id: 205 + transactions: [] + epoch: "2.5" + - id: 206 + transactions: [] + epoch: "2.5" + - id: 207 + transactions: [] + epoch: "2.5" + - id: 208 + transactions: [] + epoch: "2.5" + - id: 209 + transactions: [] + epoch: "2.5" + - id: 210 + transactions: [] + epoch: "2.5" + - id: 211 + transactions: [] + epoch: "2.5" + - id: 212 + transactions: [] + epoch: "2.5" + - id: 213 + transactions: [] + epoch: "2.5" + - id: 214 + transactions: [] + epoch: "2.5" + - id: 215 + transactions: [] + epoch: "2.5" + - id: 216 + transactions: [] + epoch: "2.5" + - id: 217 + transactions: [] + epoch: "2.5" + - id: 218 + transactions: [] + epoch: "2.5" + - id: 219 + transactions: [] + epoch: "2.5" + - id: 220 + transactions: [] + epoch: "2.5" + - id: 221 + transactions: [] + epoch: "2.5" + - id: 222 + transactions: [] + epoch: "2.5" + - id: 223 + transactions: [] + epoch: "2.5" + - id: 224 + transactions: [] + epoch: "2.5" + - id: 225 + transactions: [] + epoch: "2.5" + - id: 226 + transactions: [] + epoch: "2.5" + - id: 227 + transactions: [] + epoch: "2.5" + - id: 228 + transactions: [] + epoch: "2.5" + - id: 229 + transactions: [] + epoch: "2.5" + - id: 230 + transactions: [] + epoch: "2.5" + - id: 231 + transactions: [] + epoch: "2.5" + - id: 232 + transactions: [] + epoch: "2.5" + - id: 233 + transactions: [] + epoch: "2.5" + - id: 234 + transactions: [] + epoch: "2.5" + - id: 235 + transactions: [] + epoch: "2.5" + - id: 236 + transactions: [] + epoch: "2.5" + - id: 237 + transactions: [] + epoch: "2.5" + - id: 238 + transactions: [] + epoch: "2.5" + - id: 239 + transactions: [] + epoch: "2.5" + - id: 240 + transactions: [] + epoch: "2.5" + - id: 241 + transactions: [] + epoch: "2.5" + - id: 242 + transactions: [] + epoch: "2.5" + - id: 243 + transactions: [] + epoch: "2.5" + - id: 244 + transactions: [] + epoch: "2.5" + - id: 245 + transactions: [] + epoch: "2.5" + - id: 246 + transactions: [] + epoch: "2.5" + - id: 247 + transactions: [] + epoch: "2.5" + - id: 248 + transactions: [] + epoch: "2.5" + - id: 249 + transactions: [] + epoch: "2.5" + - id: 250 + transactions: [] + epoch: "2.5" + - id: 251 + transactions: [] + epoch: "2.5" + - id: 252 + transactions: [] + epoch: "2.5" + - id: 253 + transactions: [] + epoch: "2.5" + - id: 254 + transactions: [] + epoch: "2.5" + - id: 255 + transactions: [] + epoch: "2.5" + - id: 256 + transactions: [] + epoch: "2.5" + - id: 257 + transactions: [] + epoch: "2.5" + - id: 258 + transactions: [] + epoch: "2.5" + - id: 259 + transactions: [] + epoch: "2.5" + - id: 260 + transactions: [] + epoch: "2.5" + - id: 261 + transactions: [] + epoch: "2.5" + - id: 262 + transactions: [] + epoch: "2.5" + - id: 263 + transactions: [] + epoch: "2.5" + - id: 264 + transactions: [] + epoch: "2.5" + - id: 265 + transactions: [] + epoch: "2.5" + - id: 266 + transactions: [] + epoch: "2.5" + - id: 267 + transactions: [] + epoch: "2.5" + - id: 268 + transactions: [] + epoch: "2.5" + - id: 269 + transactions: [] + epoch: "2.5" + - id: 270 + transactions: [] + epoch: "2.5" + - id: 271 + transactions: [] + epoch: "2.5" + - id: 272 + transactions: [] + epoch: "2.5" + - id: 273 + transactions: [] + epoch: "2.5" + - id: 274 + transactions: [] + epoch: "2.5" + - id: 275 + transactions: [] + epoch: "2.5" + - id: 276 + transactions: [] + epoch: "2.5" + - id: 277 + transactions: [] + epoch: "2.5" + - id: 278 + transactions: [] + epoch: "2.5" + - id: 279 + transactions: [] + epoch: "2.5" + - id: 280 + transactions: [] + epoch: "2.5" + - id: 281 + transactions: [] + epoch: "2.5" + - id: 282 + transactions: [] + epoch: "2.5" + - id: 283 + transactions: [] + epoch: "2.5" + - id: 284 + transactions: [] + epoch: "2.5" + - id: 285 + transactions: [] + epoch: "2.5" + - id: 286 + transactions: [] + epoch: "2.5" + - id: 287 + transactions: [] + epoch: "2.5" + - id: 288 + transactions: [] + epoch: "2.5" + - id: 289 + transactions: [] + epoch: "2.5" + - id: 290 + transactions: [] + epoch: "2.5" + - id: 291 + transactions: [] + epoch: "2.5" + - id: 292 + transactions: [] + epoch: "2.5" + - id: 293 + transactions: [] + epoch: "2.5" + - id: 294 + transactions: [] + epoch: "2.5" + - id: 295 + transactions: [] + epoch: "2.5" + - id: 296 + transactions: [] + epoch: "2.5" + - id: 297 + transactions: [] + epoch: "2.5" + - id: 298 + transactions: [] + epoch: "2.5" + - id: 299 + transactions: [] + epoch: "2.5" + - id: 300 + transactions: [] + epoch: "2.5" + - id: 301 + transactions: [] + epoch: "2.5" + - id: 302 + transactions: [] + epoch: "2.5" + - id: 303 + transactions: [] + epoch: "2.5" + - id: 304 + transactions: [] + epoch: "2.5" + - id: 305 + transactions: [] + epoch: "2.5" + - id: 306 + transactions: [] + epoch: "2.5" + - id: 307 + transactions: [] + epoch: "2.5" + - id: 308 + transactions: [] + epoch: "2.5" + - id: 309 + transactions: [] + epoch: "2.5" + - id: 310 + transactions: [] + epoch: "2.5" + - id: 311 + transactions: [] + epoch: "2.5" + - id: 312 + transactions: [] + epoch: "2.5" + - id: 313 + transactions: [] + epoch: "2.5" + - id: 314 + transactions: [] + epoch: "2.5" + - id: 315 + transactions: [] + epoch: "2.5" + - id: 316 + transactions: [] + epoch: "2.5" + - id: 317 + transactions: [] + epoch: "2.5" + - id: 318 + transactions: [] + epoch: "2.5" + - id: 319 + transactions: [] + epoch: "2.5" + - id: 320 + transactions: [] + epoch: "2.5" + - id: 321 + transactions: [] + epoch: "2.5" + - id: 322 + transactions: [] + epoch: "2.5" + - id: 323 + transactions: [] + epoch: "2.5" + - id: 324 + transactions: [] + epoch: "2.5" + - id: 325 + transactions: [] + epoch: "2.5" + - id: 326 + transactions: [] + epoch: "2.5" + - id: 327 + transactions: [] + epoch: "2.5" + - id: 328 + transactions: [] + epoch: "2.5" + - id: 329 + transactions: [] + epoch: "2.5" + - id: 330 + transactions: [] + epoch: "2.5" + - id: 331 + transactions: [] + epoch: "2.5" + - id: 332 + transactions: [] + epoch: "2.5" + - id: 333 + transactions: [] + epoch: "2.5" + - id: 334 + transactions: [] + epoch: "2.5" + - id: 335 + transactions: [] + epoch: "2.5" + - id: 336 + transactions: [] + epoch: "2.5" + - id: 337 + transactions: [] + epoch: "2.5" + - id: 338 + transactions: [] + epoch: "2.5" + - id: 339 + transactions: [] + epoch: "2.5" + - id: 340 + transactions: [] + epoch: "2.5" + - id: 341 + transactions: [] + epoch: "2.5" + - id: 342 + transactions: [] + epoch: "2.5" + - id: 343 + transactions: [] + epoch: "2.5" + - id: 344 + transactions: [] + epoch: "2.5" + - id: 345 + transactions: [] + epoch: "2.5" + - id: 346 + transactions: [] + epoch: "2.5" + - id: 347 + transactions: [] + epoch: "2.5" + - id: 348 + transactions: [] + epoch: "2.5" + - id: 349 + transactions: [] + epoch: "2.5" + - id: 350 + transactions: [] + epoch: "2.5" + - id: 351 + transactions: [] + epoch: "2.5" + - id: 352 + transactions: [] + epoch: "2.5" + - id: 353 + transactions: [] + epoch: "2.5" + - id: 354 + transactions: [] + epoch: "2.5" + - id: 355 + transactions: [] + epoch: "2.5" + - id: 356 + transactions: [] + epoch: "2.5" + - id: 357 + transactions: [] + epoch: "2.5" + - id: 358 + transactions: [] + epoch: "2.5" + - id: 359 + transactions: [] + epoch: "2.5" + - id: 360 + transactions: [] + epoch: "2.5" + - id: 361 + transactions: [] + epoch: "2.5" + - id: 362 + transactions: [] + epoch: "2.5" + - id: 363 + transactions: [] + epoch: "2.5" + - id: 364 + transactions: [] + epoch: "2.5" + - id: 365 + transactions: [] + epoch: "2.5" + - id: 366 + transactions: [] + epoch: "2.5" + - id: 367 + transactions: [] + epoch: "2.5" + - id: 368 + transactions: [] + epoch: "2.5" + - id: 369 + transactions: [] + epoch: "2.5" + - id: 370 + transactions: [] + epoch: "2.5" + - id: 371 + transactions: [] + epoch: "2.5" + - id: 372 + transactions: [] + epoch: "2.5" + - id: 373 + transactions: [] + epoch: "2.5" + - id: 374 + transactions: [] + epoch: "2.5" + - id: 375 + transactions: [] + epoch: "2.5" + - id: 376 + transactions: [] + epoch: "2.5" + - id: 377 + transactions: [] + epoch: "2.5" + - id: 378 + transactions: [] + epoch: "2.5" + - id: 379 + transactions: [] + epoch: "2.5" + - id: 380 + transactions: [] + epoch: "2.5" + - id: 381 + transactions: [] + epoch: "2.5" + - id: 382 + transactions: [] + epoch: "2.5" + - id: 383 + transactions: [] + epoch: "2.5" + - id: 384 + transactions: [] + epoch: "2.5" + - id: 385 + transactions: [] + epoch: "2.5" + - id: 386 + transactions: [] + epoch: "2.5" + - id: 387 + transactions: [] + epoch: "2.5" + - id: 388 + transactions: [] + epoch: "2.5" + - id: 389 + transactions: [] + epoch: "2.5" + - id: 390 + transactions: [] + epoch: "2.5" + - id: 391 + transactions: [] + epoch: "2.5" + - id: 392 + transactions: [] + epoch: "2.5" + - id: 393 + transactions: [] + epoch: "2.5" + - id: 394 + transactions: [] + epoch: "2.5" + - id: 395 + transactions: [] + epoch: "2.5" + - id: 396 + transactions: [] + epoch: "2.5" + - id: 397 + transactions: [] + epoch: "2.5" + - id: 398 + transactions: [] + epoch: "2.5" + - id: 399 + transactions: [] + epoch: "2.5" + - id: 400 + transactions: [] + epoch: "2.5" + - id: 401 + transactions: [] + epoch: "2.5" + - id: 402 + transactions: [] + epoch: "2.5" + - id: 403 + transactions: [] + epoch: "2.5" + - id: 404 + transactions: [] + epoch: "2.5" + - id: 405 + transactions: [] + epoch: "2.5" + - id: 406 + transactions: [] + epoch: "2.5" + - id: 407 + transactions: [] + epoch: "2.5" + - id: 408 + transactions: [] + epoch: "2.5" + - id: 409 + transactions: [] + epoch: "2.5" + - id: 410 + transactions: [] + epoch: "2.5" + - id: 411 + transactions: [] + epoch: "2.5" + - id: 412 + transactions: [] + epoch: "2.5" + - id: 413 + transactions: [] + epoch: "2.5" + - id: 414 + transactions: [] + epoch: "2.5" + - id: 415 + transactions: [] + epoch: "2.5" + - id: 416 + transactions: [] + epoch: "2.5" + - id: 417 + transactions: [] + epoch: "2.5" + - id: 418 + transactions: [] + epoch: "2.5" + - id: 419 + transactions: [] + epoch: "2.5" + - id: 420 + transactions: [] + epoch: "2.5" + - id: 421 + transactions: [] + epoch: "2.5" + - id: 422 + transactions: [] + epoch: "2.5" + - id: 423 + transactions: [] + epoch: "2.5" + - id: 424 + transactions: [] + epoch: "2.5" + - id: 425 + transactions: [] + epoch: "2.5" + - id: 426 + transactions: [] + epoch: "2.5" + - id: 427 + transactions: [] + epoch: "2.5" + - id: 428 + transactions: [] + epoch: "2.5" + - id: 429 + transactions: [] + epoch: "2.5" + - id: 430 + transactions: [] + epoch: "2.5" + - id: 431 + transactions: [] + epoch: "2.5" + - id: 432 + transactions: [] + epoch: "2.5" + - id: 433 + transactions: [] + epoch: "2.5" + - id: 434 + transactions: [] + epoch: "2.5" + - id: 435 + transactions: [] + epoch: "2.5" + - id: 436 + transactions: [] + epoch: "2.5" + - id: 437 + transactions: [] + epoch: "2.5" + - id: 438 + transactions: [] + epoch: "2.5" + - id: 439 + transactions: [] + epoch: "2.5" + - id: 440 + transactions: [] + epoch: "2.5" + - id: 441 + transactions: [] + epoch: "2.5" + - id: 442 + transactions: [] + epoch: "2.5" + - id: 443 + transactions: [] + epoch: "2.5" + - id: 444 + transactions: [] + epoch: "2.5" + - id: 445 + transactions: [] + epoch: "2.5" + - id: 446 + transactions: [] + epoch: "2.5" + - id: 447 + transactions: [] + epoch: "2.5" + - id: 448 + transactions: [] + epoch: "2.5" + - id: 449 + transactions: [] + epoch: "2.5" + - id: 450 + transactions: [] + epoch: "2.5" + - id: 451 + transactions: [] + epoch: "2.5" + - id: 452 + transactions: [] + epoch: "2.5" + - id: 453 + transactions: [] + epoch: "2.5" + - id: 454 + transactions: [] + epoch: "2.5" + - id: 455 + transactions: [] + epoch: "2.5" + - id: 456 + transactions: [] + epoch: "2.5" + - id: 457 + transactions: [] + epoch: "2.5" + - id: 458 + transactions: [] + epoch: "2.5" + - id: 459 + transactions: [] + epoch: "2.5" + - id: 460 + transactions: [] + epoch: "2.5" + - id: 461 + transactions: [] + epoch: "2.5" + - id: 462 + transactions: [] + epoch: "2.5" + - id: 463 + transactions: [] + epoch: "2.5" + - id: 464 + transactions: [] + epoch: "2.5" + - id: 465 + transactions: [] + epoch: "2.5" + - id: 466 + transactions: [] + epoch: "2.5" + - id: 467 + transactions: [] + epoch: "2.5" + - id: 468 + transactions: [] + epoch: "2.5" + - id: 469 + transactions: [] + epoch: "2.5" + - id: 470 + transactions: [] + epoch: "2.5" + - id: 471 + transactions: [] + epoch: "2.5" + - id: 472 + transactions: [] + epoch: "2.5" + - id: 473 + transactions: [] + epoch: "2.5" + - id: 474 + transactions: [] + epoch: "2.5" + - id: 475 + transactions: [] + epoch: "2.5" + - id: 476 + transactions: [] + epoch: "2.5" + - id: 477 + transactions: [] + epoch: "2.5" + - id: 478 + transactions: [] + epoch: "2.5" + - id: 479 + transactions: [] + epoch: "2.5" + - id: 480 + transactions: [] + epoch: "2.5" + - id: 481 + transactions: [] + epoch: "2.5" + - id: 482 + transactions: [] + epoch: "2.5" + - id: 483 + transactions: [] + epoch: "2.5" + - id: 484 + transactions: [] + epoch: "2.5" + - id: 485 + transactions: [] + epoch: "2.5" + - id: 486 + transactions: [] + epoch: "2.5" + - id: 487 + transactions: [] + epoch: "2.5" + - id: 488 + transactions: [] + epoch: "2.5" + - id: 489 + transactions: [] + epoch: "2.5" + - id: 490 + transactions: [] + epoch: "2.5" + - id: 491 + transactions: [] + epoch: "2.5" + - id: 492 + transactions: [] + epoch: "2.5" + - id: 493 + transactions: [] + epoch: "2.5" + - id: 494 + transactions: [] + epoch: "2.5" + - id: 495 + transactions: [] + epoch: "2.5" + - id: 496 + transactions: [] + epoch: "2.5" + - id: 497 + transactions: [] + epoch: "2.5" + - id: 498 + transactions: [] + epoch: "2.5" + - id: 499 + transactions: [] + epoch: "2.5" + - id: 500 + transactions: [] + epoch: "2.5" + - id: 501 + transactions: [] + epoch: "2.5" + - id: 502 + transactions: [] + epoch: "2.5" + - id: 503 + transactions: [] + epoch: "2.5" + - id: 504 + transactions: [] + epoch: "2.5" + - id: 505 + transactions: [] + epoch: "2.5" + - id: 506 + transactions: [] + epoch: "2.5" + - id: 507 + transactions: [] + epoch: "2.5" + - id: 508 + transactions: [] + epoch: "2.5" + - id: 509 + transactions: [] + epoch: "2.5" + - id: 510 + transactions: [] + epoch: "2.5" + - id: 511 + transactions: [] + epoch: "2.5" + - id: 512 + transactions: [] + epoch: "2.5" + - id: 513 + transactions: [] + epoch: "2.5" + - id: 514 + transactions: [] + epoch: "2.5" + - id: 515 + transactions: [] + epoch: "2.5" + - id: 516 + transactions: [] + epoch: "2.5" + - id: 517 + transactions: [] + epoch: "2.5" + - id: 518 + transactions: [] + epoch: "2.5" + - id: 519 + transactions: [] + epoch: "2.5" + - id: 520 + transactions: [] + epoch: "2.5" + - id: 521 + transactions: [] + epoch: "2.5" + - id: 522 + transactions: [] + epoch: "2.5" + - id: 523 + transactions: [] + epoch: "2.5" + - id: 524 + transactions: [] + epoch: "2.5" + - id: 525 + transactions: [] + epoch: "2.5" + - id: 526 + transactions: [] + epoch: "2.5" + - id: 527 + transactions: [] + epoch: "2.5" + - id: 528 + transactions: [] + epoch: "2.5" + - id: 529 + transactions: [] + epoch: "2.5" + - id: 530 + transactions: [] + epoch: "2.5" + - id: 531 + transactions: [] + epoch: "2.5" + - id: 532 + transactions: [] + epoch: "2.5" + - id: 533 + transactions: [] + epoch: "2.5" + - id: 534 + transactions: [] + epoch: "2.5" + - id: 535 + transactions: [] + epoch: "2.5" + - id: 536 + transactions: [] + epoch: "2.5" + - id: 537 + transactions: [] + epoch: "2.5" + - id: 538 + transactions: [] + epoch: "2.5" + - id: 539 + transactions: [] + epoch: "2.5" + - id: 540 + transactions: [] + epoch: "2.5" + - id: 541 + transactions: [] + epoch: "2.5" + - id: 542 + transactions: [] + epoch: "2.5" + - id: 543 + transactions: [] + epoch: "2.5" + - id: 544 + transactions: [] + epoch: "2.5" + - id: 545 + transactions: [] + epoch: "2.5" + - id: 546 + transactions: [] + epoch: "2.5" + - id: 547 + transactions: [] + epoch: "2.5" + - id: 548 + transactions: [] + epoch: "2.5" + - id: 549 + transactions: [] + epoch: "2.5" + - id: 550 + transactions: [] + epoch: "2.5" + - id: 551 + transactions: [] + epoch: "2.5" + - id: 552 + transactions: [] + epoch: "2.5" + - id: 553 + transactions: [] + epoch: "2.5" + - id: 554 + transactions: [] + epoch: "2.5" + - id: 555 + transactions: [] + epoch: "2.5" + - id: 556 + transactions: [] + epoch: "2.5" + - id: 557 + transactions: [] + epoch: "2.5" + - id: 558 + transactions: [] + epoch: "2.5" + - id: 559 + transactions: [] + epoch: "2.5" + - id: 560 + transactions: [] + epoch: "2.5" + - id: 561 + transactions: [] + epoch: "2.5" + - id: 562 + transactions: [] + epoch: "2.5" + - id: 563 + transactions: [] + epoch: "2.5" + - id: 564 + transactions: [] + epoch: "2.5" + - id: 565 + transactions: [] + epoch: "2.5" + - id: 566 + transactions: [] + epoch: "2.5" + - id: 567 + transactions: [] + epoch: "2.5" + - id: 568 + transactions: [] + epoch: "2.5" + - id: 569 + transactions: [] + epoch: "2.5" + - id: 570 + transactions: [] + epoch: "2.5" + - id: 571 + transactions: [] + epoch: "2.5" + - id: 572 + transactions: [] + epoch: "2.5" + - id: 573 + transactions: [] + epoch: "2.5" + - id: 574 + transactions: [] + epoch: "2.5" + - id: 575 + transactions: [] + epoch: "2.5" + - id: 576 + transactions: [] + epoch: "2.5" + - id: 577 + transactions: [] + epoch: "2.5" + - id: 578 + transactions: [] + epoch: "2.5" + - id: 579 + transactions: [] + epoch: "2.5" + - id: 580 + transactions: [] + epoch: "2.5" + - id: 581 + transactions: [] + epoch: "2.5" + - id: 582 + transactions: [] + epoch: "2.5" + - id: 583 + transactions: [] + epoch: "2.5" + - id: 584 + transactions: [] + epoch: "2.5" + - id: 585 + transactions: [] + epoch: "2.5" + - id: 586 + transactions: [] + epoch: "2.5" + - id: 587 + transactions: [] + epoch: "2.5" + - id: 588 + transactions: [] + epoch: "2.5" + - id: 589 + transactions: [] + epoch: "2.5" + - id: 590 + transactions: [] + epoch: "2.5" + - id: 591 + transactions: [] + epoch: "2.5" + - id: 592 + transactions: [] + epoch: "2.5" + - id: 593 + transactions: [] + epoch: "2.5" + - id: 594 + transactions: [] + epoch: "2.5" + - id: 595 + transactions: [] + epoch: "2.5" + - id: 596 + transactions: [] + epoch: "2.5" + - id: 597 + transactions: [] + epoch: "2.5" + - id: 598 + transactions: [] + epoch: "2.5" + - id: 599 + transactions: [] + epoch: "2.5" + - id: 600 + transactions: [] + epoch: "2.5" + - id: 601 + transactions: [] + epoch: "2.5" + - id: 602 + transactions: [] + epoch: "2.5" + - id: 603 + transactions: [] + epoch: "2.5" + - id: 604 + transactions: [] + epoch: "2.5" + - id: 605 + transactions: [] + epoch: "2.5" + - id: 606 + transactions: [] + epoch: "2.5" + - id: 607 + transactions: [] + epoch: "2.5" + - id: 608 + transactions: [] + epoch: "2.5" + - id: 609 + transactions: [] + epoch: "2.5" + - id: 610 + transactions: [] + epoch: "2.5" + - id: 611 + transactions: [] + epoch: "2.5" + - id: 612 + transactions: [] + epoch: "2.5" + - id: 613 + transactions: [] + epoch: "2.5" + - id: 614 + transactions: [] + epoch: "2.5" + - id: 615 + transactions: [] + epoch: "2.5" + - id: 616 + transactions: [] + epoch: "2.5" + - id: 617 + transactions: [] + epoch: "2.5" + - id: 618 + transactions: [] + epoch: "2.5" + - id: 619 + transactions: [] + epoch: "2.5" + - id: 620 + transactions: [] + epoch: "2.5" + - id: 621 + transactions: [] + epoch: "2.5" + - id: 622 + transactions: [] + epoch: "2.5" + - id: 623 + transactions: [] + epoch: "2.5" + - id: 624 + transactions: [] + epoch: "2.5" + - id: 625 + transactions: [] + epoch: "2.5" + - id: 626 + transactions: [] + epoch: "2.5" + - id: 627 + transactions: [] + epoch: "2.5" + - id: 628 + transactions: [] + epoch: "2.5" + - id: 629 + transactions: [] + epoch: "2.5" + - id: 630 + transactions: [] + epoch: "2.5" + - id: 631 + transactions: [] + epoch: "2.5" + - id: 632 + transactions: [] + epoch: "2.5" + - id: 633 + transactions: [] + epoch: "2.5" + - id: 634 + transactions: [] + epoch: "2.5" + - id: 635 + transactions: [] + epoch: "2.5" + - id: 636 + transactions: [] + epoch: "2.5" + - id: 637 + transactions: [] + epoch: "2.5" + - id: 638 + transactions: [] + epoch: "2.5" + - id: 639 + transactions: [] + epoch: "2.5" + - id: 640 + transactions: [] + epoch: "2.5" + - id: 641 + transactions: [] + epoch: "2.5" + - id: 642 + transactions: [] + epoch: "2.5" + - id: 643 + transactions: [] + epoch: "2.5" + - id: 644 + transactions: [] + epoch: "2.5" + - id: 645 + transactions: [] + epoch: "2.5" + - id: 646 + transactions: [] + epoch: "2.5" + - id: 647 + transactions: [] + epoch: "2.5" + - id: 648 + transactions: [] + epoch: "2.5" + - id: 649 + transactions: [] + epoch: "2.5" + - id: 650 + transactions: [] + epoch: "2.5" + - id: 651 + transactions: [] + epoch: "2.5" + - id: 652 + transactions: [] + epoch: "2.5" + - id: 653 + transactions: [] + epoch: "2.5" + - id: 654 + transactions: [] + epoch: "2.5" + - id: 655 + transactions: [] + epoch: "2.5" + - id: 656 + transactions: [] + epoch: "2.5" + - id: 657 + transactions: [] + epoch: "2.5" + - id: 658 + transactions: [] + epoch: "2.5" + - id: 659 + transactions: [] + epoch: "2.5" + - id: 660 + transactions: [] + epoch: "2.5" + - id: 661 + transactions: [] + epoch: "2.5" + - id: 662 + transactions: [] + epoch: "2.5" + - id: 663 + transactions: [] + epoch: "2.5" + - id: 664 + transactions: [] + epoch: "2.5" + - id: 665 + transactions: [] + epoch: "2.5" + - id: 666 + transactions: [] + epoch: "2.5" + - id: 667 + transactions: [] + epoch: "2.5" + - id: 668 + transactions: [] + epoch: "2.5" + - id: 669 + transactions: [] + epoch: "2.5" + - id: 670 + transactions: [] + epoch: "2.5" + - id: 671 + transactions: [] + epoch: "2.5" + - id: 672 + transactions: [] + epoch: "2.5" + - id: 673 + transactions: [] + epoch: "2.5" + - id: 674 + transactions: [] + epoch: "2.5" + - id: 675 + transactions: [] + epoch: "2.5" + - id: 676 + transactions: [] + epoch: "2.5" + - id: 677 + transactions: [] + epoch: "2.5" + - id: 678 + transactions: [] + epoch: "2.5" + - id: 679 + transactions: [] + epoch: "2.5" + - id: 680 + transactions: [] + epoch: "2.5" + - id: 681 + transactions: [] + epoch: "2.5" + - id: 682 + transactions: [] + epoch: "2.5" + - id: 683 + transactions: [] + epoch: "2.5" + - id: 684 + transactions: [] + epoch: "2.5" + - id: 685 + transactions: [] + epoch: "2.5" + - id: 686 + transactions: [] + epoch: "2.5" + - id: 687 + transactions: [] + epoch: "2.5" + - id: 688 + transactions: [] + epoch: "2.5" + - id: 689 + transactions: [] + epoch: "2.5" + - id: 690 + transactions: [] + epoch: "2.5" + - id: 691 + transactions: [] + epoch: "2.5" + - id: 692 + transactions: [] + epoch: "2.5" + - id: 693 + transactions: [] + epoch: "2.5" + - id: 694 + transactions: [] + epoch: "2.5" + - id: 695 + transactions: [] + epoch: "2.5" + - id: 696 + transactions: [] + epoch: "2.5" + - id: 697 + transactions: [] + epoch: "2.5" + - id: 698 + transactions: [] + epoch: "2.5" + - id: 699 + transactions: [] + epoch: "2.5" + - id: 700 + transactions: [] + epoch: "2.5" + - id: 701 + transactions: [] + epoch: "2.5" + - id: 702 + transactions: [] + epoch: "2.5" + - id: 703 + transactions: [] + epoch: "2.5" + - id: 704 + transactions: [] + epoch: "2.5" + - id: 705 + transactions: [] + epoch: "2.5" + - id: 706 + transactions: [] + epoch: "2.5" + - id: 707 + transactions: [] + epoch: "2.5" + - id: 708 + transactions: [] + epoch: "2.5" + - id: 709 + transactions: [] + epoch: "2.5" + - id: 710 + transactions: [] + epoch: "2.5" + - id: 711 + transactions: [] + epoch: "2.5" + - id: 712 + transactions: [] + epoch: "2.5" + - id: 713 + transactions: [] + epoch: "2.5" + - id: 714 + transactions: [] + epoch: "2.5" + - id: 715 + transactions: [] + epoch: "2.5" + - id: 716 + transactions: [] + epoch: "2.5" + - id: 717 + transactions: [] + epoch: "2.5" + - id: 718 + transactions: [] + epoch: "2.5" + - id: 719 + transactions: [] + epoch: "2.5" + - id: 720 + transactions: [] + epoch: "2.5" + - id: 721 + transactions: [] + epoch: "2.5" + - id: 722 + transactions: [] + epoch: "2.5" + - id: 723 + transactions: [] + epoch: "2.5" + - id: 724 + transactions: [] + epoch: "2.5" + - id: 725 + transactions: [] + epoch: "2.5" + - id: 726 + transactions: [] + epoch: "2.5" + - id: 727 + transactions: [] + epoch: "2.5" + - id: 728 + transactions: [] + epoch: "2.5" + - id: 729 + transactions: [] + epoch: "2.5" + - id: 730 + transactions: [] + epoch: "2.5" + - id: 731 + transactions: [] + epoch: "2.5" + - id: 732 + transactions: [] + epoch: "2.5" + - id: 733 + transactions: [] + epoch: "2.5" + - id: 734 + transactions: [] + epoch: "2.5" + - id: 735 + transactions: [] + epoch: "2.5" + - id: 736 + transactions: [] + epoch: "2.5" + - id: 737 + transactions: [] + epoch: "2.5" + - id: 738 + transactions: [] + epoch: "2.5" + - id: 739 + transactions: [] + epoch: "2.5" + - id: 740 + transactions: [] + epoch: "2.5" + - id: 741 + transactions: [] + epoch: "2.5" + - id: 742 + transactions: [] + epoch: "2.5" + - id: 743 + transactions: [] + epoch: "2.5" + - id: 744 + transactions: [] + epoch: "2.5" + - id: 745 + transactions: [] + epoch: "2.5" + - id: 746 + transactions: [] + epoch: "2.5" + - id: 747 + transactions: [] + epoch: "2.5" + - id: 748 + transactions: [] + epoch: "2.5" + - id: 749 + transactions: [] + epoch: "2.5" + - id: 750 + transactions: [] + epoch: "2.5" + - id: 751 + transactions: [] + epoch: "2.5" + - id: 752 + transactions: [] + epoch: "2.5" + - id: 753 + transactions: [] + epoch: "2.5" + - id: 754 + transactions: [] + epoch: "2.5" + - id: 755 + transactions: [] + epoch: "2.5" + - id: 756 + transactions: [] + epoch: "2.5" + - id: 757 + transactions: [] + epoch: "2.5" + - id: 758 + transactions: [] + epoch: "2.5" + - id: 759 + transactions: [] + epoch: "2.5" + - id: 760 + transactions: [] + epoch: "2.5" + - id: 761 + transactions: [] + epoch: "2.5" + - id: 762 + transactions: [] + epoch: "2.5" + - id: 763 + transactions: [] + epoch: "2.5" + - id: 764 + transactions: [] + epoch: "2.5" + - id: 765 + transactions: [] + epoch: "2.5" + - id: 766 + transactions: [] + epoch: "2.5" + - id: 767 + transactions: [] + epoch: "2.5" + - id: 768 + transactions: [] + epoch: "2.5" + - id: 769 + transactions: [] + epoch: "2.5" + - id: 770 + transactions: [] + epoch: "2.5" + - id: 771 + transactions: [] + epoch: "2.5" + - id: 772 + transactions: [] + epoch: "2.5" + - id: 773 + transactions: [] + epoch: "2.5" + - id: 774 + transactions: [] + epoch: "2.5" + - id: 775 + transactions: [] + epoch: "2.5" + - id: 776 + transactions: [] + epoch: "2.5" + - id: 777 + transactions: [] + epoch: "2.5" + - id: 778 + transactions: [] + epoch: "2.5" + - id: 779 + transactions: [] + epoch: "2.5" + - id: 780 + transactions: [] + epoch: "2.5" + - id: 781 + transactions: [] + epoch: "2.5" + - id: 782 + transactions: [] + epoch: "2.5" + - id: 783 + transactions: [] + epoch: "2.5" + - id: 784 + transactions: [] + epoch: "2.5" + - id: 785 + transactions: [] + epoch: "2.5" + - id: 786 + transactions: [] + epoch: "2.5" + - id: 787 + transactions: [] + epoch: "2.5" + - id: 788 + transactions: [] + epoch: "2.5" + - id: 789 + transactions: [] + epoch: "2.5" + - id: 790 + transactions: [] + epoch: "2.5" + - id: 791 + transactions: [] + epoch: "2.5" + - id: 792 + transactions: [] + epoch: "2.5" + - id: 793 + transactions: [] + epoch: "2.5" + - id: 794 + transactions: [] + epoch: "2.5" + - id: 795 + transactions: [] + epoch: "2.5" + - id: 796 + transactions: [] + epoch: "2.5" + - id: 797 + transactions: [] + epoch: "2.5" + - id: 798 + transactions: [] + epoch: "2.5" + - id: 799 + transactions: [] + epoch: "2.5" + - id: 800 + transactions: [] + epoch: "2.5" + - id: 801 + transactions: [] + epoch: "2.5" + - id: 802 + transactions: [] + epoch: "2.5" + - id: 803 + transactions: [] + epoch: "2.5" + - id: 804 + transactions: [] + epoch: "2.5" + - id: 805 + transactions: [] + epoch: "2.5" + - id: 806 + transactions: [] + epoch: "2.5" + - id: 807 + transactions: [] + epoch: "2.5" + - id: 808 + transactions: [] + epoch: "2.5" + - id: 809 + transactions: [] + epoch: "2.5" + - id: 810 + transactions: [] + epoch: "2.5" + - id: 811 + transactions: [] + epoch: "2.5" + - id: 812 + transactions: [] + epoch: "2.5" + - id: 813 + transactions: [] + epoch: "2.5" + - id: 814 + transactions: [] + epoch: "2.5" + - id: 815 + transactions: [] + epoch: "2.5" + - id: 816 + transactions: [] + epoch: "2.5" + - id: 817 + transactions: [] + epoch: "2.5" + - id: 818 + transactions: [] + epoch: "2.5" + - id: 819 + transactions: [] + epoch: "2.5" + - id: 820 + transactions: [] + epoch: "2.5" + - id: 821 + transactions: [] + epoch: "2.5" + - id: 822 + transactions: [] + epoch: "2.5" + - id: 823 + transactions: [] + epoch: "2.5" + - id: 824 + transactions: [] + epoch: "2.5" + - id: 825 + transactions: [] + epoch: "2.5" + - id: 826 + transactions: [] + epoch: "2.5" + - id: 827 + transactions: [] + epoch: "2.5" + - id: 828 + transactions: [] + epoch: "2.5" + - id: 829 + transactions: [] + epoch: "2.5" + - id: 830 + transactions: [] + epoch: "2.5" + - id: 831 + transactions: [] + epoch: "2.5" + - id: 832 + transactions: [] + epoch: "2.5" + - id: 833 + transactions: [] + epoch: "2.5" + - id: 834 + transactions: [] + epoch: "2.5" + - id: 835 + transactions: [] + epoch: "2.5" + - id: 836 + transactions: [] + epoch: "2.5" + - id: 837 + transactions: [] + epoch: "2.5" + - id: 838 + transactions: [] + epoch: "2.5" + - id: 839 + transactions: [] + epoch: "2.5" + - id: 840 + transactions: [] + epoch: "2.5" + - id: 841 + transactions: [] + epoch: "2.5" + - id: 842 + transactions: [] + epoch: "2.5" + - id: 843 + transactions: [] + epoch: "2.5" + - id: 844 + transactions: [] + epoch: "2.5" + - id: 845 + transactions: [] + epoch: "2.5" + - id: 846 + transactions: [] + epoch: "2.5" + - id: 847 + transactions: [] + epoch: "2.5" + - id: 848 + transactions: [] + epoch: "2.5" + - id: 849 + transactions: [] + epoch: "2.5" + - id: 850 + transactions: [] + epoch: "2.5" + - id: 851 + transactions: [] + epoch: "2.5" + - id: 852 + transactions: [] + epoch: "2.5" + - id: 853 + transactions: [] + epoch: "2.5" + - id: 854 + transactions: [] + epoch: "2.5" + - id: 855 + transactions: [] + epoch: "2.5" + - id: 856 + transactions: [] + epoch: "2.5" + - id: 857 + transactions: [] + epoch: "2.5" + - id: 858 + transactions: [] + epoch: "2.5" + - id: 859 + transactions: [] + epoch: "2.5" + - id: 860 + transactions: [] + epoch: "2.5" + - id: 861 + transactions: [] + epoch: "2.5" + - id: 862 + transactions: [] + epoch: "2.5" + - id: 863 + transactions: [] + epoch: "2.5" + - id: 864 + transactions: [] + epoch: "2.5" + - id: 865 + transactions: [] + epoch: "2.5" + - id: 866 + transactions: [] + epoch: "2.5" + - id: 867 + transactions: [] + epoch: "2.5" + - id: 868 + transactions: [] + epoch: "2.5" + - id: 869 + transactions: [] + epoch: "2.5" + - id: 870 + transactions: [] + epoch: "2.5" + - id: 871 + transactions: [] + epoch: "2.5" + - id: 872 + transactions: [] + epoch: "2.5" + - id: 873 + transactions: [] + epoch: "2.5" + - id: 874 + transactions: [] + epoch: "2.5" + - id: 875 + transactions: [] + epoch: "2.5" + - id: 876 + transactions: [] + epoch: "2.5" + - id: 877 + transactions: [] + epoch: "2.5" + - id: 878 + transactions: [] + epoch: "2.5" + - id: 879 + transactions: [] + epoch: "2.5" + - id: 880 + transactions: [] + epoch: "2.5" + - id: 881 + transactions: [] + epoch: "2.5" + - id: 882 + transactions: [] + epoch: "2.5" + - id: 883 + transactions: [] + epoch: "2.5" + - id: 884 + transactions: [] + epoch: "2.5" + - id: 885 + transactions: [] + epoch: "2.5" + - id: 886 + transactions: [] + epoch: "2.5" + - id: 887 + transactions: [] + epoch: "2.5" + - id: 888 + transactions: [] + epoch: "2.5" + - id: 889 + transactions: [] + epoch: "2.5" + - id: 890 + transactions: [] + epoch: "2.5" + - id: 891 + transactions: [] + epoch: "2.5" + - id: 892 + transactions: [] + epoch: "2.5" + - id: 893 + transactions: [] + epoch: "2.5" + - id: 894 + transactions: [] + epoch: "2.5" + - id: 895 + transactions: [] + epoch: "2.5" + - id: 896 + transactions: [] + epoch: "2.5" + - id: 897 + transactions: [] + epoch: "2.5" + - id: 898 + transactions: [] + epoch: "2.5" + - id: 899 + transactions: [] + epoch: "2.5" + - id: 900 + transactions: [] + epoch: "2.5" + - id: 901 + transactions: [] + epoch: "2.5" + - id: 902 + transactions: + - emulated-contract-publish: + contract-name: debug + emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM + path: contracts/debug.clar + clarity-version: 3 + epoch: "3.0" + - id: 903 + transactions: [] + epoch: "3.0" + - id: 904 + transactions: [] + epoch: "3.0" + - id: 905 + transactions: [] + epoch: "3.0" + - id: 906 + transactions: [] + epoch: "3.0" + - id: 907 + transactions: [] + epoch: "3.0" + - id: 908 + transactions: [] + epoch: "3.0" + - id: 909 + transactions: [] + epoch: "3.0" + - id: 910 + transactions: [] + epoch: "3.0" + - id: 911 + transactions: [] + epoch: "3.0" + - id: 912 + transactions: [] + epoch: "3.0" + - id: 913 + transactions: [] + epoch: "3.0" + - id: 914 + transactions: [] + epoch: "3.0" + - id: 915 + transactions: [] + epoch: "3.0" + - id: 916 + transactions: [] + epoch: "3.0" + - id: 917 + transactions: [] + epoch: "3.0" + - id: 918 + transactions: [] + epoch: "3.0" + - id: 919 + transactions: [] + epoch: "3.0" + - id: 920 + transactions: [] + epoch: "3.0" + - id: 921 + transactions: [] + epoch: "3.0" + - id: 922 + transactions: [] + epoch: "3.0" + - id: 923 + transactions: [] + epoch: "3.0" + - id: 924 + transactions: [] + epoch: "3.0" + - id: 925 + transactions: [] + epoch: "3.0" + - id: 926 + transactions: [] + epoch: "3.0" + - id: 927 + transactions: [] + epoch: "3.0" + - id: 928 + transactions: [] + epoch: "3.0" + - id: 929 + transactions: [] + epoch: "3.0" + - id: 930 + transactions: [] + epoch: "3.0" + - id: 931 + transactions: [] + epoch: "3.0" + - id: 932 + transactions: [] + epoch: "3.0" + - id: 933 + transactions: [] + epoch: "3.0" + - id: 934 + transactions: [] + epoch: "3.0" + - id: 935 + transactions: [] + epoch: "3.0" + - id: 936 + transactions: [] + epoch: "3.0" + - id: 937 + transactions: [] + epoch: "3.0" + - id: 938 + transactions: [] + epoch: "3.0" + - id: 939 + transactions: [] + epoch: "3.0" + - id: 940 + transactions: [] + epoch: "3.0" + - id: 941 + transactions: [] + epoch: "3.0" + - id: 942 + transactions: [] + epoch: "3.0" + - id: 943 + transactions: [] + epoch: "3.0" + - id: 944 + transactions: [] + epoch: "3.0" + - id: 945 + transactions: [] + epoch: "3.0" + - id: 946 + transactions: [] + epoch: "3.0" + - id: 947 + transactions: [] + epoch: "3.0" + - id: 948 + transactions: [] + epoch: "3.0" + - id: 949 + transactions: [] + epoch: "3.0" + - id: 950 + transactions: [] + epoch: "3.0" + - id: 951 + transactions: [] + epoch: "3.0" + - id: 952 + transactions: [] + epoch: "3.0" + - id: 953 + transactions: [] + epoch: "3.0" + - id: 954 + transactions: [] + epoch: "3.0" + - id: 955 + transactions: [] + epoch: "3.0" + - id: 956 + transactions: [] + epoch: "3.0" + - id: 957 + transactions: [] + epoch: "3.0" + - id: 958 + transactions: [] + epoch: "3.0" + - id: 959 + transactions: [] + epoch: "3.0" + - id: 960 + transactions: [] + epoch: "3.0" + - id: 961 + transactions: [] + epoch: "3.0" + - id: 962 + transactions: [] + epoch: "3.0" + - id: 963 + transactions: [] + epoch: "3.0" + - id: 964 + transactions: [] + epoch: "3.0" + - id: 965 + transactions: [] + epoch: "3.0" + - id: 966 + transactions: [] + epoch: "3.0" + - id: 967 + transactions: [] + epoch: "3.0" + - id: 968 + transactions: [] + epoch: "3.0" + - id: 969 + transactions: [] + epoch: "3.0" + - id: 970 + transactions: [] + epoch: "3.0" + - id: 971 + transactions: [] + epoch: "3.0" + - id: 972 + transactions: [] + epoch: "3.0" + - id: 973 + transactions: [] + epoch: "3.0" + - id: 974 + transactions: [] + epoch: "3.0" + - id: 975 + transactions: [] + epoch: "3.0" + - id: 976 + transactions: [] + epoch: "3.0" + - id: 977 + transactions: [] + epoch: "3.0" + - id: 978 + transactions: [] + epoch: "3.0" + - id: 979 + transactions: [] + epoch: "3.0" + - id: 980 + transactions: [] + epoch: "3.0" + - id: 981 + transactions: [] + epoch: "3.0" + - id: 982 + transactions: [] + epoch: "3.0" + - id: 983 + transactions: [] + epoch: "3.0" + - id: 984 + transactions: [] + epoch: "3.0" + - id: 985 + transactions: [] + epoch: "3.0" + - id: 986 + transactions: [] + epoch: "3.0" + - id: 987 + transactions: [] + epoch: "3.0" + - id: 988 + transactions: [] + epoch: "3.0" + - id: 989 + transactions: [] + epoch: "3.0" + - id: 990 + transactions: [] + epoch: "3.0" + - id: 991 + transactions: [] + epoch: "3.0" + - id: 992 + transactions: [] + epoch: "3.0" + - id: 993 + transactions: [] + epoch: "3.0" + - id: 994 + transactions: [] + epoch: "3.0" + - id: 995 + transactions: [] + epoch: "3.0" + - id: 996 + transactions: [] + epoch: "3.0" + - id: 997 + transactions: [] + epoch: "3.0" + - id: 998 + transactions: [] + epoch: "3.0" + - id: 999 + transactions: [] + epoch: "3.0" + - id: 1000 + transactions: [] + epoch: "3.0" + - id: 1001 + transactions: [] + epoch: "3.0" + - id: 1002 + transactions: [] + epoch: "3.0" + - id: 1003 + transactions: [] + epoch: "3.0" + - id: 1004 + transactions: [] + epoch: "3.0" + - id: 1005 + transactions: [] + epoch: "3.0" + - id: 1006 + transactions: [] + epoch: "3.0" + - id: 1007 + transactions: [] + epoch: "3.0" + - id: 1008 + transactions: [] + epoch: "3.0" + - id: 1009 + transactions: [] + epoch: "3.0" + - id: 1010 + transactions: [] + epoch: "3.0" + - id: 1011 + transactions: [] + epoch: "3.0" + - id: 1012 + transactions: [] + epoch: "3.0" + - id: 1013 + transactions: [] + epoch: "3.0" + - id: 1014 + transactions: [] + epoch: "3.0" + - id: 1015 + transactions: [] + epoch: "3.0" + - id: 1016 + transactions: [] + epoch: "3.0" + - id: 1017 + transactions: [] + epoch: "3.0" + - id: 1018 + transactions: [] + epoch: "3.0" + - id: 1019 + transactions: [] + epoch: "3.0" + - id: 1020 + transactions: [] + epoch: "3.0" + - id: 1021 + transactions: [] + epoch: "3.0" + - id: 1022 + transactions: [] + epoch: "3.0" + - id: 1023 + transactions: [] + epoch: "3.0" + - id: 1024 + transactions: [] + epoch: "3.0" + - id: 1025 + transactions: [] + epoch: "3.0" + - id: 1026 + transactions: [] + epoch: "3.0" + - id: 1027 + transactions: [] + epoch: "3.0" + - id: 1028 + transactions: [] + epoch: "3.0" + - id: 1029 + transactions: [] + epoch: "3.0" + - id: 1030 + transactions: [] + epoch: "3.0" + - id: 1031 + transactions: [] + epoch: "3.0" + - id: 1032 + transactions: [] + epoch: "3.0" + - id: 1033 + transactions: [] + epoch: "3.0" + - id: 1034 + transactions: [] + epoch: "3.0" + - id: 1035 + transactions: [] + epoch: "3.0" + - id: 1036 + transactions: [] + epoch: "3.0" + - id: 1037 + transactions: [] + epoch: "3.0" + - id: 1038 + transactions: [] + epoch: "3.0" + - id: 1039 + transactions: [] + epoch: "3.0" + - id: 1040 + transactions: [] + epoch: "3.0" + - id: 1041 + transactions: [] + epoch: "3.0" + - id: 1042 + transactions: [] + epoch: "3.0" + - id: 1043 + transactions: [] + epoch: "3.0" + - id: 1044 + transactions: [] + epoch: "3.0" + - id: 1045 + transactions: [] + epoch: "3.0" + - id: 1046 + transactions: [] + epoch: "3.0" + - id: 1047 + transactions: [] + epoch: "3.0" + - id: 1048 + transactions: [] + epoch: "3.0" + - id: 1049 + transactions: [] + epoch: "3.0" + - id: 1050 + transactions: [] + epoch: "3.0" + - id: 1051 + transactions: [] + epoch: "3.0" + - id: 1052 + transactions: [] + epoch: "3.0" + - id: 1053 + transactions: [] + epoch: "3.0" + - id: 1054 + transactions: [] + epoch: "3.0" + - id: 1055 + transactions: [] + epoch: "3.0" + - id: 1056 + transactions: [] + epoch: "3.0" + - id: 1057 + transactions: [] + epoch: "3.0" + - id: 1058 + transactions: [] + epoch: "3.0" + - id: 1059 + transactions: [] + epoch: "3.0" + - id: 1060 + transactions: [] + epoch: "3.0" + - id: 1061 + transactions: [] + epoch: "3.0" + - id: 1062 + transactions: [] + epoch: "3.0" + - id: 1063 + transactions: [] + epoch: "3.0" + - id: 1064 + transactions: [] + epoch: "3.0" + - id: 1065 + transactions: [] + epoch: "3.0" + - id: 1066 + transactions: [] + epoch: "3.0" + - id: 1067 + transactions: [] + epoch: "3.0" diff --git a/contracts/stacks/deployments/default.testnet-plan.yaml b/contracts/stacks/deployments/default.testnet-plan.yaml new file mode 100644 index 000000000..74826dbf2 --- /dev/null +++ b/contracts/stacks/deployments/default.testnet-plan.yaml @@ -0,0 +1,88 @@ +--- +id: 0 +name: Testnet deployment +network: testnet +stacks-node: "https://api.testnet.hiro.so" +bitcoin-node: "http://blockstack:blockstacksystem@bitcoind.testnet.stacks.co:18332" +plan: + batches: + - id: 0 + transactions: + - contract-publish: + contract-name: xcall-common-trait + expected-sender: ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH + cost: 401659 + path: contracts/xcall/xcall-common-trait.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: xcall-receiver-trait + expected-sender: ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH + cost: 401659 + path: contracts/xcall/xcall-receiver-trait.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: xcall-impl-trait + expected-sender: ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH + cost: 401901 + path: contracts/xcall/xcall-impl-trait.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: xcall-proxy-trait + expected-sender: ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH + cost: 402046 + path: contracts/xcall/xcall-proxy-trait.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: xcall-proxy + expected-sender: ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH + cost: 403306 + path: contracts/xcall/xcall-proxy.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: centralized-connection + expected-sender: ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH + cost: 402434 + path: contracts/connections/centralized-connection.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: rlp-decode + expected-sender: ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH + cost: 402773 + path: lib/rlp/rlp-decode.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: mock-dapp + expected-sender: ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH + cost: 402385 + path: tests/mocks/mock-dapp.clar + anchor-block-only: true + clarity-version: 2 + - contract-publish: + contract-name: rlp-encode + expected-sender: ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH + cost: 402192 + path: lib/rlp/rlp-encode.clar + anchor-block-only: true + clarity-version: 2 + # - contract-publish: + # contract-name: util + # expected-sender: ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH + # cost: 402288 + # path: contracts/util.clar + # anchor-block-only: true + # clarity-version: 2 + - contract-publish: + contract-name: xcall-impl + expected-sender: ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH + cost: 406648 + path: contracts/xcall/xcall-impl.clar + anchor-block-only: true + clarity-version: 2 + epoch: "2.5" diff --git a/contracts/stacks/lib/rlp/rlp-decode.clar b/contracts/stacks/lib/rlp/rlp-decode.clar new file mode 100644 index 000000000..c593b46f0 --- /dev/null +++ b/contracts/stacks/lib/rlp/rlp-decode.clar @@ -0,0 +1,194 @@ +(define-constant ERR_INVALID_INPUT (err u400)) +(define-constant ERR_INVALID_RLP (err u401)) +(define-constant ERR_INVALID_LENGTH (err u402)) +(define-constant MAX_SIZE 512) + +(define-read-only (get-item (input (list 2 (buff 2048)))) + (unwrap-panic (element-at? input u0)) +) + +(define-read-only (get-rlp (input (list 2 (buff 2048)))) + (unwrap-panic (element-at? input u1)) +) + +(define-read-only (rlp-decode-string (rlp (list 500 (buff 2048))) (index uint)) + (let ( + (data (unwrap-panic (element-at? rlp index)))) + (decode-string data) + ) +) + +(define-read-only (decode-string (input (buff 2048))) + (let ( + (length (unwrap-panic (to-consensus-buff? (len input)))) + (sliced (unwrap-panic (slice? length u13 (len length)))) + (data (concat sliced input)) + (res (concat 0x0d data)) + ) + (from-consensus-buff? (string-ascii 2048) res) + ) +) + +(define-read-only (rlp-decode-uint (rlp (list 500 (buff 2048))) (index uint)) + (let ( + (data (unwrap-panic (element-at? rlp index)))) + + (decode-uint data) + ) +) + +(define-read-only (decode-uint (input (buff 2048))) + (buff-to-uint-be (unwrap-panic (as-max-len? input u16))) +) + +(define-read-only (rlp-decode-buff (rlp (list 500 (buff 2048))) (index uint)) + (let ( + (data (unwrap-panic (element-at? rlp index))) + (decoded (decode-item data)) + ) + + (unwrap-panic (element-at? decoded u0)) + ) +) + +(define-private (get-long-item (id uint) (index uint) (input (buff 2048))) + (let ( + (length-bytes-count (- index id)) + (length-bytes (unwrap-panic (slice? input u1 (+ u1 length-bytes-count)))) + (item-length (buff-to-uint-be (unwrap-panic (as-max-len? length-bytes u16)))) + ) + (list (default-to 0x (slice? input (+ u1 length-bytes-count) (+ u1 length-bytes-count item-length))) + (default-to 0x (slice? input (+ u1 length-bytes-count item-length) (len input))) + ) + ) +) + +(define-private (get-short-item (id uint) (index uint) (input (buff 2048))) + (let ((item-length (- index id))) + (list + (default-to 0x (slice? input u1 (+ u1 item-length))) + (default-to 0x (slice? input (+ u1 item-length) (len input))) + ) + ) +) + +(define-read-only (decode-item (input (buff 2048))) + (let ( + (first-byte (unwrap-panic (element-at? input u0))) + (length (buff-to-uint-be first-byte)) + ) + (if (< length u128) + ;; Check if this is a string (first byte between 0x80 and 0xb7) + (if (and (>= length u128) (< length u184)) + ;; For strings, keep the length prefix + (list + input + (default-to 0x (slice? input u1 (len input))) + ) + ;; For other types, strip the length prefix + (list + (default-to 0x (slice? input u0 u1)) + (default-to 0x (slice? input u1 (len input))) + )) + (if (< length u184) + (get-short-item u128 length input) + (if (< length u192) + (get-long-item u183 length input) + (if (< length u248) + (get-short-item u192 length input) + (get-long-item u247 length input) + )))) + ) +) + +(define-read-only (rlp-decode-list (rlp (list 500 (buff 2048))) (index uint)) + (let ( + (data (unwrap-panic (element-at? rlp index)))) + + (to-list data) + ) +) + +(define-read-only (rlp-to-list (input (buff 2048))) + (let ( + (item (decode-item input)) + (lst (get-item item)) + ) + (to-list lst) + ) +) + +(define-read-only (to-list (input (buff 2048))) + (if (is-eq input 0x) + (list ) + (let ( + (d1 (decode-item input)) + (i1 (get-item d1)) + (d2_ (get-rlp d1)) + ) + (if (is-eq d2_ 0x) + (list i1) + (let ( + (d2 (decode-item d2_)) + (i2 (get-item d2)) + (d3_ (get-rlp d2)) + ) + (if (is-eq d3_ 0x) + (list i1 i2) + (let ( + (d3 (decode-item d3_)) + (i3 (get-item d3)) + (d4_ (get-rlp d3)) + ) + (if (is-eq d4_ 0x) + (list i1 i2 i3) + (let ( + (d4 (decode-item d4_)) + (i4 (get-item d4)) + (d5_ (get-rlp d4)) + ) + (if (is-eq d5_ 0x) + (list i1 i2 i3 i4) + (let ( + (d5 (decode-item d5_)) + (i5 (get-item d5)) + (d6_ (get-rlp d5)) + ) + (if (is-eq d6_ 0x) + (list i1 i2 i3 i4 i5) + (let ( + (d6 (decode-item d6_)) + (i6 (get-item d6)) + (d7_ (get-rlp d6)) + ) + (if (is-eq d7_ 0x) + (list i1 i2 i3 i4 i5 i6) + (let ( + (d7 (decode-item d7_)) + (i7 (get-item d7)) + (d8_ (get-rlp d7)) + ) + (if (is-eq d8_ 0x) + (list i1 i2 i3 i4 i5 i6 i7) + (let ( + (d8 (decode-item d8_)) + (i8 (get-item d8)) + (d9_ (get-rlp d8)) + ) + (if (is-eq d8_ 0x) + (list i1 i2 i3 i4 i5 i6 i7 i8) + (let ( + (d9 (decode-item d8_)) + (i9 (get-item d8)) + ) + (list i1 i2 i3 i4 i5 i6 i7 i8 i9) + )) + )) + )) + )) + )) + )) + )) + )) + )) +) \ No newline at end of file diff --git a/contracts/stacks/lib/rlp/rlp-encode.clar b/contracts/stacks/lib/rlp/rlp-encode.clar new file mode 100644 index 000000000..041734a47 --- /dev/null +++ b/contracts/stacks/lib/rlp/rlp-encode.clar @@ -0,0 +1,172 @@ +(define-private (check-length (data (buff 4092))) + (unwrap-panic (as-max-len? data u1024)) +) + +(define-private (encode-buff-arr (objects (list 500 (buff 1024)))) + (fold concat-buff objects 0x) +) + +(define-private (concat-buff (a (buff 1024)) (b (buff 1024))) + (check-length (concat b a)) +) + +(define-private (rm-lead (num (buff 1)) (buffer (buff 1024))) + (if (is-eq 0x00 buffer) + num + (check-length (concat buffer num)) + ) +) + +(define-read-only (encode-string (message (string-ascii 1024))) + (let ( + (encoded (unwrap-panic (to-consensus-buff? message))) + ) + (if (is-eq (len encoded) u5) + ;; Special case for empty string + 0x80 + (let ( + ;; Remove type prefix and length bytes + (encoded-length (- (len encoded) u5)) + (string-content (unwrap-panic (slice? encoded u5 (len encoded)))) + ) + (if (> encoded-length u55) + ;; Long string case (>55 bytes) + (let ( + (length-bytes (unwrap-panic (to-consensus-buff? encoded-length))) + (length-byte (unwrap-panic (element-at? length-bytes u16))) + (length-hex (unwrap-panic (slice? length-bytes u1 (len length-bytes)))) + (prefix (if (> encoded-length u255) + 0xb9 ;; Two bytes needed for length + 0xb8 ;; One byte needed for length + )) + ) + (check-length (concat + (if (> encoded-length u255) + (concat prefix length-hex) ;; Use full length for large strings + (concat prefix length-byte) ;; Use single byte for smaller strings + ) + string-content))) + ;; Short string case (<=55 bytes) + (let ( + (id (unwrap-panic (to-consensus-buff? (+ u128 encoded-length)))) + (prefix (unwrap-panic (element-at? id u16))) + (res (concat prefix string-content)) + ) + (check-length res)) + ) + ) + ) + ) +) + +(define-private (encode-uint-raw (data uint)) + (if (is-eq data u0) + 0x00 + (let ( + (encoded (unwrap-panic (to-consensus-buff? data))) + (sliced (unwrap-panic (slice? encoded u1 (len encoded)))) + (stripped (fold rm-lead sliced 0x00)) + ) + (if (>= data (pow u256 u3)) + (check-length (concat 0x00 stripped)) + stripped) + ) + ) +) + +(define-read-only (encode-uint (data uint)) + (if (>= data (pow u256 u15)) + (check-length (concat 0x91 (encode-uint-raw data))) + (if (>= data (pow u256 u14)) + (check-length (concat 0x90 (encode-uint-raw data))) + (if (>= data (pow u256 u13)) + (check-length (concat 0x8f (encode-uint-raw data))) + (if (>= data (pow u256 u12)) + (check-length (concat 0x8e (encode-uint-raw data))) + (if (>= data (pow u256 u11)) + (check-length (concat 0x8d (encode-uint-raw data))) + (if (>= data (pow u256 u10)) + (check-length (concat 0x8c (encode-uint-raw data))) + (if (>= data (pow u256 u9)) + (check-length (concat 0x8b (encode-uint-raw data))) + (if (>= data (pow u256 u8)) + (check-length (concat 0x8a (encode-uint-raw data))) + (if (>= data (pow u256 u7)) + (check-length (concat 0x89 (encode-uint-raw data))) + (if (>= data (pow u256 u6)) + (check-length (concat 0x88 (encode-uint-raw data))) + (if (>= data (pow u256 u5)) + (check-length (concat 0x87 (encode-uint-raw data))) + (if (>= data (pow u256 u4)) + (check-length (concat 0x86 (encode-uint-raw data))) + (if (>= data (pow u256 u3)) + (check-length (concat 0x85 (encode-uint-raw data))) + (if (>= data (pow u256 u2)) + (check-length (concat 0x83 (encode-uint-raw data))) + (if (>= data u256) + (check-length (concat 0x82 (encode-uint-raw data))) + (if (>= data u128) + (check-length (concat 0x81 (encode-uint-raw data))) + (encode-uint-raw data))))))))))))))))) +) + +(define-private (make-long-list-prefix (data (buff 1024))) + (let ( + (length-bytes (unwrap-panic (to-consensus-buff? (len data)))) + (length-byte (unwrap-panic (element-at? length-bytes u16))) + ) + (check-length (concat 0xf8 length-byte))) +) + +(define-read-only (encode-arr (objects (list 500 (buff 1024)))) + (let ( + (encoded-data (encode-buff-arr objects)) + (total-length (len encoded-data)) + ) + (if (and (> total-length u55) (is-eq (len objects) u2)) + (let ( + (first-element (unwrap-panic (element-at? objects u0))) + (second-element (unwrap-panic (element-at? objects u1))) + (second-length (len second-element)) + ) + (if (> second-length u55) + ;; Handle case where second element is a long string/list + (let ( + ;; Total bytes calculation: + ;; 1 (first element) + + ;; 2 (0xb8 + length byte for inner) + + ;; second_length + (total-bytes (+ u1 (+ u2 second-length))) + (total-length-bytes (unwrap-panic (to-consensus-buff? total-bytes))) + (total-length-byte (unwrap-panic (element-at? total-length-bytes u16))) + (inner-length-bytes (unwrap-panic (to-consensus-buff? second-length))) + (inner-length-byte (unwrap-panic (element-at? inner-length-bytes u16))) + ) + (check-length (concat + 0xf8 + (concat total-length-byte + (concat first-element + (concat 0xb8 + (concat inner-length-byte second-element))))))) + (check-length (concat (make-long-list-prefix encoded-data) encoded-data)))) + (if (> total-length u55) + (check-length (concat (make-long-list-prefix encoded-data) encoded-data)) + (check-length (concat (encode-uint-raw (+ u192 total-length)) encoded-data))) + )) +) + + + +(define-read-only (encode-buff (data (buff 1024))) + (if (< u1 (len data)) + (encode-buff-long data) + data + ) +) + +(define-private (encode-buff-long (data (buff 1024))) + (let + ((prefix (unwrap-panic (element-at? (unwrap-panic (to-consensus-buff? (+ u128 (len data)))) u16) ))) + (check-length (concat prefix data)) + ) +) \ No newline at end of file diff --git a/contracts/stacks/package-lock.json b/contracts/stacks/package-lock.json new file mode 100644 index 000000000..017ff233f --- /dev/null +++ b/contracts/stacks/package-lock.json @@ -0,0 +1,2420 @@ +{ + "name": "stacks-tests", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "stacks-tests", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@hirosystems/clarinet-sdk": "^2.3.2", + "@stacks/transactions": "^6.12.0", + "chokidar-cli": "^3.0.0", + "typescript": "^5.3.3", + "vite": "^5.1.4", + "vitest": "^1.3.1", + "vitest-environment-clarinet": "^2.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@hirosystems/clarinet-sdk": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@hirosystems/clarinet-sdk/-/clarinet-sdk-2.9.0.tgz", + "integrity": "sha512-9Ad4fbcdEa285ap6grpj9OXmDv5e0W5uYYIlM0zY5xRwqy3rTSjoTSnhjkN3Yy3t4BixOHuZhbwpz9lMIGT1LA==", + "license": "GPL-3.0", + "dependencies": { + "@hirosystems/clarinet-sdk-wasm": "^2.9.0", + "@stacks/transactions": "^6.13.0", + "kolorist": "^1.8.0", + "prompts": "^2.4.2", + "vitest": "^1.0.4", + "yargs": "^17.7.2" + }, + "bin": { + "clarinet-sdk": "dist/cjs/node/src/bin/index.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@hirosystems/clarinet-sdk-wasm": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@hirosystems/clarinet-sdk-wasm/-/clarinet-sdk-wasm-2.9.0.tgz", + "integrity": "sha512-5jLGWbHU4TlhMR4UwTjkASpd8WbKve1t1WwJxSAs4KITlNd84ZfPbs5jx+O092CCinbnbyyaiC9q4ur8H+MtdQ==", + "license": "GPL-3.0" + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@noble/hashes": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.5.tgz", + "integrity": "sha512-LTMZiiLc+V4v1Yi16TD6aX2gmtKszNye0pQgbaLqkvhIqP7nVsSaJsWloGQjJfJ8offaoP5GtX3yY5swbcJxxQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, + "node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", + "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz", + "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz", + "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz", + "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz", + "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz", + "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz", + "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz", + "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz", + "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz", + "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz", + "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz", + "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz", + "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", + "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz", + "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz", + "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "license": "MIT" + }, + "node_modules/@stacks/common": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@stacks/common/-/common-6.16.0.tgz", + "integrity": "sha512-PnzvhrdGRMVZvxTulitlYafSK4l02gPCBBoI9QEoTqgSnv62oaOXhYAUUkTMFKxdHW1seVEwZsrahuXiZPIAwg==", + "license": "MIT", + "dependencies": { + "@types/bn.js": "^5.1.0", + "@types/node": "^18.0.4" + } + }, + "node_modules/@stacks/network": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.16.0.tgz", + "integrity": "sha512-uqz9Nb6uf+SeyCKENJN+idt51HAfEeggQKrOMfGjpAeFgZV2CR66soB/ci9+OVQR/SURvasncAz2ScI1blfS8A==", + "license": "MIT", + "dependencies": { + "@stacks/common": "^6.16.0", + "cross-fetch": "^3.1.5" + } + }, + "node_modules/@stacks/transactions": { + "version": "6.16.1", + "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.16.1.tgz", + "integrity": "sha512-yCtUM+8IN0QJbnnlFhY1wBW7Q30Cxje3Zmy8DgqdBoM/EPPWadez/8wNWFANVAMyUZeQ9V/FY+8MAw4E+pCReA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.1.5", + "@noble/secp256k1": "1.7.1", + "@stacks/common": "^6.16.0", + "@stacks/network": "^6.16.0", + "c32check": "^2.0.0", + "lodash.clonedeep": "^4.5.0" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.6.tgz", + "integrity": "sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "18.19.54", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.54.tgz", + "integrity": "sha512-+BRgt0G5gYjTvdLac9sIeE0iZcJxi4Jc4PV5EUzqi+88jmQLr+fRZdv2tCTV7IHKSGxM6SaLoOXQWWUiLUItMw==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@vitest/expect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", + "license": "MIT", + "dependencies": { + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", + "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", + "license": "MIT", + "dependencies": { + "@vitest/utils": "1.6.0", + "p-limit": "^5.0.0", + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", + "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", + "license": "MIT", + "dependencies": { + "tinyspy": "^2.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", + "license": "MIT", + "dependencies": { + "diff-sequences": "^29.6.3", + "estree-walker": "^3.0.3", + "loupe": "^2.3.7", + "pretty-format": "^29.7.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/base-x": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", + "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==", + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/c32check": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/c32check/-/c32check-2.0.0.tgz", + "integrity": "sha512-rpwfAcS/CMqo0oCqDf3r9eeLgScRE3l/xHDCXhM3UyrfvIn7PrLq63uHh7yYbv8NzaZn5MVsVhIRpQ+5GZ5HyA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.2", + "base-x": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar-cli": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chokidar-cli/-/chokidar-cli-3.0.0.tgz", + "integrity": "sha512-xVW+Qeh7z15uZRxHOkP93Ux8A0xbPzwK4GaqD8dQOYc34TlkqUhVSS59fK36DOp5WdJlrRzlYSy02Ht99FjZqQ==", + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "yargs": "^13.3.0" + }, + "bin": { + "chokidar": "index.js" + }, + "engines": { + "node": ">= 8.10.0" + } + }, + "node_modules/chokidar-cli/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chokidar-cli/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar-cli/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "license": "ISC", + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/chokidar-cli/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "license": "MIT" + }, + "node_modules/chokidar-cli/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar-cli/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/chokidar-cli/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/chokidar-cli/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/chokidar-cli/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/chokidar-cli/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "license": "MIT", + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/chokidar-cli/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", + "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", + "license": "MIT" + }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", + "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", + "license": "MIT" + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "license": "MIT" + }, + "node_modules/local-pkg": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "license": "MIT", + "dependencies": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT" + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/magic-string": { + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mlly": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", + "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.1.1", + "ufo": "^1.5.3" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", + "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "license": "MIT" + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.0.tgz", + "integrity": "sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.7", + "mlly": "^1.7.1", + "pathe": "^1.1.2" + } + }, + "node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, + "node_modules/rollup": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", + "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.24.0", + "@rollup/rollup-android-arm64": "4.24.0", + "@rollup/rollup-darwin-arm64": "4.24.0", + "@rollup/rollup-darwin-x64": "4.24.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", + "@rollup/rollup-linux-arm-musleabihf": "4.24.0", + "@rollup/rollup-linux-arm64-gnu": "4.24.0", + "@rollup/rollup-linux-arm64-musl": "4.24.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", + "@rollup/rollup-linux-riscv64-gnu": "4.24.0", + "@rollup/rollup-linux-s390x-gnu": "4.24.0", + "@rollup/rollup-linux-x64-gnu": "4.24.0", + "@rollup/rollup-linux-x64-musl": "4.24.0", + "@rollup/rollup-win32-arm64-msvc": "4.24.0", + "@rollup/rollup-win32-ia32-msvc": "4.24.0", + "@rollup/rollup-win32-x64-msvc": "4.24.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz", + "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==", + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "license": "MIT" + }, + "node_modules/tinypool": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", + "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", + "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, + "node_modules/vite": { + "version": "5.4.8", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", + "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", + "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", + "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", + "license": "MIT", + "dependencies": { + "@vitest/expect": "1.6.0", + "@vitest/runner": "1.6.0", + "@vitest/snapshot": "1.6.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", + "acorn-walk": "^8.3.2", + "chai": "^4.3.10", + "debug": "^4.3.4", + "execa": "^8.0.1", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "std-env": "^3.5.0", + "strip-literal": "^2.0.0", + "tinybench": "^2.5.1", + "tinypool": "^0.8.3", + "vite": "^5.0.0", + "vite-node": "1.6.0", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "1.6.0", + "@vitest/ui": "1.6.0", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest-environment-clarinet": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vitest-environment-clarinet/-/vitest-environment-clarinet-2.1.0.tgz", + "integrity": "sha512-1SA9XZh47qmbV724sGo2FyjVU+Ar3m5TOU4bLGSlWDb/x388IKUPrHbHWqIQNwY+gwEm9VBfXEAd1LOSUdemBw==", + "license": "GPL-3.0", + "peerDependencies": { + "@hirosystems/clarinet-sdk": ">=2.6.0", + "vitest": "^1.5.2" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/contracts/stacks/package.json b/contracts/stacks/package.json new file mode 100644 index 000000000..f07af0ff9 --- /dev/null +++ b/contracts/stacks/package.json @@ -0,0 +1,27 @@ + +{ + "name": "stacks-tests", + "version": "1.0.0", + "description": "Run unit tests on this project.", + "type": "module", + "private": true, + "scripts": { + "test": "vitest run", + "test:xcall-impl": "vitest run tests/xcall.test.ts", + "test:rlp": "vitest run tests/rlp.test.ts", + "test:util": "vitest run tests/util.test.ts", + "test:report": "vitest run -- --coverage --costs", + "test:watch": "chokidar \"tests/**/*.ts\" \"contracts/**/*.clar\" -c \"npm run test:report\"" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@hirosystems/clarinet-sdk": "^2.3.2", + "@stacks/transactions": "^6.12.0", + "chokidar-cli": "^3.0.0", + "typescript": "^5.3.3", + "vite": "^5.1.4", + "vitest": "^1.3.1", + "vitest-environment-clarinet": "^2.0.0" + } +} diff --git a/contracts/stacks/settings/Devnet.toml b/contracts/stacks/settings/Devnet.toml new file mode 100644 index 000000000..86a588aeb --- /dev/null +++ b/contracts/stacks/settings/Devnet.toml @@ -0,0 +1,155 @@ +[network] +name = "devnet" +deployment_fee_rate = 10 + +[accounts.deployer] +mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw" +balance = 100_000_000_000_000 +# secret_key: 753b7cc01a1a2e86221266a154af739463fce51219d97e4f856cd7200c3bd2a601 +# stx_address: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM +# btc_address: mqVnk6NPRdhntvfm4hh9vvjiRkFDUuSYsH + +[accounts.wallet_1] +mnemonic = "sell invite acquire kitten bamboo drastic jelly vivid peace spawn twice guilt pave pen trash pretty park cube fragile unaware remain midnight betray rebuild" +balance = 100_000_000_000_000 +# secret_key: 7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801 +# stx_address: ST1SJ3DTE5DN7X54YDH5D64R3BCB6A2AG2ZQ8YPD5 +# btc_address: mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC + +[accounts.wallet_2] +mnemonic = "hold excess usual excess ring elephant install account glad dry fragile donkey gaze humble truck breeze nation gasp vacuum limb head keep delay hospital" +balance = 100_000_000_000_000 +# secret_key: 530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101 +# stx_address: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG +# btc_address: muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG + +[accounts.wallet_3] +mnemonic = "cycle puppy glare enroll cost improve round trend wrist mushroom scorpion tower claim oppose clever elephant dinosaur eight problem before frozen dune wagon high" +balance = 100_000_000_000_000 +# secret_key: d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901 +# stx_address: ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC +# btc_address: mvZtbibDAAA3WLpY7zXXFqRa3T4XSknBX7 + +[accounts.wallet_4] +mnemonic = "board list obtain sugar hour worth raven scout denial thunder horse logic fury scorpion fold genuine phrase wealth news aim below celery when cabin" +balance = 100_000_000_000_000 +# secret_key: f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701 +# stx_address: ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND +# btc_address: mg1C76bNTutiCDV3t9nWhZs3Dc8LzUufj8 + +[accounts.wallet_5] +mnemonic = "hurry aunt blame peanut heavy update captain human rice crime juice adult scale device promote vast project quiz unit note reform update climb purchase" +balance = 100_000_000_000_000 +# secret_key: 3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801 +# stx_address: ST2REHHS5J3CERCRBEPMGH7921Q6PYKAADT7JP2VB +# btc_address: mweN5WVqadScHdA81aATSdcVr4B6dNokqx + +[accounts.wallet_6] +mnemonic = "area desk dutch sign gold cricket dawn toward giggle vibrant indoor bench warfare wagon number tiny universe sand talk dilemma pottery bone trap buddy" +balance = 100_000_000_000_000 +# secret_key: 7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01 +# stx_address: ST3AM1A56AK2C1XAFJ4115ZSV26EB49BVQ10MGCS0 +# btc_address: mzxXgV6e4BZSsz8zVHm3TmqbECt7mbuErt + +[accounts.wallet_7] +mnemonic = "prevent gallery kind limb income control noise together echo rival record wedding sense uncover school version force bleak nuclear include danger skirt enact arrow" +balance = 100_000_000_000_000 +# secret_key: b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401 +# stx_address: ST3PF13W7Z0RRM42A8VZRVFQ75SV1K26RXEP8YGKJ +# btc_address: n37mwmru2oaVosgfuvzBwgV2ysCQRrLko7 + +[accounts.wallet_8] +mnemonic = "female adjust gallery certain visit token during great side clown fitness like hurt clip knife warm bench start reunion globe detail dream depend fortune" +balance = 100_000_000_000_000 +# secret_key: 6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01 +# stx_address: ST3NBRSFKX28FQ2ZJ1MAKX58HKHSDGNV5N7R21XCP +# btc_address: n2v875jbJ4RjBnTjgbfikDfnwsDV5iUByw + +[accounts.faucet] +mnemonic = "shadow private easily thought say logic fault paddle word top book during ignore notable orange flight clock image wealth health outside kitten belt reform" +balance = 100_000_000_000_000 +# secret_key: de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801 +# stx_address: STNHKEPYEPJ8ET55ZZ0M5A34J0R3N5FM2CMMMAZ6 +# btc_address: mjSrB3wS4xab3kYqFktwBzfTdPg367ZJ2d + +[devnet] +disable_stacks_explorer = false +disable_stacks_api = false +# disable_subnet_api = false +# disable_bitcoin_explorer = true +# working_dir = "tmp/devnet" +# stacks_node_events_observers = ["host.docker.internal:8002"] +# miner_mnemonic = "fragile loan twenty basic net assault jazz absorb diet talk art shock innocent float punch travel gadget embrace caught blossom hockey surround initial reduce" +# miner_derivation_path = "m/44'/5757'/0'/0/0" +# faucet_mnemonic = "shadow private easily thought say logic fault paddle word top book during ignore notable orange flight clock image wealth health outside kitten belt reform" +# faucet_derivation_path = "m/44'/5757'/0'/0/0" +# orchestrator_port = 20445 +# bitcoin_node_p2p_port = 18444 +# bitcoin_node_rpc_port = 18443 +# bitcoin_node_username = "devnet" +# bitcoin_node_password = "devnet" +# bitcoin_controller_block_time = 30_000 +# stacks_node_rpc_port = 20443 +# stacks_node_p2p_port = 20444 +# stacks_api_port = 3999 +# stacks_api_events_port = 3700 +# bitcoin_explorer_port = 8001 +# stacks_explorer_port = 8000 +# postgres_port = 5432 +# postgres_username = "postgres" +# postgres_password = "postgres" +# postgres_database = "postgres" +# bitcoin_node_image_url = "quay.io/hirosystems/bitcoind:26.0" +# stacks_node_image_url = "quay.io/hirosystems/stacks-node:devnet-2.5" +# stacks_signer_image_url = "quay.io/hirosystems/stacks-signer:devnet-2.5" +# stacks_api_image_url = "hirosystems/stacks-blockchain-api:master" +# stacks_explorer_image_url = "hirosystems/explorer:latest" +# bitcoin_explorer_image_url = "quay.io/hirosystems/bitcoin-explorer:devnet" +# postgres_image_url = "postgres:alpine" +# enable_subnet_node = true +# subnet_node_image_url = "hirosystems/stacks-subnets:0.8.1" +# subnet_leader_mnemonic = "twice kind fence tip hidden tilt action fragile skin nothing glory cousin green tomorrow spring wrist shed math olympic multiply hip blue scout claw" +# subnet_leader_derivation_path = "m/44'/5757'/0'/0/0" +# subnet_contract_id = "ST173JK7NZBA4BS05ZRATQH1K89YJMTGEH1Z5J52E.subnet-v3-0-1" +# subnet_node_rpc_port = 30443 +# subnet_node_p2p_port = 30444 +# subnet_events_ingestion_port = 30445 +# subnet_node_events_observers = ["host.docker.internal:8002"] +# subnet_api_image_url = "hirosystems/stacks-blockchain-api:master" +# subnet_api_postgres_database = "subnet_api" + +# epoch_2_0 = 100 +# epoch_2_05 = 100 +# epoch_2_1 = 101 +# epoch_2_2 = 102 +# epoch_2_3 = 103 +# epoch_2_4 = 104 +# epoch_2_5 = 108 +# epoch_3_0 = 144 + + +# Send some stacking orders +[[devnet.pox_stacking_orders]] +start_at_cycle = 1 +duration = 10 +auto_extend = true +wallet = "wallet_1" +slots = 2 +btc_address = "mr1iPkD9N3RJZZxXRk7xF9d36gffa6exNC" + +[[devnet.pox_stacking_orders]] +start_at_cycle = 1 +duration = 10 +auto_extend = true +wallet = "wallet_2" +slots = 2 +btc_address = "muYdXKmX9bByAueDe6KFfHd5Ff1gdN9ErG" + +[[devnet.pox_stacking_orders]] +start_at_cycle = 1 +duration = 10 +auto_extend = true +wallet = "wallet_3" +slots = 2 +btc_address = "mvZtbibDAAA3WLpY7zXXFqRa3T4XSknBX7" + diff --git a/contracts/stacks/tests/mocks/mock-dapp.clar b/contracts/stacks/tests/mocks/mock-dapp.clar new file mode 100644 index 000000000..14a1caf59 --- /dev/null +++ b/contracts/stacks/tests/mocks/mock-dapp.clar @@ -0,0 +1,81 @@ +(use-trait xcall-common-trait .xcall-common-trait.xcall-common-trait) +(impl-trait .xcall-receiver-trait.xcall-receiver-trait) + +(define-constant ERR_UNAUTHORIZED (err u800)) +(define-constant ERR_INVALID_PROTOCOL (err u801)) +(define-constant ERR_INVALID_MESSAGE (err u802)) +(define-constant ERR_RLP_DECODE (err u803)) + +(define-data-var call-service principal tx-sender) + +(define-map sources {nid: (string-ascii 128)} (list 10 (string-ascii 128))) +(define-map destinations {nid: (string-ascii 128)} (list 10 (string-ascii 128))) + +(define-public (initialize (call-svc principal)) + (begin + (var-set call-service call-svc) + (ok true))) + +(define-private (is-call-service) + (is-eq tx-sender (var-get call-service))) + +(define-public (add-connection (nid (string-ascii 128)) (source (string-ascii 128)) (destination (string-ascii 128))) + (begin + (map-set sources {nid: nid} + (unwrap! (as-max-len? (append (default-to (list) (map-get? sources {nid: nid})) source) u10) ERR_INVALID_PROTOCOL)) + (map-set destinations {nid: nid} + (unwrap! (as-max-len? (append (default-to (list) (map-get? destinations {nid: nid})) destination) u10) ERR_INVALID_PROTOCOL)) + (ok true))) + +(define-read-only (get-sources (nid (string-ascii 128))) + (default-to (list) (map-get? sources {nid: nid}))) + +(define-read-only (get-destinations (nid (string-ascii 128))) + (default-to (list) (map-get? destinations {nid: nid}))) + +(define-public (send-message (to (string-ascii 128)) (data (buff 2048)) (rollback (optional (buff 1024))) (xcall-common )) + (let + ( + (net (unwrap! (slice? to u0 (unwrap-panic (index-of to "/"))) ERR_INVALID_MESSAGE)) + (sources-list (get-sources net)) + (destinations-list (get-destinations net)) + ) + (contract-call? .xcall-proxy send-call-message to data rollback (some sources-list) (some destinations-list) xcall-common))) + +(define-private (decode-rlp-message (data (buff 2048))) + (let + ( + (message (unwrap-panic (as-max-len? (unwrap-panic (slice? data u1 (len data))) u2048))) ;; Drop RLP prefix byte + ) + (ok (unwrap-panic (contract-call? .rlp-decode decode-string message))))) + +(define-public (handle-call-message (from (string-ascii 128)) (data (buff 2048)) (protocols (list 10 (string-ascii 128))) (xcall-common )) + (begin + ;; (asserts! (is-call-service) ERR_UNAUTHORIZED) + (let + ( + (from-net (unwrap! (slice? from u0 (unwrap-panic (index-of from "/"))) ERR_INVALID_MESSAGE)) + (rollback-address (unwrap! (contract-call? .xcall-proxy get-network-address xcall-common) ERR_INVALID_MESSAGE)) + (decoded-message (unwrap! (decode-rlp-message data) ERR_INVALID_MESSAGE)) + ) + (if (is-eq rollback-address from) + (print {event: "RollbackReceived", from: from, data: decoded-message}) + (begin + (asserts! (or + (is-eq protocols (get-sources from-net)) + (and (is-eq (len protocols) u0) (> (len (get-sources from-net)) u0)) + ) + ERR_INVALID_PROTOCOL) + (asserts! (not (is-eq decoded-message "rollback")) ERR_INVALID_MESSAGE) + (if (is-eq decoded-message "reply-response") + (begin + (try! (send-message from 0x010203 none xcall-common)) + (print {event: "ReplyResponseSent", from: from, data: decoded-message}) + ) + (print {event: "MessageReceived", from: from, data: decoded-message}) + ) + ) + ) + (ok true) + ) + )) diff --git a/contracts/stacks/tests/rlp.test.ts b/contracts/stacks/tests/rlp.test.ts new file mode 100644 index 000000000..b1ac3ef52 --- /dev/null +++ b/contracts/stacks/tests/rlp.test.ts @@ -0,0 +1,266 @@ +import { Cl } from "@stacks/transactions"; +import { describe, expect, it } from "vitest"; + +const accounts = simnet.getAccounts(); +const address1 = accounts.get("wallet_1")!; + +describe("RLP Encoding Tests", () => { + it("encodes cross chain message", () => { + const sourceContract = simnet.callReadOnlyFn( + "rlp-encode", + "encode-string", + [Cl.stringAscii("0x1.icon/cxc5d40fd74995bed473e5d1b259dbc6015273ffc5")], + address1 + ); + + const destAddress = simnet.callReadOnlyFn( + "rlp-encode", + "encode-string", + [Cl.stringAscii("archway1rv84n8yczcug4rpwx028tkvwm5gerluzs28uhn")], + address1 + ); + + const sn = simnet.callReadOnlyFn( + "rlp-encode", + "encode-uint", + [Cl.uint(11580)], + address1 + ); + + const msgType = simnet.callReadOnlyFn( + "rlp-encode", + "encode-uint", + [Cl.uint(0)], + address1 + ); + + const emptyData = simnet.callReadOnlyFn( + "rlp-encode", + "encode-string", + [Cl.stringAscii("")], + address1 + ); + + const destList = simnet.callReadOnlyFn( + "rlp-encode", + "encode-arr", + [Cl.list([ + Cl.buffer(simnet.callReadOnlyFn( + "rlp-encode", + "encode-string", + [Cl.stringAscii("archway1lvmx2u6f47n8yr0dg7fangur2l72nwxxklasqyal2fhtpyw9uxfqmudel8")], + address1 + // @ts-ignore + ).result.buffer) + ])], + address1 + ); + + const innerMessage = simnet.callReadOnlyFn( + "rlp-encode", + "encode-arr", + [Cl.list([ + // @ts-ignore + Cl.buffer(sourceContract.result.buffer), + // @ts-ignore + Cl.buffer(destAddress.result.buffer), + // @ts-ignore + Cl.buffer(sn.result.buffer), + // @ts-ignore + Cl.buffer(msgType.result.buffer), + // @ts-ignore + Cl.buffer(emptyData.result.buffer), + // @ts-ignore + Cl.buffer(destList.result.buffer) + ])], + address1 + ); + + const result = simnet.callReadOnlyFn( + "rlp-encode", + "encode-arr", + [Cl.list([ + Cl.buffer(simnet.callReadOnlyFn( + "rlp-encode", + "encode-uint", + [Cl.uint(1)], + address1 + // @ts-ignore + ).result.buffer), + // @ts-ignore + Cl.buffer(innerMessage.result.buffer) + ])], + address1 + ); + + // @ts-ignore + expect(result.result.buffer).toEqual( + Cl.bufferFromHex("f8b301b8b0f8aeb33078312e69636f6e2f637863356434306664373439393562656434373365356431623235396462633630313532373366666335ae6172636877617931727638346e3879637a6375673472707778303238746b76776d356765726c757a73323875686e822d3c0080f844b84261726368776179316c766d783275366634376e3879723064673766616e677572326c37326e7778786b6c61737179616c3266687470797739757866716d7564656c38").buffer + ); + }); +}); + +it("decodes cross chain message", () => { + const encodedMessage = "f8b301b8b0f8aeb33078312e69636f6e2f637863356434306664373439393562656434373365356431623235396462633630313532373366666335ae6172636877617931727638346e3879637a6375673472707778303238746b76776d356765726c757a73323875686e822d3c0080f844b84261726368776179316c766d783275366634376e3879723064673766616e677572326c37326e7778786b6c61737179616c3266687470797739757866716d7564656c38"; + + console.log("Step 1: Initial encoded message"); + console.log("Encoded message:", encodedMessage); + + // First decode the outer array using rlp-to-list + const decoded = simnet.callReadOnlyFn( + "rlp-decode", + "rlp-to-list", + [Cl.bufferFromHex(encodedMessage)], + address1 + ); + + console.log("\nStep 2: First level decoding"); + console.log("Decoded result:", decoded.result); + + // Assert first level decoding produced a list with expected elements + expect(decoded.result.type).toBe(11); // List type + expect(decoded.result.list.length).toBe(2); // Should have 2 elements + expect(decoded.result.list[0].type).toBe(2); // First element should be a buffer + expect(decoded.result.list[1].type).toBe(2); // Second element should be a buffer + + // Extract and decode inner message + const innerDecoded = simnet.callReadOnlyFn( + "rlp-decode", + "rlp-to-list", + // @ts-ignore + [decoded.result.list[1]], + address1 + ); + + console.log("\nStep 3: Inner message decoding"); + console.log("Inner decoded result:", innerDecoded.result); + + // Assert inner decoding produced expected structure + expect(innerDecoded.result.type).toBe(11); // List type + expect(innerDecoded.result.list.length).toBe(6); // Should have 6 elements + + // Print and verify each element + console.log("\nStep 4: Decoding individual elements"); + + // Source Contract + console.log("4.1: Source Contract"); + const sourceContract = simnet.callReadOnlyFn( + "rlp-decode", + "rlp-decode-string", + [ + Cl.list([innerDecoded.result.list[0]]), + Cl.uint(0) + ], + address1 + ); + console.log("Source contract result:", sourceContract.result); + expect(sourceContract.result).toEqual( + Cl.some(Cl.stringAscii("0x1.icon/cxc5d40fd74995bed473e5d1b259dbc6015273ffc5")) + ); + + + // Destination Address + console.log("\n4.2: Destination Address"); + const destAddress = simnet.callReadOnlyFn( + "rlp-decode", + "rlp-decode-string", + [ + Cl.list([innerDecoded.result.list[1]]), + Cl.uint(0) + ], + address1 + ); + console.log("Destination address result:", destAddress.result); + expect(destAddress.result).toEqual( + Cl.some(Cl.stringAscii("archway1rv84n8yczcug4rpwx028tkvwm5gerluzs28uhn")) + ); + + // Sequence Number + console.log("\n4.3: Sequence Number"); + const sn = simnet.callReadOnlyFn( + "rlp-decode", + "rlp-decode-uint", + [ + Cl.list([innerDecoded.result.list[2]]), + Cl.uint(0) + ], + address1 + ); + console.log("Sequence number result:", sn.result); + expect(sn.result).toEqual(Cl.uint(11580)); + + // Message Type + console.log("\n4.4: Message Type"); + const msgType = simnet.callReadOnlyFn( + "rlp-decode", + "rlp-decode-uint", + [ + Cl.list([innerDecoded.result.list[3]]), + Cl.uint(0) + ], + address1 + ); + console.log("Message type result:", msgType.result); + expect(msgType.result).toEqual(Cl.uint(0)); + + // Empty Data + console.log("\n4.5: Empty Data"); + const emptyData = simnet.callReadOnlyFn( + "rlp-decode", + "rlp-decode-string", + [ + Cl.list([innerDecoded.result.list[4]]), + Cl.uint(0) + ], + address1 + ); + console.log("Empty data buffer:", Buffer.from(innerDecoded.result.list[4].buffer).toString('hex')); + console.log("Data result:", emptyData.result); + expect(emptyData.result).toEqual(Cl.some(Cl.stringAscii(""))); + + + console.log("\n4.6: Destination List"); +// Print the raw buffer before decoding +const destListBuffer = innerDecoded.result.list[5]; +console.log("Destination list raw buffer:", + Buffer.from(destListBuffer.buffer).toString('hex') +); + +const destListDecoded = simnet.callReadOnlyFn( + "rlp-decode", + "rlp-to-list", + [innerDecoded.result.list[5]], + address1 +); +console.log("Destination list decoded:", destListDecoded.result); +console.log("Destination list decoded result list:", destListDecoded.result.list) + +console.log("\nDebug events from decode-string:"); +console.log(destListDecoded.events.map(event => event.data).join('\n')); + +// Print the first item's buffer before string decoding +const firstItem = destListDecoded.result.list[0]; +console.log("First destination buffer:", + Buffer.from(firstItem.buffer).toString('hex') +); + +const destAddress1 = simnet.callReadOnlyFn( + "rlp-decode", + "rlp-decode-string", + [ + Cl.list([destListDecoded.result.list[0]]), + Cl.uint(0) + ], + address1 +); + +console.log("\nDebug events from string decoding:"); +console.log(destAddress1.events.map(event => event.data).join('\n')); + + console.log("Destination address 1 result:", destAddress1.result); + expect(destAddress1.result).toEqual( + Cl.stringAscii("archway1lvmx2u6f47n8yr0dg7fangur2l72nwxxklasqyal2fhtpyw9uxfqmudel8") + ); + + console.log("\nStep 5: All elements decoded successfully"); +}); diff --git a/contracts/stacks/tests/util.test.ts b/contracts/stacks/tests/util.test.ts new file mode 100644 index 000000000..a9ed18930 --- /dev/null +++ b/contracts/stacks/tests/util.test.ts @@ -0,0 +1,26 @@ +import { describe, it, expect } from "vitest"; +import { Cl } from "@stacks/transactions"; + +const accounts = simnet.getAccounts(); +const deployer = accounts.get("deployer"); + +describe("util", () => { + it("converts address string to principal correctly", () => { + const address = "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM" + "." + "centralized-connection"; + + const result = simnet.callPublicFn( + "util", + "address-string-to-principal", + [Cl.stringAscii(address)], + deployer! + ); + + // Check if the result is successful + expect(result.result).toBeOk( + Cl.contractPrincipal( + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + "centralized-connection" + ) + ); + }); +}); \ No newline at end of file diff --git a/contracts/stacks/tests/xcall.test.ts b/contracts/stacks/tests/xcall.test.ts new file mode 100644 index 000000000..929f685e6 --- /dev/null +++ b/contracts/stacks/tests/xcall.test.ts @@ -0,0 +1,841 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { encode } from "rlp"; +import { Cl } from "@stacks/transactions"; + +const accounts = simnet.getAccounts(); +const deployer = accounts.get("deployer"); + +const XCALL_IMPL_CONTRACT_NAME = "xcall-impl"; +const XCALL_PROXY_CONTRACT_NAME = "xcall-proxy"; +const CENTRALIZED_CONNECTION_CONTRACT_NAME = "centralized-connection"; +const MOCK_DAPP_CONTRACT_NAME = "mock-dapp"; + +const STACKS_NID = "stacks"; +const ICON_NID = "test"; + +const sourceContract = accounts.get("wallet_1")!; +const destinationContract = deployer! + "." + MOCK_DAPP_CONTRACT_NAME; + +const from = `${STACKS_NID}/${sourceContract}`; +const to = `${ICON_NID}/${destinationContract}`; + +const CS_MESSAGE_TYPE_REQUEST = 1; +const CS_MESSAGE_TYPE_RESULT = 2; +const CS_MESSAGE_RESULT_SUCCESS = 1; +const CS_MESSAGE_RESULT_FAILURE = 0; + +const xcallImpl = Cl.contractPrincipal(deployer!, XCALL_IMPL_CONTRACT_NAME); +const xcallProxy = Cl.contractPrincipal(deployer!, XCALL_PROXY_CONTRACT_NAME); +const centralizedConnection = Cl.contractPrincipal( + deployer!, + CENTRALIZED_CONNECTION_CONTRACT_NAME +); +const mockDapp = Cl.contractPrincipal(deployer!, MOCK_DAPP_CONTRACT_NAME); + +describe("xcall", () => { + beforeEach(() => { + simnet.callPublicFn( + XCALL_IMPL_CONTRACT_NAME, + "init", + [ + Cl.stringAscii(STACKS_NID), + Cl.stringAscii(deployer! + "." + XCALL_IMPL_CONTRACT_NAME), + ], + deployer! + ); + + const upgradeProxyResult = simnet.callPublicFn( + XCALL_PROXY_CONTRACT_NAME, + "upgrade", + [xcallImpl, Cl.none()], + deployer! + ); + expect(upgradeProxyResult.result).toBeOk(Cl.bool(true)); + + const setAdminResult = simnet.callPublicFn( + XCALL_IMPL_CONTRACT_NAME, + "set-admin", + [Cl.principal(deployer!)], + deployer! + ); + expect(setAdminResult.result).toBeOk(Cl.bool(true)); + + simnet.callPublicFn( + CENTRALIZED_CONNECTION_CONTRACT_NAME, + "initialize", + [xcallProxy, Cl.principal(deployer!)], + deployer! + ); + + simnet.callPublicFn( + XCALL_PROXY_CONTRACT_NAME, + "set-default-connection", + [ + Cl.stringAscii(STACKS_NID), + Cl.stringAscii(deployer! + "." + CENTRALIZED_CONNECTION_CONTRACT_NAME), + xcallImpl, + ], + deployer! + ); + + simnet.callPublicFn( + XCALL_PROXY_CONTRACT_NAME, + "set-default-connection", + [ + Cl.stringAscii(ICON_NID), + Cl.stringAscii(deployer! + "." + CENTRALIZED_CONNECTION_CONTRACT_NAME), + xcallImpl, + ], + deployer! + ); + + simnet.callPublicFn( + XCALL_PROXY_CONTRACT_NAME, + "set-protocol-fee-handler", + [centralizedConnection, xcallImpl], + deployer! + ); + + simnet.callPublicFn( + CENTRALIZED_CONNECTION_CONTRACT_NAME, + "set-fee", + [Cl.stringAscii(STACKS_NID), Cl.uint(500000), Cl.uint(250000)], + deployer! + ); + + simnet.callPublicFn( + CENTRALIZED_CONNECTION_CONTRACT_NAME, + "set-fee", + [Cl.stringAscii(ICON_NID), Cl.uint(1000000), Cl.uint(500000)], + deployer! + ); + + const protocolFee = 100000; + simnet.callPublicFn( + XCALL_PROXY_CONTRACT_NAME, + "set-protocol-fee", + [Cl.uint(protocolFee), xcallImpl], + deployer! + ); + + simnet.callPublicFn( + MOCK_DAPP_CONTRACT_NAME, + "initialize", + [xcallProxy], + deployer! + ); + + simnet.callPublicFn( + MOCK_DAPP_CONTRACT_NAME, + "add-connection", + [ + Cl.stringAscii(STACKS_NID), + Cl.stringAscii(deployer! + "." + CENTRALIZED_CONNECTION_CONTRACT_NAME), + Cl.stringAscii(deployer! + "." + CENTRALIZED_CONNECTION_CONTRACT_NAME), + ], + deployer! + ); + + simnet.callPublicFn( + MOCK_DAPP_CONTRACT_NAME, + "add-connection", + [ + Cl.stringAscii(ICON_NID), + Cl.stringAscii(deployer! + "." + CENTRALIZED_CONNECTION_CONTRACT_NAME), + Cl.stringAscii(deployer! + "." + CENTRALIZED_CONNECTION_CONTRACT_NAME), + ], + deployer! + ); + }); + + it("verifies protocol sources and destinations are passed correctly in send-message", () => { + const data = Uint8Array.from(encode(["Hello, Destination Contract!"])); + const expectedSn = 1; + + const sourcesResult = simnet.callReadOnlyFn( + MOCK_DAPP_CONTRACT_NAME, + "get-sources", + [Cl.stringAscii(ICON_NID)], + deployer! + ); + expect(sourcesResult.result).toStrictEqual( + Cl.list([ + Cl.stringAscii(deployer! + "." + CENTRALIZED_CONNECTION_CONTRACT_NAME), + ]) + ); + + const destinationsResult = simnet.callReadOnlyFn( + MOCK_DAPP_CONTRACT_NAME, + "get-destinations", + [Cl.stringAscii(ICON_NID)], + deployer! + ); + expect(destinationsResult.result).toStrictEqual( + Cl.list([ + Cl.stringAscii(deployer! + "." + CENTRALIZED_CONNECTION_CONTRACT_NAME), + ]) + ); + + const sendMessageResult = simnet.callPublicFn( + MOCK_DAPP_CONTRACT_NAME, + "send-message", + [Cl.stringAscii(to), Cl.buffer(data), Cl.none(), xcallImpl], + sourceContract + ); + expect(sendMessageResult.result).toBeOk(Cl.uint(expectedSn)); + + const callMessageSentEvent = sendMessageResult.events.find( + (e) => + e.event === "print_event" && + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'TrueCV'. + e.data.value!.data.event.data === "CallMessageSent" + ); + expect(callMessageSentEvent).toBeDefined(); + + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'TrueCV'. + const eventData = callMessageSentEvent!.data.value!.data; + expect(eventData.from).toStrictEqual(Cl.principal(sourceContract)); + expect(eventData.to).toStrictEqual(Cl.stringAscii(to)); + expect(eventData.sn).toStrictEqual(Cl.uint(expectedSn)); + }); + + it("verifies send-message with specific input data", () => { + const to = "test/cxfa65fef6524222c5edad37989da26deaa5b4a40a"; + const svc = ""; + const sn = 3; + const msgHex = + "0x30783464363537333733363136373635353437323631366537333636363537323534363537333734363936653637353736393734363836663735373435323666366336633632363136333662"; + + const msg = new Uint8Array( + msgHex + .slice(2) // Remove '0x' prefix + .match(/.{1,2}/g)! // Split into pairs + .map((byte) => parseInt(byte, 16)) // Convert each pair to number + ); + + const sendMessageResult = simnet.callPublicFn( + "centralized-connection", + "send-message", + [Cl.stringAscii(to), Cl.stringAscii(svc), Cl.int(sn), Cl.buffer(msg)], + deployer! + ); + + // Verify the transaction succeeded + expect(sendMessageResult.result).toBeOk(Cl.int(1)); // Should return next conn-sn + + // Verify the Message event was emitted correctly + const messageEvent = sendMessageResult.events.find( + (e) => + e.event === "print_event" && + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue' + e.data.value.data.event.data === "Message" + ); + expect(messageEvent).toBeDefined(); + + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue' + const eventData = messageEvent!.data.value.data; + + // Verify event data matches input + expect(eventData.to).toStrictEqual(Cl.stringAscii(to)); + expect(eventData.sn).toStrictEqual(Cl.int(1)); + expect(eventData.msg).toStrictEqual(Cl.buffer(msg)); + + // Verify connection sequence number was incremented + const getConnSnResult = simnet.callReadOnlyFn( + "centralized-connection", + "get-conn-sn", + [], + deployer! + ); + expect(getConnSnResult.result).toBeOk(Cl.int(1)); + }); + + it("verifies the connection is properly initialized", () => { + const xcallResult = simnet.callReadOnlyFn( + CENTRALIZED_CONNECTION_CONTRACT_NAME, + "get-xcall", + [], + deployer! + ); + expect(xcallResult.result).toBeOk(Cl.some(xcallProxy)); + + const adminResult = simnet.callReadOnlyFn( + CENTRALIZED_CONNECTION_CONTRACT_NAME, + "get-admin", + [], + deployer! + ); + expect(adminResult.result).toBeOk(Cl.principal(deployer!)); + + const stacksFeeResult = simnet.callReadOnlyFn( + CENTRALIZED_CONNECTION_CONTRACT_NAME, + "get-fee", + [Cl.stringAscii(STACKS_NID), Cl.bool(true)], + deployer! + ); + expect(stacksFeeResult.result).toBeOk(Cl.uint(750000)); // 500000 base fee + 250000 rollback fee + + const iconFeeResult = simnet.callReadOnlyFn( + CENTRALIZED_CONNECTION_CONTRACT_NAME, + "get-fee", + [Cl.stringAscii(ICON_NID), Cl.bool(true)], + deployer! + ); + expect(iconFeeResult.result).toBeOk(Cl.uint(1500000)); // 1000000 base fee + 500000 rollback fee + + const dappResult = simnet.callReadOnlyFn( + MOCK_DAPP_CONTRACT_NAME, + "get-sources", + [Cl.stringAscii(STACKS_NID)], + deployer! + ); + expect(dappResult.result).toStrictEqual( + Cl.list([ + Cl.stringAscii(deployer! + "." + CENTRALIZED_CONNECTION_CONTRACT_NAME), + ]) + ); + }); + + it("verifies the current implementation after upgrade is xcallImpl", () => { + const getCurrentImplementationResult = simnet.callReadOnlyFn( + XCALL_PROXY_CONTRACT_NAME, + "get-current-implementation", + [], + deployer! + ); + + expect(getCurrentImplementationResult.result).toBeOk(xcallImpl); + + const isCurrentImplementationResult = simnet.callReadOnlyFn( + XCALL_PROXY_CONTRACT_NAME, + "is-current-implementation", + [xcallImpl], + deployer! + ); + + expect(isCurrentImplementationResult.result).toBeOk(Cl.bool(true)); + + const isNotCurrentImplementationResult = simnet.callReadOnlyFn( + XCALL_PROXY_CONTRACT_NAME, + "is-current-implementation", + [Cl.contractPrincipal(deployer!, CENTRALIZED_CONNECTION_CONTRACT_NAME)], + deployer! + ); + + expect(isNotCurrentImplementationResult.result).toBeOk(Cl.bool(false)); + }); + + it("sends and executes a call", () => { + const data = Uint8Array.from(encode(["Hello, Destination Contract!"])); + const expectedSn = 1; + const expectedReqId = 1; + + const sendCallResult = simnet.callPublicFn( + xcallProxy.contractName.content, + "send-call", + [Cl.stringAscii(to), Cl.buffer(data), xcallImpl], + sourceContract + ); + + console.log("Send call events:", sendCallResult.events); + + expect(sendCallResult.result).toBeOk(Cl.uint(expectedSn)); + const callMessageSentEvent = sendCallResult.events.find( + (e) => + e.event === "print_event" && + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + e?.data.value?.data.event.data === "CallMessageSent" + ); + + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + expect(callMessageSentEvent?.data.value!.data.event.data).toBe( + "CallMessageSent" + ); + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + expect(callMessageSentEvent?.data.value!.data.from).toStrictEqual( + Cl.principal(sourceContract) + ); + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + expect(callMessageSentEvent?.data.value!.data.to).toStrictEqual( + Cl.stringAscii(to) + ); + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + expect(callMessageSentEvent?.data.value!.data.sn).toStrictEqual(Cl.uint(1)); + + const messageData = encode([from, to, expectedSn, expectedReqId, data, []]); + + const csMessageRequest = encode([CS_MESSAGE_TYPE_REQUEST, messageData]); + console.log("CS Message Request hex:", csMessageRequest.toString('hex')); + + const recvMessageResult = simnet.callPublicFn( + CENTRALIZED_CONNECTION_CONTRACT_NAME, + "recv-message", + [ + Cl.stringAscii(STACKS_NID), + Cl.int(expectedSn), + Cl.buffer(csMessageRequest), + xcallImpl, + ], + deployer! + ); + + console.log("Recv message events:", recvMessageResult.events); +console.log("CS Message Request:", csMessageRequest); + + expect(recvMessageResult.result).toBeOk(Cl.bool(true)); + + const callMessageEvent = recvMessageResult.events.find( + (e) => + e.event === "print_event" && + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + e.data.value!.data.event.data === "CallMessage" + ); + expect(callMessageEvent).toBeDefined(); + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + const callMessageData = callMessageEvent!.data.value!.data; + expect(callMessageData.from.data).toBe(from); + expect(callMessageData.to.data).toBe(to); + const reqId = callMessageData["req-id"].value; + expect(Number(callMessageData.sn.value)).toBe(expectedSn); + expect(Number(callMessageData["req-id"].value)).toBe(expectedReqId); + + const slicedData = data.slice(1); // rlp decode drops length byte + const executeCallResult = simnet.callPublicFn( + XCALL_PROXY_CONTRACT_NAME, + "execute-call", + [Cl.uint(reqId), Cl.buffer(slicedData), mockDapp, xcallImpl, xcallImpl], + deployer! + ); + expect(executeCallResult.result).toBeOk(Cl.bool(true)); + + const callExecutedEvent = executeCallResult.events.find( + (e) => + e.event === "print_event" && + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + e.data.value!.data.event.data === "CallExecuted" + ); + expect(callExecutedEvent).toBeDefined(); + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + const callExecutedData = callExecutedEvent!.data.value!.data; + expect(Number(callExecutedData.code.value)).toBe(CS_MESSAGE_RESULT_SUCCESS); + expect(Number(callExecutedData["req-id"].value)).toBe(expectedReqId); + expect(callExecutedData.msg.data).toBe(""); + + const messageReceivedEvent = executeCallResult.events.find( + (e) => + e.event === "print_event" && + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + e.data.value!.data.event.data === "MessageReceived" + ); + expect(messageReceivedEvent).toBeDefined(); + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + const messageReceivedData = messageReceivedEvent!.data.value!.data; + expect(messageReceivedData.data).toStrictEqual( + Cl.stringAscii("Hello, Destination Contract!") + ); + expect(messageReceivedData.from).toStrictEqual(Cl.stringAscii(from)); + + const responseData = encode([expectedSn, CS_MESSAGE_RESULT_SUCCESS]); + + const csMessageResponse = encode([CS_MESSAGE_TYPE_RESULT, responseData]); + + const handleResponseResult = simnet.callPublicFn( + CENTRALIZED_CONNECTION_CONTRACT_NAME, + "recv-message", + [ + Cl.stringAscii(ICON_NID), + Cl.int(-expectedSn), + Cl.buffer(csMessageResponse), + xcallImpl, + ], + deployer! + ); + + expect(handleResponseResult.result).toBeErr(Cl.uint(203)); // message not found because ack is only sent on rollback + + const verifySuccessResult = simnet.callPublicFn( + XCALL_PROXY_CONTRACT_NAME, + "verify-success", + [Cl.uint(1), xcallImpl], + sourceContract + ); + expect(verifySuccessResult.result).toBeOk(Cl.bool(false)); + }); + + it("sends a message with rollback and executes rollback on failure", () => { + const expectedSn = 1; + const expectedReqId = 1; + const data = Uint8Array.from(encode(["Hello, Destination Contract!"])); + const rollbackData = Uint8Array.from(encode(["Rollback data"])).slice(1); + + const sendCallResult = simnet.callPublicFn( + XCALL_PROXY_CONTRACT_NAME, + "send-call-message", + [ + Cl.stringAscii(to), + Cl.buffer(data), + Cl.some(Cl.buffer(rollbackData)), + Cl.none(), + Cl.none(), + xcallImpl, + ], + deployer! + ); + expect(sendCallResult.result).toBeOk(Cl.uint(expectedSn)); + + const messageData = encode([from, to, expectedSn, expectedReqId, data, []]); + + const csMessageRequest = encode([CS_MESSAGE_TYPE_REQUEST, messageData]); + + const recvMessageResult = simnet.callPublicFn( + CENTRALIZED_CONNECTION_CONTRACT_NAME, + "recv-message", + [ + Cl.stringAscii(STACKS_NID), + Cl.int(expectedSn), + Cl.buffer(csMessageRequest), + xcallImpl, + ], + deployer! + ); + + expect(recvMessageResult.result).toBeOk(Cl.bool(true)); + + const callMessageEvent = recvMessageResult.events.find( + (e) => + e.event === "print_event" && + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + e.data.value!.data.event.data === "CallMessage" + ); + expect(callMessageEvent).toBeDefined(); + + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + const callMessageData = callMessageEvent!.data.value!.data; + const reqId = callMessageData["req-id"].value; + expect(callMessageData.from.data).toBe(from); + expect(callMessageData.to.data).toBe(to); + expect(Number(callMessageData.sn.value)).toBe(expectedSn); + expect(Number(reqId)).toBe(expectedReqId); + + const slicedData = data.slice(1); // rlp decode drops length byte + const executeCallResult = simnet.callPublicFn( + XCALL_PROXY_CONTRACT_NAME, + "execute-call", + [Cl.uint(reqId), Cl.buffer(slicedData), mockDapp, xcallImpl, xcallImpl], + deployer! + ); + expect(executeCallResult.result).toBeOk(Cl.bool(true)); + + const callExecutedEvent = executeCallResult.events.find( + (e) => + e.event === "print_event" && + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + e.data.value!.data.event.data === "CallExecuted" + ); + expect(callExecutedEvent).toBeDefined(); + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + const callExecutedData = callExecutedEvent!.data.value!.data; + expect(Number(callExecutedData.code.value)).toBe(CS_MESSAGE_RESULT_SUCCESS); + expect(Number(callExecutedData["req-id"].value)).toBe(expectedReqId); + expect(callExecutedData.msg.data).toBe(""); + + const messageReceivedEvent = executeCallResult.events.find( + (e) => + e.event === "print_event" && + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + e.data.value!.data.event.data === "MessageReceived" + ); + expect(messageReceivedEvent).toBeDefined(); + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + const messageReceivedData = messageReceivedEvent!.data.value!.data; + expect(messageReceivedData.data).toStrictEqual( + Cl.stringAscii("Hello, Destination Contract!") + ); + expect(messageReceivedData.from).toStrictEqual(Cl.stringAscii(from)); + + const failureResponseData = encode([expectedSn, CS_MESSAGE_RESULT_FAILURE]); + const csMessageResponse = encode([ + CS_MESSAGE_TYPE_RESULT, + failureResponseData, + ]); + + const handleFailureResult = simnet.callPublicFn( + CENTRALIZED_CONNECTION_CONTRACT_NAME, + "recv-message", + [ + Cl.stringAscii(ICON_NID), + Cl.int(-expectedSn), + Cl.buffer(csMessageResponse), + xcallImpl, + ], + deployer! + ); + expect(handleFailureResult.result).toBeOk(Cl.bool(true)); + + const responseMessageEvent = handleFailureResult.events.find( + (e) => + e.event === "print_event" && + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + e.data.value!.data.event.data === "ResponseMessage" + ); + expect(responseMessageEvent).toBeDefined(); + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + expect(responseMessageEvent!.data.value!.data.code).toStrictEqual( + Cl.uint(CS_MESSAGE_RESULT_FAILURE) + ); + + const rollbackMessageEvent = handleFailureResult.events.find( + (e) => + e.event === "print_event" && + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + e.data.value!.data.event.data === "RollbackMessage" + ); + expect(rollbackMessageEvent).toBeDefined(); + + const executeRollbackResult = simnet.callPublicFn( + XCALL_PROXY_CONTRACT_NAME, + "execute-rollback", + [Cl.uint(expectedSn), mockDapp, xcallImpl, xcallImpl], + deployer! + ); + expect(executeRollbackResult.result).toBeOk(Cl.bool(true)); + + const rollbackExecutedEvent = executeRollbackResult.events.find( + (e) => + e.event === "print_event" && + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + e.data.value!.data.event.data === "RollbackReceived" + ); + expect(rollbackExecutedEvent).toBeDefined(); + + // @ts-ignore: Property 'data' does not exist on type 'ClarityValue'. Property 'data' does not exist on type 'ContractPrincipalCV'. + const rollbackExecutedData = rollbackExecutedEvent!.data.value!.data; + expect(rollbackExecutedData.from).toStrictEqual( + Cl.stringAscii( + STACKS_NID + "/" + deployer! + "." + XCALL_IMPL_CONTRACT_NAME + ) + ); + expect(rollbackExecutedData.data).toStrictEqual( + Cl.stringAscii("Rollback data") + ); + + const getOutgoingMessage = simnet.callReadOnlyFn( + XCALL_IMPL_CONTRACT_NAME, + "get-outgoing-message", + [Cl.uint(expectedSn)], + deployer! + ); + expect(getOutgoingMessage.result).toBeNone(); + }); + + // it("handles execute-call failure correctly", () => { + // const data = Uint8Array.from(encode(["rollback"])); + // const expectedSn = 1; + // const expectedReqId = 1; + // const rollbackData = Uint8Array.from(encode(["Rollback Message"])).slice(1); + + // const sendCallResult = simnet.callPublicFn( + // XCALL_PROXY_CONTRACT_NAME, + // "send-call-message", + // [ + // Cl.stringAscii(to), + // Cl.buffer(data), + // Cl.some(Cl.buffer(rollbackData)), + // Cl.none(), + // Cl.none(), + // xcallImpl, + // ], + // deployer! + // ); + // expect(sendCallResult.result).toBeOk(Cl.uint(expectedSn)); + + // const messageData = encode([from, to, expectedSn, expectedReqId, data, []]); + + // const csMessageRequest = encode([CS_MESSAGE_TYPE_REQUEST, messageData]); + + // const recvMessageResult = simnet.callPublicFn( + // CENTRALIZED_CONNECTION_CONTRACT_NAME, + // "recv-message", + // [ + // Cl.stringAscii(STACKS_NID), + // Cl.int(expectedSn), + // Cl.buffer(csMessageRequest), + // xcallImpl, + // ], + // deployer! + // ); + // expect(recvMessageResult.result).toBeOk(Cl.bool(true)); + + // const callMessageEvent = recvMessageResult.events.find( + // (e) => + // e.event === "print_event" && + // // @ts-ignore: Property 'data' does not exist on type 'ClarityValue' + // e.data.value!.data.event.data === "CallMessage" + // ); + // expect(callMessageEvent).toBeDefined(); + // // @ts-ignore: Property 'data' does not exist on type 'ClarityValue' + // const reqId = callMessageEvent!.data.value!.data["req-id"].value; + + // const slicedData = data.slice(1); + // const executeCallResult = simnet.callPublicFn( + // XCALL_PROXY_CONTRACT_NAME, + // "execute-call", + // [Cl.uint(reqId), Cl.buffer(slicedData), mockDapp, xcallImpl, xcallImpl], + // deployer! + // ); + // expect(executeCallResult.result).toBeErr(Cl.uint(802)); // ERR_INVALID_MESSAGE + + // // Verify CallExecuted event shows failure + // const callExecutedEvent = executeCallResult.events.find( + // (e) => + // e.event === "print_event" && + // // @ts-ignore: Property 'data' does not exist on type 'ClarityValue' + // e.data.value!.data.event.data === "CallExecuted" + // ); + // expect(callExecutedEvent).toBeDefined(); + // // @ts-ignore: Property 'data' does not exist on type 'ClarityValue' + // const callExecutedData = callExecutedEvent!.data.value!.data; + // expect(Number(callExecutedData.code.value)).toBe(CS_MESSAGE_RESULT_FAILURE); + // expect(Number(callExecutedData["req-id"].value)).toBe(expectedReqId); + + // // Verify ResponseMessage event + // const responseMessageEvent = executeCallResult.events.find( + // (e) => + // e.event === "print_event" && + // // @ts-ignore: Property 'data' does not exist on type 'ClarityValue' + // e.data.value!.data.event.data === "ResponseMessage" + // ); + // expect(responseMessageEvent).toBeDefined(); + // // @ts-ignore: Property 'data' does not exist on type 'ClarityValue' + // expect(responseMessageEvent!.data.value!.data.code).toStrictEqual( + // Cl.uint(CS_MESSAGE_RESULT_FAILURE) + // ); + + // // Verify RollbackMessage event is emitted + // const rollbackMessageEvent = executeCallResult.events.find( + // (e) => + // e.event === "print_event" && + // // @ts-ignore: Property 'data' does not exist on type 'ClarityValue' + // e.data.value!.data.event.data === "RollbackMessage" + // ); + // expect(rollbackMessageEvent).toBeDefined(); + + // // Execute rollback + // const executeRollbackResult = simnet.callPublicFn( + // XCALL_PROXY_CONTRACT_NAME, + // "execute-rollback", + // [Cl.uint(expectedSn), mockDapp, xcallImpl, xcallImpl], + // deployer! + // ); + // expect(executeRollbackResult.result).toBeOk(Cl.bool(true)); + + // // Verify RollbackExecuted event + // const rollbackExecutedEvent = executeRollbackResult.events.find( + // (e) => + // e.event === "print_event" && + // // @ts-ignore: Property 'data' does not exist on type 'ClarityValue' + // e.data.value!.data.event.data === "RollbackReceived" + // ); + // expect(rollbackExecutedEvent).toBeDefined(); + // // @ts-ignore: Property 'data' does not exist on type 'ClarityValue' + // const rollbackExecutedData = rollbackExecutedEvent!.data.value!.data; + // expect(rollbackExecutedData.from).toStrictEqual( + // Cl.stringAscii( + // STACKS_NID + "/" + deployer! + "." + XCALL_IMPL_CONTRACT_NAME + // ) + // ); + // expect(rollbackExecutedData.data).toStrictEqual( + // Cl.stringAscii("Rollback Message") + // ); + // }); + + it("calculates fees correctly for different scenarios", () => { + const feeStacksNoRollback = simnet.callPublicFn( + XCALL_PROXY_CONTRACT_NAME, + "get-fee", + [Cl.stringAscii(STACKS_NID), Cl.bool(false), Cl.none(), xcallImpl], + sourceContract + ); + expect(feeStacksNoRollback.result).toBeOk(Cl.uint(600000)); // 500000 base fee + 100000 protocol fee + + const feeStacksWithRollback = simnet.callPublicFn( + XCALL_PROXY_CONTRACT_NAME, + "get-fee", + [Cl.stringAscii(STACKS_NID), Cl.bool(true), Cl.none(), xcallImpl], + sourceContract + ); + expect(feeStacksWithRollback.result).toBeOk(Cl.uint(850000)); // 500000 base fee + 250000 rollback fee + 100000 protocol fee + + const feeIconWithRollback = simnet.callPublicFn( + XCALL_PROXY_CONTRACT_NAME, + "get-fee", + [Cl.stringAscii(ICON_NID), Cl.bool(true), Cl.none(), xcallImpl], + sourceContract + ); + expect(feeIconWithRollback.result).toBeOk(Cl.uint(1600000)); // 1000000 base fee + 500000 rollback fee + 100000 protocol fee + }); + + it("parses cs-message correctly", () => { + const sn = 1; + const messageType = 1; + const data = Buffer.from("Hello, ICON!"); + const protocols = ["protocol1", "protocol2"]; + + const messageData = encode([from, to, sn, messageType, data, protocols]); + + const parseCSMessageRequestResult = simnet.callPublicFn( + XCALL_IMPL_CONTRACT_NAME, + "parse-cs-message-request", + [Cl.buffer(messageData)], + deployer! + ); + + console.log("Message data:", messageData); +console.log("Parse CS message events:", parseCSMessageRequestResult.events); + + + // @ts-ignore: Property 'value' does not exist on type 'ClarityValue'. Property 'value' does not exist on type 'ContractPrincipalCV'. + const parsedResult = parseCSMessageRequestResult.result.value.data; + expect(parsedResult.from).toStrictEqual(Cl.stringAscii(from)); + expect(parsedResult.to).toStrictEqual(Cl.stringAscii(to)); + expect(parsedResult.sn).toStrictEqual(Cl.uint(sn)); + expect(parsedResult.type).toStrictEqual(Cl.uint(messageType)); + expect(parsedResult.protocols).toStrictEqual( + Cl.list(protocols.map((p) => Cl.stringAscii(p))) + ); + + const csMessage = encode([CS_MESSAGE_TYPE_REQUEST, messageData]); + + const parseCSMessageResult = simnet.callPrivateFn( + XCALL_IMPL_CONTRACT_NAME, + "parse-cs-message", + [Cl.buffer(csMessage)], + deployer! + ); + + expect(parseCSMessageResult.result).toBeOk( + Cl.tuple({ + type: Cl.uint(1), + data: Cl.buffer(messageData), + }) + ); + + const parseCSMessageRequestResult2 = simnet.callPublicFn( + XCALL_IMPL_CONTRACT_NAME, + "parse-cs-message-request", + // @ts-ignore: Property 'value' does not exist on type 'ClarityValue'. Property 'value' does not exist on type 'ContractPrincipalCV'. + [parseCSMessageResult.result.value.data.data], + deployer! + ); + + // @ts-ignore: Property 'value' does not exist on type 'ClarityValue'. Property 'value' does not exist on type 'ContractPrincipalCV'. + const parsedResult2 = parseCSMessageRequestResult2.result.value.data; + expect(parsedResult2.from).toStrictEqual(Cl.stringAscii(from)); + expect(parsedResult2.to).toStrictEqual(Cl.stringAscii(to)); + expect(parsedResult2.sn).toStrictEqual(Cl.uint(sn)); + expect(parsedResult2.type).toStrictEqual(Cl.uint(messageType)); + expect(parsedResult2.protocols).toStrictEqual( + Cl.list(protocols.map((p) => Cl.stringAscii(p))) + ); + }); +}); diff --git a/contracts/stacks/tsconfig.json b/contracts/stacks/tsconfig.json new file mode 100644 index 000000000..1bdaf36c4 --- /dev/null +++ b/contracts/stacks/tsconfig.json @@ -0,0 +1,26 @@ + +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext"], + "skipLibCheck": true, + + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + "strict": true, + "noImplicitAny": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": [ + "node_modules/@hirosystems/clarinet-sdk/vitest-helpers/src", + "tests" + ] +} diff --git a/contracts/stacks/vitest.config.js b/contracts/stacks/vitest.config.js new file mode 100644 index 000000000..c6a850651 --- /dev/null +++ b/contracts/stacks/vitest.config.js @@ -0,0 +1,42 @@ + +/// + +import { defineConfig } from "vite"; +import { vitestSetupFilePath, getClarinetVitestsArgv } from "@hirosystems/clarinet-sdk/vitest"; + +/* + In this file, Vitest is configured so that it works seamlessly with Clarinet and the Simnet. + + The `vitest-environment-clarinet` will initialise the clarinet-sdk + and make the `simnet` object available globally in the test files. + + `vitestSetupFilePath` points to a file in the `@hirosystems/clarinet-sdk` package that does two things: + - run `before` hooks to initialize the simnet and `after` hooks to collect costs and coverage reports. + - load custom vitest matchers to work with Clarity values (such as `expect(...).toBeUint()`) + + The `getClarinetVitestsArgv()` will parse options passed to the command `vitest run --` + - vitest run -- --manifest ./Clarinet.toml # pass a custom path + - vitest run -- --coverage --costs # collect coverage and cost reports +*/ + +export default defineConfig({ + test: { + environment: "clarinet", // use vitest-environment-clarinet + pool: "forks", + poolOptions: { + threads: { singleThread: true }, + forks: { singleFork: true }, + }, + setupFiles: [ + vitestSetupFilePath, + // custom setup files can be added here + ], + environmentOptions: { + clarinet: { + ...getClarinetVitestsArgv(), + // add or override options + }, + }, + }, +}); +