create-avalanche-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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +43 -0
  3. package/dist/api.d.ts +34 -0
  4. package/dist/api.js +12 -0
  5. package/dist/api.js.map +1 -0
  6. package/dist/chunk-3YGRLI4R.js +91 -0
  7. package/dist/chunk-3YGRLI4R.js.map +1 -0
  8. package/dist/index.js +213 -0
  9. package/dist/index.js.map +1 -0
  10. package/package.json +65 -0
  11. package/templates/erc20-token/CLAUDE.md +45 -0
  12. package/templates/erc20-token/README.md +35 -0
  13. package/templates/erc20-token/app/globals.css +95 -0
  14. package/templates/erc20-token/app/layout.tsx +23 -0
  15. package/templates/erc20-token/app/page.tsx +5 -0
  16. package/templates/erc20-token/app/providers.tsx +30 -0
  17. package/templates/erc20-token/components/demo.tsx +178 -0
  18. package/templates/erc20-token/contracts/foundry.toml +9 -0
  19. package/templates/erc20-token/contracts/src/AvaKitToken.sol +53 -0
  20. package/templates/erc20-token/cursor/rules/avakit.mdc +31 -0
  21. package/templates/erc20-token/env.example +4 -0
  22. package/templates/erc20-token/gitignore +15 -0
  23. package/templates/erc20-token/lib/token-artifact.ts +239 -0
  24. package/templates/erc20-token/llms.txt +29 -0
  25. package/templates/erc20-token/manifest.json +6 -0
  26. package/templates/erc20-token/next.config.ts +7 -0
  27. package/templates/erc20-token/package.json +32 -0
  28. package/templates/erc20-token/postcss.config.mjs +7 -0
  29. package/templates/erc20-token/tsconfig.json +23 -0
  30. package/templates/minimal/CLAUDE.md +37 -0
  31. package/templates/minimal/README.md +32 -0
  32. package/templates/minimal/app/globals.css +95 -0
  33. package/templates/minimal/app/layout.tsx +23 -0
  34. package/templates/minimal/app/page.tsx +5 -0
  35. package/templates/minimal/app/providers.tsx +30 -0
  36. package/templates/minimal/components/demo.tsx +135 -0
  37. package/templates/minimal/cursor/rules/avakit.mdc +28 -0
  38. package/templates/minimal/env.example +4 -0
  39. package/templates/minimal/gitignore +10 -0
  40. package/templates/minimal/llms.txt +30 -0
  41. package/templates/minimal/manifest.json +6 -0
  42. package/templates/minimal/next.config.ts +7 -0
  43. package/templates/minimal/package.json +32 -0
  44. package/templates/minimal/postcss.config.mjs +7 -0
  45. package/templates/minimal/tsconfig.json +23 -0
  46. package/templates/nft-mint/CLAUDE.md +45 -0
  47. package/templates/nft-mint/README.md +36 -0
  48. package/templates/nft-mint/app/globals.css +95 -0
  49. package/templates/nft-mint/app/layout.tsx +23 -0
  50. package/templates/nft-mint/app/page.tsx +5 -0
  51. package/templates/nft-mint/app/providers.tsx +30 -0
  52. package/templates/nft-mint/components/demo.tsx +176 -0
  53. package/templates/nft-mint/contracts/foundry.toml +9 -0
  54. package/templates/nft-mint/contracts/src/AvaKitNFT.sol +57 -0
  55. package/templates/nft-mint/cursor/rules/avakit.mdc +32 -0
  56. package/templates/nft-mint/env.example +4 -0
  57. package/templates/nft-mint/gitignore +15 -0
  58. package/templates/nft-mint/lib/nft-artifact.ts +164 -0
  59. package/templates/nft-mint/llms.txt +31 -0
  60. package/templates/nft-mint/manifest.json +6 -0
  61. package/templates/nft-mint/next.config.ts +7 -0
  62. package/templates/nft-mint/package.json +32 -0
  63. package/templates/nft-mint/postcss.config.mjs +7 -0
  64. package/templates/nft-mint/tsconfig.json +23 -0
  65. package/templates/token-gated-app/CLAUDE.md +45 -0
  66. package/templates/token-gated-app/README.md +38 -0
  67. package/templates/token-gated-app/app/globals.css +95 -0
  68. package/templates/token-gated-app/app/layout.tsx +23 -0
  69. package/templates/token-gated-app/app/page.tsx +5 -0
  70. package/templates/token-gated-app/app/providers.tsx +30 -0
  71. package/templates/token-gated-app/components/demo.tsx +161 -0
  72. package/templates/token-gated-app/contracts/foundry.toml +9 -0
  73. package/templates/token-gated-app/contracts/src/AvaKitNFT.sol +57 -0
  74. package/templates/token-gated-app/cursor/rules/avakit.mdc +36 -0
  75. package/templates/token-gated-app/env.example +4 -0
  76. package/templates/token-gated-app/gitignore +15 -0
  77. package/templates/token-gated-app/lib/nft-artifact.ts +164 -0
  78. package/templates/token-gated-app/llms.txt +33 -0
  79. package/templates/token-gated-app/manifest.json +6 -0
  80. package/templates/token-gated-app/next.config.ts +7 -0
  81. package/templates/token-gated-app/package.json +32 -0
  82. package/templates/token-gated-app/postcss.config.mjs +7 -0
  83. package/templates/token-gated-app/tsconfig.json +23 -0
