Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: stacks #394

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0071194
wip: implement stacks (not working yet)
CyrusVorwald Oct 8, 2024
8548223
wip: stacks get fee
CyrusVorwald Oct 10, 2024
230e073
fix: update stacks expected fee
CyrusVorwald Oct 10, 2024
f6c57fe
fix: get-default-connection uses nid
CyrusVorwald Oct 10, 2024
3435422
wip(stacks): verify protocols
CyrusVorwald Oct 11, 2024
6f365bf
fix: pass nid to verify-protocols
CyrusVorwald Oct 11, 2024
f4468f2
wip: use conn recv instead of handle-call directly
CyrusVorwald Oct 11, 2024
839def2
fix: protocol verification
CyrusVorwald Oct 11, 2024
9a048ca
wip: execute arbitrary call
CyrusVorwald Oct 12, 2024
49b3790
wip: rollback fails on decode-rlp-message
CyrusVorwald Oct 12, 2024
dbd4b51
fix: rollback test passes
CyrusVorwald Oct 12, 2024
1d54b27
chore: remove unused lib files
CyrusVorwald Oct 12, 2024
d86e9fe
Merge branch 'main' into feat/stacks
CyrusVorwald Nov 7, 2024
dd2a88c
fix: rlp, callmessagesent, xcall-impl-trait
CyrusVorwald Nov 19, 2024
874b68f
fix: change rlp to match xcall instead of ethereum
CyrusVorwald Nov 21, 2024
82e1f0c
fix: get-network-address char limit
CyrusVorwald Nov 21, 2024
bad90bd
test: add rlp tests
CyrusVorwald Nov 21, 2024
2074fa7
fix: rlp encode u8 and u32
CyrusVorwald Nov 21, 2024
2138759
refactor: remove duplicate if statement
CyrusVorwald Nov 22, 2024
a50771a
fix: rlp encode call message
CyrusVorwald Nov 23, 2024
60399ed
fix: rlp encodes dynamic length strings
CyrusVorwald Nov 24, 2024
13cfe18
fix: recv-message auth
CyrusVorwald Dec 4, 2024
5f1271e
identical calls to address-string-to-principal
CyrusVorwald Dec 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions contracts/stacks/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
tests/** linguist-vendored
vitest.config.js linguist-vendored
* text=lf
13 changes: 13 additions & 0 deletions contracts/stacks/.gitignore
Original file line number Diff line number Diff line change
@@ -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
74 changes: 74 additions & 0 deletions contracts/stacks/Clarinet.toml
Original file line number Diff line number Diff line change
@@ -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
102 changes: 102 additions & 0 deletions contracts/stacks/contracts/connections/centralized-connection.clar
Original file line number Diff line number Diff line change
@@ -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 <xcall-impl-trait>))
(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))))
118 changes: 118 additions & 0 deletions contracts/stacks/contracts/debug.clar
Original file line number Diff line number Diff line change
@@ -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"
)
)
71 changes: 71 additions & 0 deletions contracts/stacks/contracts/util.clar
Original file line number Diff line number Diff line change
@@ -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))))
6 changes: 6 additions & 0 deletions contracts/stacks/contracts/xcall/xcall-common-trait.clar
Original file line number Diff line number Diff line change
@@ -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))
)
)
Loading
Loading