create-awarizon-app 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +154 -0
- package/package.json +39 -0
- package/templates/expo/.env +1 -0
- package/templates/expo/.env.example +3 -0
- package/templates/expo/_gitignore +5 -0
- package/templates/expo/app/(tabs)/_layout.tsx +24 -0
- package/templates/expo/app/(tabs)/index.tsx +79 -0
- package/templates/expo/app/_layout.tsx +24 -0
- package/templates/expo/app.json +36 -0
- package/templates/expo/package.json +35 -0
- package/templates/expo/tsconfig.json +8 -0
- package/templates/expo-js/.env +1 -0
- package/templates/expo-js/.env.example +3 -0
- package/templates/expo-js/_gitignore +5 -0
- package/templates/expo-js/app/(tabs)/_layout.jsx +24 -0
- package/templates/expo-js/app/(tabs)/index.jsx +81 -0
- package/templates/expo-js/app/_layout.jsx +24 -0
- package/templates/expo-js/app.json +33 -0
- package/templates/expo-js/babel.config.js +6 -0
- package/templates/expo-js/jsconfig.json +12 -0
- package/templates/expo-js/package.json +33 -0
- package/templates/nextjs/.env.example +11 -0
- package/templates/nextjs/.env.local +4 -0
- package/templates/nextjs/_gitignore +6 -0
- package/templates/nextjs/app/globals.css +30 -0
- package/templates/nextjs/app/layout.tsx +29 -0
- package/templates/nextjs/app/page.tsx +168 -0
- package/templates/nextjs/components/ui/Badge.tsx +32 -0
- package/templates/nextjs/components/ui/Button.tsx +43 -0
- package/templates/nextjs/components/ui/Card.tsx +15 -0
- package/templates/nextjs/components/ui/Skeleton.tsx +7 -0
- package/templates/nextjs/components/ui/StatCard.tsx +24 -0
- package/templates/nextjs/lib/awarizon.ts +8 -0
- package/templates/nextjs/lib/utils.ts +3 -0
- package/templates/nextjs/next.config.ts +7 -0
- package/templates/nextjs/package.json +29 -0
- package/templates/nextjs/postcss.config.js +6 -0
- package/templates/nextjs/tailwind.config.ts +19 -0
- package/templates/nextjs/tsconfig.json +21 -0
- package/templates/nextjs-js/.env.example +11 -0
- package/templates/nextjs-js/.env.local +4 -0
- package/templates/nextjs-js/_gitignore +5 -0
- package/templates/nextjs-js/app/globals.css +30 -0
- package/templates/nextjs-js/app/layout.jsx +29 -0
- package/templates/nextjs-js/app/page.jsx +141 -0
- package/templates/nextjs-js/components/ui/Badge.jsx +24 -0
- package/templates/nextjs-js/components/ui/Button.jsx +25 -0
- package/templates/nextjs-js/components/ui/Card.jsx +9 -0
- package/templates/nextjs-js/components/ui/Skeleton.jsx +7 -0
- package/templates/nextjs-js/components/ui/StatCard.jsx +16 -0
- package/templates/nextjs-js/jsconfig.json +21 -0
- package/templates/nextjs-js/lib/awarizon.js +7 -0
- package/templates/nextjs-js/lib/utils.js +3 -0
- package/templates/nextjs-js/next.config.js +6 -0
- package/templates/nextjs-js/package.json +25 -0
- package/templates/nextjs-js/postcss.config.js +6 -0
- package/templates/nextjs-js/tailwind.config.js +16 -0
- package/templates/react/.env +1 -0
- package/templates/react/.env.example +7 -0
- package/templates/react/_gitignore +3 -0
- package/templates/react/index.html +12 -0
- package/templates/react/package.json +28 -0
- package/templates/react/postcss.config.js +6 -0
- package/templates/react/src/App.tsx +166 -0
- package/templates/react/src/components/ui/Badge.tsx +32 -0
- package/templates/react/src/components/ui/Button.tsx +43 -0
- package/templates/react/src/components/ui/Card.tsx +15 -0
- package/templates/react/src/components/ui/Skeleton.tsx +7 -0
- package/templates/react/src/components/ui/StatCard.tsx +24 -0
- package/templates/react/src/index.css +30 -0
- package/templates/react/src/lib/utils.ts +3 -0
- package/templates/react/src/main.tsx +22 -0
- package/templates/react/tailwind.config.js +15 -0
- package/templates/react/tsconfig.app.json +20 -0
- package/templates/react/tsconfig.json +7 -0
- package/templates/react/tsconfig.node.json +15 -0
- package/templates/react/vite.config.ts +6 -0
- package/templates/react-js/.env +1 -0
- package/templates/react-js/.env.example +7 -0
- package/templates/react-js/_gitignore +3 -0
- package/templates/react-js/index.html +12 -0
- package/templates/react-js/jsconfig.json +14 -0
- package/templates/react-js/package.json +25 -0
- package/templates/react-js/postcss.config.js +6 -0
- package/templates/react-js/src/App.jsx +139 -0
- package/templates/react-js/src/components/ui/Badge.jsx +24 -0
- package/templates/react-js/src/components/ui/Button.jsx +25 -0
- package/templates/react-js/src/components/ui/Card.jsx +9 -0
- package/templates/react-js/src/components/ui/Skeleton.jsx +7 -0
- package/templates/react-js/src/components/ui/StatCard.jsx +16 -0
- package/templates/react-js/src/index.css +30 -0
- package/templates/react-js/src/lib/utils.js +3 -0
- package/templates/react-js/src/main.jsx +22 -0
- package/templates/react-js/tailwind.config.js +15 -0
- package/templates/react-js/vite.config.js +6 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import * as p from "@clack/prompts";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
import fs from "fs-extra";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import { execSync } from "child_process";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
11
|
+
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
function detectPackageManager() {
|
|
13
|
+
const ua = process.env.npm_config_user_agent ?? "";
|
|
14
|
+
if (ua.startsWith("pnpm")) return "pnpm";
|
|
15
|
+
if (ua.startsWith("yarn")) return "yarn";
|
|
16
|
+
if (ua.startsWith("bun")) return "bun";
|
|
17
|
+
return "npm";
|
|
18
|
+
}
|
|
19
|
+
function installCmd(pm) {
|
|
20
|
+
return pm === "yarn" ? "yarn" : `${pm} install`;
|
|
21
|
+
}
|
|
22
|
+
function devCmd(pm, template) {
|
|
23
|
+
const script = template === "expo" ? "start" : "dev";
|
|
24
|
+
if (pm === "yarn") return `yarn ${script}`;
|
|
25
|
+
if (pm === "pnpm") return `pnpm ${script}`;
|
|
26
|
+
if (pm === "bun") return `bun run ${script}`;
|
|
27
|
+
return `npm run ${script}`;
|
|
28
|
+
}
|
|
29
|
+
function toPascalCase(str) {
|
|
30
|
+
return str.replace(/[-_\s]+(.)/g, (_, c) => c.toUpperCase()).replace(/^(.)/, (c) => c.toUpperCase());
|
|
31
|
+
}
|
|
32
|
+
async function processTemplate(dir, projectName, apiKey) {
|
|
33
|
+
const pascal = toPascalCase(projectName);
|
|
34
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
35
|
+
for (const entry of entries) {
|
|
36
|
+
const full = path.join(dir, entry.name);
|
|
37
|
+
if (entry.isDirectory()) {
|
|
38
|
+
await processTemplate(full, projectName, apiKey);
|
|
39
|
+
} else {
|
|
40
|
+
const text2 = await fs.readFile(full, "utf-8");
|
|
41
|
+
const replaced = text2.replaceAll("{{project-name}}", projectName).replaceAll("{{ProjectName}}", pascal).replaceAll("{{API_KEY}}", apiKey);
|
|
42
|
+
await fs.writeFile(full, replaced, "utf-8");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function resolveTemplateDir(template, lang) {
|
|
47
|
+
return lang === "js" ? `${template}-js` : template;
|
|
48
|
+
}
|
|
49
|
+
var program = new Command();
|
|
50
|
+
program.name("create-awarizon-app").description("Scaffold a new project with the Awarizon Web3 SDK").version("1.0.0").argument("[project-name]", "Directory name for the new project").option("-t, --template <template>", "Template: nextjs | react | expo").option("-l, --lang <lang>", "Language: ts | js (default: ts, expo always ts)").option("-k, --api-key <key>", "Your Awarizon API key (awz_live_...)").option("--skip-install", "Skip running npm install after scaffolding").option("--pm <pm>", "Package manager: npm | pnpm | yarn | bun").action(async (nameArg, opts) => {
|
|
51
|
+
console.log("");
|
|
52
|
+
p.intro(chalk.bold.white(" create-awarizon-app ") + chalk.dim(" \u2014 Awarizon Web3 SDK"));
|
|
53
|
+
let projectName = nameArg;
|
|
54
|
+
if (!projectName) {
|
|
55
|
+
const res = await p.text({
|
|
56
|
+
message: "Project name",
|
|
57
|
+
placeholder: "my-web3-app",
|
|
58
|
+
validate: (v) => v.trim() ? void 0 : "Project name is required"
|
|
59
|
+
});
|
|
60
|
+
if (p.isCancel(res)) {
|
|
61
|
+
p.cancel("Cancelled.");
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
projectName = res.trim();
|
|
65
|
+
}
|
|
66
|
+
let template = opts.template;
|
|
67
|
+
if (!template) {
|
|
68
|
+
const res = await p.select({
|
|
69
|
+
message: "Which template?",
|
|
70
|
+
options: [
|
|
71
|
+
{ value: "nextjs", label: "Next.js 14", hint: "App Router \xB7 @awarizon/react hooks" },
|
|
72
|
+
{ value: "react", label: "React + Vite", hint: "SPA \xB7 @awarizon/react hooks" },
|
|
73
|
+
{ value: "expo", label: "Expo (React Native)", hint: "iOS + Android \xB7 TypeScript" }
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
if (p.isCancel(res)) {
|
|
77
|
+
p.cancel("Cancelled.");
|
|
78
|
+
process.exit(0);
|
|
79
|
+
}
|
|
80
|
+
template = res;
|
|
81
|
+
}
|
|
82
|
+
let lang = opts.lang ?? "ts";
|
|
83
|
+
if (!opts.lang) {
|
|
84
|
+
const res = await p.select({
|
|
85
|
+
message: "Language",
|
|
86
|
+
options: [
|
|
87
|
+
{ value: "ts", label: "TypeScript", hint: "Recommended \u2014 full type safety" },
|
|
88
|
+
{ value: "js", label: "JavaScript", hint: "Plain JS with JSDoc hints" }
|
|
89
|
+
]
|
|
90
|
+
});
|
|
91
|
+
if (p.isCancel(res)) {
|
|
92
|
+
p.cancel("Cancelled.");
|
|
93
|
+
process.exit(0);
|
|
94
|
+
}
|
|
95
|
+
lang = res;
|
|
96
|
+
}
|
|
97
|
+
let apiKey = opts.apiKey ?? "";
|
|
98
|
+
if (!apiKey) {
|
|
99
|
+
const res = await p.text({
|
|
100
|
+
message: "Awarizon API key",
|
|
101
|
+
placeholder: "awz_live_... (get one at awarizon.com/dashboard)",
|
|
102
|
+
validate: () => void 0
|
|
103
|
+
// optional — can skip
|
|
104
|
+
});
|
|
105
|
+
if (p.isCancel(res)) {
|
|
106
|
+
p.cancel("Cancelled.");
|
|
107
|
+
process.exit(0);
|
|
108
|
+
}
|
|
109
|
+
apiKey = (res ?? "").trim();
|
|
110
|
+
}
|
|
111
|
+
const pm = opts.pm ?? detectPackageManager();
|
|
112
|
+
const dest = path.resolve(process.cwd(), projectName);
|
|
113
|
+
if (await fs.pathExists(dest)) {
|
|
114
|
+
p.log.error(`Directory "${projectName}" already exists.`);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
const templateKey = resolveTemplateDir(template, lang);
|
|
118
|
+
const templateDir = path.join(__dirname, "..", "templates", templateKey);
|
|
119
|
+
if (!await fs.pathExists(templateDir)) {
|
|
120
|
+
p.log.error(`Template "${templateKey}" not found. This is a bug \u2014 please report it.`);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
const spinner2 = p.spinner();
|
|
124
|
+
spinner2.start("Copying template\u2026");
|
|
125
|
+
await fs.copy(templateDir, dest);
|
|
126
|
+
const gitignoreSrc = path.join(dest, "_gitignore");
|
|
127
|
+
if (await fs.pathExists(gitignoreSrc)) {
|
|
128
|
+
await fs.rename(gitignoreSrc, path.join(dest, ".gitignore"));
|
|
129
|
+
}
|
|
130
|
+
await processTemplate(dest, projectName, apiKey);
|
|
131
|
+
spinner2.stop("Template copied.");
|
|
132
|
+
if (!opts.skipInstall) {
|
|
133
|
+
spinner2.start(`Installing dependencies with ${pm}\u2026`);
|
|
134
|
+
try {
|
|
135
|
+
execSync(installCmd(pm), { cwd: dest, stdio: "pipe" });
|
|
136
|
+
spinner2.stop("Dependencies installed.");
|
|
137
|
+
} catch {
|
|
138
|
+
spinner2.stop(chalk.yellow("Install failed \u2014 run it manually."));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const langLabel = lang === "js" ? "JavaScript" : "TypeScript";
|
|
142
|
+
const templateLabels = {
|
|
143
|
+
nextjs: "Next.js 14",
|
|
144
|
+
react: "React + Vite",
|
|
145
|
+
expo: "Expo (React Native)"
|
|
146
|
+
};
|
|
147
|
+
p.outro(
|
|
148
|
+
chalk.green("\u2713 Project ready!") + "\n\n" + chalk.dim(` Template: `) + chalk.white(`${templateLabels[template]} \xB7 ${langLabel}`) + "\n" + chalk.bold("\n Next steps:\n") + chalk.dim(` cd ${projectName}
|
|
149
|
+
`) + (apiKey ? "" : chalk.dim(` # Add your API key to ${template === "expo" ? ".env" : ".env.local"}
|
|
150
|
+
`)) + chalk.dim(` ${devCmd(pm, template)}
|
|
151
|
+
`) + "\n" + chalk.dim(" Docs: ") + chalk.cyan("https://awarizon.com/docs") + "\n" + chalk.dim(" API keys: ") + chalk.cyan("https://awarizon.com/dashboard/api-keys")
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
program.parse(process.argv);
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-awarizon-app",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Scaffold a new project with the Awarizon Web3 SDK",
|
|
5
|
+
"keywords": ["awarizon", "web3", "evm", "create-app", "scaffold"],
|
|
6
|
+
"homepage": "https://awarizon.com/sdk",
|
|
7
|
+
"repository": "https://github.com/Awaizon-ltd/awarizon-sdk-core",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"bin": {
|
|
11
|
+
"create-awarizon-app": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"templates"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup",
|
|
19
|
+
"dev": "tsup --watch",
|
|
20
|
+
"clean": "rimraf dist"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@clack/prompts": "^0.9.1",
|
|
24
|
+
"chalk": "^5.3.0",
|
|
25
|
+
"commander": "^12.1.0",
|
|
26
|
+
"fs-extra": "^11.2.0",
|
|
27
|
+
"ora": "^8.0.1"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/fs-extra": "^11.0.4",
|
|
31
|
+
"@types/node": "^20.0.0",
|
|
32
|
+
"rimraf": "^5.0.0",
|
|
33
|
+
"tsup": "^8.0.0",
|
|
34
|
+
"typescript": "^5.5.0"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
EXPO_PUBLIC_AWARIZON_API_KEY={{API_KEY}}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Tabs } from 'expo-router'
|
|
2
|
+
import { Platform } from 'react-native'
|
|
3
|
+
|
|
4
|
+
export default function TabLayout() {
|
|
5
|
+
return (
|
|
6
|
+
<Tabs
|
|
7
|
+
screenOptions={{
|
|
8
|
+
tabBarActiveTintColor: '#6366f1',
|
|
9
|
+
tabBarInactiveTintColor: '#6b7280',
|
|
10
|
+
tabBarStyle: {
|
|
11
|
+
backgroundColor: '#111',
|
|
12
|
+
borderTopColor: '#1f1f1f',
|
|
13
|
+
height: Platform.OS === 'ios' ? 88 : 60,
|
|
14
|
+
paddingBottom: Platform.OS === 'ios' ? 28 : 8,
|
|
15
|
+
},
|
|
16
|
+
headerStyle: { backgroundColor: '#000' },
|
|
17
|
+
headerTintColor: '#fff',
|
|
18
|
+
}}
|
|
19
|
+
>
|
|
20
|
+
<Tabs.Screen name="index" options={{ title: 'Home' }} />
|
|
21
|
+
<Tabs.Screen name="explorer" options={{ title: 'Explorer' }} />
|
|
22
|
+
</Tabs>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ScrollView, View, Text, StyleSheet, ActivityIndicator } from 'react-native'
|
|
2
|
+
import { useReadContract } from '@awarizon/react-native'
|
|
3
|
+
|
|
4
|
+
const USDC_BASE = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
|
|
5
|
+
const ERC20_ABI = [
|
|
6
|
+
{ name: 'name', type: 'function', inputs: [], outputs: [{ type: 'string' }], stateMutability: 'view' },
|
|
7
|
+
{ name: 'symbol', type: 'function', inputs: [], outputs: [{ type: 'string' }], stateMutability: 'view' },
|
|
8
|
+
{ name: 'decimals', type: 'function', inputs: [], outputs: [{ type: 'uint8' }], stateMutability: 'view' },
|
|
9
|
+
{ name: 'totalSupply', type: 'function', inputs: [], outputs: [{ type: 'uint256' }], stateMutability: 'view' },
|
|
10
|
+
] as const
|
|
11
|
+
|
|
12
|
+
function usdc(fn: string) {
|
|
13
|
+
return useReadContract({ address: USDC_BASE, abi: ERC20_ABI, method: fn as never })
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function Row({ label, value }: { label: string; value?: string }) {
|
|
17
|
+
return (
|
|
18
|
+
<View style={s.row}>
|
|
19
|
+
<Text style={s.label}>{label}</Text>
|
|
20
|
+
{value === undefined
|
|
21
|
+
? <ActivityIndicator size="small" color="#6366f1" />
|
|
22
|
+
: <Text style={s.value}>{value}</Text>}
|
|
23
|
+
</View>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default function HomeScreen() {
|
|
28
|
+
const { data: name } = usdc('name')
|
|
29
|
+
const { data: symbol } = usdc('symbol')
|
|
30
|
+
const { data: decimals } = usdc('decimals')
|
|
31
|
+
const { data: totalSupply } = usdc('totalSupply')
|
|
32
|
+
|
|
33
|
+
const formatted =
|
|
34
|
+
totalSupply !== undefined && decimals !== undefined
|
|
35
|
+
? (Number(totalSupply) / 10 ** Number(decimals)).toLocaleString(undefined, { maximumFractionDigits: 2 })
|
|
36
|
+
: undefined
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<ScrollView style={s.bg} contentContainerStyle={s.container}>
|
|
40
|
+
<View style={s.hero}>
|
|
41
|
+
<Text style={s.badge}>{{ProjectName}}</Text>
|
|
42
|
+
<Text style={s.heading}>Live on-chain data</Text>
|
|
43
|
+
<Text style={s.sub}>Reading USDC on Base — no backend required.</Text>
|
|
44
|
+
</View>
|
|
45
|
+
|
|
46
|
+
<View style={s.card}>
|
|
47
|
+
<Text style={s.cardTitle}>USDC — Base</Text>
|
|
48
|
+
<Row label="Name" value={name as string | undefined} />
|
|
49
|
+
<Row label="Symbol" value={symbol as string | undefined} />
|
|
50
|
+
<Row label="Decimals" value={decimals !== undefined ? String(decimals) : undefined} />
|
|
51
|
+
<Row label="Total Supply" value={formatted} />
|
|
52
|
+
</View>
|
|
53
|
+
|
|
54
|
+
<View style={s.card}>
|
|
55
|
+
<Text style={s.cardTitle}>Next steps</Text>
|
|
56
|
+
<Text style={s.step}>1. Replace USDC_BASE with your contract address</Text>
|
|
57
|
+
<Text style={s.step}>2. Swap ERC20_ABI for your contract ABI</Text>
|
|
58
|
+
<Text style={s.step}>3. Change the chain in app/_layout.tsx</Text>
|
|
59
|
+
<Text style={s.step}>4. Use <Text style={s.code}>useWriteContract</Text> for transactions</Text>
|
|
60
|
+
</View>
|
|
61
|
+
</ScrollView>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const s = StyleSheet.create({
|
|
66
|
+
bg: { flex: 1, backgroundColor: '#0a0a0a' },
|
|
67
|
+
container: { padding: 20, paddingBottom: 40 },
|
|
68
|
+
hero: { marginBottom: 24 },
|
|
69
|
+
badge: { color: '#6366f1', fontSize: 12, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 1.5, marginBottom: 8 },
|
|
70
|
+
heading: { color: '#fff', fontSize: 28, fontWeight: '800', marginBottom: 6 },
|
|
71
|
+
sub: { color: '#9ca3af', fontSize: 15, lineHeight: 22 },
|
|
72
|
+
card: { backgroundColor: '#111', borderWidth: 1, borderColor: '#1f1f1f', borderRadius: 12, padding: 16, marginBottom: 16 },
|
|
73
|
+
cardTitle: { color: '#fff', fontWeight: '700', fontSize: 15, marginBottom: 12 },
|
|
74
|
+
row: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 8, borderBottomWidth: 1, borderBottomColor: '#1f1f1f' },
|
|
75
|
+
label: { color: '#9ca3af', fontSize: 13 },
|
|
76
|
+
value: { color: '#e5e7eb', fontSize: 13, fontWeight: '500', fontFamily: 'monospace' },
|
|
77
|
+
step: { color: '#9ca3af', fontSize: 13, lineHeight: 22, marginBottom: 4 },
|
|
78
|
+
code: { color: '#6366f1', fontFamily: 'monospace' },
|
|
79
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Stack } from 'expo-router'
|
|
2
|
+
import { AwarizonProvider } from '@awarizon/react-native'
|
|
3
|
+
|
|
4
|
+
export default function RootLayout() {
|
|
5
|
+
return (
|
|
6
|
+
/*
|
|
7
|
+
AwarizonProvider makes the SDK available throughout the app.
|
|
8
|
+
chain: EVM network — base, ethereum, polygon, etc.
|
|
9
|
+
apiKey: from EXPO_PUBLIC_AWARIZON_API_KEY in .env
|
|
10
|
+
*/
|
|
11
|
+
<AwarizonProvider
|
|
12
|
+
chain="base"
|
|
13
|
+
apiKey={process.env.EXPO_PUBLIC_AWARIZON_API_KEY!}
|
|
14
|
+
>
|
|
15
|
+
<Stack
|
|
16
|
+
screenOptions={{
|
|
17
|
+
headerStyle: { backgroundColor: '#000' },
|
|
18
|
+
headerTintColor: '#fff',
|
|
19
|
+
contentStyle: { backgroundColor: '#0a0a0a' },
|
|
20
|
+
}}
|
|
21
|
+
/>
|
|
22
|
+
</AwarizonProvider>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"expo": {
|
|
3
|
+
"name": "{{ProjectName}}",
|
|
4
|
+
"slug": "{{project-name}}",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"orientation": "portrait",
|
|
7
|
+
"icon": "./assets/images/icon.png",
|
|
8
|
+
"scheme": "{{project-name}}",
|
|
9
|
+
"userInterfaceStyle": "automatic",
|
|
10
|
+
"splash": {
|
|
11
|
+
"image": "./assets/images/splash.png",
|
|
12
|
+
"resizeMode": "contain",
|
|
13
|
+
"backgroundColor": "#000000"
|
|
14
|
+
},
|
|
15
|
+
"ios": {
|
|
16
|
+
"supportsTablet": true,
|
|
17
|
+
"bundleIdentifier": "com.awarizon.{{project-name}}"
|
|
18
|
+
},
|
|
19
|
+
"android": {
|
|
20
|
+
"adaptiveIcon": {
|
|
21
|
+
"foregroundImage": "./assets/images/adaptive-icon.png",
|
|
22
|
+
"backgroundColor": "#000000"
|
|
23
|
+
},
|
|
24
|
+
"package": "com.awarizon.{{project-name}}"
|
|
25
|
+
},
|
|
26
|
+
"web": {
|
|
27
|
+
"bundler": "metro",
|
|
28
|
+
"output": "static",
|
|
29
|
+
"favicon": "./assets/images/favicon.png"
|
|
30
|
+
},
|
|
31
|
+
"plugins": ["expo-router", "expo-secure-store"],
|
|
32
|
+
"experiments": {
|
|
33
|
+
"typedRoutes": true
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{project-name}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "expo-router/entry",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"start": "expo start",
|
|
7
|
+
"android": "expo start --android",
|
|
8
|
+
"ios": "expo start --ios",
|
|
9
|
+
"web": "expo start --web"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@awarizon/react-native": "latest",
|
|
13
|
+
"@awarizon/web3": "latest",
|
|
14
|
+
"@expo/vector-icons": "^14.0.2",
|
|
15
|
+
"expo": "~51.0.0",
|
|
16
|
+
"expo-constants": "~16.0.2",
|
|
17
|
+
"expo-font": "~12.0.9",
|
|
18
|
+
"expo-linking": "~6.3.1",
|
|
19
|
+
"expo-router": "~3.5.17",
|
|
20
|
+
"expo-secure-store": "~13.0.2",
|
|
21
|
+
"expo-splash-screen": "~0.27.5",
|
|
22
|
+
"expo-status-bar": "~1.12.1",
|
|
23
|
+
"expo-system-ui": "~3.0.7",
|
|
24
|
+
"react": "18.2.0",
|
|
25
|
+
"react-dom": "18.2.0",
|
|
26
|
+
"react-native": "0.74.5",
|
|
27
|
+
"react-native-safe-area-context": "4.10.5",
|
|
28
|
+
"react-native-screens": "3.31.1"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@babel/core": "^7.24.0",
|
|
32
|
+
"@types/react": "~18.2.45",
|
|
33
|
+
"typescript": "^5.3.3"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
EXPO_PUBLIC_AWARIZON_API_KEY={{API_KEY}}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Tabs } from 'expo-router'
|
|
2
|
+
import { Platform } from 'react-native'
|
|
3
|
+
|
|
4
|
+
export default function TabLayout() {
|
|
5
|
+
return (
|
|
6
|
+
<Tabs
|
|
7
|
+
screenOptions={{
|
|
8
|
+
tabBarActiveTintColor: '#6366f1',
|
|
9
|
+
tabBarInactiveTintColor: '#6b7280',
|
|
10
|
+
tabBarStyle: {
|
|
11
|
+
backgroundColor: '#111',
|
|
12
|
+
borderTopColor: '#1f1f1f',
|
|
13
|
+
height: Platform.OS === 'ios' ? 88 : 60,
|
|
14
|
+
paddingBottom: Platform.OS === 'ios' ? 28 : 8,
|
|
15
|
+
},
|
|
16
|
+
headerStyle: { backgroundColor: '#000' },
|
|
17
|
+
headerTintColor: '#fff',
|
|
18
|
+
}}
|
|
19
|
+
>
|
|
20
|
+
<Tabs.Screen name="index" options={{ title: 'Home' }} />
|
|
21
|
+
<Tabs.Screen name="explorer" options={{ title: 'Explorer' }} />
|
|
22
|
+
</Tabs>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { ScrollView, View, Text, StyleSheet, ActivityIndicator } from 'react-native'
|
|
2
|
+
import { useReadContract } from '@awarizon/react-native'
|
|
3
|
+
|
|
4
|
+
const USDC_BASE = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
|
|
5
|
+
|
|
6
|
+
/** @type {readonly object[]} */
|
|
7
|
+
const ERC20_ABI = [
|
|
8
|
+
{ name: 'name', type: 'function', inputs: [], outputs: [{ type: 'string' }], stateMutability: 'view' },
|
|
9
|
+
{ name: 'symbol', type: 'function', inputs: [], outputs: [{ type: 'string' }], stateMutability: 'view' },
|
|
10
|
+
{ name: 'decimals', type: 'function', inputs: [], outputs: [{ type: 'uint8' }], stateMutability: 'view' },
|
|
11
|
+
{ name: 'totalSupply', type: 'function', inputs: [], outputs: [{ type: 'uint256' }], stateMutability: 'view' },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
function usdc(fn) {
|
|
15
|
+
return useReadContract({ address: USDC_BASE, abi: ERC20_ABI, method: fn })
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function Row({ label, value }) {
|
|
19
|
+
return (
|
|
20
|
+
<View style={s.row}>
|
|
21
|
+
<Text style={s.label}>{label}</Text>
|
|
22
|
+
{value === undefined
|
|
23
|
+
? <ActivityIndicator size="small" color="#6366f1" />
|
|
24
|
+
: <Text style={s.value}>{value}</Text>}
|
|
25
|
+
</View>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default function HomeScreen() {
|
|
30
|
+
const { data: name } = usdc('name')
|
|
31
|
+
const { data: symbol } = usdc('symbol')
|
|
32
|
+
const { data: decimals } = usdc('decimals')
|
|
33
|
+
const { data: totalSupply } = usdc('totalSupply')
|
|
34
|
+
|
|
35
|
+
const formatted =
|
|
36
|
+
totalSupply !== undefined && decimals !== undefined
|
|
37
|
+
? (Number(totalSupply) / 10 ** Number(decimals)).toLocaleString(undefined, { maximumFractionDigits: 2 })
|
|
38
|
+
: undefined
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<ScrollView style={s.bg} contentContainerStyle={s.container}>
|
|
42
|
+
<View style={s.hero}>
|
|
43
|
+
<Text style={s.badge}>{{ProjectName}}</Text>
|
|
44
|
+
<Text style={s.heading}>Live on-chain data</Text>
|
|
45
|
+
<Text style={s.sub}>Reading USDC on Base — no backend required.</Text>
|
|
46
|
+
</View>
|
|
47
|
+
|
|
48
|
+
<View style={s.card}>
|
|
49
|
+
<Text style={s.cardTitle}>USDC — Base</Text>
|
|
50
|
+
<Row label="Name" value={name !== undefined ? String(name) : undefined} />
|
|
51
|
+
<Row label="Symbol" value={symbol !== undefined ? String(symbol) : undefined} />
|
|
52
|
+
<Row label="Decimals" value={decimals !== undefined ? String(decimals) : undefined} />
|
|
53
|
+
<Row label="Total Supply" value={formatted} />
|
|
54
|
+
</View>
|
|
55
|
+
|
|
56
|
+
<View style={s.card}>
|
|
57
|
+
<Text style={s.cardTitle}>Next steps</Text>
|
|
58
|
+
<Text style={s.step}>1. Replace USDC_BASE with your contract address</Text>
|
|
59
|
+
<Text style={s.step}>2. Swap ERC20_ABI for your contract ABI</Text>
|
|
60
|
+
<Text style={s.step}>3. Change the chain in app/_layout.jsx</Text>
|
|
61
|
+
<Text style={s.step}>4. Use <Text style={s.code}>useWriteContract</Text> for transactions</Text>
|
|
62
|
+
</View>
|
|
63
|
+
</ScrollView>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const s = StyleSheet.create({
|
|
68
|
+
bg: { flex: 1, backgroundColor: '#0a0a0a' },
|
|
69
|
+
container: { padding: 20, paddingBottom: 40 },
|
|
70
|
+
hero: { marginBottom: 24 },
|
|
71
|
+
badge: { color: '#6366f1', fontSize: 12, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 1.5, marginBottom: 8 },
|
|
72
|
+
heading: { color: '#fff', fontSize: 28, fontWeight: '800', marginBottom: 6 },
|
|
73
|
+
sub: { color: '#9ca3af', fontSize: 15, lineHeight: 22 },
|
|
74
|
+
card: { backgroundColor: '#111', borderWidth: 1, borderColor: '#1f1f1f', borderRadius: 12, padding: 16, marginBottom: 16 },
|
|
75
|
+
cardTitle: { color: '#fff', fontWeight: '700', fontSize: 15, marginBottom: 12 },
|
|
76
|
+
row: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 8, borderBottomWidth: 1, borderBottomColor: '#1f1f1f' },
|
|
77
|
+
label: { color: '#9ca3af', fontSize: 13 },
|
|
78
|
+
value: { color: '#e5e7eb', fontSize: 13, fontWeight: '500', fontFamily: 'monospace' },
|
|
79
|
+
step: { color: '#9ca3af', fontSize: 13, lineHeight: 22, marginBottom: 4 },
|
|
80
|
+
code: { color: '#6366f1', fontFamily: 'monospace' },
|
|
81
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Stack } from 'expo-router'
|
|
2
|
+
import { AwarizonProvider } from '@awarizon/react-native'
|
|
3
|
+
|
|
4
|
+
export default function RootLayout() {
|
|
5
|
+
return (
|
|
6
|
+
/*
|
|
7
|
+
AwarizonProvider makes the SDK available throughout the app.
|
|
8
|
+
chain: EVM network — base, ethereum, polygon, etc.
|
|
9
|
+
apiKey: from EXPO_PUBLIC_AWARIZON_API_KEY in .env
|
|
10
|
+
*/
|
|
11
|
+
<AwarizonProvider
|
|
12
|
+
chain="base"
|
|
13
|
+
apiKey={process.env.EXPO_PUBLIC_AWARIZON_API_KEY}
|
|
14
|
+
>
|
|
15
|
+
<Stack
|
|
16
|
+
screenOptions={{
|
|
17
|
+
headerStyle: { backgroundColor: '#000' },
|
|
18
|
+
headerTintColor: '#fff',
|
|
19
|
+
contentStyle: { backgroundColor: '#0a0a0a' },
|
|
20
|
+
}}
|
|
21
|
+
/>
|
|
22
|
+
</AwarizonProvider>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"expo": {
|
|
3
|
+
"name": "{{ProjectName}}",
|
|
4
|
+
"slug": "{{project-name}}",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"orientation": "portrait",
|
|
7
|
+
"icon": "./assets/images/icon.png",
|
|
8
|
+
"scheme": "{{project-name}}",
|
|
9
|
+
"userInterfaceStyle": "automatic",
|
|
10
|
+
"splash": {
|
|
11
|
+
"image": "./assets/images/splash.png",
|
|
12
|
+
"resizeMode": "contain",
|
|
13
|
+
"backgroundColor": "#000000"
|
|
14
|
+
},
|
|
15
|
+
"ios": {
|
|
16
|
+
"supportsTablet": true,
|
|
17
|
+
"bundleIdentifier": "com.awarizon.{{project-name}}"
|
|
18
|
+
},
|
|
19
|
+
"android": {
|
|
20
|
+
"adaptiveIcon": {
|
|
21
|
+
"foregroundImage": "./assets/images/adaptive-icon.png",
|
|
22
|
+
"backgroundColor": "#000000"
|
|
23
|
+
},
|
|
24
|
+
"package": "com.awarizon.{{project-name}}"
|
|
25
|
+
},
|
|
26
|
+
"web": {
|
|
27
|
+
"bundler": "metro",
|
|
28
|
+
"output": "static",
|
|
29
|
+
"favicon": "./assets/images/favicon.png"
|
|
30
|
+
},
|
|
31
|
+
"plugins": ["expo-router", "expo-secure-store"]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{project-name}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "expo-router/entry",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"start": "expo start",
|
|
7
|
+
"android": "expo start --android",
|
|
8
|
+
"ios": "expo start --ios",
|
|
9
|
+
"web": "expo start --web"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@awarizon/react-native": "latest",
|
|
13
|
+
"@awarizon/web3": "latest",
|
|
14
|
+
"@expo/vector-icons": "^14.0.2",
|
|
15
|
+
"expo": "~51.0.0",
|
|
16
|
+
"expo-constants": "~16.0.2",
|
|
17
|
+
"expo-font": "~12.0.9",
|
|
18
|
+
"expo-linking": "~6.3.1",
|
|
19
|
+
"expo-router": "~3.5.17",
|
|
20
|
+
"expo-secure-store": "~13.0.2",
|
|
21
|
+
"expo-splash-screen": "~0.27.5",
|
|
22
|
+
"expo-status-bar": "~1.12.1",
|
|
23
|
+
"expo-system-ui": "~3.0.7",
|
|
24
|
+
"react": "18.2.0",
|
|
25
|
+
"react-dom": "18.2.0",
|
|
26
|
+
"react-native": "0.74.5",
|
|
27
|
+
"react-native-safe-area-context": "4.10.5",
|
|
28
|
+
"react-native-screens": "3.31.1"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@babel/core": "^7.24.0"
|
|
32
|
+
}
|
|
33
|
+
}
|