create-avalanche-app 0.1.4 → 0.1.5
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 +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/l1-launch/CLAUDE.md +91 -0
- package/templates/l1-launch/README.md +45 -0
- package/templates/l1-launch/app/globals.css +95 -0
- package/templates/l1-launch/app/layout.tsx +23 -0
- package/templates/l1-launch/app/page.tsx +5 -0
- package/templates/l1-launch/app/providers.tsx +22 -0
- package/templates/l1-launch/components/demo.tsx +396 -0
- package/templates/l1-launch/contracts/foundry.toml +9 -0
- package/templates/l1-launch/contracts/src/AvaKitToken.sol +53 -0
- package/templates/l1-launch/cursor/rules/avakit.mdc +36 -0
- package/templates/l1-launch/env.example +9 -0
- package/templates/l1-launch/gitignore +15 -0
- package/templates/l1-launch/l1.config.json +10 -0
- package/templates/l1-launch/lib/l1.ts +40 -0
- package/templates/l1-launch/lib/token-artifact.ts +239 -0
- package/templates/l1-launch/llms.txt +31 -0
- package/templates/l1-launch/manifest.json +6 -0
- package/templates/l1-launch/next.config.ts +7 -0
- package/templates/l1-launch/package.json +34 -0
- package/templates/l1-launch/pnpm-workspace.yaml +11 -0
- package/templates/l1-launch/postcss.config.mjs +7 -0
- package/templates/l1-launch/scripts/l1-fuji.sh +100 -0
- package/templates/l1-launch/scripts/l1.sh +108 -0
- package/templates/l1-launch/tsconfig.json +23 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
// Auto-generated from contracts/src/AvaKitToken.sol via `forge build`.
|
|
2
|
+
// Re-generate after editing the contract: cd contracts && forge build, then
|
|
3
|
+
// copy abi + bytecode.object here.
|
|
4
|
+
|
|
5
|
+
import type { Abi, Hex } from "viem";
|
|
6
|
+
|
|
7
|
+
export const abi = [
|
|
8
|
+
{
|
|
9
|
+
"type": "function",
|
|
10
|
+
"name": "allowance",
|
|
11
|
+
"inputs": [
|
|
12
|
+
{
|
|
13
|
+
"name": "",
|
|
14
|
+
"type": "address",
|
|
15
|
+
"internalType": "address"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "",
|
|
19
|
+
"type": "address",
|
|
20
|
+
"internalType": "address"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"outputs": [
|
|
24
|
+
{
|
|
25
|
+
"name": "",
|
|
26
|
+
"type": "uint256",
|
|
27
|
+
"internalType": "uint256"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"stateMutability": "view"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"type": "function",
|
|
34
|
+
"name": "approve",
|
|
35
|
+
"inputs": [
|
|
36
|
+
{
|
|
37
|
+
"name": "spender",
|
|
38
|
+
"type": "address",
|
|
39
|
+
"internalType": "address"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "value",
|
|
43
|
+
"type": "uint256",
|
|
44
|
+
"internalType": "uint256"
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"outputs": [
|
|
48
|
+
{
|
|
49
|
+
"name": "",
|
|
50
|
+
"type": "bool",
|
|
51
|
+
"internalType": "bool"
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"stateMutability": "nonpayable"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"type": "function",
|
|
58
|
+
"name": "balanceOf",
|
|
59
|
+
"inputs": [
|
|
60
|
+
{
|
|
61
|
+
"name": "",
|
|
62
|
+
"type": "address",
|
|
63
|
+
"internalType": "address"
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"outputs": [
|
|
67
|
+
{
|
|
68
|
+
"name": "",
|
|
69
|
+
"type": "uint256",
|
|
70
|
+
"internalType": "uint256"
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"stateMutability": "view"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"type": "function",
|
|
77
|
+
"name": "decimals",
|
|
78
|
+
"inputs": [],
|
|
79
|
+
"outputs": [
|
|
80
|
+
{
|
|
81
|
+
"name": "",
|
|
82
|
+
"type": "uint8",
|
|
83
|
+
"internalType": "uint8"
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"stateMutability": "view"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"type": "function",
|
|
90
|
+
"name": "mint",
|
|
91
|
+
"inputs": [],
|
|
92
|
+
"outputs": [],
|
|
93
|
+
"stateMutability": "nonpayable"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"type": "function",
|
|
97
|
+
"name": "name",
|
|
98
|
+
"inputs": [],
|
|
99
|
+
"outputs": [
|
|
100
|
+
{
|
|
101
|
+
"name": "",
|
|
102
|
+
"type": "string",
|
|
103
|
+
"internalType": "string"
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"stateMutability": "view"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"type": "function",
|
|
110
|
+
"name": "symbol",
|
|
111
|
+
"inputs": [],
|
|
112
|
+
"outputs": [
|
|
113
|
+
{
|
|
114
|
+
"name": "",
|
|
115
|
+
"type": "string",
|
|
116
|
+
"internalType": "string"
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
"stateMutability": "view"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"type": "function",
|
|
123
|
+
"name": "totalSupply",
|
|
124
|
+
"inputs": [],
|
|
125
|
+
"outputs": [
|
|
126
|
+
{
|
|
127
|
+
"name": "",
|
|
128
|
+
"type": "uint256",
|
|
129
|
+
"internalType": "uint256"
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
"stateMutability": "view"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"type": "function",
|
|
136
|
+
"name": "transfer",
|
|
137
|
+
"inputs": [
|
|
138
|
+
{
|
|
139
|
+
"name": "to",
|
|
140
|
+
"type": "address",
|
|
141
|
+
"internalType": "address"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"name": "value",
|
|
145
|
+
"type": "uint256",
|
|
146
|
+
"internalType": "uint256"
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
"outputs": [
|
|
150
|
+
{
|
|
151
|
+
"name": "",
|
|
152
|
+
"type": "bool",
|
|
153
|
+
"internalType": "bool"
|
|
154
|
+
}
|
|
155
|
+
],
|
|
156
|
+
"stateMutability": "nonpayable"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"type": "function",
|
|
160
|
+
"name": "transferFrom",
|
|
161
|
+
"inputs": [
|
|
162
|
+
{
|
|
163
|
+
"name": "from",
|
|
164
|
+
"type": "address",
|
|
165
|
+
"internalType": "address"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"name": "to",
|
|
169
|
+
"type": "address",
|
|
170
|
+
"internalType": "address"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"name": "value",
|
|
174
|
+
"type": "uint256",
|
|
175
|
+
"internalType": "uint256"
|
|
176
|
+
}
|
|
177
|
+
],
|
|
178
|
+
"outputs": [
|
|
179
|
+
{
|
|
180
|
+
"name": "",
|
|
181
|
+
"type": "bool",
|
|
182
|
+
"internalType": "bool"
|
|
183
|
+
}
|
|
184
|
+
],
|
|
185
|
+
"stateMutability": "nonpayable"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"type": "event",
|
|
189
|
+
"name": "Approval",
|
|
190
|
+
"inputs": [
|
|
191
|
+
{
|
|
192
|
+
"name": "owner",
|
|
193
|
+
"type": "address",
|
|
194
|
+
"indexed": true,
|
|
195
|
+
"internalType": "address"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"name": "spender",
|
|
199
|
+
"type": "address",
|
|
200
|
+
"indexed": true,
|
|
201
|
+
"internalType": "address"
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"name": "value",
|
|
205
|
+
"type": "uint256",
|
|
206
|
+
"indexed": false,
|
|
207
|
+
"internalType": "uint256"
|
|
208
|
+
}
|
|
209
|
+
],
|
|
210
|
+
"anonymous": false
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"type": "event",
|
|
214
|
+
"name": "Transfer",
|
|
215
|
+
"inputs": [
|
|
216
|
+
{
|
|
217
|
+
"name": "from",
|
|
218
|
+
"type": "address",
|
|
219
|
+
"indexed": true,
|
|
220
|
+
"internalType": "address"
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"name": "to",
|
|
224
|
+
"type": "address",
|
|
225
|
+
"indexed": true,
|
|
226
|
+
"internalType": "address"
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"name": "value",
|
|
230
|
+
"type": "uint256",
|
|
231
|
+
"indexed": false,
|
|
232
|
+
"internalType": "uint256"
|
|
233
|
+
}
|
|
234
|
+
],
|
|
235
|
+
"anonymous": false
|
|
236
|
+
}
|
|
237
|
+
] as const satisfies Abi;
|
|
238
|
+
|
|
239
|
+
export const bytecode = "0x6080604052348015600e575f5ffd5b5061066f8061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061009b575f3560e01c8063313ce56711610063578063313ce5671461013657806370a082311461015057806395d89b411461016f578063a9059cbb14610191578063dd62ed3e146101a4575f5ffd5b806306fdde031461009f578063095ea7b3146100e05780631249c58b1461010357806318160ddd1461010d57806323b872dd14610123575b5f5ffd5b6100ca6040518060400160405280600c81526020016b20bb30a5b4ba102a37b5b2b760a11b81525081565b6040516100d791906103f4565b60405180910390f35b6100f36100ee366004610444565b6101ce565b60405190151581526020016100d7565b61010b61023a565b005b6101155f5481565b6040519081526020016100d7565b6100f361013136600461046c565b6102b2565b61013e601281565b60405160ff90911681526020016100d7565b61011561015e3660046104a6565b60016020525f908152604090205481565b6100ca604051806040016040528060038152602001621052d560ea1b81525081565b6100f361019f366004610444565b61037e565b6101156101b23660046104c6565b600260209081525f928352604080842090915290825290205481565b335f8181526002602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906102289086815260200190565b60405180910390a35060015b92915050565b5f6102476012600a6105ee565b6102529060646105fc565b9050805f5f8282546102649190610613565b9091555050335f818152600160209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a350565b6001600160a01b0383165f9081526002602090815260408083203384529091528120805483919083906102e6908490610626565b90915550506001600160a01b0384165f9081526001602052604081208054849290610312908490610626565b90915550506001600160a01b038084165f81815260016020526040908190208054860190555190918616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061036c9086815260200190565b60405180910390a35060019392505050565b335f9081526001602052604081208054839190839061039e908490610626565b90915550506001600160a01b0383165f81815260016020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906102289086815260200190565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b80356001600160a01b038116811461043f575f5ffd5b919050565b5f5f60408385031215610455575f5ffd5b61045e83610429565b946020939093013593505050565b5f5f5f6060848603121561047e575f5ffd5b61048784610429565b925061049560208501610429565b929592945050506040919091013590565b5f602082840312156104b6575f5ffd5b6104bf82610429565b9392505050565b5f5f604083850312156104d7575f5ffd5b6104e083610429565b91506104ee60208401610429565b90509250929050565b634e487b7160e01b5f52601160045260245ffd5b6001815b60018411156105465780850481111561052a5761052a6104f7565b600184161561053857908102905b60019390931c92800261050f565b935093915050565b5f8261055c57506001610234565b8161056857505f610234565b816001811461057e5760028114610588576105a4565b6001915050610234565b60ff841115610599576105996104f7565b50506001821b610234565b5060208310610133831016604e8410600b84101617156105c7575081810a610234565b6105d35f19848461050b565b805f19048211156105e6576105e66104f7565b029392505050565b5f6104bf60ff84168361054e565b8082028115828204841417610234576102346104f7565b80820180821115610234576102346104f7565b81810381811115610234576102346104f756fea26469706673582212203ba8f5901a64d91a7beec3bdc98521ea0a7279a4ebafb699842fb133050e658e64736f6c634300081c0033" as Hex;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# __PROJECT_NAME__
|
|
2
|
+
|
|
3
|
+
> Launch your own Avalanche L1 with one command, then explore it in a built-in dashboard (live blocks, transactions, balance, contract deploy). Next.js + @avakit/react + viem + avalanche-cli, no third-party explorer.
|
|
4
|
+
|
|
5
|
+
## Project map
|
|
6
|
+
|
|
7
|
+
- [scripts/l1.sh](scripts/l1.sh): `pnpm l1` — create + deploy a local Subnet-EVM L1, write l1.config.json.
|
|
8
|
+
- [scripts/l1-fuji.sh](scripts/l1-fuji.sh): `pnpm l1:fuji` — deploy the L1 to the Fuji testnet (advanced).
|
|
9
|
+
- [l1.config.json](l1.config.json): your chain (name, token, evmChainId, rpcUrl, blockchainIdHex, faucetAccount).
|
|
10
|
+
- [lib/l1.ts](lib/l1.ts): config → AvaKit chain (`defineChain`) + `isConfigured`.
|
|
11
|
+
- [components/demo.tsx](components/demo.tsx): the dashboard/explorer — polls RPC for blocks/txs/gas/balance, deploys + mints the demo token.
|
|
12
|
+
- [contracts/src/AvaKitToken.sol](contracts/src/AvaKitToken.sol) + [lib/token-artifact.ts](lib/token-artifact.ts): bundled ERC-20 for browser deploy.
|
|
13
|
+
- [CLAUDE.md](CLAUDE.md): agent guide — the flow, an explainer for every L1 config decision, the EWOQ warning, and the Fuji graduation path.
|
|
14
|
+
|
|
15
|
+
## Key APIs
|
|
16
|
+
|
|
17
|
+
- Chain: `chain` and `isConfigured` from `@/lib/l1`.
|
|
18
|
+
- Explorer reads (all read-only viem): `getPublicClient(chain)` → `getBlockNumber()`, `getGasPrice()`, `getBlock({ blockNumber, includeTransactions: true })`, `getBalance({ address })`.
|
|
19
|
+
- Deploy: `deployContract({ artifact: { abi, bytecode }, chain, provider, account })` from `@avakit/core`.
|
|
20
|
+
- Write: `getWalletClient(chain, provider).writeContract({ address, abi, functionName: "mint", account })`.
|
|
21
|
+
|
|
22
|
+
## Config decisions
|
|
23
|
+
|
|
24
|
+
Subnet-EVM VM, EVM chain id (default 9999), native token symbol, `--sovereign=false` for a
|
|
25
|
+
zero-prompt local chain (Fuji path uses a sovereign PoA L1), `--test-defaults` (EWOQ pre-funded).
|
|
26
|
+
|
|
27
|
+
## External docs
|
|
28
|
+
|
|
29
|
+
- Create/deploy an L1 locally: https://build.avax.network/docs/tooling/avalanche-cli/create-deploy-avalanche-l1s/deploy-locally
|
|
30
|
+
- Deploy on Fuji: https://build.avax.network/docs/tooling/avalanche-cli/create-deploy-avalanche-l1s/deploy-on-fuji-testnet
|
|
31
|
+
- avalanche-cli: https://build.avax.network/docs/tooling/avalanche-cli/get-avalanche-cli
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "next dev",
|
|
8
|
+
"build": "next build",
|
|
9
|
+
"start": "next start",
|
|
10
|
+
"typecheck": "tsc --noEmit",
|
|
11
|
+
"l1": "bash scripts/l1.sh",
|
|
12
|
+
"l1:fuji": "bash scripts/l1-fuji.sh"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@avakit/core": "__AVAKIT_DEP__",
|
|
16
|
+
"@avakit/react": "__AVAKIT_DEP__",
|
|
17
|
+
"lucide-react": "1.22.0",
|
|
18
|
+
"next": "16.2.9",
|
|
19
|
+
"next-themes": "0.4.6",
|
|
20
|
+
"react": "19.2.7",
|
|
21
|
+
"react-dom": "19.2.7",
|
|
22
|
+
"viem": "2.54.1"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@tailwindcss/postcss": "4.3.2",
|
|
26
|
+
"@types/node": "26.0.1",
|
|
27
|
+
"@types/react": "19.2.17",
|
|
28
|
+
"@types/react-dom": "19.2.3",
|
|
29
|
+
"postcss": "8.5.16",
|
|
30
|
+
"tailwindcss": "4.3.2",
|
|
31
|
+
"tw-animate-css": "1.4.0",
|
|
32
|
+
"typescript": "6.0.3"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# pnpm settings for this scaffolded app.
|
|
2
|
+
# allowBuilds: pre-approve native postinstall scripts so `pnpm install` / `pnpm dev`
|
|
3
|
+
# don't fail with ERR_PNPM_IGNORED_BUILDS on pnpm 10+.
|
|
4
|
+
# minimumReleaseAgeExclude: pnpm's supply-chain age gate blocks very fresh releases;
|
|
5
|
+
# exempt AvaKit's own packages so a new @avakit publish never breaks a fresh install
|
|
6
|
+
# (third-party deps keep the protection). Delete this file to opt back into defaults.
|
|
7
|
+
allowBuilds:
|
|
8
|
+
sharp: true
|
|
9
|
+
minimumReleaseAgeExclude:
|
|
10
|
+
- '@avakit/core'
|
|
11
|
+
- '@avakit/react'
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Graduate your L1 to the Fuji TESTNET (advanced).
|
|
4
|
+
#
|
|
5
|
+
# Unlike `pnpm l1` (fully local, instant, free), deploying to Fuji is a real,
|
|
6
|
+
# multi-step operation. This script wraps the avalanche-cli commands and, where
|
|
7
|
+
# the CLI needs interactive input or your own keys, walks you through it. Read
|
|
8
|
+
# the caveats below before running — a Fuji L1 needs an always-on validator and
|
|
9
|
+
# a periodically-topped-up balance, or it stops producing blocks.
|
|
10
|
+
#
|
|
11
|
+
# Configure via env (all optional; must match the chain you created with pnpm l1):
|
|
12
|
+
# L1_NAME=mychain FUJI_KEY=mykey pnpm l1:fuji
|
|
13
|
+
|
|
14
|
+
set -uo pipefail
|
|
15
|
+
|
|
16
|
+
NAME="${L1_NAME:-mychain}"
|
|
17
|
+
KEY="${FUJI_KEY:-}"
|
|
18
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
19
|
+
CONFIG="$ROOT/l1.config.json"
|
|
20
|
+
|
|
21
|
+
say() { printf "\033[1;37m▸\033[0m %s\n" "$1"; }
|
|
22
|
+
warn() { printf "\033[1;33m!\033[0m %s\n" "$1"; }
|
|
23
|
+
die() { printf "\033[1;31m✖\033[0m %s\n" "$1" >&2; exit 1; }
|
|
24
|
+
|
|
25
|
+
command -v avalanche >/dev/null 2>&1 || die "avalanche-cli not found. See CLAUDE.md."
|
|
26
|
+
|
|
27
|
+
cat <<'EOF'
|
|
28
|
+
────────────────────────────────────────────────────────────────────────
|
|
29
|
+
Deploy your L1 to Fuji — what you need first (one-time):
|
|
30
|
+
|
|
31
|
+
1. A Fuji key funded with test AVAX:
|
|
32
|
+
avalanche key create mykey # creates a key
|
|
33
|
+
# fund its C-Chain address from the Builder Hub faucet:
|
|
34
|
+
# https://build.avax.network/console/primary-network/faucet
|
|
35
|
+
# then move funds to the P-Chain:
|
|
36
|
+
avalanche key transfer --key mykey --amount 2 --sender-blockchain c --receiver-blockchain p
|
|
37
|
+
|
|
38
|
+
2. Budget ~1-2 test AVAX PER validator — an L1 validator pays a continuous
|
|
39
|
+
P-Chain fee (~1 AVAX ≈ 1 month). When the balance hits zero the validator
|
|
40
|
+
goes inactive and your L1 STOPS. Top up with:
|
|
41
|
+
avalanche blockchain addValidator / IncreaseL1ValidatorBalance
|
|
42
|
+
|
|
43
|
+
3. A bootstrap validator node that STAYS RUNNING. Your machine can be it
|
|
44
|
+
(--use-local-machine below), but if this process exits, block production
|
|
45
|
+
stops. For an always-on chain, run a real node instead.
|
|
46
|
+
────────────────────────────────────────────────────────────────────────
|
|
47
|
+
EOF
|
|
48
|
+
|
|
49
|
+
[ -n "$KEY" ] || die "Set FUJI_KEY to your funded avalanche-cli key name, e.g. FUJI_KEY=mykey pnpm l1:fuji"
|
|
50
|
+
|
|
51
|
+
say "Deploying '$NAME' to Fuji with key '$KEY' (your machine as bootstrap validator)…"
|
|
52
|
+
warn "This is interactive: the CLI will ask you to confirm the CreateSubnet / CreateChain /"
|
|
53
|
+
warn "ConvertSubnetToL1 transactions and to set up the local-machine validator. Follow its prompts."
|
|
54
|
+
|
|
55
|
+
# --use-local-machine turns this machine into the bootstrap validator; the CLI
|
|
56
|
+
# handles subnet creation, chain creation, and conversion to a sovereign L1.
|
|
57
|
+
avalanche blockchain deploy "$NAME" \
|
|
58
|
+
--fuji \
|
|
59
|
+
--key "$KEY" \
|
|
60
|
+
--use-local-machine \
|
|
61
|
+
|| die "Fuji deploy did not complete. Re-run after addressing the CLI's output."
|
|
62
|
+
|
|
63
|
+
# Discover the Fuji RPC + hex blockchain ID for the deployed L1.
|
|
64
|
+
say "Reading Fuji chain details…"
|
|
65
|
+
OUT="$(avalanche blockchain describe "$NAME" 2>/dev/null)"
|
|
66
|
+
RPC="$(printf '%s' "$OUT" | grep -oE 'https?://[^ ]*/ext/bc/[A-Za-z0-9]+/rpc' | head -1)"
|
|
67
|
+
BID="$(printf '%s' "$OUT" | grep -iE 'BlockchainID \(HEX\)' | grep -oiE '0x[0-9a-f]{64}' | head -1)"
|
|
68
|
+
CID="$(printf '%s' "$OUT" | grep -iE 'ChainID' | grep -oE '[0-9]+' | head -1)"
|
|
69
|
+
|
|
70
|
+
[ -n "$RPC" ] || die "Could not read the Fuji RPC. Run: avalanche blockchain describe $NAME"
|
|
71
|
+
|
|
72
|
+
TOKEN="$(node -e "process.stdout.write(String(require('$CONFIG').token||'MYL1'))" 2>/dev/null || echo MYL1)"
|
|
73
|
+
CID="${CID:-$(node -e "process.stdout.write(String(require('$CONFIG').evmChainId||9999))" 2>/dev/null || echo 9999)}"
|
|
74
|
+
|
|
75
|
+
cat > "$CONFIG" <<EOF
|
|
76
|
+
{
|
|
77
|
+
"configured": true,
|
|
78
|
+
"network": "fuji",
|
|
79
|
+
"name": "$NAME",
|
|
80
|
+
"token": "$TOKEN",
|
|
81
|
+
"evmChainId": $CID,
|
|
82
|
+
"rpcUrl": "$RPC",
|
|
83
|
+
"blockchainIdHex": "${BID:-}",
|
|
84
|
+
"faucetAccount": { "address": "", "privateKey": "" }
|
|
85
|
+
}
|
|
86
|
+
EOF
|
|
87
|
+
|
|
88
|
+
say "Updated l1.config.json → $RPC (network: fuji)"
|
|
89
|
+
cat <<EOF
|
|
90
|
+
|
|
91
|
+
✔ Your L1 is on Fuji.
|
|
92
|
+
|
|
93
|
+
• pnpm dev → the built-in explorer now points at your Fuji L1's RPC.
|
|
94
|
+
• Connect your OWN funded wallet (no EWOQ on Fuji).
|
|
95
|
+
• Keep this machine / your validator node running, and keep the validator
|
|
96
|
+
balance topped up, or the L1 stops producing blocks.
|
|
97
|
+
|
|
98
|
+
There is no automatic hosted explorer for a custom Fuji L1 — this app's built-in
|
|
99
|
+
explorer is your window into the chain.
|
|
100
|
+
EOF
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Launch your own local Avalanche L1 — one command.
|
|
4
|
+
#
|
|
5
|
+
# Creates a Subnet-EVM blockchain and deploys it to a local Avalanche network,
|
|
6
|
+
# then writes the discovered RPC URL + blockchain ID into l1.config.json so the
|
|
7
|
+
# app can talk to your chain. Everything runs on your machine — no test AVAX, no
|
|
8
|
+
# faucet, no always-on node. To graduate the same chain to the Fuji testnet, see
|
|
9
|
+
# `pnpm l1:fuji` (scripts/l1-fuji.sh) and CLAUDE.md.
|
|
10
|
+
#
|
|
11
|
+
# Configure via env (all optional):
|
|
12
|
+
# L1_NAME=mychain L1_CHAIN_ID=9999 L1_TOKEN=MYL1 pnpm l1
|
|
13
|
+
#
|
|
14
|
+
# Requires avalanche-cli. It downloads avalanchego + Subnet-EVM on first run.
|
|
15
|
+
|
|
16
|
+
set -uo pipefail
|
|
17
|
+
|
|
18
|
+
NAME="${L1_NAME:-mychain}"
|
|
19
|
+
CHAIN_ID="${L1_CHAIN_ID:-9999}"
|
|
20
|
+
TOKEN="${L1_TOKEN:-MYL1}"
|
|
21
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
22
|
+
CONFIG="$ROOT/l1.config.json"
|
|
23
|
+
|
|
24
|
+
# EWOQ: avalanche-cli's well-known local dev key, pre-funded on every local
|
|
25
|
+
# chain. PUBLIC — for local networks only, never a real network. Import it into
|
|
26
|
+
# your wallet to transact on your L1.
|
|
27
|
+
EWOQ_PK="0x56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027"
|
|
28
|
+
EWOQ_ADDR="0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC"
|
|
29
|
+
|
|
30
|
+
say() { printf "\033[1;37m▸\033[0m %s\n" "$1"; }
|
|
31
|
+
die() { printf "\033[1;31m✖\033[0m %s\n" "$1" >&2; exit 1; }
|
|
32
|
+
|
|
33
|
+
# --- 0. avalanche-cli present? ---------------------------------------------
|
|
34
|
+
if ! command -v avalanche >/dev/null 2>&1; then
|
|
35
|
+
cat >&2 <<'EOF'
|
|
36
|
+
✖ avalanche-cli not found. Install it:
|
|
37
|
+
|
|
38
|
+
curl -sSfL https://raw.githubusercontent.com/ava-labs/avalanche-cli/main/scripts/install.sh | sh -s -- -b /usr/local/bin
|
|
39
|
+
|
|
40
|
+
# or: brew install ava-labs/tap/avalanche-cli
|
|
41
|
+
|
|
42
|
+
Then re-run: pnpm l1
|
|
43
|
+
EOF
|
|
44
|
+
exit 1
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# --- 1. Create the L1 -------------------------------------------------------
|
|
48
|
+
# --sovereign=false keeps this fully non-interactive for local dev (a true
|
|
49
|
+
# sovereign L1 prompts for a validator-manager owner). --test-defaults uses
|
|
50
|
+
# local dev settings (EWOQ pre-funded, fast finality). CLAUDE.md explains each
|
|
51
|
+
# knob (VM, consensus, chain ID, sovereignty) and the Fuji path uses a real
|
|
52
|
+
# sovereign L1.
|
|
53
|
+
say "Creating L1 '$NAME' (Subnet-EVM · chainId $CHAIN_ID · token $TOKEN)…"
|
|
54
|
+
avalanche blockchain create "$NAME" \
|
|
55
|
+
--evm --latest \
|
|
56
|
+
--evm-chain-id "$CHAIN_ID" \
|
|
57
|
+
--evm-token "$TOKEN" \
|
|
58
|
+
--test-defaults \
|
|
59
|
+
--sovereign=false \
|
|
60
|
+
--force </dev/null >/dev/null 2>&1 \
|
|
61
|
+
|| die "Failed to create '$NAME'. Try: avalanche blockchain delete $NAME"
|
|
62
|
+
|
|
63
|
+
# --- 2. Deploy it to a local network ----------------------------------------
|
|
64
|
+
say "Deploying '$NAME' locally (first run boots the local network)…"
|
|
65
|
+
avalanche blockchain deploy "$NAME" --local </dev/null || die "Deploy of '$NAME' failed."
|
|
66
|
+
|
|
67
|
+
# --- 3. Discover RPC URL + hex blockchain ID --------------------------------
|
|
68
|
+
# `describe` prints both. We grep by shape (robust across CLI versions).
|
|
69
|
+
say "Reading chain details…"
|
|
70
|
+
OUT="$(avalanche blockchain describe "$NAME" 2>/dev/null)"
|
|
71
|
+
RPC="$(printf '%s' "$OUT" | grep -oE 'http://127\.0\.0\.1:[0-9]+/ext/bc/[A-Za-z0-9]+/rpc' | head -1)"
|
|
72
|
+
BID="$(printf '%s' "$OUT" | grep -iE 'BlockchainID \(HEX\)' | grep -oiE '0x[0-9a-f]{64}' | head -1)"
|
|
73
|
+
|
|
74
|
+
[ -n "$RPC" ] || die "Could not read '$NAME' RPC. Run: avalanche blockchain describe $NAME"
|
|
75
|
+
|
|
76
|
+
# --- 4. Write l1.config.json ------------------------------------------------
|
|
77
|
+
cat > "$CONFIG" <<EOF
|
|
78
|
+
{
|
|
79
|
+
"configured": true,
|
|
80
|
+
"network": "local",
|
|
81
|
+
"name": "$NAME",
|
|
82
|
+
"token": "$TOKEN",
|
|
83
|
+
"evmChainId": $CHAIN_ID,
|
|
84
|
+
"rpcUrl": "$RPC",
|
|
85
|
+
"blockchainIdHex": "${BID:-}",
|
|
86
|
+
"faucetAccount": { "address": "$EWOQ_ADDR", "privateKey": "$EWOQ_PK" }
|
|
87
|
+
}
|
|
88
|
+
EOF
|
|
89
|
+
|
|
90
|
+
say "Wrote l1.config.json → $RPC"
|
|
91
|
+
cat <<EOF
|
|
92
|
+
|
|
93
|
+
✔ Your L1 is live locally.
|
|
94
|
+
|
|
95
|
+
Next:
|
|
96
|
+
1. Import the EWOQ dev key into your wallet (Core / MetaMask) — pre-funded on your chain:
|
|
97
|
+
$EWOQ_PK
|
|
98
|
+
(public dev key, local only)
|
|
99
|
+
2. pnpm dev → http://localhost:3000 (your chain dashboard + explorer)
|
|
100
|
+
3. Deploy the demo token, watch blocks and transactions land in real time.
|
|
101
|
+
|
|
102
|
+
Manage the network:
|
|
103
|
+
avalanche network stop # pause (keeps state)
|
|
104
|
+
avalanche network clean # wipe (new blockchain ID — re-run pnpm l1)
|
|
105
|
+
|
|
106
|
+
Graduate to the Fuji testnet (advanced, needs test AVAX + an always-on node):
|
|
107
|
+
pnpm l1:fuji
|
|
108
|
+
EOF
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "preserve",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [{ "name": "next" }],
|
|
17
|
+
"paths": {
|
|
18
|
+
"@/*": ["./*"]
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
22
|
+
"exclude": ["node_modules"]
|
|
23
|
+
}
|