strade-stx 1.0.0 → 1.0.1
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/package.json +10 -1
- package/contracts/CoreMarketPlace.clar +0 -227
- package/contracts/DisputeResolution_clar.clar +0 -265
- package/contracts/EscrowService.clar +0 -171
- package/contracts/UserProfile.clar +0 -280
- package/contracts/ft-trait.clar +0 -24
- package/contracts/token.clar +0 -178
- package/frontend/README.md +0 -10
- package/frontend/components.json +0 -22
- package/frontend/dist/assets/index-BacuuL66.css +0 -1
- package/frontend/dist/assets/index-jryypd5B.js +0 -194
- package/frontend/dist/favicon.png +0 -0
- package/frontend/dist/index.html +0 -15
- package/frontend/dist/manifest.json +0 -15
- package/frontend/dist/vite.svg +0 -1
- package/frontend/empty-mock.js +0 -1
- package/frontend/eslint.config.js +0 -23
- package/frontend/eslint.config.mjs +0 -25
- package/frontend/index.html +0 -14
- package/frontend/next.config.ts +0 -17
- package/frontend/package-lock.json +0 -14740
- package/frontend/package.json +0 -56
- package/frontend/postcss.config.js +0 -5
- package/frontend/postcss.config.mjs +0 -5
- package/frontend/public/favicon.png +0 -0
- package/frontend/public/file.svg +0 -1
- package/frontend/public/globe.svg +0 -1
- package/frontend/public/manifest.json +0 -15
- package/frontend/public/next.svg +0 -1
- package/frontend/public/vercel.svg +0 -1
- package/frontend/public/vite.svg +0 -1
- package/frontend/public/window.svg +0 -1
- package/frontend/src/App.css +0 -42
- package/frontend/src/App.tsx +0 -177
- package/frontend/src/app/about/page.tsx +0 -208
- package/frontend/src/app/favicon.ico +0 -0
- package/frontend/src/app/globals.css +0 -129
- package/frontend/src/app/help/page.tsx +0 -167
- package/frontend/src/app/how-it-works/page.tsx +0 -274
- package/frontend/src/app/layout.tsx +0 -55
- package/frontend/src/app/marketplace/page.tsx +0 -324
- package/frontend/src/app/my-listings/page.tsx +0 -318
- package/frontend/src/app/page.tsx +0 -15
- package/frontend/src/assets/react.svg +0 -1
- package/frontend/src/components/ConfirmDialog.tsx +0 -54
- package/frontend/src/components/CreateListingForm.tsx +0 -231
- package/frontend/src/components/ErrorBoundary.tsx +0 -73
- package/frontend/src/components/FilterPanel.tsx +0 -10
- package/frontend/src/components/Footer.tsx +0 -100
- package/frontend/src/components/Header.tsx +0 -268
- package/frontend/src/components/ImageUpload.tsx +0 -147
- package/frontend/src/components/LandingPage.tsx +0 -322
- package/frontend/src/components/ListingCard.tsx +0 -154
- package/frontend/src/components/LoadingSkeleton.tsx +0 -44
- package/frontend/src/components/MobileNav.tsx +0 -89
- package/frontend/src/components/NotificationBell.tsx +0 -8
- package/frontend/src/components/NotificationPanel.tsx +0 -14
- package/frontend/src/components/README.md +0 -14
- package/frontend/src/components/SearchBar.tsx +0 -10
- package/frontend/src/components/TestnetBanner.tsx +0 -29
- package/frontend/src/components/ThemeToggle.tsx +0 -32
- package/frontend/src/components/__tests__/Header.test.tsx +0 -70
- package/frontend/src/components/__tests__/ListingCard.test.tsx +0 -86
- package/frontend/src/components/providers/ThemeProvider.tsx +0 -9
- package/frontend/src/components/ui/alert-dialog.tsx +0 -141
- package/frontend/src/components/ui/avatar.tsx +0 -53
- package/frontend/src/components/ui/badge.tsx +0 -46
- package/frontend/src/components/ui/button.tsx +0 -60
- package/frontend/src/components/ui/card.tsx +0 -92
- package/frontend/src/components/ui/dialog.tsx +0 -143
- package/frontend/src/components/ui/dropdown-menu.tsx +0 -257
- package/frontend/src/components/ui/input.tsx +0 -21
- package/frontend/src/components/ui/label.tsx +0 -24
- package/frontend/src/components/ui/select.tsx +0 -187
- package/frontend/src/components/ui/sonner.tsx +0 -40
- package/frontend/src/components/ui/textarea.tsx +0 -18
- package/frontend/src/context/README.md +0 -27
- package/frontend/src/index.css +0 -166
- package/frontend/src/lib/notificationEvents.ts +0 -10
- package/frontend/src/lib/notificationStore.ts +0 -13
- package/frontend/src/lib/notifications.ts +0 -13
- package/frontend/src/lib/search.ts +0 -28
- package/frontend/src/lib/stacks.ts +0 -189
- package/frontend/src/lib/utils.ts +0 -6
- package/frontend/src/main.tsx +0 -10
- package/frontend/src/test/setup.ts +0 -23
- package/frontend/src/types.d.ts +0 -9
- package/frontend/tsconfig.app.json +0 -28
- package/frontend/tsconfig.json +0 -41
- package/frontend/tsconfig.node.json +0 -26
- package/frontend/vercel.json +0 -4
- package/frontend/vite.config.ts +0 -6
- package/frontend/vitest.config.ts +0 -17
- package/scripts/auto-activity.sh +0 -9
- package/scripts/cancel-pending.ts +0 -67
- package/scripts/check-balances.ts +0 -23
- package/scripts/distribute-evenly.ts +0 -56
- package/scripts/drain-accounts.ts +0 -70
- package/scripts/fund-accounts.ts +0 -88
- package/scripts/fund-active.ts +0 -59
- package/scripts/fund-unfunded.ts +0 -88
- package/scripts/generate-activity.ts +0 -181
- package/scripts/git-activity-generator.ts +0 -154
- package/scripts/mobile-server.ts +0 -123
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
;; UserProfile Contract
|
|
2
|
-
;; This contract manages user profiles, including usernames, bios, ratings, and reputation scores.
|
|
3
|
-
;; It provides functions for users to register, update their profiles, and rate each other.
|
|
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_USER_NOT_FOUND (err u101)) ;; Error when a user profile cannot be found.
|
|
11
|
-
(define-constant ERR_INVALID_RATING (err u102)) ;; Error for invalid rating values (must be between 1 and 5).
|
|
12
|
-
(define-constant ERR_SELF_RATING (err u103)) ;; Error when a user attempts to rate themselves.
|
|
13
|
-
(define-constant ERR_ALREADY_REGISTERED (err u104)) ;; Error if a user is already registered.
|
|
14
|
-
(define-constant ERR_INVALID_INPUT (err u105)) ;; Error for invalid input parameters.
|
|
15
|
-
(define-constant ERR_DATA_STORE_FAILURE (err u106)) ;; Error for data storage failures.
|
|
16
|
-
(define-constant ERR_INVALID_PRINCIPAL (err u107)) ;; Error for invalid principal addresses.
|
|
17
|
-
(define-constant ERR_INVALID_USERNAME (err u108)) ;; Error for invalid usernames.
|
|
18
|
-
(define-constant ERR_INVALID_BIO (err u109)) ;; Error for invalid bio lengths.
|
|
19
|
-
(define-constant ERR_INVALID_EMAIL (err u110)) ;; Error for invalid email formats or lengths.
|
|
20
|
-
|
|
21
|
-
;; --- Data Maps ---
|
|
22
|
-
;; Defines the data structures used to store user profile information.
|
|
23
|
-
|
|
24
|
-
(define-map Users principal
|
|
25
|
-
{
|
|
26
|
-
username: (string-utf8 64), ;; The user's chosen username.
|
|
27
|
-
bio: (string-utf8 256), ;; A short biography or description.
|
|
28
|
-
email: (string-utf8 64), ;; The user's email address.
|
|
29
|
-
registration-date: uint, ;; The block height of the user's registration.
|
|
30
|
-
total-ratings: uint, ;; The total number of ratings the user has received.
|
|
31
|
-
rating-sum: uint, ;; The sum of all ratings received.
|
|
32
|
-
reputation-score: uint ;; A calculated score based on ratings and other factors.
|
|
33
|
-
}
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
(define-map UserAuthorization principal bool) ;; Stores authorization status for specific users.
|
|
37
|
-
|
|
38
|
-
;; --- Private Functions ---
|
|
39
|
-
;; Helper functions for internal contract use.
|
|
40
|
-
|
|
41
|
-
;; Checks if a string is within the specified length constraints.
|
|
42
|
-
(define-private (is-valid-string (str (string-utf8 256)) (max-len uint))
|
|
43
|
-
(and (>= (len str) u1) (<= (len str) max-len))
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
;; Checks if a principal is a valid user address.
|
|
47
|
-
(define-private (is-valid-principal (user principal))
|
|
48
|
-
(not (is-eq user (as-contract tx-sender)))
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
;; Validates the format and length of a username.
|
|
52
|
-
(define-private (validate-username (username (string-utf8 64)))
|
|
53
|
-
(if (is-valid-string username u64)
|
|
54
|
-
(ok username)
|
|
55
|
-
(err ERR_INVALID_USERNAME))
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
;; Validates the length of a user's bio.
|
|
59
|
-
(define-private (validate-bio (bio (string-utf8 256)))
|
|
60
|
-
(if (is-valid-string bio u256)
|
|
61
|
-
(ok bio)
|
|
62
|
-
(err ERR_INVALID_BIO))
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
;; Validates the format and length of an email address.
|
|
66
|
-
(define-private (validate-email (email (string-utf8 64)))
|
|
67
|
-
(if (is-valid-string email u64)
|
|
68
|
-
(ok email)
|
|
69
|
-
(err ERR_INVALID_EMAIL))
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
;; Sets the user data in the Users map.
|
|
73
|
-
(define-private (set-user-data (user principal) (data {
|
|
74
|
-
username: (string-utf8 64),
|
|
75
|
-
bio: (string-utf8 256),
|
|
76
|
-
email: (string-utf8 64),
|
|
77
|
-
registration-date: uint,
|
|
78
|
-
total-ratings: uint,
|
|
79
|
-
rating-sum: uint,
|
|
80
|
-
reputation-score: uint
|
|
81
|
-
}))
|
|
82
|
-
(if (map-set Users user data)
|
|
83
|
-
(ok true)
|
|
84
|
-
(err ERR_DATA_STORE_FAILURE))
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
;; --- Read-Only Functions ---
|
|
88
|
-
;; Functions for retrieving data from the contract without making state changes.
|
|
89
|
-
|
|
90
|
-
;; Retrieves a user's profile.
|
|
91
|
-
;; @param user: The principal of the user to retrieve.
|
|
92
|
-
;; @returns (ok {<user-data>}): The user's profile data or an error if not found.
|
|
93
|
-
(define-read-only (get-user-profile (user principal))
|
|
94
|
-
(match (map-get? Users user)
|
|
95
|
-
user-data (ok user-data)
|
|
96
|
-
(err ERR_USER_NOT_FOUND)))
|
|
97
|
-
|
|
98
|
-
;; Retrieves a user's average rating.
|
|
99
|
-
;; @param user: The principal of the user.
|
|
100
|
-
;; @returns (ok uint): The user's average rating or 0 if no ratings.
|
|
101
|
-
(define-read-only (get-user-rating (user principal))
|
|
102
|
-
(match (map-get? Users user)
|
|
103
|
-
user-data (let (
|
|
104
|
-
(total-ratings (get total-ratings user-data))
|
|
105
|
-
(rating-sum (get rating-sum user-data))
|
|
106
|
-
)
|
|
107
|
-
(if (> total-ratings u0)
|
|
108
|
-
(ok (/ rating-sum total-ratings))
|
|
109
|
-
(ok u0)))
|
|
110
|
-
(err ERR_USER_NOT_FOUND)
|
|
111
|
-
)
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
;; Checks if a user is authorized.
|
|
115
|
-
;; @param user: The principal to check.
|
|
116
|
-
;; @returns (ok bool): True if the user is authorized.
|
|
117
|
-
(define-read-only (is-user-authorized (user principal))
|
|
118
|
-
(ok (default-to false (map-get? UserAuthorization user))))
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
;; --- Public Functions ---
|
|
122
|
-
;; Functions that can be called by any user.
|
|
123
|
-
|
|
124
|
-
;; Registers a new user.
|
|
125
|
-
;; @param username: The desired username.
|
|
126
|
-
;; @param bio: A short bio.
|
|
127
|
-
;; @param email: The user's email address.
|
|
128
|
-
;; @returns (ok bool): True if registration is successful.
|
|
129
|
-
(define-public (register-user (username (string-utf8 64)) (bio (string-utf8 256)) (email (string-utf8 64)))
|
|
130
|
-
(let (
|
|
131
|
-
(existing-user (map-get? Users tx-sender))
|
|
132
|
-
)
|
|
133
|
-
(asserts! (is-none existing-user) (err ERR_ALREADY_REGISTERED))
|
|
134
|
-
(asserts! (and
|
|
135
|
-
(> (len username) u0)
|
|
136
|
-
(>= (len username) u1)
|
|
137
|
-
(<= (len username) u64)
|
|
138
|
-
(> (len bio) u0)
|
|
139
|
-
(>= (len bio) u1)
|
|
140
|
-
(<= (len bio) u256)
|
|
141
|
-
(> (len email) u0)
|
|
142
|
-
(>= (len email) u1)
|
|
143
|
-
(<= (len email) u64))
|
|
144
|
-
(err ERR_INVALID_INPUT))
|
|
145
|
-
(let (
|
|
146
|
-
(validated-username (try! (validate-username username)))
|
|
147
|
-
(validated-bio (try! (validate-bio bio)))
|
|
148
|
-
(validated-email (try! (validate-email email)))
|
|
149
|
-
)
|
|
150
|
-
(match (set-user-data tx-sender
|
|
151
|
-
{
|
|
152
|
-
username: validated-username,
|
|
153
|
-
bio: validated-bio,
|
|
154
|
-
email: validated-email,
|
|
155
|
-
registration-date: stacks-block-height,
|
|
156
|
-
total-ratings: u0,
|
|
157
|
-
rating-sum: u0,
|
|
158
|
-
reputation-score: u0
|
|
159
|
-
})
|
|
160
|
-
success (ok true)
|
|
161
|
-
error (err ERR_DATA_STORE_FAILURE))
|
|
162
|
-
))
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
;; Updates a user's profile.
|
|
166
|
-
;; @param bio: The new bio.
|
|
167
|
-
;; @param email: The new email address.
|
|
168
|
-
;; @returns (ok bool): True if the update is successful.
|
|
169
|
-
(define-public (update-profile (bio (string-utf8 256)) (email (string-utf8 64)))
|
|
170
|
-
(begin
|
|
171
|
-
(asserts! (and
|
|
172
|
-
(> (len bio) u0)
|
|
173
|
-
(>= (len bio) u1)
|
|
174
|
-
(<= (len bio) u256)
|
|
175
|
-
(> (len email) u0)
|
|
176
|
-
(>= (len email) u1)
|
|
177
|
-
(<= (len email) u64))
|
|
178
|
-
(err ERR_INVALID_INPUT))
|
|
179
|
-
(let (
|
|
180
|
-
(validated-bio (try! (validate-bio bio)))
|
|
181
|
-
(validated-email (try! (validate-email email)))
|
|
182
|
-
)
|
|
183
|
-
(match (map-get? Users tx-sender)
|
|
184
|
-
user-data
|
|
185
|
-
(match (set-user-data tx-sender
|
|
186
|
-
(merge user-data
|
|
187
|
-
{
|
|
188
|
-
bio: validated-bio,
|
|
189
|
-
email: validated-email
|
|
190
|
-
}
|
|
191
|
-
))
|
|
192
|
-
success (ok true)
|
|
193
|
-
error (err ERR_DATA_STORE_FAILURE))
|
|
194
|
-
(err ERR_USER_NOT_FOUND)
|
|
195
|
-
)
|
|
196
|
-
)
|
|
197
|
-
)
|
|
198
|
-
)
|
|
199
|
-
|
|
200
|
-
;; Rates a user.
|
|
201
|
-
;; @param user: The principal of the user to rate.
|
|
202
|
-
;; @param rating: The rating value (1-5).
|
|
203
|
-
;; @returns (ok bool): True if the rating is successful.
|
|
204
|
-
(define-public (rate-user (user principal) (rating uint))
|
|
205
|
-
(begin
|
|
206
|
-
(asserts! (is-valid-principal user) (err ERR_INVALID_PRINCIPAL))
|
|
207
|
-
(asserts! (not (is-eq tx-sender user)) (err ERR_SELF_RATING))
|
|
208
|
-
(asserts! (and (>= rating u1) (<= rating u5)) (err ERR_INVALID_RATING))
|
|
209
|
-
(match (map-get? Users user)
|
|
210
|
-
user-data
|
|
211
|
-
(match (set-user-data user
|
|
212
|
-
(merge user-data
|
|
213
|
-
{
|
|
214
|
-
total-ratings: (+ (get total-ratings user-data) u1),
|
|
215
|
-
rating-sum: (+ (get rating-sum user-data) rating)
|
|
216
|
-
}
|
|
217
|
-
))
|
|
218
|
-
success (ok true)
|
|
219
|
-
error (err ERR_DATA_STORE_FAILURE))
|
|
220
|
-
(err ERR_USER_NOT_FOUND)
|
|
221
|
-
)
|
|
222
|
-
)
|
|
223
|
-
)
|
|
224
|
-
|
|
225
|
-
;; Calculates a user's reputation score.
|
|
226
|
-
;; @param user: The principal of the user.
|
|
227
|
-
;; @returns (ok bool): True if the calculation is successful.
|
|
228
|
-
(define-public (calculate-reputation (user principal))
|
|
229
|
-
(begin
|
|
230
|
-
(asserts! (is-valid-principal user) (err ERR_INVALID_PRINCIPAL))
|
|
231
|
-
(match (map-get? Users user)
|
|
232
|
-
user-data
|
|
233
|
-
(let (
|
|
234
|
-
(total-ratings (get total-ratings user-data))
|
|
235
|
-
(rating-sum (get rating-sum user-data))
|
|
236
|
-
(avg-rating (if (> total-ratings u0) (/ rating-sum total-ratings) u0))
|
|
237
|
-
(new-reputation (+ (* avg-rating u20) (* total-ratings u2)))
|
|
238
|
-
)
|
|
239
|
-
(match (set-user-data user
|
|
240
|
-
(merge user-data
|
|
241
|
-
{
|
|
242
|
-
reputation-score: new-reputation
|
|
243
|
-
}
|
|
244
|
-
))
|
|
245
|
-
success (ok true)
|
|
246
|
-
error (err ERR_DATA_STORE_FAILURE)))
|
|
247
|
-
(err ERR_USER_NOT_FOUND)
|
|
248
|
-
)
|
|
249
|
-
)
|
|
250
|
-
)
|
|
251
|
-
|
|
252
|
-
;; Authorizes a user for specific actions.
|
|
253
|
-
;; @param user: The principal to authorize.
|
|
254
|
-
;; @returns (ok bool): True if authorization is successful.
|
|
255
|
-
(define-public (authorize-user (user principal))
|
|
256
|
-
(begin
|
|
257
|
-
(asserts! (is-eq tx-sender CONTRACT_OWNER) (err ERR_NOT_AUTHORIZED))
|
|
258
|
-
(asserts! (is-valid-principal user) (err ERR_INVALID_PRINCIPAL))
|
|
259
|
-
(ok (map-set UserAuthorization user true))
|
|
260
|
-
)
|
|
261
|
-
)
|
|
262
|
-
|
|
263
|
-
;; Revokes a user's authorization.
|
|
264
|
-
;; @param user: The principal to revoke authorization from.
|
|
265
|
-
;; @returns (ok bool): True if revocation is successful.
|
|
266
|
-
(define-public (revoke-authorization (user principal))
|
|
267
|
-
(begin
|
|
268
|
-
(asserts! (is-eq tx-sender CONTRACT_OWNER) (err ERR_NOT_AUTHORIZED))
|
|
269
|
-
(asserts! (is-valid-principal user) (err ERR_INVALID_PRINCIPAL))
|
|
270
|
-
(ok (map-set UserAuthorization user false))
|
|
271
|
-
)
|
|
272
|
-
)
|
|
273
|
-
|
|
274
|
-
;; --- Contract Initialization ---
|
|
275
|
-
;; Initializes the contract upon deployment.
|
|
276
|
-
(begin
|
|
277
|
-
(map-set UserAuthorization CONTRACT_OWNER true)
|
|
278
|
-
(print "UserProfile contract initialized")
|
|
279
|
-
(ok true)
|
|
280
|
-
)
|
package/contracts/ft-trait.clar
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
(define-trait ft-trait
|
|
2
|
-
(
|
|
3
|
-
;; Transfer from the caller to a new principal
|
|
4
|
-
(transfer (uint principal principal) (response bool uint))
|
|
5
|
-
|
|
6
|
-
;; the human readable name of the token
|
|
7
|
-
(get-name () (response (string-ascii 32) uint))
|
|
8
|
-
|
|
9
|
-
;; the ticker symbol, or empty if none
|
|
10
|
-
(get-symbol () (response (string-ascii 32) uint))
|
|
11
|
-
|
|
12
|
-
;; the number of decimals used, e.g. 6 would mean 1_000_000 represents 1 token
|
|
13
|
-
(get-decimals () (response uint uint))
|
|
14
|
-
|
|
15
|
-
;; the balance of the passed principal
|
|
16
|
-
(get-balance (principal) (response uint uint))
|
|
17
|
-
|
|
18
|
-
;; the current total supply (which does not need to be a constant)
|
|
19
|
-
(get-total-supply () (response uint uint))
|
|
20
|
-
|
|
21
|
-
;; an optional URI that represents metadata of this token
|
|
22
|
-
(get-token-uri () (response (optional (string-utf8 256)) uint))
|
|
23
|
-
)
|
|
24
|
-
)
|
package/contracts/token.clar
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
;; Strade Token (BST) Contract
|
|
2
|
-
;; This contract defines the Strade Token (BST), a fungible token compliant with the SIP-010 standard.
|
|
3
|
-
;; It includes functions for transferring, minting, and burning tokens, as well as managing token metadata.
|
|
4
|
-
|
|
5
|
-
;; --- Token Properties ---
|
|
6
|
-
(define-fungible-token bst u1000000000000)
|
|
7
|
-
|
|
8
|
-
;; --- Constants ---
|
|
9
|
-
;; Defines immutable values used throughout the contract for error handling and configuration.
|
|
10
|
-
|
|
11
|
-
(define-constant CONTRACT_OWNER tx-sender) ;; Sets the contract deployer as the owner.
|
|
12
|
-
(define-constant ERR_OWNER_ONLY (err u100)) ;; Error for actions restricted to the contract owner.
|
|
13
|
-
(define-constant ERR_NOT_AUTHORIZED (err u101)) ;; Error for unauthorized actions.
|
|
14
|
-
(define-constant ERR_INVALID_AMOUNT (err u102)) ;; Error for invalid token amounts.
|
|
15
|
-
(define-constant ERR_INSUFFICIENT_BALANCE (err u103)) ;; Error when a user has an insufficient token balance.
|
|
16
|
-
(define-constant ERR_INVALID_RECIPIENT (err u104)) ;; Error for invalid recipient addresses.
|
|
17
|
-
(define-constant ERR_INVALID_URI (err u105)) ;; Error for invalid token URIs.
|
|
18
|
-
(define-constant ERR_MAX_SUPPLY_REACHED (err u106)) ;; Error when the maximum token supply is reached.
|
|
19
|
-
(define-constant ERR_CONTRACT_PAUSED (err u107)) ;; Error for actions attempted while the contract is paused.
|
|
20
|
-
(define-constant MAX_SUPPLY u10000000000000) ;; The maximum total supply of the token.
|
|
21
|
-
|
|
22
|
-
;; --- Variables ---
|
|
23
|
-
;; Defines mutable variables for tracking the token's state and metadata.
|
|
24
|
-
|
|
25
|
-
(define-data-var token-name (string-utf8 32) u"Strade Token") ;; The name of the token.
|
|
26
|
-
(define-data-var token-symbol (string-utf8 10) u"BST") ;; The symbol of the token.
|
|
27
|
-
(define-data-var token-decimals uint u6) ;; The number of decimal places for the token.
|
|
28
|
-
(define-data-var token-uri (optional (string-utf8 256)) none) ;; The URI for the token's metadata.
|
|
29
|
-
(define-data-var contract-paused bool false) ;; A flag to pause or unpause the contract.
|
|
30
|
-
|
|
31
|
-
;; --- Helper Functions ---
|
|
32
|
-
|
|
33
|
-
;; Checks if a principal is a valid recipient for token transfers.
|
|
34
|
-
(define-private (is-valid-recipient (recipient principal))
|
|
35
|
-
(not (is-eq recipient (as-contract tx-sender))))
|
|
36
|
-
|
|
37
|
-
;; Checks if the contract is currently paused.
|
|
38
|
-
(define-private (is-contract-not-paused)
|
|
39
|
-
(not (var-get contract-paused)))
|
|
40
|
-
|
|
41
|
-
;; --- SIP-010 Functions ---
|
|
42
|
-
;; Standard functions for a fungible token.
|
|
43
|
-
|
|
44
|
-
;; Transfers tokens from the sender to the recipient.
|
|
45
|
-
(define-public (transfer (amount uint) (sender principal) (recipient principal) (memo (optional (buff 34))))
|
|
46
|
-
(begin
|
|
47
|
-
(asserts! (is-contract-not-paused) ERR_CONTRACT_PAUSED)
|
|
48
|
-
(asserts! (is-eq tx-sender sender) ERR_NOT_AUTHORIZED)
|
|
49
|
-
(asserts! (> amount u0) ERR_INVALID_AMOUNT)
|
|
50
|
-
(asserts! (<= amount (ft-get-balance bst sender)) ERR_INSUFFICIENT_BALANCE)
|
|
51
|
-
(asserts! (is-valid-recipient recipient) ERR_INVALID_RECIPIENT)
|
|
52
|
-
(try! (ft-transfer? bst amount sender recipient))
|
|
53
|
-
(print (merge
|
|
54
|
-
{event: "token_transferred", amount: amount, sender: sender, recipient: recipient}
|
|
55
|
-
(match memo
|
|
56
|
-
some-memo {memo: (some some-memo)}
|
|
57
|
-
{memo: none}
|
|
58
|
-
)
|
|
59
|
-
))
|
|
60
|
-
(ok true)
|
|
61
|
-
)
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
;; Gets the name of the token.
|
|
65
|
-
(define-read-only (get-name)
|
|
66
|
-
(ok (var-get token-name))
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
;; Gets the symbol of the token.
|
|
70
|
-
(define-read-only (get-symbol)
|
|
71
|
-
(ok (var-get token-symbol))
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
;; Gets the number of decimals for the token.
|
|
75
|
-
(define-read-only (get-decimals)
|
|
76
|
-
(ok (var-get token-decimals))
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
;; Gets the balance of a given principal.
|
|
80
|
-
(define-read-only (get-balance (who principal))
|
|
81
|
-
(ok (ft-get-balance bst who))
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
;; Gets the total supply of the token.
|
|
85
|
-
(define-read-only (get-total-supply)
|
|
86
|
-
(ok (ft-get-supply bst))
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
;; Gets the token's metadata URI.
|
|
90
|
-
(define-read-only (get-token-uri)
|
|
91
|
-
(ok (var-get token-uri))
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
;; --- Public Management Functions ---
|
|
95
|
-
|
|
96
|
-
;; Mints new tokens and assigns them to a recipient.
|
|
97
|
-
;; @param amount: The amount of tokens to mint.
|
|
98
|
-
;; @param recipient: The principal to receive the new tokens.
|
|
99
|
-
(define-public (mint (amount uint) (recipient principal))
|
|
100
|
-
(begin
|
|
101
|
-
(asserts! (is-contract-not-paused) ERR_CONTRACT_PAUSED)
|
|
102
|
-
(asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_OWNER_ONLY)
|
|
103
|
-
(asserts! (> amount u0) ERR_INVALID_AMOUNT)
|
|
104
|
-
(asserts! (is-valid-recipient recipient) ERR_INVALID_RECIPIENT)
|
|
105
|
-
(asserts! (<= (+ amount (ft-get-supply bst)) MAX_SUPPLY) ERR_MAX_SUPPLY_REACHED)
|
|
106
|
-
(match (ft-mint? bst amount recipient)
|
|
107
|
-
success (begin
|
|
108
|
-
(print {event: "token_minted", amount: amount, recipient: recipient})
|
|
109
|
-
(ok success))
|
|
110
|
-
error (err error))
|
|
111
|
-
)
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
;; Burns a specified amount of tokens from the sender's balance.
|
|
115
|
-
;; @param amount: The amount of tokens to burn.
|
|
116
|
-
;; @param sender: The principal whose tokens will be burned.
|
|
117
|
-
(define-public (burn (amount uint) (sender principal))
|
|
118
|
-
(begin
|
|
119
|
-
(asserts! (is-contract-not-paused) ERR_CONTRACT_PAUSED)
|
|
120
|
-
(asserts! (is-eq tx-sender sender) ERR_NOT_AUTHORIZED)
|
|
121
|
-
(asserts! (> amount u0) ERR_INVALID_AMOUNT)
|
|
122
|
-
(asserts! (<= amount (ft-get-balance bst sender)) ERR_INSUFFICIENT_BALANCE)
|
|
123
|
-
(match (ft-burn? bst amount sender)
|
|
124
|
-
success (begin
|
|
125
|
-
(print {event: "token_burned", amount: amount, sender: sender})
|
|
126
|
-
(ok success))
|
|
127
|
-
error (err error))
|
|
128
|
-
)
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
;; Sets the token's metadata URI.
|
|
132
|
-
;; @param new-uri: The new URI for the token metadata.
|
|
133
|
-
(define-public (set-token-uri (new-uri (optional (string-utf8 256))))
|
|
134
|
-
(begin
|
|
135
|
-
(asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_OWNER_ONLY)
|
|
136
|
-
(match new-uri
|
|
137
|
-
some-uri
|
|
138
|
-
(begin
|
|
139
|
-
(asserts! (<= (len some-uri) u256) ERR_INVALID_URI)
|
|
140
|
-
(var-set token-uri (some some-uri))
|
|
141
|
-
(print {event: "token_uri_updated", new_uri: some-uri})
|
|
142
|
-
(ok true)
|
|
143
|
-
)
|
|
144
|
-
(begin
|
|
145
|
-
(var-set token-uri none)
|
|
146
|
-
(print {event: "token_uri_removed"})
|
|
147
|
-
(ok true)
|
|
148
|
-
)
|
|
149
|
-
)
|
|
150
|
-
)
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
;; Pauses the contract, disabling most functions.
|
|
154
|
-
(define-public (pause-contract)
|
|
155
|
-
(begin
|
|
156
|
-
(asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_OWNER_ONLY)
|
|
157
|
-
(var-set contract-paused true)
|
|
158
|
-
(print {event: "contract_paused"})
|
|
159
|
-
(ok true)
|
|
160
|
-
)
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
;; Unpauses the contract, re-enabling all functions.
|
|
164
|
-
(define-public (unpause-contract)
|
|
165
|
-
(begin
|
|
166
|
-
(asserts! (is-eq tx-sender CONTRACT_OWNER) ERR_OWNER_ONLY)
|
|
167
|
-
(var-set contract-paused false)
|
|
168
|
-
(print {event: "contract_unpaused"})
|
|
169
|
-
(ok true)
|
|
170
|
-
)
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
;; --- Contract Initialization ---
|
|
174
|
-
;; Initializes the contract upon deployment, minting the initial supply to the contract owner.
|
|
175
|
-
(begin
|
|
176
|
-
(try! (ft-mint? bst u1000000000000 CONTRACT_OWNER))
|
|
177
|
-
(print {event: "contract_deployed", initial_supply: u1000000000000})
|
|
178
|
-
)
|
package/frontend/README.md
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
post 1 = https://x.com/DavidMarvyy/status/1978875809151492437
|
|
2
|
-
post 2 = https://x.com/DavidMarvyy/status/1978878793742778729
|
|
3
|
-
post 3 = https://x.com/DavidMarvyy/status/1978880338169328012
|
|
4
|
-
https://drive.google.com/file/d/11pDyazpgvBbHt96UWq6--Lk-myduWJ_5/view?usp=drivesdk
|
|
5
|
-
SP2DGFM08B5RANZC4E9Q36NT9E2FBKCQYPMSV44PV
|
|
6
|
-
SP34EBMKMRR6SXX65GRKJ1FHEXV7AGHJ2D8ASQ5M3
|
|
7
|
-
SP3785G95XDXW7VS4T6M3Z5R6DD770EWFCZ1JC97Y
|
|
8
|
-
SP1W2EERN213N3SPHSD25V4VE937P3B776ZZVPE6V
|
|
9
|
-
SP3125QHD69Q9H142EVKZMYDN60NNJQ7MXF1XJ5W8
|
|
10
|
-
https://www.loom.com/share/13f890069bc746feac671ee9f27924b2
|
package/frontend/components.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
-
"style": "new-york",
|
|
4
|
-
"rsc": true,
|
|
5
|
-
"tsx": true,
|
|
6
|
-
"tailwind": {
|
|
7
|
-
"config": "",
|
|
8
|
-
"css": "src/app/globals.css",
|
|
9
|
-
"baseColor": "slate",
|
|
10
|
-
"cssVariables": true,
|
|
11
|
-
"prefix": ""
|
|
12
|
-
},
|
|
13
|
-
"iconLibrary": "lucide",
|
|
14
|
-
"aliases": {
|
|
15
|
-
"components": "@/components",
|
|
16
|
-
"utils": "@/lib/utils",
|
|
17
|
-
"ui": "@/components/ui",
|
|
18
|
-
"lib": "@/lib",
|
|
19
|
-
"hooks": "@/hooks"
|
|
20
|
-
},
|
|
21
|
-
"registries": {}
|
|
22
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@import"https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&family=Outfit:wght@100;200;300;400;500;600;700;800;900&family=Syne:wght@400;500;600;700;800&display=swap";@layer properties,theme,base,components,utilities;@layer theme{:root,:host{--font-sans:"Outfit",sans-serif;--font-serif:"Cormorant Garamond",serif;--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-2xl:42rem;--container-6xl:72rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5/2.25);--text-6xl:3.75rem;--text-6xl--line-height:1;--text-7xl:4.5rem;--text-7xl--line-height:1;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tighter:-.05em;--tracking-widest:.1em;--leading-relaxed:1.625;--radius-xl:.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-app-bg:#fcfcfd;--color-app-border:#e5e7eb;--color-app-hover:#f9fafb;--color-accent-indigo:#4f46e5;--color-accent-indigo-hover:#4338ca;--color-text-main:#111827;--color-text-dim:#4b5563;--color-text-pale:#9ca3af;--font-display:"Syne",sans-serif}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer utilities{.fixed{position:fixed}.relative{position:relative}.top-6{top:calc(var(--spacing)*6)}.left-1\/2{left:50%}.z-50{z-index:50}.mx-auto{margin-inline:auto}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-6{margin-bottom:calc(var(--spacing)*6)}.mb-10{margin-bottom:calc(var(--spacing)*10)}.mb-20{margin-bottom:calc(var(--spacing)*20)}.flex{display:flex}.grid{display:grid}.inline-flex{display:inline-flex}.min-h-screen{min-height:100vh}.w-\[95\%\]{width:95%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-7xl{max-width:var(--container-7xl)}.max-w-xs{max-width:var(--container-xs)}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-2{gap:calc(var(--spacing)*2)}.gap-4{gap:calc(var(--spacing)*4)}.gap-5{gap:calc(var(--spacing)*5)}.gap-6{gap:calc(var(--spacing)*6)}.gap-10{gap:calc(var(--spacing)*10)}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-app-border{border-color:var(--color-app-border)}.bg-accent-indigo{background-color:var(--color-accent-indigo)}.bg-app-bg{background-color:var(--color-app-bg)}.bg-white{background-color:var(--color-white)}.p-8{padding:calc(var(--spacing)*8)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.px-8{padding-inline:calc(var(--spacing)*8)}.py-2{padding-block:calc(var(--spacing)*2)}.py-4{padding-block:calc(var(--spacing)*4)}.py-16{padding-block:calc(var(--spacing)*16)}.pt-32{padding-top:calc(var(--spacing)*32)}.pt-44{padding-top:calc(var(--spacing)*44)}.pb-24{padding-bottom:calc(var(--spacing)*24)}.text-center{text-align:center}.font-serif{font-family:var(--font-serif)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-tighter{--tw-tracking:var(--tracking-tighter);letter-spacing:var(--tracking-tighter)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-accent-indigo{color:var(--color-accent-indigo)}.text-text-dim{color:var(--color-text-dim)}.text-text-main{color:var(--color-text-main)}.text-text-pale{color:var(--color-text-pale)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.shadow-floating{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000000d),0 10px 10px -5px var(--tw-shadow-color,#00000005);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-premium{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000000d),0 2px 4px -1px var(--tw-shadow-color,#00000008);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}@media(hover:hover){.group-hover\:text-accent-indigo:is(:where(.group):hover *){color:var(--color-accent-indigo)}}.selection\:bg-accent-indigo\/10 ::selection{background-color:#4f46e51a}@supports (color:color-mix(in lab,red,red)){.selection\:bg-accent-indigo\/10 ::selection{background-color:color-mix(in oklab,var(--color-accent-indigo)10%,transparent)}}.selection\:bg-accent-indigo\/10::selection{background-color:#4f46e51a}@supports (color:color-mix(in lab,red,red)){.selection\:bg-accent-indigo\/10::selection{background-color:color-mix(in oklab,var(--color-accent-indigo)10%,transparent)}}.selection\:text-accent-indigo ::selection{color:var(--color-accent-indigo)}.selection\:text-accent-indigo::selection{color:var(--color-accent-indigo)}@media(hover:hover){.hover\:bg-app-hover:hover{background-color:var(--color-app-hover)}.hover\:text-accent-indigo:hover{color:var(--color-accent-indigo)}.hover\:shadow-premium:hover{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000000d),0 2px 4px -1px var(--tw-shadow-color,#00000008);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}@media(min-width:48rem){.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-end{align-items:flex-end}.md\:items-start{align-items:flex-start}.md\:text-left{text-align:left}.md\:text-7xl{font-size:var(--text-7xl);line-height:var(--tw-leading,var(--text-7xl--line-height))}}}@keyframes reveal{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-10px)}}@keyframes softPulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.8;transform:scale(.98)}}html{scroll-behavior:smooth}body{background-color:var(--color-app-bg);color:var(--color-text-main);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;margin:0;overflow-x:hidden}h1,h2,h3,.font-serif{font-family:var(--font-serif)}.font-display{font-family:var(--font-display)}.glass{-webkit-backdrop-filter:blur(16px);background:#ffffffd9;border:1px solid #ffffff80}.grid-subtle{background-image:radial-gradient(#e5e7eb 1px,#0000 1px);background-size:40px 40px}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:var(--color-app-bg)}::-webkit-scrollbar-thumb{background:var(--color-app-border);border-radius:10px}::-webkit-scrollbar-thumb:hover{background:var(--color-text-pale)}.no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{-ms-overflow-style:none;scrollbar-width:none}.btn-primary{background-color:var(--color-accent-indigo);padding-inline:calc(var(--spacing)*8);padding-block:calc(var(--spacing)*3.5);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--color-white);transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.3s;border-radius:3.40282e38px;transition-duration:.3s}@media(hover:hover){.btn-primary:hover{background-color:var(--color-accent-indigo-hover);--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000000d),0 10px 10px -5px var(--tw-shadow-color,#00000005);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}.btn-primary:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x)var(--tw-scale-y)}.btn-primary:disabled{pointer-events:none;opacity:.5}.btn-secondary{border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-app-border);background-color:var(--color-white);padding-inline:calc(var(--spacing)*8);padding-block:calc(var(--spacing)*3.5);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--color-accent-indigo);transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.3s;border-radius:3.40282e38px;transition-duration:.3s}@media(hover:hover){.btn-secondary:hover{background-color:var(--color-app-hover);--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000000d),0 2px 4px -1px var(--tw-shadow-color,#00000008);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}.btn-secondary:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x)var(--tw-scale-y)}.btn-secondary:disabled{opacity:.5}.btn-ghost{border-radius:var(--radius-xl);padding-inline:calc(var(--spacing)*4);padding-block:calc(var(--spacing)*2.5);color:var(--color-text-dim);transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s}@media(hover:hover){.btn-ghost:hover{background-color:var(--color-app-hover);color:var(--color-accent-indigo)}}.card-premium{border-radius:var(--radius-3xl);border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-app-border);background-color:var(--color-white);padding:calc(var(--spacing)*8);transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.5s;transition-duration:.5s}@media(hover:hover){.card-premium:hover{border-color:#4f46e533}@supports (color:color-mix(in lab,red,red)){.card-premium:hover{border-color:color-mix(in oklab,var(--color-accent-indigo)20%,transparent)}}.card-premium:hover{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000000d),0 10px 10px -5px var(--tw-shadow-color,#00000005);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}.input-premium{border-radius:var(--radius-xl);border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-app-border);background-color:var(--color-white);width:100%;padding-inline:calc(var(--spacing)*5);padding-block:calc(var(--spacing)*4);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--color-text-main);transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.2s;transition-duration:.2s}.input-premium::placeholder{color:var(--color-text-pale)}.input-premium:focus{border-color:var(--color-accent-indigo);--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);--tw-ring-color:#4f46e51a}@supports (color:color-mix(in lab,red,red)){.input-premium:focus{--tw-ring-color:color-mix(in oklab,var(--color-accent-indigo)10%,transparent)}}.input-premium:focus{--tw-outline-style:none;outline-style:none}.stagger-reveal>*{opacity:0;animation:.8s cubic-bezier(.16,1,.3,1) forwards reveal}.stagger-1{animation-delay:.1s}.stagger-2{animation-delay:.2s}.stagger-3{animation-delay:.3s}.stagger-4{animation-delay:.4s}.stagger-5{animation-delay:.5s}:focus-visible{outline:2px solid var(--color-accent-indigo);outline-offset:2px}::selection{color:var(--color-accent-indigo);background-color:#4f46e51a}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-duration{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}
|