strade-stx 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.activity_counter +1 -0
- package/.gitattributes +3 -0
- package/.vscode/settings.json +4 -0
- package/.vscode/tasks.json +19 -0
- package/CHANGELOG.md +1 -0
- package/Clarinet.toml +56 -0
- package/Clarinet.toml.backup +174 -0
- package/Clarinet.toml.old +146 -0
- package/DEPLOYMENT_RESULTS.md +160 -0
- package/README.md +344 -0
- package/TODO.md +34 -0
- package/contracts/CoreMarketPlace.clar +227 -0
- package/contracts/DisputeResolution_clar.clar +265 -0
- package/contracts/EscrowService.clar +171 -0
- package/contracts/UserProfile.clar +280 -0
- package/contracts/ft-trait.clar +24 -0
- package/contracts/token.clar +178 -0
- package/costs-reports.json +76026 -0
- package/deployments/default.mainnet-plan.yaml +67 -0
- package/deployments/default.simnet-plan.yaml +105 -0
- package/deployments/default.testnet-plan.yaml +67 -0
- package/deployments/new-contracts.testnet-plan.yaml +32 -0
- package/frontend/README.md +10 -0
- package/frontend/components.json +22 -0
- package/frontend/dist/assets/index-BacuuL66.css +1 -0
- package/frontend/dist/assets/index-jryypd5B.js +194 -0
- package/frontend/dist/favicon.png +0 -0
- package/frontend/dist/index.html +15 -0
- package/frontend/dist/manifest.json +15 -0
- package/frontend/dist/vite.svg +1 -0
- package/frontend/empty-mock.js +1 -0
- package/frontend/eslint.config.js +23 -0
- package/frontend/eslint.config.mjs +25 -0
- package/frontend/index.html +14 -0
- package/frontend/next.config.ts +17 -0
- package/frontend/package-lock.json +14740 -0
- package/frontend/package.json +56 -0
- package/frontend/postcss.config.js +5 -0
- package/frontend/postcss.config.mjs +5 -0
- package/frontend/public/favicon.png +0 -0
- package/frontend/public/file.svg +1 -0
- package/frontend/public/globe.svg +1 -0
- package/frontend/public/manifest.json +15 -0
- package/frontend/public/next.svg +1 -0
- package/frontend/public/vercel.svg +1 -0
- package/frontend/public/vite.svg +1 -0
- package/frontend/public/window.svg +1 -0
- package/frontend/src/App.css +42 -0
- package/frontend/src/App.tsx +177 -0
- package/frontend/src/app/about/page.tsx +208 -0
- package/frontend/src/app/favicon.ico +0 -0
- package/frontend/src/app/globals.css +129 -0
- package/frontend/src/app/help/page.tsx +167 -0
- package/frontend/src/app/how-it-works/page.tsx +274 -0
- package/frontend/src/app/layout.tsx +55 -0
- package/frontend/src/app/marketplace/page.tsx +324 -0
- package/frontend/src/app/my-listings/page.tsx +318 -0
- package/frontend/src/app/page.tsx +15 -0
- package/frontend/src/assets/react.svg +1 -0
- package/frontend/src/components/ConfirmDialog.tsx +54 -0
- package/frontend/src/components/CreateListingForm.tsx +231 -0
- package/frontend/src/components/ErrorBoundary.tsx +73 -0
- package/frontend/src/components/FilterPanel.tsx +10 -0
- package/frontend/src/components/Footer.tsx +100 -0
- package/frontend/src/components/Header.tsx +268 -0
- package/frontend/src/components/ImageUpload.tsx +147 -0
- package/frontend/src/components/LandingPage.tsx +322 -0
- package/frontend/src/components/ListingCard.tsx +154 -0
- package/frontend/src/components/LoadingSkeleton.tsx +44 -0
- package/frontend/src/components/MobileNav.tsx +89 -0
- package/frontend/src/components/NotificationBell.tsx +8 -0
- package/frontend/src/components/NotificationPanel.tsx +14 -0
- package/frontend/src/components/README.md +14 -0
- package/frontend/src/components/SearchBar.tsx +10 -0
- package/frontend/src/components/TestnetBanner.tsx +29 -0
- package/frontend/src/components/ThemeToggle.tsx +32 -0
- package/frontend/src/components/__tests__/Header.test.tsx +70 -0
- package/frontend/src/components/__tests__/ListingCard.test.tsx +86 -0
- package/frontend/src/components/providers/ThemeProvider.tsx +9 -0
- package/frontend/src/components/ui/alert-dialog.tsx +141 -0
- package/frontend/src/components/ui/avatar.tsx +53 -0
- package/frontend/src/components/ui/badge.tsx +46 -0
- package/frontend/src/components/ui/button.tsx +60 -0
- package/frontend/src/components/ui/card.tsx +92 -0
- package/frontend/src/components/ui/dialog.tsx +143 -0
- package/frontend/src/components/ui/dropdown-menu.tsx +257 -0
- package/frontend/src/components/ui/input.tsx +21 -0
- package/frontend/src/components/ui/label.tsx +24 -0
- package/frontend/src/components/ui/select.tsx +187 -0
- package/frontend/src/components/ui/sonner.tsx +40 -0
- package/frontend/src/components/ui/textarea.tsx +18 -0
- package/frontend/src/context/README.md +27 -0
- package/frontend/src/index.css +166 -0
- package/frontend/src/lib/notificationEvents.ts +10 -0
- package/frontend/src/lib/notificationStore.ts +13 -0
- package/frontend/src/lib/notifications.ts +13 -0
- package/frontend/src/lib/search.ts +28 -0
- package/frontend/src/lib/stacks.ts +189 -0
- package/frontend/src/lib/utils.ts +6 -0
- package/frontend/src/main.tsx +10 -0
- package/frontend/src/test/setup.ts +23 -0
- package/frontend/src/types.d.ts +9 -0
- package/frontend/tsconfig.app.json +28 -0
- package/frontend/tsconfig.json +41 -0
- package/frontend/tsconfig.node.json +26 -0
- package/frontend/vercel.json +4 -0
- package/frontend/vite.config.ts +6 -0
- package/frontend/vitest.config.ts +17 -0
- package/lcov.info +31338 -0
- package/mainnetcontracts.md +16 -0
- package/package.json +53 -0
- package/scripts/auto-activity.sh +9 -0
- package/scripts/cancel-pending.ts +67 -0
- package/scripts/check-balances.ts +23 -0
- package/scripts/distribute-evenly.ts +56 -0
- package/scripts/drain-accounts.ts +70 -0
- package/scripts/fund-accounts.ts +88 -0
- package/scripts/fund-active.ts +59 -0
- package/scripts/fund-unfunded.ts +88 -0
- package/scripts/generate-activity.ts +181 -0
- package/scripts/git-activity-generator.ts +154 -0
- package/scripts/mobile-server.ts +123 -0
- package/settings/Devnet.toml +155 -0
- package/settings/Mainnet.toml +7 -0
- package/settings/Testnet.toml +9 -0
- package/tests/CoreMarketPlace.fuzz.test.ts +435 -0
- package/tests/CoreMarketPlace.test.ts +564 -0
- package/tsconfig.json +26 -0
- package/vitest.config.js +49 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
;; DisputeResolution Contract
|
|
2
|
+
;; This contract handles the dispute resolution process for the Strade marketplace.
|
|
3
|
+
;; It allows users to raise disputes, arbitrators to vote on them, and resolves disputes based on the outcome.
|
|
4
|
+
|
|
5
|
+
;; --- Constants ---
|
|
6
|
+
;; Defines immutable values used throughout the contract for error handling and configuration.
|
|
7
|
+
|
|
8
|
+
(define-constant CONTRACT_OWNER tx-sender) ;; Sets the contract deployer as the owner.
|
|
9
|
+
(define-constant ERR_NOT_AUTHORIZED (err u100)) ;; Error for unauthorized actions.
|
|
10
|
+
(define-constant ERR_DISPUTE_NOT_FOUND (err u101)) ;; Error when a dispute cannot be found.
|
|
11
|
+
(define-constant ERR_INVALID_STATE (err u102)) ;; Error for invalid dispute states.
|
|
12
|
+
(define-constant ERR_NOT_ARBITRATOR (err u103)) ;; Error when a user is not an authorized arbitrator.
|
|
13
|
+
(define-constant ERR_ALREADY_VOTED (err u104)) ;; Error if an arbitrator has already voted.
|
|
14
|
+
(define-constant ERR_VOTING_CLOSED (err u105)) ;; Error when voting on a dispute is closed.
|
|
15
|
+
(define-constant ERR_INSUFFICIENT_VOTES (err u106)) ;; Error if there are not enough votes to resolve a dispute.
|
|
16
|
+
(define-constant ERR_INVALID_VOTE (err u107)) ;; Error for invalid vote values.
|
|
17
|
+
(define-constant ERR_NOT_INVOLVED_PARTY (err u108)) ;; Error when a user is not a party to the dispute.
|
|
18
|
+
(define-constant ERR_INVALID_ESCROW_ID (err u109)) ;; Error for invalid escrow IDs.
|
|
19
|
+
(define-constant ERR_INVALID_REASON (err u110)) ;; Error for invalid dispute reasons.
|
|
20
|
+
(define-constant ERR_INVALID_DISPUTE_ID (err u111)) ;; Error for invalid dispute IDs.
|
|
21
|
+
(define-constant ERR_INVALID_REWARD (err u112)) ;; Error for invalid arbitrator rewards.
|
|
22
|
+
(define-constant ERR_INVALID_PRINCIPAL (err u113)) ;; Error for invalid principal addresses.
|
|
23
|
+
(define-constant VOTING_PERIOD u144) ;; The duration of the voting period in blocks (approximately 24 hours).
|
|
24
|
+
(define-constant MIN_VOTES_REQUIRED u3) ;; The minimum number of votes required to resolve a dispute.
|
|
25
|
+
|
|
26
|
+
;; --- Data Maps ---
|
|
27
|
+
;; Defines the data structures used to store dispute and arbitrator information.
|
|
28
|
+
|
|
29
|
+
(define-map Disputes
|
|
30
|
+
{ dispute-id: uint }
|
|
31
|
+
{
|
|
32
|
+
escrow-id: uint, ;; The ID of the associated escrow.
|
|
33
|
+
initiator: principal, ;; The principal who initiated the dispute.
|
|
34
|
+
counterparty: principal, ;; The other party in the dispute.
|
|
35
|
+
reason: (string-utf8 256), ;; The reason for the dispute.
|
|
36
|
+
status: (string-ascii 20), ;; The current status of the dispute (e.g., "open", "resolved").
|
|
37
|
+
created-at: uint, ;; The block height at which the dispute was created.
|
|
38
|
+
votes-for: uint, ;; The number of votes in favor of the initiator.
|
|
39
|
+
votes-against: uint, ;; The number of votes against the initiator.
|
|
40
|
+
resolution: (optional (string-ascii 20)) ;; The resolution of the dispute.
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
(define-map Arbitrators principal bool) ;; Stores the set of authorized arbitrators.
|
|
45
|
+
(define-map ArbitratorVotes { dispute-id: uint, arbitrator: principal } bool) ;; Tracks votes cast by arbitrators.
|
|
46
|
+
|
|
47
|
+
;; --- Variables ---
|
|
48
|
+
;; Defines mutable variables for tracking the contract's state.
|
|
49
|
+
|
|
50
|
+
(define-data-var last-dispute-id uint u0) ;; Tracks the ID of the last created dispute.
|
|
51
|
+
(define-data-var arbitrator-reward uint u100) ;; The reward amount for arbitrators who vote on a dispute.
|
|
52
|
+
|
|
53
|
+
;; --- Private Functions ---
|
|
54
|
+
;; Helper functions intended for internal use by the contract.
|
|
55
|
+
|
|
56
|
+
;; Checks if a given user is an authorized arbitrator.
|
|
57
|
+
(define-private (is-arbitrator (user principal))
|
|
58
|
+
(default-to false (map-get? Arbitrators user))
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
;; Checks if an arbitrator has already voted on a specific dispute.
|
|
62
|
+
(define-private (has-voted (dispute-id uint) (arbitrator principal))
|
|
63
|
+
(is-some (map-get? ArbitratorVotes { dispute-id: dispute-id, arbitrator: arbitrator }))
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
;; Updates the vote count for a dispute.
|
|
67
|
+
(define-private (update-vote-count (dispute-id uint) (vote bool))
|
|
68
|
+
(match (map-get? Disputes { dispute-id: dispute-id })
|
|
69
|
+
dispute (let
|
|
70
|
+
(
|
|
71
|
+
(new-votes-for (if vote (+ (get votes-for dispute) u1) (get votes-for dispute)))
|
|
72
|
+
(new-votes-against (if vote (get votes-against dispute) (+ (get votes-against dispute) u1)))
|
|
73
|
+
)
|
|
74
|
+
(map-set Disputes { dispute-id: dispute-id }
|
|
75
|
+
(merge dispute {
|
|
76
|
+
votes-for: new-votes-for,
|
|
77
|
+
votes-against: new-votes-against
|
|
78
|
+
}))
|
|
79
|
+
(ok true))
|
|
80
|
+
(err ERR_DISPUTE_NOT_FOUND)
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
;; Checks if an escrow ID is valid.
|
|
85
|
+
(define-private (is-valid-escrow-id (escrow-id uint))
|
|
86
|
+
(> escrow-id u0)
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
;; Checks if a dispute reason is valid.
|
|
90
|
+
(define-private (is-valid-reason (reason (string-utf8 256)))
|
|
91
|
+
(and (> (len reason) u0) (<= (len reason) u256))
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
;; Checks if a dispute ID is valid.
|
|
95
|
+
(define-private (is-valid-dispute-id (dispute-id uint))
|
|
96
|
+
(<= dispute-id (var-get last-dispute-id))
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
;; --- Public Functions ---
|
|
100
|
+
;; Functions that can be called by any user.
|
|
101
|
+
|
|
102
|
+
;; Raises a new dispute.
|
|
103
|
+
;; @param escrow-id: The ID of the escrow to dispute.
|
|
104
|
+
;; @param counterparty: The other party in the dispute.
|
|
105
|
+
;; @param reason: The reason for the dispute.
|
|
106
|
+
;; @returns (ok uint): The ID of the newly created dispute.
|
|
107
|
+
(define-public (raise-dispute (escrow-id uint) (counterparty principal) (reason (string-utf8 256)))
|
|
108
|
+
(let
|
|
109
|
+
(
|
|
110
|
+
(dispute-id (+ (var-get last-dispute-id) u1))
|
|
111
|
+
)
|
|
112
|
+
(asserts! (is-valid-escrow-id escrow-id) (err ERR_INVALID_ESCROW_ID))
|
|
113
|
+
(asserts! (is-valid-reason reason) (err ERR_INVALID_REASON))
|
|
114
|
+
(asserts! (not (is-eq tx-sender counterparty)) (err ERR_NOT_INVOLVED_PARTY))
|
|
115
|
+
(map-set Disputes
|
|
116
|
+
{ dispute-id: dispute-id }
|
|
117
|
+
{
|
|
118
|
+
escrow-id: escrow-id,
|
|
119
|
+
initiator: tx-sender,
|
|
120
|
+
counterparty: counterparty,
|
|
121
|
+
reason: reason,
|
|
122
|
+
status: "open",
|
|
123
|
+
created-at: stacks-block-height,
|
|
124
|
+
votes-for: u0,
|
|
125
|
+
votes-against: u0,
|
|
126
|
+
resolution: none
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
(var-set last-dispute-id dispute-id)
|
|
130
|
+
(print { event: "dispute_raised", dispute-id: dispute-id, escrow-id: escrow-id, initiator: tx-sender })
|
|
131
|
+
(ok dispute-id)
|
|
132
|
+
)
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
;; Allows an arbitrator to vote on a dispute.
|
|
136
|
+
;; @param dispute-id: The ID of the dispute to vote on.
|
|
137
|
+
;; @param vote: The arbitrator's vote (true for initiator, false for counterparty).
|
|
138
|
+
;; @returns (ok bool): True if the vote is successful.
|
|
139
|
+
(define-public (vote-on-dispute (dispute-id uint) (vote bool))
|
|
140
|
+
(let
|
|
141
|
+
(
|
|
142
|
+
(dispute (unwrap! (map-get? Disputes { dispute-id: dispute-id }) (err ERR_DISPUTE_NOT_FOUND)))
|
|
143
|
+
)
|
|
144
|
+
(asserts! (is-valid-dispute-id dispute-id) (err ERR_INVALID_DISPUTE_ID))
|
|
145
|
+
(asserts! (is-arbitrator tx-sender) (err ERR_NOT_ARBITRATOR))
|
|
146
|
+
(asserts! (is-eq (get status dispute) "open") (err ERR_VOTING_CLOSED))
|
|
147
|
+
(asserts! (<= (- stacks-block-height (get created-at dispute)) VOTING_PERIOD) (err ERR_VOTING_CLOSED))
|
|
148
|
+
(asserts! (not (has-voted dispute-id tx-sender)) (err ERR_ALREADY_VOTED))
|
|
149
|
+
(try! (update-vote-count dispute-id vote))
|
|
150
|
+
(map-set ArbitratorVotes { dispute-id: dispute-id, arbitrator: tx-sender } vote)
|
|
151
|
+
(print { event: "arbitrator_voted", dispute-id: dispute-id, arbitrator: tx-sender, vote: vote })
|
|
152
|
+
(ok true)
|
|
153
|
+
)
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
;; Resolves a dispute based on the votes.
|
|
157
|
+
;; @param dispute-id: The ID of the dispute to resolve.
|
|
158
|
+
;; @returns (ok (string-ascii 20)): The resolution of the dispute.
|
|
159
|
+
(define-public (resolve-dispute (dispute-id uint))
|
|
160
|
+
(let
|
|
161
|
+
(
|
|
162
|
+
(dispute (unwrap! (map-get? Disputes { dispute-id: dispute-id }) (err ERR_DISPUTE_NOT_FOUND)))
|
|
163
|
+
)
|
|
164
|
+
(asserts! (is-valid-dispute-id dispute-id) (err ERR_INVALID_DISPUTE_ID))
|
|
165
|
+
(asserts! (is-eq (get status dispute) "open") (err ERR_INVALID_STATE))
|
|
166
|
+
(asserts! (>= (+ (get votes-for dispute) (get votes-against dispute)) MIN_VOTES_REQUIRED) (err ERR_INSUFFICIENT_VOTES))
|
|
167
|
+
(asserts! (<= (- stacks-block-height (get created-at dispute)) VOTING_PERIOD) (err ERR_VOTING_CLOSED))
|
|
168
|
+
(let
|
|
169
|
+
(
|
|
170
|
+
(resolution (if (> (get votes-for dispute) (get votes-against dispute)) "for_initiator" "for_counterparty"))
|
|
171
|
+
)
|
|
172
|
+
(map-set Disputes { dispute-id: dispute-id }
|
|
173
|
+
(merge dispute {
|
|
174
|
+
status: "resolved",
|
|
175
|
+
resolution: (some resolution)
|
|
176
|
+
})
|
|
177
|
+
)
|
|
178
|
+
(print { event: "dispute_resolved", dispute-id: dispute-id, resolution: resolution })
|
|
179
|
+
(ok resolution)
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
;; Adds a new arbitrator.
|
|
185
|
+
;; @param arbitrator: The principal of the new arbitrator.
|
|
186
|
+
;; @returns (ok bool): True if the arbitrator is added successfully.
|
|
187
|
+
(define-public (add-arbitrator (arbitrator principal))
|
|
188
|
+
(begin
|
|
189
|
+
(asserts! (is-eq tx-sender CONTRACT_OWNER) (err ERR_NOT_AUTHORIZED))
|
|
190
|
+
(asserts! (is-valid-principal arbitrator) (err ERR_INVALID_PRINCIPAL))
|
|
191
|
+
(map-set Arbitrators arbitrator true)
|
|
192
|
+
(print { event: "arbitrator_added", arbitrator: arbitrator })
|
|
193
|
+
(ok true)
|
|
194
|
+
)
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
;; Removes an arbitrator.
|
|
198
|
+
;; @param arbitrator: The principal of the arbitrator to remove.
|
|
199
|
+
;; @returns (ok bool): True if the arbitrator is removed successfully.
|
|
200
|
+
(define-public (remove-arbitrator (arbitrator principal))
|
|
201
|
+
(begin
|
|
202
|
+
(asserts! (is-eq tx-sender CONTRACT_OWNER) (err ERR_NOT_AUTHORIZED))
|
|
203
|
+
(asserts! (is-valid-principal arbitrator) (err ERR_INVALID_PRINCIPAL))
|
|
204
|
+
(map-delete Arbitrators arbitrator)
|
|
205
|
+
(print { event: "arbitrator_removed", arbitrator: arbitrator })
|
|
206
|
+
(ok true)
|
|
207
|
+
)
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
;; Sets the reward for arbitrators.
|
|
211
|
+
;; @param new-reward: The new reward amount.
|
|
212
|
+
;; @returns (ok bool): True if the reward is set successfully.
|
|
213
|
+
(define-public (set-arbitrator-reward (new-reward uint))
|
|
214
|
+
(begin
|
|
215
|
+
(asserts! (is-eq tx-sender CONTRACT_OWNER) (err ERR_NOT_AUTHORIZED))
|
|
216
|
+
(asserts! (> new-reward u0) (err ERR_INVALID_REWARD))
|
|
217
|
+
(var-set arbitrator-reward new-reward)
|
|
218
|
+
(print { event: "arbitrator_reward_set", new-reward: new-reward })
|
|
219
|
+
(ok true)
|
|
220
|
+
)
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
;; --- Read-Only Functions ---
|
|
224
|
+
;; Functions for retrieving data from the contract without making state changes.
|
|
225
|
+
|
|
226
|
+
;; Retrieves a dispute by its ID.
|
|
227
|
+
;; @param dispute-id: The ID of the dispute to retrieve.
|
|
228
|
+
;; @returns (optional {<dispute-data>}): The dispute data or none if not found.
|
|
229
|
+
(define-read-only (get-dispute (dispute-id uint))
|
|
230
|
+
(map-get? Disputes { dispute-id: dispute-id })
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
;; Retrieves the ID of the last created dispute.
|
|
234
|
+
;; @returns (ok uint): The last dispute ID.
|
|
235
|
+
(define-read-only (get-last-dispute-id)
|
|
236
|
+
(ok (var-get last-dispute-id))
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
;; Retrieves the arbitrator reward amount.
|
|
240
|
+
;; @returns (ok uint): The arbitrator reward amount.
|
|
241
|
+
(define-read-only (get-arbitrator-reward)
|
|
242
|
+
(ok (var-get arbitrator-reward))
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
;; Checks if a user is an authorized arbitrator.
|
|
246
|
+
;; @param user: The principal to check.
|
|
247
|
+
;; @returns (ok bool): True if the user is an arbitrator.
|
|
248
|
+
(define-read-only (is-user-arbitrator (user principal))
|
|
249
|
+
(ok (is-arbitrator user))
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
;; --- Helper function for principal validation ---
|
|
253
|
+
(define-private (is-valid-principal (principal principal))
|
|
254
|
+
(and
|
|
255
|
+
(not (is-eq principal CONTRACT_OWNER))
|
|
256
|
+
(not (is-eq principal (as-contract tx-sender)))
|
|
257
|
+
)
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
;; --- Contract Initialization ---
|
|
261
|
+
;; Initializes the contract upon deployment.
|
|
262
|
+
(begin
|
|
263
|
+
(print "DisputeResolution contract initialized")
|
|
264
|
+
(ok true)
|
|
265
|
+
)
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
;; EscrowService Contract
|
|
2
|
+
;; This contract provides a secure escrow service for transactions between buyers and sellers.
|
|
3
|
+
;; It holds funds until the buyer releases them to the seller or a dispute is resolved.
|
|
4
|
+
|
|
5
|
+
;; --- Constants ---
|
|
6
|
+
;; Defines immutable values used throughout the contract for error handling and configuration.
|
|
7
|
+
|
|
8
|
+
(define-constant CONTRACT_OWNER tx-sender) ;; Sets the contract deployer as the owner.
|
|
9
|
+
(define-constant ERR_NOT_AUTHORIZED (err u100)) ;; Error for unauthorized actions.
|
|
10
|
+
(define-constant ERR_ESCROW_NOT_FOUND (err u101)) ;; Error when an escrow cannot be found.
|
|
11
|
+
(define-constant ERR_ALREADY_RELEASED (err u102)) ;; Error if funds have already been released.
|
|
12
|
+
(define-constant ERR_TRANSFER_FAILED (err u103)) ;; Error for failed STX transfers.
|
|
13
|
+
(define-constant ERR_INVALID_ESCROW_ID (err u104)) ;; Error for invalid escrow IDs.
|
|
14
|
+
(define-constant ERR_INVALID_AMOUNT (err u105)) ;; Error for invalid transaction amounts.
|
|
15
|
+
(define-constant ERR_INVALID_SELLER (err u106)) ;; Error for invalid seller principals.
|
|
16
|
+
(define-constant ERR_ESCROW_EXPIRED (err u107)) ;; Error for expired escrows.
|
|
17
|
+
(define-constant ESCROW_DURATION u1008) ;; The duration of the escrow in blocks (approximately 7 days).
|
|
18
|
+
|
|
19
|
+
;; --- Data Maps ---
|
|
20
|
+
;; Defines the data structures used to store escrow information.
|
|
21
|
+
|
|
22
|
+
(define-map Escrows
|
|
23
|
+
{ escrow-id: uint }
|
|
24
|
+
{
|
|
25
|
+
buyer: principal, ;; The principal of the buyer.
|
|
26
|
+
seller: principal, ;; The principal of the seller.
|
|
27
|
+
amount: uint, ;; The amount of STX held in escrow.
|
|
28
|
+
state: (string-ascii 10), ;; The current state of the escrow (e.g., "locked", "released", "refunded").
|
|
29
|
+
created-at: uint, ;; The block height at which the escrow was created.
|
|
30
|
+
expires-at: uint ;; The block height at which the escrow expires.
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
;; --- Variables ---
|
|
35
|
+
;; Defines mutable variables for tracking the contract's state.
|
|
36
|
+
|
|
37
|
+
(define-data-var last-escrow-id uint u0) ;; Tracks the ID of the last created escrow.
|
|
38
|
+
|
|
39
|
+
;; --- Helper functions ---
|
|
40
|
+
|
|
41
|
+
;; Checks if a seller principal is valid.
|
|
42
|
+
(define-private (is-valid-seller (seller principal))
|
|
43
|
+
(and
|
|
44
|
+
(not (is-eq seller tx-sender))
|
|
45
|
+
(not (is-eq seller (as-contract tx-sender)))
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
;; Checks if an escrow ID is valid.
|
|
50
|
+
(define-private (is-valid-escrow-id (escrow-id uint))
|
|
51
|
+
(<= escrow-id (var-get last-escrow-id))
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
;; --- Public Functions ---
|
|
55
|
+
|
|
56
|
+
;; Creates a new escrow.
|
|
57
|
+
;; @param seller: The principal of the seller.
|
|
58
|
+
;; @param amount: The amount of STX to hold in escrow.
|
|
59
|
+
;; @returns (ok uint): The ID of the newly created escrow.
|
|
60
|
+
(define-public (create-escrow (seller principal) (amount uint))
|
|
61
|
+
(let
|
|
62
|
+
(
|
|
63
|
+
(escrow-id (+ (var-get last-escrow-id) u1))
|
|
64
|
+
(expires-at (+ stacks-block-height ESCROW_DURATION))
|
|
65
|
+
)
|
|
66
|
+
(asserts! (> amount u0) (err ERR_INVALID_AMOUNT))
|
|
67
|
+
(asserts! (is-valid-seller seller) (err ERR_INVALID_SELLER))
|
|
68
|
+
(match (stx-transfer? amount tx-sender (as-contract tx-sender))
|
|
69
|
+
success
|
|
70
|
+
(begin
|
|
71
|
+
(map-set Escrows
|
|
72
|
+
{ escrow-id: escrow-id }
|
|
73
|
+
{
|
|
74
|
+
buyer: tx-sender,
|
|
75
|
+
seller: seller,
|
|
76
|
+
amount: amount,
|
|
77
|
+
state: "locked",
|
|
78
|
+
created-at: stacks-block-height,
|
|
79
|
+
expires-at: expires-at
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
(var-set last-escrow-id escrow-id)
|
|
83
|
+
(print {event: "escrow_created", escrow-id: escrow-id, buyer: tx-sender, seller: seller, amount: amount})
|
|
84
|
+
(ok escrow-id)
|
|
85
|
+
)
|
|
86
|
+
error (err ERR_TRANSFER_FAILED)
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
;; Releases funds to the seller.
|
|
92
|
+
;; @param escrow-id: The ID of the escrow to release.
|
|
93
|
+
;; @returns (ok bool): True if the funds are released successfully.
|
|
94
|
+
(define-public (release-funds (escrow-id uint))
|
|
95
|
+
(begin
|
|
96
|
+
(asserts! (is-valid-escrow-id escrow-id) (err ERR_INVALID_ESCROW_ID))
|
|
97
|
+
(let
|
|
98
|
+
(
|
|
99
|
+
(escrow (unwrap! (map-get? Escrows { escrow-id: escrow-id }) (err ERR_ESCROW_NOT_FOUND)))
|
|
100
|
+
(seller (get seller escrow))
|
|
101
|
+
(amount (get amount escrow))
|
|
102
|
+
)
|
|
103
|
+
(asserts! (or (is-eq tx-sender CONTRACT_OWNER) (is-eq tx-sender (get buyer escrow))) (err ERR_NOT_AUTHORIZED))
|
|
104
|
+
(asserts! (is-eq (get state escrow) "locked") (err ERR_ALREADY_RELEASED))
|
|
105
|
+
(asserts! (<= stacks-block-height (get expires-at escrow)) (err ERR_ESCROW_EXPIRED))
|
|
106
|
+
(match (as-contract (stx-transfer? amount tx-sender seller))
|
|
107
|
+
success
|
|
108
|
+
(begin
|
|
109
|
+
(map-set Escrows
|
|
110
|
+
{ escrow-id: escrow-id }
|
|
111
|
+
(merge escrow { state: "released" })
|
|
112
|
+
)
|
|
113
|
+
(print {event: "funds_released", escrow-id: escrow-id, seller: seller, amount: amount})
|
|
114
|
+
(ok true)
|
|
115
|
+
)
|
|
116
|
+
error (err ERR_TRANSFER_FAILED)
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
;; Refunds the buyer.
|
|
123
|
+
;; @param escrow-id: The ID of the escrow to refund.
|
|
124
|
+
;; @returns (ok bool): True if the refund is successful.
|
|
125
|
+
(define-public (refund-buyer (escrow-id uint))
|
|
126
|
+
(begin
|
|
127
|
+
(asserts! (is-valid-escrow-id escrow-id) (err ERR_INVALID_ESCROW_ID))
|
|
128
|
+
(let
|
|
129
|
+
(
|
|
130
|
+
(escrow (unwrap! (map-get? Escrows { escrow-id: escrow-id }) (err ERR_ESCROW_NOT_FOUND)))
|
|
131
|
+
(buyer (get buyer escrow))
|
|
132
|
+
(amount (get amount escrow))
|
|
133
|
+
)
|
|
134
|
+
(asserts! (is-eq tx-sender CONTRACT_OWNER) (err ERR_NOT_AUTHORIZED))
|
|
135
|
+
(asserts! (is-eq (get state escrow) "locked") (err ERR_ALREADY_RELEASED))
|
|
136
|
+
(match (as-contract (stx-transfer? amount tx-sender buyer))
|
|
137
|
+
success
|
|
138
|
+
(begin
|
|
139
|
+
(map-set Escrows
|
|
140
|
+
{ escrow-id: escrow-id }
|
|
141
|
+
(merge escrow { state: "refunded" })
|
|
142
|
+
)
|
|
143
|
+
(print {event: "buyer_refunded", escrow-id: escrow-id, buyer: buyer, amount: amount})
|
|
144
|
+
(ok true)
|
|
145
|
+
)
|
|
146
|
+
error (err ERR_TRANSFER_FAILED)
|
|
147
|
+
)
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
;; --- Read-Only Functions ---
|
|
153
|
+
|
|
154
|
+
;; Retrieves escrow details by ID.
|
|
155
|
+
;; @param escrow-id: The ID of the escrow to retrieve.
|
|
156
|
+
;; @returns (ok {<escrow-data>}): The escrow data or an error if not found.
|
|
157
|
+
(define-read-only (get-escrow (escrow-id uint))
|
|
158
|
+
(begin
|
|
159
|
+
(asserts! (is-valid-escrow-id escrow-id) (err ERR_INVALID_ESCROW_ID))
|
|
160
|
+
(match (map-get? Escrows { escrow-id: escrow-id })
|
|
161
|
+
escrow (ok escrow)
|
|
162
|
+
(err ERR_ESCROW_NOT_FOUND)
|
|
163
|
+
)
|
|
164
|
+
)
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
;; Retrieves the ID of the last created escrow.
|
|
168
|
+
;; @returns (ok uint): The last escrow ID.
|
|
169
|
+
(define-read-only (get-last-escrow-id)
|
|
170
|
+
(ok (var-get last-escrow-id))
|
|
171
|
+
)
|