去中心化网文平台 · 前端 Web 应用
面向作者与读者的 Web3 小说站点,内置多钱包连接(支持所有主流钱包:浏览器注入钱包、Coinbase Wallet、WalletConnect 扫码/深链),可切 Base/以太坊等 EVM 链,后续可扩展上链发布与章节加密解锁。
仓库:
https://github.com/tao-999/novel-web
技术栈(默认):SvelteKit / Vite / TypeScript / wagmi v2 / viem / WalletConnect / EIP-6963 多钱包发现
lib/web3/
下集中管理连接器、配置、工具方法novel-web/
├─ src/
│ ├─ lib/
│ │ └─ web3/
│ │ ├─ config.ts # 链&RPC、WalletConnect 项目ID、序列化
│ │ ├─ account.ts # 账户状态、短地址、连接/断开入口
│ │ ├─ connectors.ts # EIP-6963、WalletConnect、CoinbaseWallet 连接器
│ │ ├─ installed.ts # 已安装钱包探测(注入 + EIP-6963 事件)
│ │ └─ helpers.ts # 持久化、自动恢复、错误归因
│ └─ routes/
│ └─ +page.svelte # 示例页面:ConnectButton / 账户面板
├─ .env.example # 环境变量示例
├─ package.json
└─ README.md
git clone https://github.com/tao-999/novel-web.git
cd novel-web
pnpm i
cp .env.example .env
pnpm dev
pnpm build
pnpm preview
VITE_CHAIN_ID=8453
VITE_RPC_URL=https://base-rpc.publicnode.com
VITE_WC_PROJECT_ID=YOUR_PROJECT_ID
VITE_API_BASE=https://api.your-novel.com/api
需要多链?在
src/lib/web3/config.ts
添加更多chains
并在 UI 中提供切链入口即可。
src/lib/web3/connectors.ts
)import { createConfig } from '@wagmi/core'
import { http } from 'viem'
import { base, mainnet, sepolia } from 'viem/chains'
import { coinbaseWallet, walletConnect, injected } from '@wagmi/connectors'
export const chains = [base]
export const wagmiConfig = createConfig({
chains,
transports: { [base.id]: http(import.meta.env.VITE_RPC_URL) },
connectors: [
injected({ shimDisconnect: true }),
walletConnect({
projectId: import.meta.env.VITE_WC_PROJECT_ID!,
showQrModal: true,
}),
coinbaseWallet({ appName: 'novel-web', preference: 'all' }),
],
ssr: false,
})
src/lib/web3/installed.ts
)eip6963:announceProvider
+ 兼容旧的 window.ethereum
注入<script lang="ts">
import { connectById, disconnectWallet, account, short } from '$lib/web3/account';
let openSelect = false;
</script>
<button on:click={() => (openSelect = true)}>🔗 连接钱包</button>
{#if openSelect}
<div class="modal">
<h3>选择你的钱包</h3>
{#each account.installedWallets as w}
<button on:click={() => connectById(w.id)}>{w.emoji} {w.label}(已安装)</button>
{/each}
<button on:click={() => connectById('walletConnect')}>📷 WalletConnect(扫码)</button>
<button on:click={() => connectById('coinbaseWallet')}>🟦 Coinbase Wallet</button>
<button on:click={() => (openSelect = false)}>关闭</button>
</div>
{/if}
{#if $account.address}
<div class="panel">
已连接:{$account.chain?.name} · {short($account.address)}
<button on:click={disconnectWallet}>断开</button>
</div>
{/if}
MIT