create-sbc-app 0.1.2 → 0.1.3

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/README.md CHANGED
@@ -105,6 +105,8 @@ The template includes comprehensive environment configuration:
105
105
  ```bash
106
106
  # Your SBC API key (get from SBC dashboard)
107
107
  VITE_SBC_API_KEY=your_api_key_here
108
+ # "base" or "baseSepolia"
109
+ VITE_CHAIN="baseSepolia"
108
110
  ```
109
111
 
110
112
  ## 📱 UI Components
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-sbc-app",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Scaffold a new SBC App Kit project with one command.",
5
5
  "bin": {
6
6
  "create-sbc-app": "bin/cli.js"
@@ -9,7 +9,14 @@
9
9
  "build": "tsc",
10
10
  "dev": "tsc --watch",
11
11
  "start": "node bin/cli.js",
12
- "prepublishOnly": "npm run build"
12
+ "prepublishOnly": "npm run build",
13
+ "preversion": "npm run build && npm run test-pack",
14
+ "test-pack": "npm pack --dry-run",
15
+ "test-cli": "mkdir -p test-cli && cd test-cli && node ../bin/cli.js test-app --template react && rm -rf test-cli",
16
+ "prepare-publish": "npm run build && npm run test-pack && npm run test-cli",
17
+ "publish-patch": "npm run prepare-publish && npm version patch && npm publish",
18
+ "publish-minor": "npm run prepare-publish && npm version minor && npm publish",
19
+ "publish-major": "npm run prepare-publish && npm version major && npm publish"
13
20
  },
14
21
  "type": "module",
