@devvmichael/create-stacks-app 0.1.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.
Files changed (115) hide show
  1. package/dist/commands/add.d.ts +8 -0
  2. package/dist/commands/add.d.ts.map +1 -0
  3. package/dist/commands/add.js +215 -0
  4. package/dist/commands/add.js.map +1 -0
  5. package/dist/commands/create.d.ts +3 -0
  6. package/dist/commands/create.d.ts.map +1 -0
  7. package/dist/commands/create.js +63 -0
  8. package/dist/commands/create.js.map +1 -0
  9. package/dist/commands/deploy.d.ts +7 -0
  10. package/dist/commands/deploy.d.ts.map +1 -0
  11. package/dist/commands/deploy.js +159 -0
  12. package/dist/commands/deploy.js.map +1 -0
  13. package/dist/index.d.ts +3 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +47 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/prompts/project.d.ts +4 -0
  18. package/dist/prompts/project.d.ts.map +1 -0
  19. package/dist/prompts/project.js +124 -0
  20. package/dist/prompts/project.js.map +1 -0
  21. package/dist/templates/installer.d.ts +4 -0
  22. package/dist/templates/installer.d.ts.map +1 -0
  23. package/dist/templates/installer.js +91 -0
  24. package/dist/templates/installer.js.map +1 -0
  25. package/dist/types/index.d.ts +40 -0
  26. package/dist/types/index.d.ts.map +1 -0
  27. package/dist/types/index.js +2 -0
  28. package/dist/types/index.js.map +1 -0
  29. package/dist/utils/clarinet.d.ts +5 -0
  30. package/dist/utils/clarinet.d.ts.map +1 -0
  31. package/dist/utils/clarinet.js +72 -0
  32. package/dist/utils/clarinet.js.map +1 -0
  33. package/dist/utils/filesystem.d.ts +4 -0
  34. package/dist/utils/filesystem.d.ts.map +1 -0
  35. package/dist/utils/filesystem.js +158 -0
  36. package/dist/utils/filesystem.js.map +1 -0
  37. package/dist/utils/git.d.ts +2 -0
  38. package/dist/utils/git.d.ts.map +1 -0
  39. package/dist/utils/git.js +21 -0
  40. package/dist/utils/git.js.map +1 -0
  41. package/dist/utils/logger.d.ts +7 -0
  42. package/dist/utils/logger.d.ts.map +1 -0
  43. package/dist/utils/logger.js +45 -0
  44. package/dist/utils/logger.js.map +1 -0
  45. package/dist/utils/package-manager.d.ts +5 -0
  46. package/dist/utils/package-manager.d.ts.map +1 -0
  47. package/dist/utils/package-manager.js +65 -0
  48. package/dist/utils/package-manager.js.map +1 -0
  49. package/dist/utils/validation.d.ts +5 -0
  50. package/dist/utils/validation.d.ts.map +1 -0
  51. package/dist/utils/validation.js +41 -0
  52. package/dist/utils/validation.js.map +1 -0
  53. package/package.json +52 -0
  54. package/templates/base/editorconfig +12 -0
  55. package/templates/base/gitignore +13 -0
  56. package/templates/base/prettierrc +7 -0
  57. package/templates/contracts/counter/counter.clar +43 -0
  58. package/templates/contracts/counter/counter.test.ts +127 -0
  59. package/templates/contracts/defi/sip010-trait.clar +11 -0
  60. package/templates/contracts/defi/staking-pool.clar +20 -0
  61. package/templates/contracts/marketplace/nft-marketplace.clar +44 -0
  62. package/templates/contracts/marketplace/nft-trait.clar +8 -0
  63. package/templates/contracts/marketplace/sip009-nft.clar +25 -0
  64. package/templates/contracts/nft/nft.clar +111 -0
  65. package/templates/contracts/nft/nft.test.ts +204 -0
  66. package/templates/contracts/token/token.clar +67 -0
  67. package/templates/contracts/token/token.test.ts +139 -0
  68. package/templates/frontends/nextjs/template/.env.example +2 -0
  69. package/templates/frontends/nextjs/template/app/globals.css +40 -0
  70. package/templates/frontends/nextjs/template/app/layout.tsx +36 -0
  71. package/templates/frontends/nextjs/template/app/page.tsx +42 -0
  72. package/templates/frontends/nextjs/template/app/providers.tsx +31 -0
  73. package/templates/frontends/nextjs/template/components/contracts/counter-interaction.tsx +80 -0
  74. package/templates/frontends/nextjs/template/components/header.tsx +24 -0
  75. package/templates/frontends/nextjs/template/components/wallet/connect-button.tsx +44 -0
  76. package/templates/frontends/nextjs/template/hooks/use-contract-call.ts +52 -0
  77. package/templates/frontends/nextjs/template/hooks/use-contract-read.ts +49 -0
  78. package/templates/frontends/nextjs/template/hooks/use-stacks.ts +26 -0
  79. package/templates/frontends/nextjs/template/lib/contracts.ts +29 -0
  80. package/templates/frontends/nextjs/template/lib/stacks.ts +18 -0
  81. package/templates/frontends/nextjs/template/next.config.js +6 -0
  82. package/templates/frontends/nextjs/template/package.json +29 -0
  83. package/templates/frontends/nextjs/template/postcss.config.js +6 -0
  84. package/templates/frontends/nextjs/template/public/logo.svg +3 -0
  85. package/templates/frontends/nextjs/template/tailwind.config.js +18 -0
  86. package/templates/frontends/nextjs/template/tsconfig.json +26 -0
  87. package/templates/frontends/react/template/.env.example +2 -0
  88. package/templates/frontends/react/template/index.html +13 -0
  89. package/templates/frontends/react/template/package.json +29 -0
  90. package/templates/frontends/react/template/postcss.config.js +6 -0
  91. package/templates/frontends/react/template/public/logo.svg +3 -0
  92. package/templates/frontends/react/template/src/App.tsx +100 -0
  93. package/templates/frontends/react/template/src/components/CounterInteraction.tsx +121 -0
  94. package/templates/frontends/react/template/src/components/Header.tsx +39 -0
  95. package/templates/frontends/react/template/src/index.css +33 -0
  96. package/templates/frontends/react/template/src/main.tsx +10 -0
  97. package/templates/frontends/react/template/tailwind.config.js +15 -0
  98. package/templates/frontends/react/template/tsconfig.json +25 -0
  99. package/templates/frontends/react/template/tsconfig.node.json +10 -0
  100. package/templates/frontends/react/template/vite.config.ts +12 -0
  101. package/templates/frontends/vue/template/.env.example +2 -0
  102. package/templates/frontends/vue/template/index.html +13 -0
  103. package/templates/frontends/vue/template/package.json +27 -0
  104. package/templates/frontends/vue/template/postcss.config.js +6 -0
  105. package/templates/frontends/vue/template/public/logo.svg +3 -0
  106. package/templates/frontends/vue/template/src/App.vue +98 -0
  107. package/templates/frontends/vue/template/src/components/AppHeader.vue +39 -0
  108. package/templates/frontends/vue/template/src/components/CounterInteraction.vue +120 -0
  109. package/templates/frontends/vue/template/src/env.d.ts +16 -0
  110. package/templates/frontends/vue/template/src/main.ts +5 -0
  111. package/templates/frontends/vue/template/src/style.css +33 -0
  112. package/templates/frontends/vue/template/tailwind.config.js +15 -0
  113. package/templates/frontends/vue/template/tsconfig.json +25 -0
  114. package/templates/frontends/vue/template/tsconfig.node.json +10 -0
  115. package/templates/frontends/vue/template/vite.config.ts +12 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { PackageManager } from "../types/index.js";
