├── .changeset ├── README.md └── config.json ├── .gitignore ├── CHANGELOG.md ├── README.md ├── bun.lockb ├── index.ts ├── package.json ├── src └── create.ts └── tsconfig.json /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Caches 14 | 15 | .cache 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 20 | 21 | # Runtime data 22 | 23 | pids 24 | _.pid 25 | _.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | 30 | lib-cov 31 | 32 | # Coverage directory used by tools like istanbul 33 | 34 | coverage 35 | *.lcov 36 | 37 | # nyc test coverage 38 | 39 | .nyc_output 40 | 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 42 | 43 | .grunt 44 | 45 | # Bower dependency directory (https://bower.io/) 46 | 47 | bower_components 48 | 49 | # node-waf configuration 50 | 51 | .lock-wscript 52 | 53 | # Compiled binary addons (https://nodejs.org/api/addons.html) 54 | 55 | build/Release 56 | 57 | # Dependency directories 58 | 59 | node_modules/ 60 | jspm_packages/ 61 | 62 | # Snowpack dependency directory (https://snowpack.dev/) 63 | 64 | web_modules/ 65 | 66 | # TypeScript cache 67 | 68 | *.tsbuildinfo 69 | 70 | # Optional npm cache directory 71 | 72 | .npm 73 | 74 | # Optional eslint cache 75 | 76 | .eslintcache 77 | 78 | # Optional stylelint cache 79 | 80 | .stylelintcache 81 | 82 | # Microbundle cache 83 | 84 | .rpt2_cache/ 85 | .rts2_cache_cjs/ 86 | .rts2_cache_es/ 87 | .rts2_cache_umd/ 88 | 89 | # Optional REPL history 90 | 91 | .node_repl_history 92 | 93 | # Output of 'npm pack' 94 | 95 | *.tgz 96 | 97 | # Yarn Integrity file 98 | 99 | .yarn-integrity 100 | 101 | # dotenv environment variable files 102 | 103 | .env 104 | .env.development.local 105 | .env.test.local 106 | .env.production.local 107 | .env.local 108 | 109 | # parcel-bundler cache (https://parceljs.org/) 110 | 111 | .parcel-cache 112 | 113 | # Next.js build output 114 | 115 | .next 116 | out 117 | 118 | # Nuxt.js build / generate output 119 | 120 | .nuxt 121 | dist 122 | 123 | # Gatsby files 124 | 125 | # Comment in the public line in if your project uses Gatsby and not Next.js 126 | 127 | # https://nextjs.org/blog/next-9-1#public-directory-support 128 | 129 | # public 130 | 131 | # vuepress build output 132 | 133 | .vuepress/dist 134 | 135 | # vuepress v2.x temp and cache directory 136 | 137 | .temp 138 | 139 | # Docusaurus cache and generated files 140 | 141 | .docusaurus 142 | 143 | # Serverless directories 144 | 145 | .serverless/ 146 | 147 | # FuseBox cache 148 | 149 | .fusebox/ 150 | 151 | # DynamoDB Local files 152 | 153 | .dynamodb/ 154 | 155 | # TernJS port file 156 | 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | 161 | .vscode-test 162 | 163 | # yarn v2 164 | 165 | .yarn/cache 166 | .yarn/unplugged 167 | .yarn/build-state.yml 168 | .yarn/install-state.gz 169 | .pnp.* 170 | 171 | # IntelliJ based IDEs 172 | .idea 173 | 174 | # Finder (MacOS) folder config 175 | .DS_Store 176 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # create-web3-sdk 2 | 3 | ## 1.3.2 4 | 5 | ### Patch Changes 6 | 7 | - revert last version 8 | 9 | ## 1.3.1 10 | 11 | ### Patch Changes 12 | 13 | - Added version command "--v" 14 | 15 | ## 1.3.0 16 | 17 | ### Minor Changes 18 | 19 | - Implemented built-in network fork for quick and easy testing of on-chain actions. 20 | 21 | ## 1.2.1 22 | 23 | ### Patch Changes 24 | 25 | - update readme 26 | 27 | ## 1.2.0 28 | 29 | ### Minor Changes 30 | 31 | - Added changeset 32 | 33 | ## 1.1.0 34 | 35 | ### Minor Changes 36 | 37 | - bfc27ce: - added typechain 38 | - added changeset to chore package 39 | - added github repository url to npm page 40 | - fixed issue with typedoc config 41 | - Removed typechain, now relying on viem contract instances + some changes on example code. 42 | 43 | ## 1.0.0 44 | 45 | ### Major Changes 46 | 47 | - Added typechain support 48 | - Added changeset to chore package 49 | - Fixed bugs with typedoc config 50 | - Added repository URL to npm package page 51 | 52 | ## 0.2.0 53 | 54 | ### Minor Changes 55 | 56 | - Initial release with basic Web3 SDK creation support 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # create-web3-sdk 2 | 3 | A CLI tool to quickly scaffold a modern Web3 SDK with TypeScript, testing, documentation and more. 4 | 5 | ## Features 6 | 7 | - ✅ TypeScript-first development 8 | - ✅ Automatic API documentation with TypeDoc 9 | - ✅ Testing setup with Vitest 10 | - ✅ Code quality with Biome (linting, formatting) 11 | - ✅ Dual ESM/CJS builds 12 | - ✅ Modern tooling with Bun 13 | - ✅ viem for Ethereum RPC 14 | - ✅ Built in versioning and changelog with changesets 15 | - ✅ Built in anvil network for fast and easy testing of on-chain actions 16 | 17 | ## Upcoming Features 18 | - ⚙️ Professional documentation website with vocs 19 | - ⚙️ CI/CD setup with Github Actions 20 | - ⚙️ Easy deployment of smart contracts on anvil network for testing 21 | - ⚙️ Automatic typescript interfaces for your contracts 22 | 23 | ## Usage 24 | 25 | Create a new SDK project: 26 | 27 | ```bash 28 | npm install -g create-web3-sdk 29 | npx create-web3-sdk my-sdk 30 | cd my-sdk 31 | bun install 32 | bun run test # Run tests 33 | bun run build # Build the SDK 34 | bun run start # Start the SDK 35 | ``` 36 | 37 | Built with ❤️ -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VGabriel45/create-web3-sdk/b25e84cd6852ccef73f887306094a2d235824d08/bun.lockb -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { program } from 'commander'; 4 | import { create } from './src/create.js'; 5 | import { fileURLToPath } from 'url'; 6 | import { dirname, join } from 'path'; 7 | import { readFileSync } from 'fs'; 8 | 9 | const __dirname = dirname(fileURLToPath(import.meta.url)); 10 | const pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8')); 11 | 12 | program 13 | .name('create-web3-sdk') 14 | .description('CLI tool to scaffold Web3 SDK projects') 15 | .version(pkg.version) 16 | .argument('', 'Name of the SDK project') 17 | .option('--typescript', 'Use TypeScript (default: true)', true) 18 | .option('--git', 'Initialize git repository (default: true)', true) 19 | .action(async (projectName: string, options) => { 20 | try { 21 | await create(projectName, options); 22 | } catch (error) { 23 | if (error instanceof Error) { 24 | console.error('Error:', error.message); 25 | } else { 26 | console.error('Error:', String(error)); 27 | } 28 | process.exit(1); 29 | } 30 | }); 31 | 32 | program.parse(); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-web3-sdk", 3 | "author": "Vasile Gabriel", 4 | "version": "1.3.2", 5 | "description": "Quickly create a Web3 SDK with built in TypeScript, Biome, Vitest, viem, and more.", 6 | "keywords": [ 7 | "web3", 8 | "sdk", 9 | "typescript", 10 | "ethereum", 11 | "blockchain", 12 | "viem", 13 | "biome", 14 | "vitest" 15 | ], 16 | "type": "module", 17 | "main": "./dist/src/create.js", 18 | "types": "./dist/src/create.d.ts", 19 | "bin": { 20 | "create-web3-sdk": "./dist/index.js" 21 | }, 22 | "files": [ 23 | "dist" 24 | ], 25 | "scripts": { 26 | "build": "tsc", 27 | "prepare": "npm run build", 28 | "create-web3-sdk": "node dist/index.js", 29 | "start": "node dist/index.js", 30 | "changeset": "changeset", 31 | "version": "changeset version", 32 | "release": "npm run build && changeset publish --access public" 33 | }, 34 | "dependencies": { 35 | "commander": "^11.0.0", 36 | "ora": "^7.0.0" 37 | }, 38 | "devDependencies": { 39 | "@types/node": "^20.0.0", 40 | "typescript": "^5.0.0", 41 | "@changesets/cli": "^2.27.11" 42 | }, 43 | "repository": { 44 | "type": "git", 45 | "url": "https://github.com/VGabriel45/create-web3-sdk.git" 46 | }, 47 | "homepage": "https://github.com/VGabriel45/create-web3-sdk.git", 48 | "license": "MIT" 49 | } -------------------------------------------------------------------------------- /src/create.ts: -------------------------------------------------------------------------------- 1 | import { mkdir, writeFile } from 'fs/promises'; 2 | import { join } from 'path'; 3 | import { execSync } from 'child_process'; 4 | import ora from 'ora'; 5 | 6 | interface CreateOptions { 7 | typescript: boolean; 8 | git: boolean; 9 | } 10 | 11 | const packageJson = (projectName: string) => ({ 12 | name: projectName, 13 | version: '0.1.0', 14 | type: "module", 15 | main: "./dist/cjs/index.js", 16 | module: "./dist/esm/index.js", 17 | types: "./dist/types/index.d.ts", 18 | exports: { 19 | ".": { 20 | types: "./dist/types/index.d.ts", 21 | import: "./dist/esm/index.js", 22 | require: "./dist/cjs/index.js" 23 | } 24 | }, 25 | scripts: { 26 | build: "rimraf dist && bun run build:esm && bun run build:cjs && bun run build:types", 27 | "build:esm": "tsc -p tsconfig/esm.json", 28 | "build:cjs": "tsc -p tsconfig/cjs.json", 29 | "build:types": "tsc -p tsconfig/types.json", 30 | "docs": "typedoc", 31 | "docs:watch": "typedoc --watch", 32 | "format": "biome format --write ./src", 33 | "lint": "biome lint ./src", 34 | "check": "biome check ./src", 35 | "fork:base-sepolia": "anvil --fork-url https://sepolia.base.org -vvvv", 36 | "test": "concurrently \"bun run fork:base-sepolia\" \"wait-on tcp:8545 && vitest\" \"kill -9 $(lsof -t -i:8545)\"", 37 | prepare: "bun run build", 38 | "changeset": "changeset", 39 | "version": "changeset version", 40 | "release": "npm run build && changeset publish --access public" 41 | }, 42 | dependencies: { 43 | "viem": "^2.22.12" 44 | }, 45 | devDependencies: { 46 | "@biomejs/biome": "1.5.3", 47 | "@changesets/cli": "^2.27.11", 48 | "rimraf": "^5.0.0", 49 | "typedoc": "^0.25.0", 50 | "typescript": "^5.7.0", 51 | "vitest": "^3.0.0", 52 | "concurrently": "^8.2.2", 53 | "wait-on": "^7.2.0", 54 | "@viem/anvil": "^0.0.10" 55 | }, 56 | peerDependencies: { 57 | "typescript": "^5.0.0" 58 | } 59 | }); 60 | 61 | const tsConfig = { 62 | compilerOptions: { 63 | target: 'ES2020', 64 | module: 'ESNext', 65 | moduleResolution: 'node', 66 | declaration: true, 67 | strict: true, 68 | esModuleInterop: true, 69 | skipLibCheck: true, 70 | forceConsistentCasingInFileNames: true, 71 | outDir: './dist' 72 | }, 73 | include: ['src'], 74 | exclude: ['node_modules', 'dist', '**/*.test.ts'] 75 | }; 76 | 77 | export async function create(projectName: string, options: CreateOptions) { 78 | const spinner = ora('Creating Web3 SDK project...').start(); 79 | 80 | try { 81 | // Create project directory 82 | const projectPath = join(process.cwd(), projectName); 83 | await mkdir(projectPath); 84 | process.chdir(projectPath); 85 | 86 | // Create necessary directories 87 | await mkdir('src'); 88 | await mkdir('test'); 89 | await mkdir('tsconfig'); 90 | 91 | // Write tsconfig files in the tsconfig folder 92 | await writeFile('tsconfig/base.json', JSON.stringify({ 93 | ...tsConfig, 94 | compilerOptions: { 95 | ...tsConfig.compilerOptions, 96 | rootDir: "../src", 97 | outDir: "../dist" 98 | }, 99 | include: ["../src/**/*"], 100 | exclude: ["../node_modules", "../dist", "../**/*.test.ts"] 101 | }, null, 2)); 102 | 103 | await writeFile('tsconfig/esm.json', JSON.stringify({ 104 | extends: "../tsconfig/base.json", 105 | compilerOptions: { 106 | outDir: "../dist/esm" 107 | } 108 | }, null, 2)); 109 | 110 | await writeFile('tsconfig/cjs.json', JSON.stringify({ 111 | extends: "../tsconfig/base.json", 112 | compilerOptions: { 113 | module: "CommonJS", 114 | outDir: "../dist/cjs" 115 | } 116 | }, null, 2)); 117 | 118 | await writeFile('tsconfig/types.json', JSON.stringify({ 119 | extends: "../tsconfig/base.json", 120 | compilerOptions: { 121 | emitDeclarationOnly: true, 122 | outDir: "../dist/types" 123 | } 124 | }, null, 2)); 125 | 126 | // Update main tsconfig.json to extend from base 127 | await writeFile('tsconfig.json', JSON.stringify({ 128 | extends: "./tsconfig/base.json" 129 | }, null, 2)); 130 | 131 | // Write package.json 132 | const pkg = packageJson(projectName); 133 | await writeFile('package.json', JSON.stringify(pkg, null, 2)); 134 | 135 | // Add typedoc configuration 136 | await writeFile('typedoc.json', JSON.stringify({ 137 | "$schema": "https://typedoc.org/schema.json", 138 | "entryPoints": ["src/index.ts"], 139 | "exclude": [ 140 | "src/test/**/*.ts" 141 | ], 142 | "basePath": "src/", 143 | "includes": "src/", 144 | "out": "docs", 145 | "gitRevision": "main" 146 | } 147 | , null, 2)); 148 | 149 | // Add Biome configuration 150 | await writeFile('biome.json', JSON.stringify({ 151 | "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", 152 | "organizeImports": { 153 | "enabled": false 154 | }, 155 | "linter": { 156 | "enabled": true, 157 | "rules": { 158 | "recommended": true, 159 | "suspicious": { 160 | "noConsoleLog": "off" 161 | }, 162 | "style": { 163 | "noNonNullAssertion": "off", 164 | "useShorthandArrayType": "off", 165 | "noUselessElse": "off", 166 | "noUnusedTemplateLiteral": "off", 167 | "useSingleVarDeclarator": "off", 168 | "noParameterAssign": "off", 169 | "useTemplate": "off", 170 | "noShoutyConstants": "off" 171 | } 172 | } 173 | }, 174 | "formatter": { 175 | "enabled": true, 176 | "formatWithErrors": false, 177 | "indentStyle": "space", 178 | "indentWidth": 2, 179 | "lineWidth": 80 180 | }, 181 | "files": { 182 | "ignore": [ 183 | "dist/**/*", 184 | "node_modules/**/*" 185 | ] 186 | } 187 | }, null, 2)); 188 | 189 | // Create .env.example file 190 | await writeFile('.env.example', ` 191 | # Required for testing token transfers 192 | TESTING_PRIVATE_KEY=your_private_key_here 193 | 194 | # Optional: Override default RPC URL 195 | RPC_URL=your_rpc_url_here 196 | `); 197 | 198 | // Create example SDK file 199 | const sdkContent = ` 200 | // Implement SDK 201 | `; 202 | 203 | await writeFile('src/index.ts', sdkContent); 204 | 205 | // Create test config file 206 | const testConfigContent = ` 207 | import { createTestClient, defineChain, http, publicActions, walletActions } from 'viem' 208 | 209 | export const ANVIL_RPC_URL = 'http://127.0.0.1:8545' 210 | 211 | export const testChain = defineChain({ 212 | id: 84532, 213 | name: 'Base Sepolia Fork', 214 | nativeCurrency: { 215 | decimals: 18, 216 | name: 'Ether', 217 | symbol: 'ETH', 218 | }, 219 | rpcUrls: { 220 | default: { 221 | http: [ANVIL_RPC_URL], 222 | }, 223 | }, 224 | blockExplorers: { 225 | default: { name: 'Explorer', url: 'https://sepolia.basescan.org' }, 226 | }, 227 | }) 228 | 229 | export const testClient = createTestClient({ 230 | chain: testChain, 231 | mode: 'anvil', 232 | transport: http(ANVIL_RPC_URL), 233 | }) 234 | .extend(walletActions) 235 | .extend(publicActions) 236 | 237 | // Anvil's first test account - has 10000 ETH 238 | export const TEST_ACCOUNT = { 239 | address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', 240 | privateKey: '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' 241 | } as const 242 | `; 243 | 244 | // Create test utilities file 245 | const testUtilsContent = ` 246 | import { createWalletClient, http, parseEther, type Address } from 'viem' 247 | import { privateKeyToAccount } from 'viem/accounts' 248 | import { testChain, TEST_ACCOUNT, testClient } from './test.config' 249 | 250 | export async function fundAddress(address: Address, amount: string) { 251 | const account = privateKeyToAccount(TEST_ACCOUNT.privateKey) 252 | const client = createWalletClient({ 253 | account, 254 | chain: testChain, 255 | transport: http() 256 | }) 257 | 258 | const tx = await client.sendTransaction({ 259 | to: address, 260 | value: parseEther(amount) 261 | }) 262 | 263 | return tx 264 | } 265 | 266 | export async function getBalance(address: Address) { 267 | return testClient.getBalance({ address }) 268 | } 269 | 270 | export async function impersonateAccount(address: Address) { 271 | await testClient.impersonateAccount({ address }) 272 | } 273 | `; 274 | 275 | // Update the test file content 276 | const testFileContent = ` 277 | import { describe, it, expect } from 'vitest' 278 | import { http, parseEther, createPublicClient } from 'viem' 279 | import { testChain, ANVIL_RPC_URL, testClient } from './config/test.config' 280 | import { fundAddress, getBalance, impersonateAccount } from './config/test.utils' 281 | 282 | // Vitalik's address for impersonation test 283 | const VITALIK = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' as const 284 | 285 | describe('SDK Example Tests', () => { 286 | it('should fund an address using utility function', async () => { 287 | const recipient = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8' 288 | 289 | // Fund the recipient using our utility function 290 | const fundTx = await fundAddress(recipient, '1.5') 291 | 292 | // Verify the transfer 293 | const publicClient = createPublicClient({ 294 | transport: http(ANVIL_RPC_URL), 295 | chain: testChain 296 | }) 297 | 298 | const receipt = await publicClient.waitForTransactionReceipt({ hash: fundTx }) 299 | expect(receipt.status).toBe('success') 300 | 301 | const balance = await getBalance(recipient) 302 | expect(balance >= parseEther('1.5')).toBe(true) 303 | }) 304 | 305 | it('should impersonate Vitalik and send ETH', async () => { 306 | const recipient = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8' 307 | 308 | // Get initial balances 309 | const initialBalance = await getBalance(recipient) 310 | 311 | const vitalikBalance = await getBalance(VITALIK) 312 | console.log('Vitalik balance:', vitalikBalance) 313 | 314 | // Impersonate Vitalik 315 | await impersonateAccount(VITALIK) 316 | 317 | // Send 1 ETH from Vitalik's account to the recipient 318 | const txHash = await testClient.sendUnsignedTransaction({ 319 | from: VITALIK, 320 | to: recipient, 321 | value: parseEther('1') 322 | }) 323 | 324 | // Wait for transaction 325 | const receipt = await testClient.waitForTransactionReceipt({ hash: txHash }) 326 | expect(receipt.status).toBe('success') 327 | 328 | // Verify the transfer 329 | const finalBalance = await getBalance(recipient) 330 | expect(finalBalance - initialBalance).toBe(parseEther('1')) 331 | 332 | // Stop impersonating 333 | await testClient.stopImpersonatingAccount({ address: VITALIK }) 334 | }) 335 | })`; 336 | 337 | // In the create function, add these files: 338 | await mkdir('test/config'); 339 | await writeFile('test/config/test.config.ts', testConfigContent); 340 | await writeFile('test/config/test.utils.ts', testUtilsContent); 341 | await writeFile('test/sdk.test.ts', testFileContent); 342 | 343 | // Add changesets configuration 344 | await mkdir('.changeset'); 345 | await writeFile('.changeset/config.json', JSON.stringify({ 346 | "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", 347 | "changelog": "@changesets/cli/changelog", 348 | "commit": false, 349 | "fixed": [], 350 | "linked": [], 351 | "access": "public", 352 | "baseBranch": "main", 353 | "updateInternalDependencies": "patch", 354 | "ignore": [] 355 | }, null, 2)); 356 | 357 | // Update README with versioning instructions 358 | const readmeContent = ` 359 | # ${projectName} 360 | 361 | ## Installation 362 | 363 | Using bun (recommended): 364 | \`\`\`bash 365 | bunx create-web3-sdk my-sdk 366 | \`\`\` 367 | 368 | Using npm: 369 | \`\`\`bash 370 | npx create-web3-sdk my-sdk 371 | \`\`\` 372 | 373 | ## Development 374 | 375 | ### Scripts 376 | 377 | - \`bun run build\` - Build the SDK 378 | - \`bun run test\` - Run tests against Base Sepolia 379 | - \`bun run test:fork\` - Run tests against local Anvil fork 380 | - \`bun run fork:base-sepolia\` - Start Anvil fork of Base Sepolia 381 | - \`bun run check\` - Format and lint code 382 | 383 | ### Testing with Local Fork 384 | 385 | For faster and more reliable tests, you can run them against a local Anvil fork: 386 | 387 | 1. Install Anvil (comes with Foundry): https://book.getfoundry.sh/ 388 | 2. Run \`bun run test:fork\` - This will: 389 | - Start an Anvil fork of Base Sepolia 390 | - Wait for the fork to be ready 391 | - Run the tests against the local fork 392 | 393 | ### Versioning and Changelog 394 | 395 | This project uses [changesets](https://github.com/changesets/changesets) for versioning and changelog generation. 396 | 397 | 1. Make your changes 398 | 2. Run \`bun changeset\` to create a new changeset 399 | 3. Follow the prompts to describe your changes 400 | 4. Commit the generated changeset file 401 | 5. When ready to release: 402 | - Run \`bun run version\` to update versions and changelog 403 | - Run \`bun run release\` to publish to npm 404 | `; 405 | 406 | await writeFile('README.md', readmeContent); 407 | 408 | // Update .gitignore 409 | if (options.git) { 410 | await writeFile('.gitignore', ` 411 | node_modules 412 | dist 413 | docs 414 | .env 415 | `); 416 | } 417 | 418 | // Initialize git if requested 419 | if (options.git) { 420 | execSync('git init'); 421 | } 422 | 423 | // Install dependencies 424 | spinner.text = 'Installing dependencies...'; 425 | execSync('bun install', { stdio: 'inherit' }); 426 | 427 | spinner.succeed(`Successfully created ${projectName}!`); 428 | console.log('\nNext steps:'); 429 | console.log(` cd ${projectName}`); 430 | console.log(' bun install # Install dependencies'); 431 | console.log(' bun run check # Format and lint code'); 432 | console.log(' bun run test # Run tests'); 433 | console.log(' bun run build # Build the SDK'); 434 | 435 | } catch (error) { 436 | spinner.fail('Failed to create project'); 437 | throw error; 438 | } 439 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2021", 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "sourceMap": true, 9 | "outDir": "./dist", 10 | "rootDir": "./", 11 | 12 | // Strict Type Checking 13 | "strict": true, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "noUnusedLocals": true, 17 | "noUnusedParameters": true, 18 | "noImplicitOverride": true, 19 | 20 | // Module Settings 21 | "esModuleInterop": true, 22 | "resolveJsonModule": true, 23 | "forceConsistentCasingInFileNames": true, 24 | "skipLibCheck": true, 25 | 26 | // Additional Settings 27 | "useDefineForClassFields": true, 28 | "importHelpers": true 29 | }, 30 | "include": ["index.ts", "src/**/*"], 31 | "exclude": [ 32 | "src/**/*.test.ts", 33 | "src/**/*.spec.ts", 34 | "src/test/**/*" 35 | ] 36 | } --------------------------------------------------------------------------------