15
22
  "dependencies": {
@@ -1,2 +1,3 @@
1
1
  # SBC App Kit Configuration
2
+ VITE_CHAIN="baseSepolia"
2
3
  VITE_SBC_API_KEY={{apiKey}}
@@ -1,15 +1,41 @@
1
1
  import { useState, useEffect, useRef, createContext, useContext } from 'react';
2
2
  import { SbcProvider, WalletButton, useSbcApp, useUserOperation } from '@stablecoin.xyz/react';
3
- import { {{chain}} } from 'viem/chains';
3
+ import { base, baseSepolia } from 'viem/chains';
4
4
  import { createPublicClient, http, getAddress, parseSignature, WalletClient, PublicClient } from 'viem';
5
5
  import { parseUnits, encodeFunctionData, erc20Abi } from 'viem';
6
6
  import './App.css';
7
7
 
8
- // SBC Token Configuration
9
- const SBC_TOKEN_ADDRESS = '0xf9FB20B8E097904f0aB7d12e9DbeE88f2dcd0F16';
10
- const SBC_DECIMALS = 6;
8
+ // Chain selection helpers
9
+ const chain = (import.meta.env.VITE_CHAIN === 'base') ? base : baseSepolia;
11
10
 
12
- const publicClient = createPublicClient({ chain: {{chain}}, transport: http() });
11
+ const SBC_TOKEN_ADDRESS = (chain) => {
12
+ if (chain.id === baseSepolia.id) {
13
+ return '0xf9FB20B8E097904f0aB7d12e9DbeE88f2dcd0F16';
14
+ } else if (chain.id === base.id) {
15
+ return '0xfdcC3dd6671eaB0709A4C0f3F53De9a333d80798';
16
+ }
17
+ throw new Error('Unsupported chain');
18
+ };
19
+
20
+ const SBC_DECIMALS = (chain) => {
21
+ if (chain.id === baseSepolia.id) {
22
+ return 6;
23
+ } else if (chain.id === base.id) {
24
+ return 18;
25
+ }
26
+ throw new Error('Unsupported chain');
27
+ };
28
+
29
+ const chainExplorer = (chain) => {
30
+ if (chain.id === baseSepolia.id) {
31
+ return 'https://sepolia.basescan.org';
32
+ } else if (chain.id === base.id) {
33
+ return 'https://basescan.org';
34
+ }
35
+ throw new Error('Unsupported chain');
36
+ };
37
+
38
+ const publicClient = createPublicClient({ chain, transport: http() });
13
39
 
14
40
  const erc20PermitAbi = [
15
41
  ...erc20Abi,
@@ -63,6 +89,10 @@ function WalletStatus({ onDisconnect }: { onDisconnect: () => void }) {
63
89
  <label>Connection:</label>
64
90
  <div className="value">Connected via wallet extension</div>
65
91
  </div>
92
+ <div className="info-row">
93
+ <label>Chain:</label>
94
+ <div className="value">{chain.name}</div>
95
+ </div>
66
96
  </div>
67
97
  );
68
98
  }
@@ -81,7 +111,7 @@ function SmartAccountInfo() {
81
111
  setIsLoadingBalance(true);
82
112
  try {
83
113
  const balance = await publicClient.readContract({
84
- address: SBC_TOKEN_ADDRESS as `0x${string}`,
114
+ address: SBC_TOKEN_ADDRESS(chain) as `0x${string}`,
85
115
  abi: erc20Abi,
86
116
  functionName: 'balanceOf',
87
117
  args: [account.address as `0x${string}`],
@@ -107,7 +137,7 @@ function SmartAccountInfo() {
107
137
  setIsLoadingBalance(true);
108
138
  try {
109
139
  const balance = await publicClient.readContract({
110
- address: SBC_TOKEN_ADDRESS as `0x${string}`,
140
+ address: SBC_TOKEN_ADDRESS(chain) as `0x${string}`,
111
141
  abi: erc20Abi,
112
142
  functionName: 'balanceOf',
113
143
  args: [account.address as `0x${string}`],
@@ -138,7 +168,7 @@ function SmartAccountInfo() {
138
168
  const formatSbcBalance = (balance: string | null): string => {
139
169
  if (!balance) return '0.00';
140
170
  try {
141
- return (Number(balance) / Math.pow(10, SBC_DECIMALS)).toFixed(2);
171
+ return (Number(balance) / Math.pow(10, SBC_DECIMALS(chain))).toFixed(2);
142
172
  } catch {
143
173
  return '0.00';
144
174
  }
@@ -198,7 +228,7 @@ function SendSBCForm() {
198
228
  try {
199
229
  const ownerChecksum = getAddress(ownerAddress);
200
230
  const spenderChecksum = getAddress(account.address);
201
- const value = parseUnits('1', SBC_DECIMALS); // Send 1 SBC
231
+ const value = parseUnits('1', SBC_DECIMALS(chain)); // Send 1 SBC
202
232
  const deadline = Math.floor(Date.now() / 1000) + 60 * 30; // 30 min
203
233
 
204
234
  const signature = await getPermitSignature({
@@ -207,8 +237,8 @@ function SendSBCForm() {
207
237
  owner: ownerChecksum,
208
238
  spender: spenderChecksum,
209
239
  value,
210
- tokenAddress: SBC_TOKEN_ADDRESS,
211
- chainId: {{chain}}.id,
240
+ tokenAddress: SBC_TOKEN_ADDRESS(chain),
241
+ chainId: chain.id,
212
242
  deadline,
213
243
  });
214
244
 
@@ -231,8 +261,8 @@ function SendSBCForm() {
231
261
 
232
262
  await sendUserOperation({
233
263
  calls: [
234
- { to: SBC_TOKEN_ADDRESS as `0x${string}`, data: permitCallData },
235
- { to: SBC_TOKEN_ADDRESS as `0x${string}`, data: transferFromCallData },
264
+ { to: SBC_TOKEN_ADDRESS(chain) as `0x${string}`, data: permitCallData },
265
+ { to: SBC_TOKEN_ADDRESS(chain) as `0x${string}`, data: transferFromCallData },
236
266
  ],
237
267
  });
238
268
  } catch (err) {
@@ -286,7 +316,7 @@ function SendSBCForm() {
286
316
  <div className="success-message">
287
317
  <p>✅ Transaction Successful!</p>
288
318
  <a
289
- href={`https://sepolia.basescan.org/tx/${data.transactionHash}`}
319
+ href={`${chainExplorer(chain)}/tx/${data.transactionHash}`}
290
320
  target="_blank"
291
321
  rel="noopener noreferrer"
292
322
  >
@@ -369,7 +399,7 @@ function ThemeToggle() {
369
399
  export default function App() {
370
400
  const sbcConfig = {
371
401
  apiKey: import.meta.env.VITE_SBC_API_KEY || '{{apiKey}}',
372
- chain: {{chain}},
402
+ chain,
373
403
  wallet: 'auto' as const,
374
404
  debug: true,
375
405
  walletOptions: { autoConnect: false },
@@ -462,7 +492,7 @@ async function getPermitSignature({
462
492
  name: tokenName as string,
463
493
  version: '1',
464
494
  chainId: BigInt(chainId),
465
- verifyingContract: SBC_TOKEN_ADDRESS as `0x${string}`,
495
+ verifyingContract: tokenAddress as `0x${string}`,
466
496
  };
467
497
 
468
498
  const types = {