2
+ export declare function detectPackageManager(): Promise<PackageManager>;
3
+ export declare function installDependencies(projectPath: string, pm: PackageManager): Promise<void>;
4
+ export declare function getRunCommand(pm: PackageManager, script: string): string;
5
+ //# sourceMappingURL=package-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-manager.d.ts","sourceRoot":"","sources":["../../src/utils/package-manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIxD,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,cAAc,CAAC,CAiBpE;AAED,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,cAAc,GACjB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAQxE"}
@@ -0,0 +1,65 @@
1
+ import { spawn } from "child_process";
2
+ import { exec } from "child_process";
3
+ import { promisify } from "util";
4
+ const execAsync = promisify(exec);
5
+ export async function detectPackageManager() {
6
+ const checks = [
7
+ { pm: "pnpm", command: "pnpm --version" },
8
+ { pm: "yarn", command: "yarn --version" },
9
+ { pm: "npm", command: "npm --version" },
10
+ ];
11
+ for (const { pm, command } of checks) {
12
+ try {
13
+ await execAsync(command);
14
+ return pm;
15
+ }
16
+ catch {
17
+ continue;
18
+ }
19
+ }
20
+ return "npm"; // fallback
21
+ }
22
+ export async function installDependencies(projectPath, pm) {
23
+ console.log("Installing dependencies...");
24
+ try {
25
+ // Install root dependencies
26
+ await runCommand(pm, ["install"], projectPath);
27
+ // Install frontend dependencies
28
+ // For frontend, we want to respect the package manager choice
29
+ await runCommand(pm, ["install"], `${projectPath}/frontend`);
30
+ console.log("Dependencies installed");
31
+ }
32
+ catch (error) {
33
+ console.error("Failed to install dependencies");
34
+ throw error;
35
+ }
36
+ }
37
+ export function getRunCommand(pm, script) {
38
+ const commands = {
39
+ npm: `npm run ${script}`,
40
+ pnpm: `pnpm ${script}`,
41
+ yarn: `yarn ${script}`,
42
+ };
43
+ return commands[pm];
44
+ }
45
+ function runCommand(command, args, cwd) {
46
+ return new Promise((resolve, reject) => {
47
+ const child = spawn(command, args, {
48
+ cwd,
49
+ stdio: "inherit",
50
+ shell: true,
51
+ });
52
+ child.on("close", (code) => {
53
+ if (code !== 0) {
54
+ reject(new Error(`Command ${command} ${args.join(" ")} failed`));
55
+ }
56
+ else {
57
+ resolve();
58
+ }
59
+ });
60
+ child.on("error", (err) => {
61
+ reject(err);
62
+ });
63
+ });
64
+ }
65
+ //# sourceMappingURL=package-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-manager.js","sourceRoot":"","sources":["../../src/utils/package-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAGjC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAElC,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,MAAM,MAAM,GAAmD;QAC7D,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE;QACzC,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE;QACzC,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE;KACxC,CAAC;IAEF,KAAK,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,MAAM,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC;YACzB,OAAO,EAAE,CAAC;QACZ,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,CAAC,WAAW;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAmB,EACnB,EAAkB;IAElB,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAE1C,IAAI,CAAC;QACH,4BAA4B;QAC5B,MAAM,UAAU,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC,CAAC;QAE/C,gCAAgC;QAChC,8DAA8D;QAC9D,MAAM,UAAU,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,GAAG,WAAW,WAAW,CAAC,CAAC;QAE7D,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAChD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAAkB,EAAE,MAAc;IAC9D,MAAM,QAAQ,GAAmC;QAC/C,GAAG,EAAE,WAAW,MAAM,EAAE;QACxB,IAAI,EAAE,QAAQ,MAAM,EAAE;QACtB,IAAI,EAAE,QAAQ,MAAM,EAAE;KACvB,CAAC;IAEF,OAAO,QAAQ,CAAC,EAAE,CAAC,CAAC;AACtB,CAAC;AAED,SAAS,UAAU,CACjB,OAAe,EACf,IAAc,EACd,GAAW;IAEX,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;YACjC,GAAG;YACH,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,KAAK,CAAC,WAAW,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;YACnE,CAAC;iBAAM,CAAC;gBACN,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function validateProjectName(name: string): void;
2
+ export declare function validateProjectPath(projectPath: string): Promise<void>;
3
+ export declare function validatePackageManager(pm: string): void;
4
+ export declare function validateContracts(contracts: string[]): void;
5
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAiBA,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAKtD;AAED,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAe5E;AAED,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAOvD;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAS3D"}
@@ -0,0 +1,41 @@
1
+ import { z } from 'zod';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ const projectNameSchema = z
5
+ .string()
6
+ .min(1, 'Project name is required')
7
+ .max(50, 'Project name must be less than 50 characters')
8
+ .regex(/^[a-z0-9-]+$/, 'Project name must contain only lowercase letters, numbers, and hyphens')
9
+ .refine((name) => !name.startsWith('-') && !name.endsWith('-'), 'Project name cannot start or end with a hyphen');
10
+ export function validateProjectName(name) {
11
+ const result = projectNameSchema.safeParse(name);
12
+ if (!result.success) {
13
+ throw new Error(result.error.errors[0].message);
14
+ }
15
+ }
16
+ export async function validateProjectPath(projectPath) {
17
+ if (await fs.pathExists(projectPath)) {
18
+ throw new Error(`Directory already exists at ${projectPath}. Please choose a different name or remove the existing directory.`);
19
+ }
20
+ const parentDir = path.dirname(projectPath);
21
+ try {
22
+ await fs.access(parentDir, fs.constants.W_OK);
23
+ }
24
+ catch {
25
+ throw new Error(`No write permission in directory ${parentDir}. Please check your permissions.`);
26
+ }
27
+ }
28
+ export function validatePackageManager(pm) {
29
+ const validPMs = ['npm', 'pnpm', 'yarn'];
30
+ if (!validPMs.includes(pm)) {
31
+ throw new Error(`Invalid package manager: ${pm}. Must be one of: ${validPMs.join(', ')}`);
32
+ }
33
+ }
34
+ export function validateContracts(contracts) {
35
+ const validContracts = ['counter', 'token', 'nft'];
36
+ const invalid = contracts.filter((c) => !validContracts.includes(c));
37
+ if (invalid.length > 0) {
38
+ throw new Error(`Invalid contracts: ${invalid.join(', ')}. Valid options are: ${validContracts.join(', ')}`);
39
+ }
40
+ }
41
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,iBAAiB,GAAG,CAAC;KACxB,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,EAAE,0BAA0B,CAAC;KAClC,GAAG,CAAC,EAAE,EAAE,8CAA8C,CAAC;KACvD,KAAK,CACJ,cAAc,EACd,wEAAwE,CACzE;KACA,MAAM,CACL,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EACtD,gDAAgD,CACjD,CAAC;AAEJ,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,WAAmB;IAC3D,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CACb,+BAA+B,WAAW,oEAAoE,CAC/G,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,oCAAoC,SAAS,kCAAkC,CAChF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,EAAU;IAC/C,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CACb,4BAA4B,EAAE,qBAAqB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACzE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAAmB;IACnD,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAErE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,sBAAsB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,wBAAwB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5F,CAAC;IACJ,CAAC;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@devvmichael/create-stacks-app",
3
+ "version": "0.1.0",
4
+ "description": "Scaffold full-stack Stacks blockchain applications",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "bin": {
8
+ "create-stacks-app": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "templates"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "clean": "rm -rf dist",
18
+ "lint": "eslint src --ext .ts",
19
+ "test": "vitest run",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "stacks",
24
+ "blockchain",
25
+ "clarity",
26
+ "smart-contracts",
27
+ "scaffold",
28
+ "cli",
29
+ "create-app"
30
+ ],
31
+ "author": "",
32
+ "license": "MIT",
33
+ "dependencies": {
34
+ "chalk": "^5.3.0",
35
+ "commander": "^11.1.0",
36
+ "fs-extra": "^11.2.0",
37
+ "handlebars": "^4.7.8",
38
+ "inquirer": "^9.2.12",
39
+ "ora": "^7.0.1",
40
+ "zod": "^3.22.4"
41
+ },
42
+ "devDependencies": {
43
+ "@types/fs-extra": "^11.0.4",
44
+ "@types/inquirer": "^9.0.7",
45
+ "@types/node": "^20.10.0",
46
+ "typescript": "^5.3.3",
47
+ "vitest": "^1.0.4"
48
+ },
49
+ "engines": {
50
+ "node": ">=18.0.0"
51
+ }
52
+ }
@@ -0,0 +1,12 @@
1
+ root = true
2
+
3
+ [*]
4
+ indent_style = space
5
+ indent_size = 2
6
+ end_of_line = lf
7
+ charset = utf-8
8
+ trim_trailing_whitespace = true
9
+ insert_final_newline = true
10
+
11
+ [*.md]
12
+ trim_trailing_whitespace = false
@@ -0,0 +1,13 @@
1
+ node_modules/
2
+ dist/
3
+ .cache/
4
+ .pnpm-store/
5
+ *.log
6
+ .DS_Store
7
+ .env
8
+ .env.local
9
+ .env.*.local
10
+ coverage/
11
+ .next/
12
+ out/
13
+ build/
@@ -0,0 +1,7 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": true,
4
+ "tabWidth": 2,
5
+ "trailingComma": "es5",
6
+ "printWidth": 100
7
+ }
@@ -0,0 +1,43 @@
1
+ ;; Counter Contract
2
+ ;; A simple contract demonstrating state management in Clarity
3
+
4
+ ;; Data variables
5
+ (define-data-var counter uint u0)
6
+ (define-data-var owner principal tx-sender)
7
+
8
+ ;; Error codes
9
+ (define-constant ERR-NOT-OWNER (err u403))
10
+
11
+ ;; Public functions
12
+
13
+ ;; Increment the counter by 1
14
+ (define-public (increment)
15
+ (ok (var-set counter (+ (var-get counter) u1))))
16
+
17
+ ;; Decrement the counter by 1
18
+ (define-public (decrement)
19
+ (let ((current (var-get counter)))
20
+ (asserts! (> current u0) (err u400))
21
+ (ok (var-set counter (- current u1)))))
22
+
23
+ ;; Reset the counter to 0 (owner only)
24
+ (define-public (reset)
25
+ (begin
26
+ (asserts! (is-eq tx-sender (var-get owner)) ERR-NOT-OWNER)
27
+ (ok (var-set counter u0))))
28
+
29
+ ;; Set the counter to a specific value (owner only)
30
+ (define-public (set-counter (value uint))
31
+ (begin
32
+ (asserts! (is-eq tx-sender (var-get owner)) ERR-NOT-OWNER)
33
+ (ok (var-set counter value))))
34
+
35
+ ;; Read-only functions
36
+
37
+ ;; Get the current counter value
38
+ (define-read-only (get-counter)
39
+ (ok (var-get counter)))
40
+
41
+ ;; Get the contract owner
42
+ (define-read-only (get-owner)
43
+ (ok (var-get owner)))
@@ -0,0 +1,127 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { Cl } from "@stacks/transactions";
3
+
4
+ const accounts = simnet.getAccounts();
5
+ const deployer = accounts.get("deployer")!;
6
+ const wallet1 = accounts.get("wallet_1")!;
7
+
8
+ describe("Counter Contract", () => {
9
+ describe("Initialization", () => {
10
+ it("should start at zero", () => {
11
+ const result = simnet.callReadOnlyFn(
12
+ "counter",
13
+ "get-counter",
14
+ [],
15
+ deployer
16
+ );
17
+ expect(result.result).toBeOk(Cl.uint(0));
18
+ });
19
+
20
+ it("should have deployer as owner", () => {
21
+ const result = simnet.callReadOnlyFn(
22
+ "counter",
23
+ "get-owner",
24
+ [],
25
+ deployer
26
+ );
27
+ expect(result.result).toBeOk(Cl.principal(deployer));
28
+ });
29
+ });
30
+
31
+ describe("Increment", () => {
32
+ it("should increment counter by 1", () => {
33
+ const block = simnet.callPublicFn("counter", "increment", [], deployer);
34
+ expect(block.result).toBeOk(Cl.bool(true));
35
+
36
+ const result = simnet.callReadOnlyFn(
37
+ "counter",
38
+ "get-counter",
39
+ [],
40
+ deployer
41
+ );
42
+ expect(result.result).toBeOk(Cl.uint(1));
43
+ });
44
+
45
+ it("should allow anyone to increment", () => {
46
+ const block = simnet.callPublicFn("counter", "increment", [], wallet1);
47
+ expect(block.result).toBeOk(Cl.bool(true));
48
+ });
49
+ });
50
+
51
+ describe("Decrement", () => {
52
+ it("should decrement counter by 1", () => {
53
+ // First increment
54
+ simnet.callPublicFn("counter", "increment", [], deployer);
55
+
56
+ const block = simnet.callPublicFn("counter", "decrement", [], deployer);
57
+ expect(block.result).toBeOk(Cl.bool(true));
58
+
59
+ const result = simnet.callReadOnlyFn(
60
+ "counter",
61
+ "get-counter",
62
+ [],
63
+ deployer
64
+ );
65
+ expect(result.result).toBeOk(Cl.uint(0));
66
+ });
67
+
68
+ it("should fail when counter is at zero", () => {
69
+ const block = simnet.callPublicFn("counter", "decrement", [], deployer);
70
+ expect(block.result).toBeErr(Cl.uint(400));
71
+ });
72
+ });
73
+
74
+ describe("Reset", () => {
75
+ it("should allow owner to reset", () => {
76
+ // First increment
77
+ simnet.callPublicFn("counter", "increment", [], deployer);
78
+ simnet.callPublicFn("counter", "increment", [], deployer);
79
+
80
+ const block = simnet.callPublicFn("counter", "reset", [], deployer);
81
+ expect(block.result).toBeOk(Cl.bool(true));
82
+
83
+ const result = simnet.callReadOnlyFn(
84
+ "counter",
85
+ "get-counter",
86
+ [],
87
+ deployer
88
+ );
89
+ expect(result.result).toBeOk(Cl.uint(0));
90
+ });
91
+
92
+ it("should prevent non-owner from resetting", () => {
93
+ const block = simnet.callPublicFn("counter", "reset", [], wallet1);
94
+ expect(block.result).toBeErr(Cl.uint(403));
95
+ });
96
+ });
97
+
98
+ describe("Set Counter", () => {
99
+ it("should allow owner to set counter", () => {
100
+ const block = simnet.callPublicFn(
101
+ "counter",
102
+ "set-counter",
103
+ [Cl.uint(100)],
104
+ deployer
105
+ );
106
+ expect(block.result).toBeOk(Cl.bool(true));
107
+
108
+ const result = simnet.callReadOnlyFn(
109
+ "counter",
110
+ "get-counter",
111
+ [],
112
+ deployer
113
+ );
114
+ expect(result.result).toBeOk(Cl.uint(100));
115
+ });
116
+
117
+ it("should prevent non-owner from setting counter", () => {
118
+ const block = simnet.callPublicFn(
119
+ "counter",
120
+ "set-counter",
121
+ [Cl.uint(100)],
122
+ wallet1
123
+ );
124
+ expect(block.result).toBeErr(Cl.uint(403));
125
+ });
126
+ });
127
+ });
@@ -0,0 +1,11 @@
1
+ (define-trait sip010-trait
2
+ (
3
+ (transfer (uint principal principal (optional (buff 34))) (response bool uint))
4
+ (get-name () (response (string-ascii 32) uint))
5
+ (get-symbol () (response (string-ascii 32) uint))
6
+ (get-decimals () (response uint uint))
7
+ (get-balance (principal) (response uint uint))
8
+ (get-total-supply () (response uint uint))
9
+ (get-token-uri () (response (optional (string-utf8 256)) uint))
10
+ )
11
+ )
@@ -0,0 +1,20 @@
1
+ ;; Staking Pool
2
+ (use-trait sip010-trait .sip010-trait.sip010-trait)
3
+
4
+ (define-map stakes principal uint)
5
+
6
+ (define-public (stake (token <sip010-trait>) (amount uint))
7
+ (begin
8
+ (try! (contract-call? token transfer amount tx-sender (as-contract tx-sender) none))
9
+ (map-set stakes tx-sender (+ (default-to u0 (map-get? stakes tx-sender)) amount))
10
+ (ok true)))
11
+
12
+ (define-public (unstake (token <sip010-trait>) (amount uint))
13
+ (begin
14
+ (asserts! (>= (default-to u0 (map-get? stakes tx-sender)) amount) (err u100))
15
+ (try! (as-contract (contract-call? token transfer amount tx-sender tx-sender none)))
16
+ (map-set stakes tx-sender (- (default-to u0 (map-get? stakes tx-sender)) amount))
17
+ (ok true)))
18
+
19
+ (define-read-only (get-stake (staker principal))
20
+ (ok (default-to u0 (map-get? stakes staker))))
@@ -0,0 +1,44 @@
1
+ ;; NFT Marketplace
2
+ (use-trait nft-trait .nft-trait.nft-trait)
3
+
4
+ (define-constant ERR-NOT-AUTHORIZED (err u100))
5
+ (define-constant ERR-LISTING-NOT-FOUND (err u101))
6
+ (define-constant ERR-WRONG-PRICE (err u102))
7
+
8
+ (define-map listings
9
+ { contract: principal, token-id: uint }
10
+ { price: uint, seller: principal }
11
+ )
12
+
13
+ (define-public (list-asset (nft-asset-contract <nft-trait>) (token-id uint) (price uint))
14
+ (let ((listing-id { contract: (contract-of nft-asset-contract), token-id: token-id }))
15
+ ;; Transfer NFT to contract
16
+ (try! (contract-call? nft-asset-contract transfer token-id tx-sender (as-contract tx-sender)))
17
+ ;; Create listing
18
+ (map-set listings listing-id { price: price, seller: tx-sender })
19
+ (ok true)))
20
+
21
+ (define-public (unlist-asset (nft-asset-contract <nft-trait>) (token-id uint))
22
+ (let (
23
+ (listing-id { contract: (contract-of nft-asset-contract), token-id: token-id })
24
+ (listing (unwrap! (map-get? listings listing-id) ERR-LISTING-NOT-FOUND))
25
+ )
26
+ (asserts! (is-eq tx-sender (get seller listing)) ERR-NOT-AUTHORIZED)
27
+ ;; Return NFT
28
+ (as-contract (try! (contract-call? nft-asset-contract transfer token-id tx-sender (get seller listing))))
29
+ (map-delete listings listing-id)
30
+ (ok true)))
31
+
32
+ (define-public (purchase-asset (nft-asset-contract <nft-trait>) (token-id uint))
33
+ (let (
34
+ (listing-id { contract: (contract-of nft-asset-contract), token-id: token-id })
35
+ (listing (unwrap! (map-get? listings listing-id) ERR-LISTING-NOT-FOUND))
36
+ (price (get price listing))
37
+ (seller (get seller listing))
38
+ )
39
+ ;; Transfer STX to seller
40
+ (try! (stx-transfer? price tx-sender seller))
41
+ ;; Transfer NFT to buyer
42
+ (as-contract (try! (contract-call? nft-asset-contract transfer token-id tx-sender tx-sender)))
43
+ (map-delete listings listing-id)
44
+ (ok true)))
@@ -0,0 +1,8 @@
1
+ (define-trait nft-trait
2
+ (
3
+ (get-last-token-id () (response uint uint))
4
+ (get-token-uri (uint) (response (optional (string-ascii 256)) uint))
5
+ (get-owner (uint) (response (optional principal) uint))
6
+ (transfer (uint principal principal) (response bool uint))
7
+ )
8
+ )
@@ -0,0 +1,25 @@
1
+ ;; SIP-009 NFT Contract
2
+ (impl-trait .nft-trait.nft-trait)
3
+
4
+ (define-non-fungible-token my-nft uint)
5
+ (define-data-var last-token-id uint u0)
6
+
7
+ (define-public (transfer (token-id uint) (sender principal) (recipient principal))
8
+ (begin
9
+ (try! (nft-transfer? my-nft token-id sender recipient))
10
+ (ok true)))
11
+
12
+ (define-public (mint (recipient principal))
13
+ (let ((token-id (+ (var-get last-token-id) u1)))
14
+ (try! (nft-mint? my-nft token-id recipient))
15
+ (var-set last-token-id token-id)
16
+ (ok token-id)))
17
+
18
+ (define-read-only (get-last-token-id)
19
+ (ok (var-get last-token-id)))
20
+
21
+ (define-read-only (get-token-uri (token-id uint))
22
+ (ok none))
23
+
24
+ (define-read-only (get-owner (token-id uint))
25
+ (ok (nft-get-owner? my-nft token-id)))
@@ -0,0 +1,111 @@
1
+ ;; SIP-009 Non-Fungible Token
2
+ ;; A standard NFT implementation
3
+
4
+ (impl-trait 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.nft-trait)
5
+
6
+ ;; NFT Configuration
7
+ (define-constant CONTRACT-OWNER tx-sender)
8
+ (define-constant COLLECTION-NAME "MyNFTCollection")
9
+ (define-constant COLLECTION-SYMBOL "MNFT")
10
+
11
+ ;; Error codes
12
+ (define-constant ERR-OWNER-ONLY (err u100))
13
+ (define-constant ERR-NOT-TOKEN-OWNER (err u101))
14
+ (define-constant ERR-TOKEN-EXISTS (err u102))
15
+ (define-constant ERR-TOKEN-NOT-FOUND (err u103))
16
+ (define-constant ERR-LISTING-NOT-FOUND (err u104))
17
+ (define-constant ERR-WRONG-PRICE (err u105))
18
+
19
+ ;; Storage
20
+ (define-non-fungible-token my-nft uint)
21
+ (define-data-var last-token-id uint u0)
22
+ (define-data-var base-token-uri (string-ascii 256) "")
23
+
24
+ ;; Token metadata storage
25
+ (define-map token-metadata uint {
26
+ uri: (string-ascii 256)
27
+ })
28
+
29
+ ;; Marketplace listings
30
+ (define-map listings uint {
31
+ price: uint,
32
+ seller: principal
33
+ })
34
+
35
+ ;; SIP-009 Functions
36
+
37
+ (define-public (transfer (token-id uint) (sender principal) (recipient principal))
38
+ (begin
39
+ (asserts! (is-eq tx-sender sender) ERR-NOT-TOKEN-OWNER)
40
+ (map-delete listings token-id)
41
+ (nft-transfer? my-nft token-id sender recipient)))
42
+
43
+ (define-read-only (get-last-token-id)
44
+ (ok (var-get last-token-id)))
45
+
46
+ (define-read-only (get-token-uri (token-id uint))
47
+ (match (map-get? token-metadata token-id)
48
+ metadata (ok (some (get uri metadata)))
49
+ (ok none)))
50
+
51
+ (define-read-only (get-owner (token-id uint))
52
+ (ok (nft-get-owner? my-nft token-id)))
53
+
54
+ ;; Mint function
55
+ (define-public (mint (recipient principal) (token-uri (string-ascii 256)))
56
+ (let
57
+ ((token-id (+ (var-get last-token-id) u1)))
58
+ (try! (nft-mint? my-nft token-id recipient))
59
+ (map-set token-metadata token-id { uri: token-uri })
60
+ (var-set last-token-id token-id)
61
+ (ok token-id)))
62
+
63
+ ;; Batch mint function
64
+ (define-public (mint-batch (recipient principal) (uris (list 10 (string-ascii 256))))
65
+ (let
66
+ ((start-id (var-get last-token-id)))
67
+ (fold mint-single uris (ok start-id))))
68
+
69
+ (define-private (mint-single (uri (string-ascii 256)) (prev-result (response uint uint)))
70
+ (match prev-result
71
+ prev-id
72
+ (let
73
+ ((new-id (+ prev-id u1)))
74
+ (try! (nft-mint? my-nft new-id tx-sender))
75
+ (map-set token-metadata new-id { uri: uri })
76
+ (var-set last-token-id new-id)
77
+ (ok new-id))
78
+ err-code (err err-code)))
79
+
80
+ ;; Admin functions
81
+ (define-public (set-base-uri (new-base-uri (string-ascii 256)))
82
+ (begin
83
+ (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-OWNER-ONLY)
84
+ (ok (var-set base-token-uri new-base-uri))))
85
+
86
+ ;; Marketplace functions
87
+
88
+ (define-public (list-for-sale (token-id uint) (price uint))
89
+ (let
90
+ ((owner (unwrap! (nft-get-owner? my-nft token-id) ERR-TOKEN-NOT-FOUND)))
91
+ (asserts! (is-eq tx-sender owner) ERR-NOT-TOKEN-OWNER)
92
+ (ok (map-set listings token-id { price: price, seller: tx-sender }))))
93
+
94
+ (define-public (unlist (token-id uint))
95
+ (let
96
+ ((listing (unwrap! (map-get? listings token-id) ERR-LISTING-NOT-FOUND)))
97
+ (asserts! (is-eq tx-sender (get seller listing)) ERR-NOT-TOKEN-OWNER)
98
+ (ok (map-delete listings token-id))))
99
+
100
+ (define-public (buy (token-id uint))
101
+ (let
102
+ ((listing (unwrap! (map-get? listings token-id) ERR-LISTING-NOT-FOUND))
103
+ (price (get price listing))
104
+ (seller (get seller listing)))
105
+ (try! (stx-transfer? price tx-sender seller))
106
+ (try! (nft-transfer? my-nft token-id seller tx-sender))
107
+ (map-delete listings token-id)
108
+ (ok token-id)))
109
+
110
+ (define-read-only (get-listing (token-id uint))
111
+ (map-get? listings token-id))