@@ -0,0 +1,176 @@
1
+ "use client";
2
+
3
+ import {
4
+ Button,
5
+ ConnectAvalanche,
6
+ shortenAddress,
7
+ useAvaAccount,
8
+ useAvaChain,
9
+ useAvaDeploy,
10
+ useContract,
11
+ } from "@avakit/react";
12
+ import { Moon, Sun } from "lucide-react";
13
+ import { useTheme } from "next-themes";
14
+ import { useCallback, useEffect, useState } from "react";
15
+ import type { Address } from "viem";
16
+ import { abi, bytecode } from "@/lib/nft-artifact";
17
+
18
+ const ZERO = "0x0000000000000000000000000000000000000000" as const;
19
+
20
+ function ThemeToggle() {
21
+ const { resolvedTheme, setTheme } = useTheme();
22
+ return (
23
+ <Button
24
+ variant="outline"
25
+ size="icon"
26
+ aria-label="Toggle theme"
27
+ onClick={() => setTheme(resolvedTheme === "dark" ? "light" : "dark")}
28
+ >
29
+ <Sun className="hidden size-4 dark:block" />
30
+ <Moon className="block size-4 dark:hidden" />
31
+ </Button>
32
+ );
33
+ }
34
+
35
+ export function Demo() {
36
+ const { address, isConnected } = useAvaAccount();
37
+ const { chain } = useAvaChain();
38
+ const { deploy, status: deployStatus } = useAvaDeploy();
39
+
40
+ const [contractAddress, setContractAddress] = useState<Address | null>(null);
41
+ const contract = useContract({ address: contractAddress ?? ZERO, abi });
42
+
43
+ const [minting, setMinting] = useState(false);
44
+ const [mintHash, setMintHash] = useState<string | null>(null);
45
+ const [supply, setSupply] = useState<bigint | null>(null);
46
+ const [owned, setOwned] = useState<bigint | null>(null);
47
+ const [error, setError] = useState<string | null>(null);
48
+
49
+ const refreshCounts = useCallback(async () => {
50
+ if (!contractAddress || !address) return;
51
+ try {
52
+ const [total, balance] = await Promise.all([
53
+ contract.read("totalSupply"),
54
+ contract.read("balanceOf", [address]),
55
+ ]);
56
+ setSupply(total as bigint);
57
+ setOwned(balance as bigint);
58
+ } catch {
59
+ // contract not ready yet
60
+ }
61
+ }, [contract, contractAddress, address]);
62
+
63
+ useEffect(() => {
64
+ void refreshCounts();
65
+ }, [refreshCounts]);
66
+
67
+ async function handleDeploy() {
68
+ setError(null);
69
+ try {
70
+ const result = await deploy({ abi, bytecode });
71
+ setContractAddress(result.address);
72
+ } catch (e) {
73
+ setError(e instanceof Error ? e.message : String(e));
74
+ }
75
+ }
76
+
77
+ async function handleMint() {
78
+ if (!contractAddress) return;
79
+ setMinting(true);
80
+ setError(null);
81
+ setMintHash(null);
82
+ try {
83
+ const hash = await contract.write("mint", []);
84
+ setMintHash(hash);
85
+ await refreshCounts();
86
+ } catch (e) {
87
+ setError(e instanceof Error ? e.message : String(e));
88
+ } finally {
89
+ setMinting(false);
90
+ }
91
+ }
92
+
93
+ return (
94
+ <div className="mx-auto flex min-h-dvh max-w-xl flex-col gap-8 px-6 py-16">
95
+ <header className="flex items-center justify-between">
96
+ <span className="font-mono text-sm font-semibold">__PROJECT_NAME__</span>
97
+ <div className="flex items-center gap-2">
98
+ <ConnectAvalanche />
99
+ <ThemeToggle />
100
+ </div>
101
+ </header>
102
+
103
+ <div className="flex flex-col gap-2">
104
+ <h1 className="text-3xl font-semibold tracking-tight">Mint an NFT on Avalanche</h1>
105
+ <p className="text-muted-foreground text-sm">
106
+ Deploy the NFT contract from your wallet, then mint — all on {chain.name}. The bytecode is
107
+ bundled, so no Foundry is needed to run this.
108
+ </p>
109
+ </div>
110
+
111
+ {!isConnected || !address ? (
112
+ <div className="text-muted-foreground rounded-xl border border-dashed p-10 text-center text-sm">
113
+ Connect a wallet to begin.
114
+ </div>
115
+ ) : !contractAddress ? (
116
+ <div className="flex flex-col gap-3 rounded-xl border p-6">
117
+ <p className="text-sm">Step 1 — deploy your NFT contract.</p>
118
+ <Button onClick={handleDeploy} disabled={deployStatus === "deploying"}>
119
+ {deployStatus === "deploying" ? "Deploying…" : "Deploy NFT contract"}
120
+ </Button>
121
+ {chain.faucetUrl ? (
122
+ <a
123
+ href={chain.faucetUrl}
124
+ target="_blank"
125
+ rel="noreferrer"
126
+ className="text-muted-foreground text-center text-xs underline underline-offset-4"
127
+ >
128
+ Need test AVAX? Open the faucet
129
+ </a>
130
+ ) : null}
131
+ </div>
132
+ ) : (
133
+ <div className="flex flex-col gap-4 rounded-xl border p-6">
134
+ <Row label="Contract" value={shortenAddress(contractAddress, 6)} mono />
135
+ <Row label="Total minted" value={supply === null ? "…" : supply.toString()} mono />
136
+ <Row label="You own" value={owned === null ? "…" : owned.toString()} mono />
137
+
138
+ <Button onClick={handleMint} disabled={minting}>
139
+ {minting ? "Minting…" : "Mint NFT"}
140
+ </Button>
141
+
142
+ <a
143
+ href={`${chain.explorerUrl}/address/${contractAddress}`}
144
+ target="_blank"
145
+ rel="noreferrer"
146
+ className="text-muted-foreground text-center text-xs underline underline-offset-4"
147
+ >
148
+ View contract on explorer
149
+ </a>
150
+
151
+ {mintHash ? (
152
+ <a
153
+ href={`${chain.explorerUrl}/tx/${mintHash}`}
154
+ target="_blank"
155
+ rel="noreferrer"
156
+ className="text-sm break-all underline underline-offset-4"
157
+ >
158
+ ✓ Minted: {mintHash}
159
+ </a>
160
+ ) : null}
161
+ </div>
162
+ )}
163
+
164
+ {error ? <p className="text-muted-foreground text-sm">{error}</p> : null}
165
+ </div>
166
+ );
167
+ }
168
+
169
+ function Row({ label, value, mono }: { label: string; value: string; mono?: boolean }) {
170
+ return (
171
+ <div className="flex items-center justify-between gap-4">
172
+ <span className="text-muted-foreground text-sm">{label}</span>
173
+ <span className={mono ? "font-mono text-sm" : "text-sm"}>{value}</span>
174
+ </div>
175
+ );
176
+ }
@@ -0,0 +1,9 @@
1
+ [profile.default]
2
+ src = "src"
3
+ out = "out"
4
+ libs = ["lib"]
5
+ optimizer = true
6
+ optimizer_runs = 200
7
+
8
+ [rpc_endpoints]
9
+ fuji = "https://api.avax-test.network/ext/bc/C/rpc"
@@ -0,0 +1,57 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.20;
3
+
4
+ /// @title AvaKitNFT
5
+ /// @notice A minimal, self-contained ERC-721 mint demo (no external deps so it
6
+ /// compiles out of the box with `forge build`). Public mint, on-chain
7
+ /// metadata. Not a full ERC-721 (no transfer/approve) — it's a starting
8
+ /// point you can extend.
9
+ contract AvaKitNFT {
10
+ string public constant name = "AvaKit NFT";
11
+ string public constant symbol = "AVAKIT";
12
+
13
+ uint256 public totalSupply;
14
+ mapping(uint256 => address) public ownerOf;
15
+ mapping(address => uint256) public balanceOf;
16
+
17
+ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
18
+
19
+ /// @notice Mint the next token to the caller.
20
+ function mint() external returns (uint256 tokenId) {
21
+ tokenId = ++totalSupply;
22
+ ownerOf[tokenId] = msg.sender;
23
+ unchecked {
24
+ balanceOf[msg.sender] += 1;
25
+ }
26
+ emit Transfer(address(0), msg.sender, tokenId);
27
+ }
28
+
29
+ /// @notice Minimal on-chain metadata.
30
+ function tokenURI(uint256 tokenId) external pure returns (string memory) {
31
+ return string.concat(
32
+ 'data:application/json;utf8,{"name":"AvaKit #', _toString(tokenId), '"}'
33
+ );
34
+ }
35
+
36
+ /// @notice ERC-165: advertises ERC-721 + ERC-165 interface ids.
37
+ function supportsInterface(bytes4 interfaceId) external pure returns (bool) {
38
+ return interfaceId == 0x80ac58cd || interfaceId == 0x01ffc9a7;
39
+ }
40
+
41
+ function _toString(uint256 value) internal pure returns (string memory) {
42
+ if (value == 0) return "0";
43
+ uint256 temp = value;
44
+ uint256 digits;
45
+ while (temp != 0) {
46
+ digits++;
47
+ temp /= 10;
48
+ }
49
+ bytes memory buffer = new bytes(digits);
50
+ while (value != 0) {
51
+ digits -= 1;
52
+ buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
53
+ value /= 10;
54
+ }
55
+ return string(buffer);
56
+ }
57
+ }
@@ -0,0 +1,32 @@
1
+ ---
2
+ description: AvaKit + Avalanche NFT conventions for this project
3
+ globs: ["**/*.ts", "**/*.tsx", "**/*.sol", "**/*.css"]
4
+ alwaysApply: true
5
+ ---
6
+
7
+ # AvaKit NFT project rules
8
+
9
+ This is an Avalanche NFT dapp built with AvaKit. It deploys an ERC-721 from the browser, then mints.
10
+
11
+ ## Flow
12
+
13
+ - Deploy: `useAvaDeploy().deploy({ abi, bytecode })` (artifact in `lib/nft-artifact.ts`).
14
+ - Mint: `useContract({ address, abi }).write("mint", [])`.
15
+ - Read: `.read("totalSupply")`, `.read("balanceOf", [address])`.
16
+
17
+ ## Contract
18
+
19
+ - Source: `contracts/src/AvaKitNFT.sol` (minimal, self-contained ERC-721 — no external deps).
20
+ - After editing, recompile: `cd contracts && forge build`, then update `lib/nft-artifact.ts` with the new abi + bytecode.object.
21
+
22
+ ## UI
23
+
24
+ - shadcn/ui only; `@avakit/react` components are shadcn-styled.
25
+ - Black & white only for now; dark/light via next-themes; both must work.
26
+ - Animations: Framer Motion or GSAP only.
27
+
28
+ ## Safety
29
+
30
+ - Deploying and minting cost gas — fund the wallet on Fuji first.
31
+ - Default chain is Fuji testnet; mainnet requires explicit opt-in.
32
+ - Never hardcode secrets; keys stay in the wallet provider.
@@ -0,0 +1,4 @@
1
+ # Web3Auth (MetaMask Embedded Wallets) — free client ID for social login.
2
+ # Get one at https://dashboard.web3auth.io (Sapphire Devnet, EVM).
3
+ # Public value, safe to expose. Leave empty to use only the browser wallet.
4
+ NEXT_PUBLIC_WEB3AUTH_CLIENT_ID=
@@ -0,0 +1,15 @@
1
+ node_modules/
2
+ .next/
3
+ out/
4
+ *.tsbuildinfo
5
+ next-env.d.ts
6
+ .env
7
+ .env.*
8
+ !.env.example
9
+ .DS_Store
10
+ *.log
11
+
12
+ # Foundry
13
+ contracts/out/
14
+ contracts/cache/
15
+ contracts/broadcast/
@@ -0,0 +1,164 @@
1
+ // Auto-generated from contracts/src/AvaKitNFT.sol via `forge build`.
2
+ // Re-generate after editing the contract: cd contracts && forge build, then
3
+ // copy abi + bytecode.object here. Lets the app deploy from the browser with
4
+ // no Foundry required at runtime.
5
+
6
+ import type { Abi, Hex } from "viem";
7
+
8
+ export const abi = [
9
+ {
10
+ "type": "function",
11
+ "name": "balanceOf",
12
+ "inputs": [
13
+ {
14
+ "name": "",
15
+ "type": "address",
16
+ "internalType": "address"
17
+ }
18
+ ],
19
+ "outputs": [
20
+ {
21
+ "name": "",
22
+ "type": "uint256",
23
+ "internalType": "uint256"
24
+ }
25
+ ],
26
+ "stateMutability": "view"
27
+ },
28
+ {
29
+ "type": "function",
30
+ "name": "mint",
31
+ "inputs": [],
32
+ "outputs": [
33
+ {
34
+ "name": "tokenId",
35
+ "type": "uint256",
36
+ "internalType": "uint256"
37
+ }
38
+ ],
39
+ "stateMutability": "nonpayable"
40
+ },
41
+ {
42
+ "type": "function",
43
+ "name": "name",
44
+ "inputs": [],
45
+ "outputs": [
46
+ {
47
+ "name": "",
48
+ "type": "string",
49
+ "internalType": "string"
50
+ }
51
+ ],
52
+ "stateMutability": "view"
53
+ },
54
+ {
55
+ "type": "function",
56
+ "name": "ownerOf",
57
+ "inputs": [
58
+ {
59
+ "name": "",
60
+ "type": "uint256",
61
+ "internalType": "uint256"
62
+ }
63
+ ],
64
+ "outputs": [
65
+ {
66
+ "name": "",
67
+ "type": "address",
68
+ "internalType": "address"
69
+ }
70
+ ],
71
+ "stateMutability": "view"
72
+ },
73
+ {
74
+ "type": "function",
75
+ "name": "supportsInterface",
76
+ "inputs": [
77
+ {
78
+ "name": "interfaceId",
79
+ "type": "bytes4",
80
+ "internalType": "bytes4"
81
+ }
82
+ ],
83
+ "outputs": [
84
+ {
85
+ "name": "",
86
+ "type": "bool",
87
+ "internalType": "bool"
88
+ }
89
+ ],
90
+ "stateMutability": "pure"
91
+ },
92
+ {
93
+ "type": "function",
94
+ "name": "symbol",
95
+ "inputs": [],
96
+ "outputs": [
97
+ {
98
+ "name": "",
99
+ "type": "string",
100
+ "internalType": "string"
101
+ }
102
+ ],
103
+ "stateMutability": "view"
104
+ },
105
+ {
106
+ "type": "function",
107
+ "name": "tokenURI",
108
+ "inputs": [
109
+ {
110
+ "name": "tokenId",
111
+ "type": "uint256",
112
+ "internalType": "uint256"
113
+ }
114
+ ],
115
+ "outputs": [
116
+ {
117
+ "name": "",
118
+ "type": "string",
119
+ "internalType": "string"
120
+ }
121
+ ],
122
+ "stateMutability": "pure"
123
+ },
124
+ {
125
+ "type": "function",
126
+ "name": "totalSupply",
127
+ "inputs": [],
128
+ "outputs": [
129
+ {
130
+ "name": "",
131
+ "type": "uint256",
132
+ "internalType": "uint256"
133
+ }
134
+ ],
135
+ "stateMutability": "view"
136
+ },
137
+ {
138
+ "type": "event",
139
+ "name": "Transfer",
140
+ "inputs": [
141
+ {
142
+ "name": "from",
143
+ "type": "address",
144
+ "indexed": true,
145
+ "internalType": "address"
146
+ },
147
+ {
148
+ "name": "to",
149
+ "type": "address",
150
+ "indexed": true,
151
+ "internalType": "address"
152
+ },
153
+ {
154
+ "name": "tokenId",
155
+ "type": "uint256",
156
+ "indexed": true,
157
+ "internalType": "uint256"
158
+ }
159
+ ],
160
+ "anonymous": false
161
+ }
162
+ ] as const satisfies Abi;
163
+
164
+ export const bytecode = "0x6080604052348015600e575f5ffd5b5061056b8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610085575f3560e01c80636352211e116100585780636352211e1461010557806370a082311461014557806395d89b4114610164578063c87b56dd14610189575f5ffd5b806301ffc9a71461008957806306fdde03146100b15780631249c58b146100e757806318160ddd146100fd575b5f5ffd5b61009c610097366004610383565b61019c565b60405190151581526020015b60405180910390f35b6100da6040518060400160405280600a815260200169105d9852da5d0813919560b21b81525081565b6040516100a891906103b1565b6100ef6101d2565b6040519081526020016100a8565b6100ef5f5481565b61012d6101133660046103e6565b60016020525f90815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016100a8565b6100ef6101533660046103fd565b60026020525f908152604090205481565b6100da6040518060400160405280600681526020016510559052d25560d21b81525081565b6100da6101973660046103e6565b61024d565b5f6380ac58cd60e01b6001600160e01b0319831614806101cc57506301ffc9a760e01b6001600160e01b03198316145b92915050565b5f5f5f81546101e090610437565b91829055505f81815260016020818152604080842080546001600160a01b0319163390811790915580855260029092528084208054909301909255905192935083929091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a490565b60606102588261027e565b604051602001610268919061044f565b6040516020818303038152906040529050919050565b6060815f036102a45750506040805180820190915260018152600360fc1b602082015290565b815f5b81156102cd57806102b781610437565b91506102c69050600a836104c1565b91506102a7565b5f8167ffffffffffffffff8111156102e7576102e76104d4565b6040519080825280601f01601f191660200182016040528015610311576020820181803683370190505b5090505b841561037b576103266001836104e8565b9150610333600a866104fb565b61033e90603061050e565b60f81b81838151811061035357610353610521565b60200101906001600160f81b03191690815f1a905350610374600a866104c1565b9450610315565b949350505050565b5f60208284031215610393575f5ffd5b81356001600160e01b0319811681146103aa575f5ffd5b9392505050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f602082840312156103f6575f5ffd5b5035919050565b5f6020828403121561040d575f5ffd5b81356001600160a01b03811681146103aa575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b5f6001820161044857610448610423565b5060010190565b7f646174613a6170706c69636174696f6e2f6a736f6e3b757466382c7b226e616d81526b65223a224176614b6974202360a01b60208201525f82518060208501602c85015e61227d60f01b602c939091019283015250602e01919050565b634e487b7160e01b5f52601260045260245ffd5b5f826104cf576104cf6104ad565b500490565b634e487b7160e01b5f52604160045260245ffd5b818103818111156101cc576101cc610423565b5f82610509576105096104ad565b500690565b808201808211156101cc576101cc610423565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220636aeafda61f36794e1b5b3ea1a8dfe71613339168fec5fb9f9f3cb22f2abc9464736f6c634300081c0033" as Hex;
@@ -0,0 +1,31 @@
1
+ # __PROJECT_NAME__
2
+
3
+ > An Avalanche NFT dapp scaffolded with AvaKit. Deploy an ERC-721 from the browser, then mint. Next.js + @avakit/react + shadcn/ui + Foundry.
4
+
5
+ ## Project map
6
+
7
+ - [contracts/src/AvaKitNFT.sol](contracts/src/AvaKitNFT.sol): minimal self-contained ERC-721 mint contract.
8
+ - [lib/nft-artifact.ts](lib/nft-artifact.ts): compiled ABI + bytecode (browser deploy, no Foundry at runtime).
9
+ - [components/demo.tsx](components/demo.tsx): deploy + mint flow.
10
+ - [app/providers.tsx](app/providers.tsx): AvaKitProvider (chains + wallet adapters) + theme.
11
+ - [CLAUDE.md](CLAUDE.md): agent guide (AvaKit API, contract workflow, rules).
12
+
13
+ ## Key APIs
14
+
15
+ - Deploy: `useAvaDeploy().deploy({ abi, bytecode })`
16
+ - Contract: `useContract({ address, abi }).write("mint", [])` / `.read("totalSupply")`
17
+ - Wallet: `<ConnectAvalanche />`, `useAvaAccount()`, `useAvaChain()`
18
+ - Core: `deployContract`, `getWalletClient`, `ensureChain` from `@avakit/core`
19
+
20
+ ## Recompile the contract
21
+
22
+ ```
23
+ cd contracts && forge build
24
+ ```
25
+ Then copy abi + bytecode.object from `out/AvaKitNFT.sol/AvaKitNFT.json` into `lib/nft-artifact.ts`.
26
+
27
+ ## External docs
28
+
29
+ - Avalanche Builder Hub: https://build.avax.network/llms.txt
30
+ - Foundry book: https://book.getfoundry.sh
31
+ - Fuji faucet: https://core.app/tools/testnet-faucet
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "nft-mint",
3
+ "title": "NFT mint",
4
+ "description": "Deploy an NFT contract from the browser, then mint",
5
+ "contracts": true
6
+ }
@@ -0,0 +1,7 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {
4
+ reactStrictMode: true,
5
+ };
6
+
7
+ export default nextConfig;
@@ -0,0 +1,32 @@
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
+ },
12
+ "dependencies": {
13
+ "@avakit/core": "__AVAKIT_DEP__",
14
+ "@avakit/react": "__AVAKIT_DEP__",
15
+ "lucide-react": "1.22.0",
16
+ "next": "16.2.9",
17
+ "next-themes": "0.4.6",
18
+ "react": "19.2.7",
19
+ "react-dom": "19.2.7",
20
+ "viem": "2.54.1"
21
+ },
22
+ "devDependencies": {
23
+ "@tailwindcss/postcss": "4.3.2",
24
+ "@types/node": "26.0.1",
25
+ "@types/react": "19.2.17",
26
+ "@types/react-dom": "19.2.3",
27
+ "postcss": "8.5.16",
28
+ "tailwindcss": "4.3.2",
29
+ "tw-animate-css": "1.4.0",
30
+ "typescript": "6.0.3"
31
+ }
32
+ }
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -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
+ }
@@ -0,0 +1,45 @@
1
+ # __PROJECT_NAME__ — Token-gated Avalanche dapp (scaffolded with AvaKit)
2
+
3
+ Operational guide for AI agents (Claude Code / Cursor).
4
+
5
+ ## Stack
6
+
7
+ Next.js 16 (App Router) · React 19 · `@avakit/react` · `@avakit/core` · viem · shadcn/ui · next-themes · Foundry (access-pass contract)
8
+
9
+ ## Idea
10
+
11
+ Content is gated behind ownership of an **access-pass NFT**. If `balanceOf(address) > 0`, the gated section renders; otherwise it stays locked with a mint button.
12
+
13
+ ## Architecture
14
+
15
+ - `contracts/src/AvaKitNFT.sol` — the access-pass ERC-721 (minimal, self-contained).
16
+ - `lib/nft-artifact.ts` — compiled ABI + bytecode (browser deploy, no Foundry at runtime).
17
+ - `components/demo.tsx` — deploy pass → mint → gate logic.
18
+ - `app/providers.tsx` — `<AvaKitProvider>` + `ThemeProvider`.
19
+
20
+ ## The gate
21
+
22
+ ```ts
23
+ const contract = useContract({ address, abi });
24
+ const balance = (await contract.read("balanceOf", [address])) as bigint;
25
+ const hasAccess = balance > 0n; // render gated content only when true
26
+ ```
27
+
28
+ - Deploy: `useAvaDeploy().deploy({ abi, bytecode })`
29
+ - Mint a pass: `contract.write("mint", [])`
30
+
31
+ To gate on a different token (e.g. an existing ERC-20 or NFT), point `useContract` at that address/ABI and adjust the `hasAccess` check (e.g. balance ≥ threshold).
32
+
33
+ ## Rules
34
+
35
+ - shadcn/ui only; `@avakit/react` components are shadcn-styled.
36
+ - Black & white only for now; dark/light via next-themes; both must work.
37
+ - Animations: Framer Motion or GSAP only.
38
+ - Deploying/minting costs gas — fund the wallet on Fuji first.
39
+ - Never gate sensitive data purely client-side: the gated content here is illustrative. For real secrets, verify ownership server-side (e.g. sign-in-with-Ethereum + an API check).
40
+ - Social login needs `NEXT_PUBLIC_WEB3AUTH_CLIENT_ID` in `.env.local`.
41
+
42
+ ## Commands
43
+
44
+ - `pnpm dev` — dev server
45
+ - `cd contracts && forge build` — recompile the access-pass contract
@@ -0,0 +1,38 @@
1
+ # __PROJECT_NAME__
2
+
3
+ A **token-gated** Avalanche dapp scaffolded with [AvaKit](https://github.com/mericcintosun/AvaKit). Content unlocks for holders of an access-pass NFT — no Foundry required to run it.
4
+
5
+ ## Getting started
6
+
7
+ ```bash
8
+ # 1. (social login, optional) add a free Web3Auth client ID
9
+ cp .env.example .env.local
10
+ # → https://dashboard.web3auth.io (Sapphire Devnet, EVM)
11
+
12
+ # 2. run it
13
+ pnpm dev # http://localhost:3000
14
+ ```
15
+
16
+ Then: connect a wallet → **Deploy access-pass contract** → **Mint access pass** → the gated content unlocks. Deploying and minting cost gas, so fund your wallet on Fuji first (in-app faucet link).
17
+
18
+ ## How the gate works
19
+
20
+ The gated section renders only when `balanceOf(address) > 0`:
21
+
22
+ ```ts
23
+ const balance = (await useContract({ address, abi }).read("balanceOf", [address])) as bigint;
24
+ const hasAccess = balance > 0n;
25
+ ```
26
+
27
+ - `contracts/src/AvaKitNFT.sol` — the access-pass ERC-721 (self-contained).
28
+ - `lib/nft-artifact.ts` — compiled ABI + bytecode, bundled for browser deploy.
29
+
30
+ > **Security:** client-side gating is illustrative. For real protected content, verify ownership server-side (e.g. Sign-In with Ethereum + an API check).
31
+
32
+ ## Stack
33
+
34
+ Next.js 16 · `@avakit/react` · `@avakit/core` · viem · shadcn/ui · Foundry
35
+
36
+ ## AI-native
37
+
38
+ Ships with `CLAUDE.md`, `llms.txt`, and `.cursor/rules` so Claude Code / Cursor understand the gate pattern and project conventions.