开发者指南
代码示例 v1.1
Microcosm 代码示例
版本: v1.1 | 日期: 2026-02-15
配套文档:
Microcosm-开发者接入指南.md|Microcosm-API参考手册.md
目录
- Next.js 完整接入(4 个文件)
- 认证 Hooks
- 资产数据 Hooks
- 挖矿 & 轮回 Hooks
- 领地 & 生态 Hooks
- 图表 & 聚合 Hooks
- 通用 API 查询
- 菜单嵌入
- 路由守卫
- 纯后端调用(无 SDK)
- 钱包管理
- 领地管理(完整)
- 投票系统
- 拍卖增强
- 回购管理
- 挖矿增强
- MCD 详情
- 统计数据
- 挖矿执行(写操作)
- 回购执行(写操作)
- 领地编辑(写操作)
- 拍卖出价/取消(写操作)
- 投票操作(写操作)
- MCC 综合历史
- 链上交易构建指南
1. Next.js 完整接入
1.1 安装
bash
npm install @microcosmmoney/auth-core @microcosmmoney/auth-react @microcosmmoney/portal-react
1.2 后端: Token Exchange
typescript
// app/api/auth/exchange/route.ts
import { createTokenExchangeHandler } from '@microcosmmoney/auth-react/server'
export const POST = createTokenExchangeHandler({
clientId: process.env.OAUTH_CLIENT_ID!,
clientSecret: process.env.OAUTH_CLIENT_SECRET!,
})
1.3 前端: Provider
tsx
// app/providers.tsx
'use client'
import { MicrocosmAuthProvider } from '@microcosmmoney/auth-react'
export function Providers({ children }: { children: React.ReactNode }) {
return (
<MicrocosmAuthProvider
clientId={process.env.NEXT_PUBLIC_OAUTH_CLIENT_ID!}
redirectUri="/auth/callback"
>
{children}
</MicrocosmAuthProvider>
)
}
在 app/layout.tsx 中使用:
tsx
// app/layout.tsx
import { Providers } from './providers'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}
1.4 回调页
tsx
// app/auth/callback/page.tsx
import { AuthCallback } from '@microcosmmoney/auth-react'
export default function CallbackPage() {
return <AuthCallback redirectTo="/dashboard" />
}
1.5 环境变量
bash
# .env.local
NEXT_PUBLIC_OAUTH_CLIENT_ID=your_client_id # 前端用 (浏览器可见)
OAUTH_CLIENT_ID=your_client_id # 后端用 (Token Exchange 必须)
OAUTH_CLIENT_SECRET=your_client_secret # 后端用 (Token Exchange 必须)
重要: 后端
OAUTH_CLIENT_ID和OAUTH_CLIENT_SECRET缺少任一,首次请求时会返回 500 错误(server_configuration_error)。SDK ≥1.0.2 不会在构建时抛出异常,兼容next build。
2. 认证 Hooks
2.1 useAuth — 登录/登出
tsx
import { useAuth } from '@microcosmmoney/auth-react'
function LoginButton() {
const { user, isAuthenticated, isLoading, login, logout } = useAuth()
if (isLoading) return <div>Loading...</div>
if (!isAuthenticated) {
return <button onClick={() => login()}>Login with Microcosm</button>
}
return (
<div>
<p>Welcome, {user?.displayName || user?.email}</p>
<p>Role: {user?.role} | Level: {user?.level}</p>
<button onClick={logout}>Logout</button>
</div>
)
}
useAuth 返回值:
typescript
{
user: User | null // 用户信息
isAuthenticated: boolean // 是否已登录
isLoading: boolean // 初始化中
error: Error | null // 错误
login: (options?) => void // 触发登录
logout: () => Promise<void> // 登出
getAccessToken: () => Promise<string | null> // 获取 Token
client: MicrocosmAuthClient // 底层客户端
}
2.2 useProfile — 资料管理
tsx
import { useProfile } from '@microcosmmoney/auth-react'
function ProfileEditor() {
const { profile, loading, updateProfile, uploadAvatar } = useProfile()
async function handleNameChange() {
await updateProfile({ display_name: 'New Name' })
}
async function handleAvatarUpload(e: React.ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0]
if (file) {
const url = await uploadAvatar(file)
console.log('Avatar uploaded:', url)
}
}
if (loading) return <div>Loading...</div>
return (
<div>
<img src={profile?.avatarUrl || '/default-avatar.png'} alt="Avatar" />
<p>{profile?.displayName}</p>
<p>{profile?.email}</p>
<button onClick={handleNameChange}>Change Name</button>
<input type="file" accept="image/*" onChange={handleAvatarUpload} />
</div>
)
}
useProfile 返回值:
typescript
{
profile: User | null
loading: boolean
error: Error | null
updateProfile: (data: { display_name?: string }) => Promise<void>
uploadAvatar: (file: File) => Promise<string | null>
refresh: () => Promise<void>
}
3. 资产数据 Hooks
3.1 useMCC — MCC 余额 + 价格
tsx
import { useMCC } from '@microcosmmoney/auth-react'
function MCCWallet() {
const { balance, price, loading, refresh } = useMCC()
if (loading) return <div>Loading...</div>
return (
<div>
<h3>MCC Balance</h3>
<p>Balance: {balance?.balance} MCC</p>
<p>Raw: {balance?.raw_balance} (9 decimals)</p>
{balance?.wallet_address && (
<p>Wallet: {balance.wallet_address}</p>
)}
{balance?.wallets?.map(w => (
<p key={w.wallet_address}>{w.wallet_address}: {w.balance} MCC {w.is_primary ? '(primary)' : ''}</p>
))}
<h3>MCC Price</h3>
<p>${price?.price?.toFixed(6)}</p>
<p>Buyback: ${price?.buyback_price?.toFixed(6)}</p>
<p>Source: {price?.source}</p>
<button onClick={refresh}>Refresh</button>
</div>
)
}
useMCC 返回值:
typescript
{
balance: {
balance: number
raw_balance: number
decimals: number
symbol: string
wallet_address?: string | null
wallets?: MCCWalletBalance[]
mint?: string
} | null
price: MCCPrice | null
loading: boolean
error: Error | null
refresh: () => Promise<void>
}
3.2 useMCD — MCD 余额
tsx
import { useMCD } from '@microcosmmoney/auth-react'
function MCDBalance() {
const { balance, loading } = useMCD()
if (loading) return <div>Loading...</div>
return (
<div>
{/* MCDBalance 字段是 string 类型,需 parseFloat 参与计算 */}
<p>Total MCD: {balance?.total_balance}</p>
<p>Available: {balance?.available_balance}</p>
<p>Frozen: {balance?.frozen_balance}</p>
</div>
)
}
3.3 useMCCPrice — 实时价格(无需登录)
tsx
import { useMCCPrice } from '@microcosmmoney/auth-react'
function PriceTicker() {
// 默认 30 秒刷新,可自定义
const { data: price, loading } = useMCCPrice({ refetchInterval: 10_000 })
if (loading) return <span>--</span>
return <span>${price?.price?.toFixed(6)}</span>
}
3.4 useMCCStats / useMCDStats — 全局统计(无需登录)
tsx
import { useMCCStats, useMCDStats } from '@microcosmmoney/auth-react'
function TokenStats() {
const { data: mccStats } = useMCCStats() // 5 分钟缓存
const { data: mcdStats } = useMCDStats()
return (
<div>
<h3>MCC Stats</h3>
<pre>{JSON.stringify(mccStats, null, 2)}</pre>
<h3>MCD Stats</h3>
<pre>{JSON.stringify(mcdStats, null, 2)}</pre>
</div>
)
}
4. 挖矿 & 轮回 Hooks
4.1 useMiningStats — 用户挖矿统计
tsx
import { useMiningStats } from '@microcosmmoney/auth-react'
function MiningDashboard() {
const { data: stats, loading } = useMiningStats()
if (loading) return <div>Loading...</div>
return (
<div>
<h3>Mining Stats</h3>
<p>Total Mined: {stats?.total_mined?.toFixed(2)} MCC</p>
<p>Total Paid: ${stats?.total_paid?.toFixed(2)}</p>
<p>Mining Count: {stats?.mining_count}</p>
<p>Today: {stats?.today_mined?.toFixed(2)} MCC</p>
<p>Last 30d: {stats?.last_30d_mined?.toFixed(2)} MCC</p>
<p>Active Days (30d): {stats?.active_days_30d}</p>
<p>Last Mined: {stats?.last_mined_at ? new Date(stats.last_mined_at).toLocaleString() : 'Never'}</p>
</div>
)
}
4.2 useMiningRecords — 挖矿历史
tsx
import { useMiningRecords } from '@microcosmmoney/auth-react'
function MiningHistory() {
const { data: records, loading } = useMiningRecords()
if (loading) return <div>Loading...</div>
return (
<table>
<thead>
<tr><th>Time</th><th>MCC Amount</th><th>Paid</th><th>TX</th></tr>
</thead>
<tbody>
{records?.map((r: any, i: number) => (
<tr key={i}>
<td>{new Date(r.mined_at).toLocaleString()}</td>
<td>{r.mcc_amount} MCC</td>
<td>${r.paid_amount} {r.stablecoin}</td>
<td>{r.tx_signature?.slice(0, 8)}...</td>
</tr>
))}
</tbody>
</table>
)
}
4.3 useReincarnationPool — 轮回池(无需登录)
tsx
import { useReincarnationPool } from '@microcosmmoney/auth-react'
function ReincarnationPool() {
const { data: pool, loading } = useReincarnationPool()
if (loading) return <div>Loading...</div>
return (
<div>
<h3>Reincarnation Pool</h3>
<p>USDC: {pool?.usdc_balance?.toFixed(2)}</p>
<p>USDT: {pool?.usdt_balance?.toFixed(2)}</p>
<p>MCC: {pool?.mcc_balance?.toFixed(2)}</p>
<p>Total Stablecoin: ${pool?.total_stablecoin?.toFixed(2)}</p>
</div>
)
}
5. 领地 & 生态 Hooks
5.1 useUserLevel — 用户等级
tsx
import { useUserLevel } from '@microcosmmoney/auth-react'
function UserLevelBadge() {
const { data: level, loading } = useUserLevel()
if (loading) return <div>Loading...</div>
return (
<div>
<span>Level: {level?.level}</span>
<span>Title: {level?.title || 'None'}</span>
</div>
)
}
5.2 useTerritoryNFTs — 领地 NFT(无需登录)
tsx
import { useTerritoryNFTs } from '@microcosmmoney/auth-react'
function TerritoryNFTList() {
const { data: nfts, loading } = useTerritoryNFTs()
if (loading) return <div>Loading...</div>
return (
<div>
{nfts?.map((nft: any) => (
<div key={nft.mint}>
<p>{nft.name}</p>
<p>Mint: {nft.mint}</p>
</div>
))}
</div>
)
}
5.3 useAuctions — 活跃拍卖
tsx
import { useAuctions } from '@microcosmmoney/auth-react'
function AuctionList() {
const { data: auctions, loading } = useAuctions()
if (loading) return <div>Loading...</div>
return (
<div>
{auctions?.map((a: any) => (
<div key={a.id}>
<p>{a.title} - Current Bid: {a.current_bid} MCC</p>
</div>
))}
</div>
)
}
5.4 useOrganizations — 组织列表
tsx
import { useOrganizations } from '@microcosmmoney/auth-react'
function OrgList() {
const { data: orgs, loading } = useOrganizations()
if (loading) return <div>Loading...</div>
return (
<ul>
{orgs?.map((org: any) => (
<li key={org.id}>{org.name} ({org.member_count} members)</li>
))}
</ul>
)
}
5.5 useTechTree — 科技树
tsx
import { useTechTree } from '@microcosmmoney/auth-react'
function TechTreeProgress() {
const { data: tree, loading } = useTechTree()
if (loading) return <div>Loading...</div>
return (
<div>
<pre>{JSON.stringify(tree, null, 2)}</pre>
</div>
)
}
6. 图表 & 聚合 Hooks
6.1 usePriceHistory — 价格走势
tsx
import { usePriceHistory } from '@microcosmmoney/auth-react'
import { useState } from 'react'
type TimeRange = '1D' | '7D' | '30D'
function PriceChart() {
const [range, setRange] = useState<TimeRange>('7D')
const { data: history, loading } = usePriceHistory(range)
return (
<div>
<div>
{(['1D', '7D', '30D'] as TimeRange[]).map((r) => (
<button
key={r}
onClick={() => setRange(r)}
style={{ fontWeight: range === r ? 'bold' : 'normal' }}
>
{r}
</button>
))}
</div>
{loading ? (
<div>Loading chart...</div>
) : (
<div>
{/* 使用 Recharts 或其他图表库渲染 */}
<pre>{JSON.stringify(history?.slice(0, 3), null, 2)}</pre>
<p>... ({history?.length} data points)</p>
</div>
)}
</div>
)
}
6.2 useDashboardSummary — 仪表盘汇总
tsx
import { useDashboardSummary } from '@microcosmmoney/auth-react'
function DashboardOverview() {
const { data: summary, loading } = useDashboardSummary()
if (loading) return <div>Loading...</div>
return (
<div>
<pre>{JSON.stringify(summary, null, 2)}</pre>
</div>
)
}
7. 通用 API 查询
useApiQuery — 调用任意 API 端点
tsx
import { useApiQuery } from '@microcosmmoney/auth-react'
// 公开端点(无需登录)
function MarketData() {
const { data, loading, error } = useApiQuery({
path: '/v1/dashboard/market',
requireAuth: false,
refetchInterval: 60_000,
})
if (loading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
return <pre>{JSON.stringify(data, null, 2)}</pre>
}
// 用户端点(需登录)— 未登录时自动 skip
function MyTransactions() {
const { data, loading } = useApiQuery({
path: '/v1/mcc/transactions?page=1&per_page=10',
requireAuth: true,
})
if (loading) return <div>Loading...</div>
return <pre>{JSON.stringify(data, null, 2)}</pre>
}
8. 菜单嵌入
8.1 基础用法
tsx
import { MicrocosmMenuSection } from '@microcosmmoney/portal-react'
import { usePathname, useRouter } from 'next/navigation'
function Sidebar() {
const pathname = usePathname()
const router = useRouter()
return (
<aside>
<MicrocosmMenuSection
basePath="/v2"
currentPath={pathname}
onNavigate={(path) => router.push(path)}
/>
</aside>
)
}
8.2 自定义渲染
tsx
import { MicrocosmMenuSection } from '@microcosmmoney/portal-react'
import type { MicrocosmMenuItem, MicrocosmMenuGroup } from '@microcosmmoney/portal-react'
function CustomSidebar() {
return (
<MicrocosmMenuSection
basePath="/app"
currentPath="/app/mcc/mining"
onNavigate={(path) => window.location.href = path}
renderSectionHeader={(group: MicrocosmMenuGroup) => (
<h4 className="text-xs uppercase text-gray-500 mt-4 mb-2">
{group.title}
</h4>
)}
renderItem={(item: MicrocosmMenuItem, path: string, isActive: boolean) => (
<a
href={path}
className={isActive ? 'font-bold text-blue-600' : 'text-gray-700'}
>
{item.icon} {item.title}
</a>
)}
/>
)
}
8.3 菜单内容
| 组 | 菜单项 | 路径 |
|---|---|---|
| Blockchain | 铸造 | {basePath}/mcc/mining |
| 轮回回购 | {basePath}/mcc/reincarnation | |
| 钱包 | {basePath}/mcc/wallet | |
| MCD 积分 | {basePath}/mcc/mcd | |
| Web3 OS | 拍卖市场 | {basePath}/mcc/auctions |
| 领地管理 | {basePath}/user-system/territory | |
| 社区投票 | {basePath}/mcc/voting | |
| 组织架构 | {basePath}/user-system/organization |
9. 路由守卫
9.1 HOC 方式
tsx
import { withAuth } from '@microcosmmoney/auth-react'
function DashboardPage() {
return <div>Protected Dashboard Content</div>
}
export default withAuth(DashboardPage)
9.2 组件方式
tsx
import { RequireRole } from '@microcosmmoney/auth-react'
function AdminPage() {
return (
<div>
<h1>Admin Area</h1>
<RequireRole roles={['admin']} fallback={<div>No permission</div>}>
<AdminPanel />
</RequireRole>
<RequireRole roles={['admin', 'user']}>
<UserContent />
</RequireRole>
</div>
)
}
10. 纯后端调用(无 SDK)
如果你的后端不使用 JavaScript/TypeScript,可以直接调用 HTTP API。
10.1 Python (Flask)
python
import requests
MICROCOSM_API = "https://api.microcosm.money"
# 公开端点 — 无需认证
def get_mcc_price():
resp = requests.get(f"{MICROCOSM_API}/v1/mcc/price")
data = resp.json()
if data["success"]:
return data["data"]
return None
# 用户端点 — Bearer Token
def get_user_balance(access_token: str):
resp = requests.get(
f"{MICROCOSM_API}/v1/mcc/balance",
headers={"Authorization": f"Bearer {access_token}"}
)
return resp.json()
# Token Exchange
def exchange_token(code: str, redirect_uri: str):
resp = requests.post(
"https://microcosm.money/api/oauth/token",
json={
"grant_type": "authorization_code",
"code": code,
"redirect_uri": redirect_uri,
"client_id": "your-client-id",
"client_secret": "your-client-secret",
}
)
return resp.json()
# Returns: { access_token, refresh_token, expires_in, user }
# Token Refresh
def refresh_token(refresh_token: str):
resp = requests.post(
"https://microcosm.money/api/oauth/token",
json={
"grant_type": "refresh_token",
"refresh_token": refresh_token,
"client_id": "your-client-id",
"client_secret": "your-client-secret",
}
)
return resp.json()
# Token Introspect
def verify_token(access_token: str):
resp = requests.post(
"https://microcosm.money/api/oauth/introspect",
json={
"token": access_token,
"client_id": "your-client-id",
"client_secret": "your-client-secret",
}
)
data = resp.json()
if data.get("active"):
return data # { active, uid, email, role, level, scope, exp, iat }
return None
10.2 cURL
bash
# 公开: MCC 价格
curl https://api.microcosm.money/v1/mcc/price
# 公开: 轮回池
curl https://api.microcosm.money/v1/reincarnation/pool
# 用户: 余额 (需 Token)
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://api.microcosm.money/v1/mcc/balance
# OAuth: Token Exchange
curl -X POST https://microcosm.money/api/oauth/token \
-H "Content-Type: application/json" \
-d '{"grant_type":"authorization_code","code":"AUTH_CODE","redirect_uri":"https://your-app.com/callback","client_id":"YOUR_ID","client_secret":"YOUR_SECRET"}'
11. 钱包管理
11.1 useWallets — 用户绑定钱包列表
tsx
import { useWallets } from '@microcosmmoney/auth-react'
function WalletList() {
const { data: wallets, loading } = useWallets()
if (loading) return <div>Loading...</div>
return (
<div>
<h3>My Wallets</h3>
{wallets?.map((w) => (
<div key={w.wallet_address}>
<p>{w.wallet_address}</p>
<p>Type: {w.wallet_type} | Primary: {w.is_primary ? 'Yes' : 'No'}</p>
</div>
))}
</div>
)
}
11.2 useTokenPortfolio — 完整代币组合
tsx
import { useTokenPortfolio } from '@microcosmmoney/auth-react'
function WalletTokens({ address }: { address: string }) {
const { data: portfolio, loading } = useTokenPortfolio(address)
if (loading) return <div>Loading...</div>
return (
<div>
<p>SOL: {portfolio?.sol_balance}</p>
<p>MCC: {portfolio?.mcc_balance}</p>
<p>USDT: {portfolio?.usdt_balance}</p>
<p>USDC: {portfolio?.usdc_balance}</p>
</div>
)
}
11.3 useMCCLocks — MCC 锁仓期
tsx
import { useMCCLocks } from '@microcosmmoney/auth-react'
function LockList() {
const { data: locks, loading } = useMCCLocks()
if (loading) return <div>Loading...</div>
return (
<div>
<h3>MCC Locks</h3>
{locks?.map((lock) => (
<div key={lock.lock_id}>
<p>{lock.amount} MCC - {lock.reason}</p>
<p>{lock.lock_start} ~ {lock.lock_end}</p>
<p>Status: {lock.status}</p>
</div>
))}
</div>
)
}
12. 领地管理(完整)
12.1 useTerritories — 领地列表
tsx
import { useTerritories } from '@microcosmmoney/auth-react'
function TerritoryList() {
const { data: territories, loading } = useTerritories({ unitType: 'station', page: 1 })
if (loading) return <div>Loading...</div>
return (
<div>
{territories?.map((t) => (
<div key={t.unit_id}>
<h4>{t.unit_name} ({t.short_id})</h4>
<p>Type: {t.unit_type} | Members: {t.member_count}/{t.max_capacity}</p>
<p>Vault: {t.vault_balance} MCD</p>
</div>
))}
</div>
)
}
12.2 useTerritoryDetail + useTerritoryStats
tsx
import { useTerritoryDetail, useTerritoryStats } from '@microcosmmoney/auth-react'
function TerritoryPage({ id }: { id: string }) {
const { data: territory, loading: l1 } = useTerritoryDetail(id)
const { data: stats, loading: l2 } = useTerritoryStats(id)
if (l1 || l2) return <div>Loading...</div>
return (
<div>
<h2>{territory?.unit_name}</h2>
<p>{territory?.description}</p>
<p>Location: {territory?.location}</p>
<h3>Stats</h3>
<p>Members: {stats?.member_count} / {stats?.max_capacity}</p>
<p>Occupancy: {((stats?.occupancy_rate ?? 0) * 100).toFixed(1)}%</p>
<p>Vault MCD: {stats?.vault_mcd}</p>
</div>
)
}
12.3 useTerritoryMembers — 成员列表
tsx
import { useTerritoryMembers } from '@microcosmmoney/auth-react'
function MemberList({ territoryId }: { territoryId: string }) {
const { data: members, loading } = useTerritoryMembers(territoryId, { page: 1, pageSize: 20 })
if (loading) return <div>Loading...</div>
return (
<table>
<thead>
<tr><th>Name</th><th>Level</th><th>MCD Received</th><th>Joined</th></tr>
</thead>
<tbody>
{members?.map((m) => (
<tr key={m.uid}>
<td>{m.display_name || m.uid}</td>
<td>{m.level}</td>
<td>{m.mcd_received}</td>
<td>{m.joined_at ? new Date(m.joined_at).toLocaleDateString() : '-'}</td>
</tr>
))}
</tbody>
</table>
)
}
12.4 useTerritorySummary — 领地汇总
tsx
import { useTerritorySummary } from '@microcosmmoney/auth-react'
function TerritorySummaryCard() {
const { data: summary, loading } = useTerritorySummary()
if (loading) return <div>Loading...</div>
return (
<div>
<p>Total Stations: {summary?.total_stations}</p>
<p>Total Members: {summary?.total_members}</p>
<p>Total Vault MCD: {summary?.total_vault_mcd}</p>
<p>Avg KPI: {summary?.avg_kpi_score?.toFixed(2)}</p>
</div>
)
}
13. 投票系统
13.1 useProposals — 提案列表
tsx
import { useProposals } from '@microcosmmoney/auth-react'
function ProposalList() {
const { data: proposals, loading } = useProposals({ status: 'active' })
if (loading) return <div>Loading...</div>
return (
<div>
{proposals?.map((p) => (
<div key={p.id}>
<h4>{p.title}</h4>
<p>{p.description}</p>
<p>Status: {p.status} | Type: {p.proposal_type}</p>
<p>Options: {p.options.join(', ')}</p>
<p>Ends: {new Date(p.ends_at).toLocaleString()}</p>
</div>
))}
</div>
)
}
13.2 useProposalDetail + useVotePower — 投票
tsx
import { useProposalDetail, useVotePower, useAuth } from '@microcosmmoney/auth-react'
function VotingPage({ proposalId }: { proposalId: string }) {
const { client } = useAuth()
const { data: proposal, loading: l1 } = useProposalDetail(proposalId)
const { data: power, loading: l2 } = useVotePower()
if (l1 || l2) return <div>Loading...</div>
async function handleVote(optionIndex: number) {
const api = client.getApiClient()
await api.post(`/voting/proposals/${proposalId}/vote`, {
option_index: optionIndex,
vote_count: 1,
})
alert('Vote cast!')
}
return (
<div>
<h2>{proposal?.title}</h2>
<p>{proposal?.description}</p>
<p>Your Vote Power: {power?.vote_power} (Max: {power?.max_votes})</p>
<h3>Results</h3>
{proposal?.vote_results?.map((r, i) => (
<div key={i}>
<p>{r.option}: {r.votes} votes ({r.voter_count} voters, {r.mcc_total} MCC)</p>
<button onClick={() => handleVote(i)} disabled={!power?.can_vote}>
Vote for "{r.option}"
</button>
</div>
))}
</div>
)
}
14. 拍卖增强
14.1 useAuctionDetail — 拍卖详情
tsx
import { useAuctionDetail } from '@microcosmmoney/auth-react'
function AuctionPage({ auctionId }: { auctionId: number }) {
const { data: auction, loading } = useAuctionDetail(auctionId)
if (loading) return <div>Loading...</div>
return (
<div>
<h2>Auction #{auctionId}</h2>
<pre>{JSON.stringify(auction, null, 2)}</pre>
</div>
)
}
14.2 useMyBids — 我的竞价 + 出价
tsx
import { useMyBids, useAuth } from '@microcosmmoney/auth-react'
import { useState } from 'react'
function MyBidsPage() {
const { data: bids, loading, refresh } = useMyBids()
const { client } = useAuth()
const [bidAmount, setBidAmount] = useState('')
const [auctionId, setAuctionId] = useState('')
async function handleBid() {
const api = client.getApiClient()
await api.post(`/auction-solana/auction/${auctionId}/bid`, {
bid_amount: parseFloat(bidAmount),
})
await refresh()
}
if (loading) return <div>Loading...</div>
return (
<div>
<h3>My Bids</h3>
{bids?.map((b) => (
<div key={b.bid_id}>
<p>Auction #{b.auction_id}: {b.bid_amount} MCC - {b.status}</p>
</div>
))}
<h3>Place Bid</h3>
<input placeholder="Auction ID" value={auctionId} onChange={e => setAuctionId(e.target.value)} />
<input placeholder="Bid Amount" value={bidAmount} onChange={e => setBidAmount(e.target.value)} />
<button onClick={handleBid}>Place Bid</button>
</div>
)
}
15. 回购管理
15.1 useBuybackQuote — 回购报价
tsx
import { useBuybackQuote } from '@microcosmmoney/auth-react'
import { useState } from 'react'
function BuybackCalculator() {
const [amount, setAmount] = useState(1)
const { data: quote, loading } = useBuybackQuote(amount)
return (
<div>
<h3>Buyback Quote</h3>
<input
type="number"
value={amount}
onChange={e => setAmount(parseFloat(e.target.value) || 0)}
min={0.01}
/>
<span> MCC</span>
{loading ? (
<p>Calculating...</p>
) : quote ? (
<div>
<p>Market Price: ${quote.market_price?.toFixed(6)}</p>
<p>Buyback Price: ${quote.buyback_price?.toFixed(6)} (+5% premium)</p>
<p>You Receive: ${quote.usdc_amount?.toFixed(6)} stablecoin</p>
<p>Premium: ${quote.premium_amount?.toFixed(6)}</p>
{quote.fee != null && <p>Fee: ${quote.fee?.toFixed(6)} ({(quote.fee_rate! * 100).toFixed(2)}%)</p>}
{quote.net_amount != null && <p>Net Amount: ${quote.net_amount?.toFixed(6)}</p>}
{quote.vault_type && <p>Vault: {quote.vault_type}</p>}
{quote.pool_remaining != null && <p>Pool Remaining: ${quote.pool_remaining?.toFixed(2)}</p>}
</div>
) : null}
</div>
)
}
15.2 useBuybackHistory — 回购记录
tsx
import { useBuybackHistory } from '@microcosmmoney/auth-react'
function BuybackHistory() {
const { data: records, loading } = useBuybackHistory({ page: 1 })
if (loading) return <div>Loading...</div>
return (
<table>
<thead>
<tr><th>Time</th><th>MCC</th><th>Received</th><th>Stablecoin</th><th>TX</th></tr>
</thead>
<tbody>
{records?.map((r, i) => (
<tr key={i}>
<td>{new Date(r.created_at).toLocaleString()}</td>
<td>{r.mcc_amount} MCC</td>
<td>${r.usdc_amount}</td>
<td>{r.stablecoin}</td>
<td>{r.tx_signature?.slice(0, 8)}...</td>
</tr>
))}
</tbody>
</table>
)
}
16. 挖矿增强
16.1 useMiningRatio — 挖矿比率/阶段
tsx
import { useMiningRatio } from '@microcosmmoney/auth-react'
function MiningRatioCard() {
const { data: ratio, loading } = useMiningRatio()
if (loading) return <div>Loading...</div>
return (
<div>
<h3>Mining Ratio</h3>
<p>Current Stage: {ratio?.current_stage}</p>
<p>Total Minted: {ratio?.total_minted?.toLocaleString()} MCC</p>
<p>Current Rate: {ratio?.current_rate}:1</p>
<p>USDC per MCC: ${ratio?.usdc_per_mcc?.toFixed(6)}</p>
</div>
)
}
16.2 useMiningDistribution — 伴生矿分配历史
tsx
import { useMiningDistribution } from '@microcosmmoney/auth-react'
function DistributionHistory() {
const { data: records, loading } = useMiningDistribution({ page: 1 })
if (loading) return <div>Loading...</div>
return (
<table>
<thead>
<tr><th>Time</th><th>User MCC</th><th>Team MCC</th><th>Magistrate MCC</th><th>Vault MCD</th></tr>
</thead>
<tbody>
{records?.map((r, i) => (
<tr key={i}>
<td>{new Date(r.created_at).toLocaleString()}</td>
<td>{r.user_mcc}</td>
<td>{r.team_mcc}</td>
<td>{r.magistrate_mcc}</td>
<td>{r.vault_mcd}</td>
</tr>
))}
</tbody>
</table>
)
}
17. MCD 详情
17.1 useMCDTransactions — 交易记录
tsx
import { useMCDTransactions } from '@microcosmmoney/auth-react'
function MCDTransactionList() {
const { data: txs, loading } = useMCDTransactions({ page: 1, type: 'reward' })
if (loading) return <div>Loading...</div>
return (
<table>
<thead>
<tr><th>Time</th><th>Type</th><th>Amount</th><th>From</th><th>To</th></tr>
</thead>
<tbody>
{txs?.map((tx) => (
<tr key={tx.id}>
<td>{new Date(tx.created_at).toLocaleString()}</td>
<td>{tx.tx_type}</td>
<td>{tx.amount} MCD</td>
<td>{tx.from_account_type}</td>
<td>{tx.to_account_type}</td>
</tr>
))}
</tbody>
</table>
)
}
17.2 useMCDRewards — 每日奖励
tsx
import { useMCDRewards } from '@microcosmmoney/auth-react'
function MCDRewardList() {
const { data: rewards, loading } = useMCDRewards({ page: 1 })
if (loading) return <div>Loading...</div>
return (
<table>
<thead>
<tr><th>Date</th><th>Territory</th><th>MCD Received</th></tr>
</thead>
<tbody>
{rewards?.map((r) => (
<tr key={r.id}>
<td>{r.reward_date}</td>
<td>{r.territory_id || '-'}</td>
<td>{r.mcd_received} MCD</td>
</tr>
))}
</tbody>
</table>
)
}
18. 统计数据
18.1 useUserStats — 用户等级分布
tsx
import { useUserStats } from '@microcosmmoney/auth-react'
function UserStatsCard() {
const { data: stats, loading } = useUserStats()
if (loading) return <div>Loading...</div>
return (
<div>
<h3>User Statistics</h3>
<pre>{JSON.stringify(stats, null, 2)}</pre>
</div>
)
}
18.2 MicrocosmAPI — 纯 TypeScript 调用
typescript
import { MicrocosmAPI } from '@microcosmmoney/auth-core'
const api = new MicrocosmAPI()
const marketPrice = await api.mcc.getPrice()
const miningRatio = await api.mining.getRatio()
const pool = await api.reincarnation.getPool()
const buybackQuote = await api.reincarnation.getQuote(10)
const userBalance = await api.mcc.getBalance(token)
const wallets = await api.wallets.list(token)
const territories = await api.territories.list(token, { unit_type: 'station' })
const proposals = await api.voting.getProposals(token, { status: 'active' })
const myBids = await api.auctions.getMyBids(token)
19. 挖矿执行(写操作)
19.1 useMiningAction — 认证用户挖矿
挖矿是两步流程:先创建请求获取支付信息,用户链上转账稳定币后确认。
tsx
import { useMiningAction, useMiningConfig } from '@microcosmmoney/auth-react'
function MiningPanel({ walletAddress }: { walletAddress: string }) {
const { createRequest, confirm, loading, error } = useMiningAction()
const { data: config } = useMiningConfig()
const [amount, setAmount] = useState(1)
const [step, setStep] = useState<'input' | 'paying' | 'done'>('input')
const [request, setRequest] = useState<any>(null)
const handleMine = async () => {
const req = await createRequest({
mcc_amount: amount,
stablecoin: 'USDT',
wallet_address: walletAddress,
})
setRequest(req)
setStep('paying')
}
const handleConfirm = async (txSignature: string) => {
await confirm({
request_id: request.request_id,
tx_signature: txSignature,
mcc_amount: request.mcc_amount,
usdc_amount: request.usdc_amount,
stablecoin_type: 'USDT',
})
setStep('done')
}
return (
<div>
{step === 'input' && (
<div>
<p>Mining Price: {config?.distribution_ratios ? 'Oracle × 2' : '...'}</p>
<input type="number" value={amount} onChange={e => setAmount(+e.target.value)} />
<button onClick={handleMine} disabled={loading}>Mine MCC</button>
</div>
)}
{step === 'paying' && request && (
<div>
<p>Transfer {request.usdc_amount} USDT to: {request.payment_address}</p>
<p>Request expires at: {request.expires_at}</p>
<button onClick={() => handleConfirm('USER_TX_SIGNATURE')}>
Confirm Payment
</button>
</div>
)}
{step === 'done' && <p>Mining complete!</p>}
{error && <p style={{ color: 'red' }}>{error.message}</p>}
</div>
)
}
19.2 usePublicMining — 钱包直连挖矿(无账户)
不需要 OAuth 登录,仅凭钱包地址即可挖矿。
tsx
import { usePublicMining } from '@microcosmmoney/auth-react'
function PublicMiningWidget() {
const { createRequest, verify, loading, error } = usePublicMining()
const handlePublicMine = async (walletAddress: string) => {
const req = await createRequest({
wallet_address: walletAddress,
mcc_amount: 1,
stablecoin: 'USDT',
})
const txSignature = 'USER_SIGNED_TX'
const result = await verify(req.request_id, txSignature)
console.log('Mining verified:', result)
}
return (
<button onClick={() => handlePublicMine('USER_WALLET')} disabled={loading}>
Mine with Wallet Only
</button>
)
}
20. 回购执行(写操作)
20.1 useBuybackAction — 记录链上回购
回购流程:前端构建 Reincarnation execute_buyback 指令 → 用户用 Phantom 签名 → 链上执行 → 调用 record 记录到后端。
tsx
import { useBuybackAction, useBuybackQuote } from '@microcosmmoney/auth-react'
function BuybackPanel() {
const { record, loading, error } = useBuybackAction()
const { data: quote } = useBuybackQuote(10)
const [txSig, setTxSig] = useState('')
const handleRecord = async () => {
await record({
tx_signature: txSig,
wallet_address: 'USER_WALLET_ADDRESS',
mcc_amount: 10,
usdc_amount: quote?.usdc_amount || 0,
stablecoin: 'USDT',
})
alert('Buyback recorded!')
}
return (
<div>
<p>Quote: {quote?.usdc_amount} USDT for 10 MCC (premium: {quote?.premium_amount})</p>
<input value={txSig} onChange={e => setTxSig(e.target.value)} placeholder="Transaction signature" />
<button onClick={handleRecord} disabled={loading || !txSig}>
Record Buyback
</button>
{error && <p style={{ color: 'red' }}>{error.message}</p>}
</div>
)
}
21. 领地编辑(写操作)
21.1 useTerritoryUpdate — 编辑领地信息
tsx
import { useTerritoryUpdate, useTerritoryDetail } from '@microcosmmoney/auth-react'
function TerritoryEditor({ territoryId }: { territoryId: string }) {
const { update, updateName, loading, error } = useTerritoryUpdate()
const { data: territory, refresh } = useTerritoryDetail(territoryId)
const [name, setName] = useState('')
const [desc, setDesc] = useState('')
useEffect(() => {
if (territory) {
setName(territory.unit_name || '')
setDesc(territory.description || '')
}
}, [territory])
const handleSave = async () => {
await update(territoryId, { description: desc, image_url: territory?.image_url })
refresh()
}
const handleRename = async () => {
await updateName(territoryId, name) // 第三参数 force=true 可跳过冷却限制
refresh()
}
return (
<div>
<div>
<label>Name (90-day cooldown)</label>
<input value={name} onChange={e => setName(e.target.value)} />
<button onClick={handleRename} disabled={loading}>Rename</button>
</div>
<div>
<label>Description</label>
<textarea value={desc} onChange={e => setDesc(e.target.value)} />
<button onClick={handleSave} disabled={loading}>Save</button>
</div>
{error && <p style={{ color: 'red' }}>{error.message}</p>}
</div>
)
}
22. 拍卖出价/取消(写操作)
22.1 useAuctionBid — 拍卖出价
tsx
import { useAuctionBid, useAuctionDetail } from '@microcosmmoney/auth-react'
function BidPanel({ auctionId }: { auctionId: number }) {
const { placeBid, loading, error } = useAuctionBid()
const { data: auction, refresh } = useAuctionDetail(auctionId)
const [amount, setAmount] = useState(0)
const handleBid = async () => {
await placeBid(auctionId, amount)
refresh()
}
return (
<div>
<h3>{auction?.unit_name} Auction</h3>
<p>Current highest: {auction?.highest_bid ?? 'No bids'}</p>
<input type="number" value={amount} onChange={e => setAmount(+e.target.value)} />
<button onClick={handleBid} disabled={loading}>Place Bid</button>
{error && <p style={{ color: 'red' }}>{error.message}</p>}
</div>
)
}
22.2 useAuctionCancel — 取消竞价/退款
tsx
import { useAuctionCancel, useMyBids } from '@microcosmmoney/auth-react'
function MyBidsPanel() {
const { prepareCancelBid, loading } = useAuctionCancel()
const { data: bids, refresh } = useMyBids()
const handleCancel = async (auctionId: number) => {
const txParams = await prepareCancelBid(auctionId)
console.log('Build Solana TX with params:', txParams)
refresh()
}
return (
<ul>
{bids?.map((bid: any) => (
<li key={bid.bid_id}>
Auction #{bid.auction_id}: {bid.bid_amount} SOL — {bid.status}
{bid.status === 'outbid' && (
<button onClick={() => handleCancel(bid.auction_id)} disabled={loading}>
Cancel & Refund
</button>
)}
</li>
))}
</ul>
)
}
23. 投票操作(写操作)
23.1 useVoteAction — 创建提案 & 投票
tsx
import {
useVoteAction, useProposals, useProposalDetail, useVotePower
} from '@microcosmmoney/auth-react'
function VotingPage() {
const { createProposal, castVote, loading, error } = useVoteAction()
const { data: proposals, refresh } = useProposals('active')
const { data: power } = useVotePower()
const handleCreate = async () => {
await createProposal({
title: 'Increase mining rate',
description: 'Proposal to increase MCC mining rate by 10%',
proposal_type: 'governance',
voting_hours: 72,
options: ['Approve', 'Reject', 'Abstain'],
})
refresh()
}
const handleVote = async (proposalId: string, optionIndex: number) => {
await castVote(proposalId, optionIndex, power?.available_votes)
refresh()
}
return (
<div>
<p>Your voting power: {power?.total_votes ?? 0} (available: {power?.available_votes ?? 0})</p>
<button onClick={handleCreate} disabled={loading}>New Proposal</button>
{proposals?.map((p: any) => (
<div key={p.proposal_id}>
<h4>{p.title}</h4>
<p>{p.description}</p>
{p.options?.map((opt: string, i: number) => (
<button key={i} onClick={() => handleVote(p.proposal_id, i)} disabled={loading}>
Vote: {opt}
</button>
))}
</div>
))}
{error && <p style={{ color: 'red' }}>{error.message}</p>}
</div>
)
}
24. MCC 综合历史
24.1 useMCCHistory — 全类型交易历史
tsx
import { useMCCHistory } from '@microcosmmoney/auth-react'
function MCCHistoryPage() {
const [txType, setTxType] = useState<string>('all')
const [page, setPage] = useState(1)
const { data, loading } = useMCCHistory({ tx_type: txType, page, page_size: 20 })
return (
<div>
<select value={txType} onChange={e => { setTxType(e.target.value); setPage(1) }}>
<option value="all">All</option>
<option value="mining">Mining</option>
<option value="buyback">Buyback</option>
<option value="transfer">Transfer</option>
</select>
{loading ? <p>Loading...</p> : (
<table>
<thead>
<tr><th>Type</th><th>MCC</th><th>Stablecoin</th><th>TX</th><th>Date</th></tr>
</thead>
<tbody>
{data?.records?.map((r, i) => (
<tr key={i}>
<td>{r.type}</td>
<td>{r.mcc_amount}</td>
<td>{r.stablecoin_amount} {r.stablecoin}</td>
<td>{r.tx_signature?.slice(0, 8)}...</td>
<td>{new Date(r.created_at).toLocaleDateString()}</td>
</tr>
))}
</tbody>
</table>
)}
<div>
<button onClick={() => setPage(p => Math.max(1, p - 1))} disabled={page <= 1}>Prev</button>
<span>Page {page} / {Math.ceil((data?.total || 0) / 20)}</span>
<button onClick={() => setPage(p => p + 1)} disabled={(data?.records?.length || 0) < 20}>Next</button>
</div>
</div>
)
}
25. 链上交易构建指南
25.1 Reincarnation 回购交易构建
回购交易需要在前端构建 Solana 指令,用户用钱包签名后广播链上。
合约地址:
- Program:
REn8oKyydvjRsistZ2cVi6tksPubvR3bEuLdVTyGknb - Pool PDA: 通过
findProgramAddressSync([Buffer.from("reincarnation_pool")], programId)计算
execute_buyback 指令必须传 10 个账户:
| # | 账户 | 说明 |
|---|---|---|
| 1 | user | 用户钱包 (Signer) |
| 2 | reincarnation_pool | Pool PDA |
| 3 | mcc_mint | MCCpDtigJLYnfGe1fW5xrSA8AXo6AeAj8ECE7wVqP5e |
| 4 | usdc_mint | USDT: Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB |
| 5 | user_mcc_account | 用户 MCC ATA |
| 6 | user_usdc_account | 用户 USDT ATA |
| 7 | usdc_vault | Pool 的 USDT Vault |
| 8 | mcc_vault | Pool 的 MCC Vault |
| 9 | mcc_token_program | TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA |
| 10 | usdc_token_program | TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA |
typescript
import {
PublicKey, TransactionInstruction, Transaction, Connection
} from '@solana/web3.js'
import { getAssociatedTokenAddressSync, TOKEN_PROGRAM_ID } from '@solana/spl-token'
const PROGRAM_ID = new PublicKey('REn8oKyydvjRsistZ2cVi6tksPubvR3bEuLdVTyGknb')
const MCC_MINT = new PublicKey('MCCpDtigJLYnfGe1fW5xrSA8AXo6AeAj8ECE7wVqP5e')
const USDT_MINT = new PublicKey('Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB')
function buildBuybackInstruction(
userPubkey: PublicKey,
mccAmount: number,
): TransactionInstruction {
const [poolPDA] = PublicKey.findProgramAddressSync(
[Buffer.from('reincarnation_pool')],
PROGRAM_ID
)
const userMccAta = getAssociatedTokenAddressSync(MCC_MINT, userPubkey, false, TOKEN_PROGRAM_ID)
const userUsdtAta = getAssociatedTokenAddressSync(USDT_MINT, userPubkey, false, TOKEN_PROGRAM_ID)
const poolMccVault = getAssociatedTokenAddressSync(MCC_MINT, poolPDA, true, TOKEN_PROGRAM_ID)
const poolUsdtVault = getAssociatedTokenAddressSync(USDT_MINT, poolPDA, true, TOKEN_PROGRAM_ID)
const discriminator = Buffer.from([47, 32, 19, 100, 184, 96, 144, 49])
const amountBuf = Buffer.alloc(8)
amountBuf.writeBigUInt64LE(BigInt(Math.floor(mccAmount * 1e9)))
const data = Buffer.concat([discriminator, amountBuf])
return new TransactionInstruction({
programId: PROGRAM_ID,
keys: [
{ pubkey: userPubkey, isSigner: true, isWritable: true },
{ pubkey: poolPDA, isSigner: false, isWritable: true },
{ pubkey: MCC_MINT, isSigner: false, isWritable: false },
{ pubkey: USDT_MINT, isSigner: false, isWritable: false },
{ pubkey: userMccAta, isSigner: false, isWritable: true },
{ pubkey: userUsdtAta, isSigner: false, isWritable: true },
{ pubkey: poolUsdtVault, isSigner: false, isWritable: true },
{ pubkey: poolMccVault, isSigner: false, isWritable: true },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
],
data,
})
}
25.2 完整回购 + 记录流程
tsx
import { useBuybackAction, useReincarnationConfig } from '@microcosmmoney/auth-react'
import { useConnection, useWallet } from '@solana/wallet-adapter-react'
function BuybackWithSolana() {
const { record, loading } = useBuybackAction()
const { data: config } = useReincarnationConfig()
const { connection } = useConnection()
const { publicKey, sendTransaction } = useWallet()
const handleBuyback = async (mccAmount: number) => {
if (!publicKey) return
const ix = buildBuybackInstruction(publicKey, mccAmount)
const tx = new Transaction().add(ix)
tx.feePayer = publicKey
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash
const signature = await sendTransaction(tx, connection)
await connection.confirmTransaction(signature, 'confirmed')
await record({
tx_signature: signature,
wallet_address: publicKey.toBase58(),
mcc_amount: mccAmount,
usdc_amount: mccAmount * (config?.premium_rate ? 1 + config.premium_rate : 1.05),
stablecoin: 'USDT',
})
}
return (
<button onClick={() => handleBuyback(10)} disabled={loading || !publicKey}>
Buyback 10 MCC
</button>
)
}
25.3 ATA 注意事项
- MCC 和 USDT 均使用 SPL Token (
TOKEN_PROGRAM_ID),不是 Token-2022 - ATA 地址 =
PDA([owner, TOKEN_PROGRAM_ID, mint]) - 如果用户没有 USDT ATA,需要先创建(使用
createAssociatedTokenAccountIdempotent) - Pool 的 Vault 是 PDA 拥有的 ATA(
allowOwnerOffCurve: true)
类型定义速查
typescript
// 用户
interface User {
uid: string
email: string
displayName?: string | null
avatarUrl?: string | null
role: 'admin' | 'user' | 'agent'
level?: 'recruit' | 'prospect' | 'miner'
title?: 'commander' | 'pioneer' | 'warden' | 'admiral' | null
stationId?: number | null
emailVerified?: boolean
}
// MCC 余额
interface MCCBalance {
balance: number
raw_balance: number
decimals: number
symbol: string
wallet_address?: string | null
wallets?: MCCWalletBalance[]
mint?: string
}
interface MCCWalletBalance {
wallet_address: string
is_primary: boolean
balance: number
raw_balance: number
}
// MCC 价格
interface MCCPrice {
price: number
price_change_24h?: number | null
volume_24h?: number | null
market_cap?: number | null
source: string
updated_at: string
buyback_price?: number
premium_rate?: number
}
// 用户挖矿统计
interface MiningStats {
total_mined: number // 累计挖矿获得 MCC
total_paid: number // 累计支付稳定币
mining_count: number // 挖矿次数
today_mined: number // 今日挖矿获得 MCC
last_30d_mined: number // 近 30 天挖矿获得 MCC
active_days_30d: number // 近 30 天活跃挖矿天数
last_mined_at: string | null // 最后挖矿时间 (ISO 8601)
}
// 挖矿记录
interface MiningRecord {
mcc_amount: number // 挖矿获得 MCC
paid_amount: number // 支付稳定币金额
stablecoin: 'USDC' | 'USDT' // 支付币种
tx_signature: string // Solana 交易签名
mined_at: string | null // 挖矿时间 (ISO 8601)
}
// MCD 余额
interface MCDBalance {
total_balance: string
available_balance: string
frozen_balance: string
}
// 钱包
interface Wallet {
wallet_address: string
wallet_type: string
is_primary: boolean
created_at: string
}
// 代币组合
interface TokenPortfolio {
sol_balance?: number
mcc_balance?: number
usdt_balance?: number
usdc_balance?: number
}
// MCC 锁仓
interface MCCLock {
lock_id: string
amount: number
reason: string
lock_start: string
lock_end: string
status: string
}
// 挖矿比率
interface MiningRatio {
current_stage?: number
total_minted?: number
ratio?: number
usdc_per_mcc?: number
current_rate?: number
}
// 伴生矿分配
interface MiningDistribution {
user_mcc: number
team_mcc: number
magistrate_mcc: number
vault_mcd: number
source: string
territory_id?: string
tx_signature?: string
created_at: string
}
// 回购报价
interface BuybackQuote {
mcc_amount: number
market_price: number
buyback_price: number
usdc_amount: number
premium_amount: number
fee?: number
fee_rate?: number
slippage?: number
net_amount?: number
vault_type?: string
pool_remaining?: number
}
// 回购记录
interface BuybackRecord {
mcc_amount: number
usdc_amount: number
stablecoin: string
tx_signature?: string
buyback_price?: number
created_at: string
}
// 领地
interface Territory {
unit_id: string
unit_name: string
short_id?: string
unit_type: string
description?: string
location?: string
image_url?: string
parent_id?: string
member_count?: number
max_capacity?: number
vault_balance?: number
manager_uid?: string
}
// 领地汇总
interface TerritorySummary {
total_stations: number
total_members: number
total_vault_mcd: number
avg_kpi_score?: number
}
// 领地统计
interface TerritoryStats {
member_count: number
max_capacity: number
vault_mcd: number
occupancy_rate: number
}
// 领地成员
interface TerritoryMember {
uid: string
display_name?: string
level?: string
mcd_received?: number
joined_at?: string
}
// 提案
interface Proposal {
id: string
title: string
description: string
proposal_type: string
status: string
options: string[]
min_votes?: number
ends_at: string
created_at: string
}
// 提案详情
interface ProposalDetail extends Proposal {
vote_results: VoteResult[]
}
// 投票结果
interface VoteResult {
option: string
votes: number
mcc_total: number
voter_count: number
}
// 投票权
interface VotePower {
vote_power: number
user_rank?: string
cost_per_vote_mcc?: number
mcc_balance?: number
max_votes?: number
can_vote: boolean
}
// 拍卖竞价
interface AuctionBid {
bid_id?: string
auction_id: number
unit_name?: string
bid_amount: number
deposit_amount?: number
status: string
created_at: string
}
// MCD 交易
interface MCDTransaction {
id: string
tx_type: string
amount: number
from_account_type?: string
to_account_type?: string
created_at: string
}
// MCD 奖励
interface MCDReward {
id: string
reward_date: string
territory_id?: string
mcd_received: number
created_at: string
}
// 挖矿请求
interface MiningRequest {
mcc_amount: number
stablecoin?: string
wallet_address: string
}
// 挖矿确认
interface MiningConfirmData {
request_id: string
tx_signature: string
mcc_amount: number
usdc_amount: number
stablecoin_type?: string
}
// 挖矿请求结果
interface MiningRequestResult {
request_id: string
mcc_amount: number
usdc_amount: number
mining_price: number
stablecoin: string
payment_address: string
expires_at: string
}
// 挖矿配置
interface MiningConfig {
program_id: string
pool_address: string
mcc_mint: string
usdt_mint: string
usdc_mint: string
distribution_ratios: Record<string, number>
min_amount: number
max_amount: number
}
// 回购记录输入
interface BuybackRecordInput {
tx_signature: string
wallet_address: string
mcc_amount: number
usdc_amount: number
stablecoin?: string
}
// 轮回合约配置
interface ReincarnationConfig {
program_id: string
pool_address: string
mcc_vault: string
usdc_vault: string
usdt_vault: string
min_buyback: number
max_buyback: number
premium_rate: number
}
// MCC 综合历史记录
interface MCCHistoryRecord {
mcc_amount: number
stablecoin_amount: number
stablecoin: string
tx_signature: string
type: string
wallet_address?: string
created_at: string
}
// 月度轮回历史
interface CycleHistory {
cycle_id: number
executed_at: string
mcc_returned: number
mcd_returned: number
status: string
}
// 拍卖历史
interface AuctionHistory {
auction_id: number
unit_name: string
winner_wallet?: string
winning_bid?: number
status: string
ended_at: string
}
// API 统一响应
interface ApiResponse<T> {
success: boolean
data: T | null
error: string | null
message?: string | null
}
// Provider 配置
interface MicrocosmAuthConfig {
clientId: string // (必填) OAuth Client ID
redirectUri: string // (必填) 回调路径
scope?: string[] // 默认 ['openid', 'profile', 'email']
authEndpoint?: string // 默认 'https://microcosm.money'
tokenExchangeUri?: string // 默认 '/api/auth/exchange'
profileUri?: string // 默认 '/api/users/profile'
storage?: 'localStorage' | 'sessionStorage' | 'memory'
autoRefresh?: boolean // 默认 true
debug?: boolean // 默认 false
}
26. Solana 钱包连接
26.1 useSolanaWallet — Phantom 钱包
tsx
import { useSolanaWallet } from '@microcosmmoney/auth-react'
function WalletButton() {
const { connected, publicKey, connect, disconnect, connecting, error, signTransaction, signAllTransactions } = useSolanaWallet()
if (connected) {
return (
<div>
<p>{publicKey?.slice(0, 8)}...{publicKey?.slice(-4)}</p>
<button onClick={disconnect}>Disconnect</button>
</div>
)
}
return <button onClick={connect} disabled={connecting}>
{connecting ? 'Connecting...' : 'Connect Phantom'}
</button>
}
26.2 useMiningFlow — 铸造完整流程
tsx
import { useMiningFlow, useSolanaWallet } from '@microcosmmoney/auth-react'
function MiningPage() {
const { step, startMining, confirmMining, reset, error } = useMiningFlow()
const { publicKey, signTransaction } = useSolanaWallet()
const handleMine = async () => {
const request = await startMining({
amount: 100,
wallet_address: publicKey!,
stablecoin: 'USDT',
})
// sign transaction with wallet, then confirm
const txSig = '...' // signed tx signature
await confirmMining(request.request_id, txSig)
}
return (
<div>
<p>Step: {step}</p>
{error && <p>Error: {error}</p>}
<button onClick={handleMine} disabled={step !== 'idle'}>Start Mining</button>
<button onClick={reset}>Reset</button>
</div>
)
}
26.3 useBuybackFlow — 回购完整流程
tsx
import { useBuybackFlow } from '@microcosmmoney/auth-react'
function BuybackPage() {
const { step, getQuote, executeBuyback, quote, reset, error } = useBuybackFlow()
const handleBuyback = async () => {
const q = await getQuote({ amount: 10, wallet_address: '...', stablecoin: 'USDT' })
// sign transaction, then execute
await executeBuyback(q.quote_id, 'tx_signature_here')
}
return (
<div>
<p>Step: {step}</p>
{quote && <p>Price: {quote.price} USDT/MCC</p>}
<button onClick={handleBuyback}>Buyback</button>
</div>
)
}
27. UI 组件 (@microcosmmoney/portal-react)
27.1 TerminalTable — 数据表格
tsx
import { TerminalTable, TerminalCard } from '@microcosmmoney/portal-react'
const columns = [
{ key: 'date', header: 'Date' },
{ key: 'amount', header: 'Amount', align: 'right' as const,
render: (row: any) => <span className="text-emerald-400">{row.amount} MCC</span> },
{ key: 'status', header: 'Status' },
]
<TerminalCard filename="history.log">
<TerminalTable columns={columns} data={records} rowKey={(r) => r.id} />
</TerminalCard>
27.2 TerminalDialog — 模态对话框
tsx
import { TerminalDialog, TerminalInput } from '@microcosmmoney/portal-react'
const [open, setOpen] = useState(false)
<TerminalDialog open={open} onClose={() => setOpen(false)} title="Confirm" width="max-w-md">
<p className="text-zinc-300 mb-4">Are you sure?</p>
<TerminalInput label="Amount" type="number" placeholder="0.00" suffix="MCC" />
<button className="mt-4 w-full bg-indigo-600 text-white py-2 rounded" onClick={confirm}>
Confirm
</button>
</TerminalDialog>
27.3 TerminalTabs — 标签页
tsx
import { TerminalTabs } from '@microcosmmoney/portal-react'
<TerminalTabs
tabs={[
{ key: 'overview', label: 'Overview' },
{ key: 'history', label: 'History' },
{ key: 'settings', label: 'Settings' },
]}
onChange={(key) => setActiveTab(key)}
>
{(activeKey) => activeKey === 'overview' ? <Overview /> : <History />}
</TerminalTabs>
27.4 TerritoryCard — 领地卡片
tsx
import { TerritoryCard } from '@microcosmmoney/portal-react'
<TerritoryCard
territoryId="S-00001"
name="Alpha Station"
type="station"
memberCount={456}
capacity={1000}
magistrate="GhXBd...TAxJ"
mcdBalance={12345.67}
status="active"
onClick={() => router.push('/territory/S-00001')}
/>
27.5 KPIRadialChart — 径向图
tsx
import { KPIRadialChart } from '@microcosmmoney/portal-react'
<KPIRadialChart value={75} max={100} label="Mining Rate" unit="%" color="#10b981" />
27.6 VoteResultBar — 投票结果
tsx
import { VoteResultBar } from '@microcosmmoney/portal-react'
<VoteResultBar
options={[
{ label: 'Approve', votes: 150 },
{ label: 'Reject', votes: 45 },
{ label: 'Abstain', votes: 20 },
]}
/>
27.7 菜单增强
tsx
import { MicrocosmMenuSection, dashboardMenu } from '@microcosmmoney/portal-react'
<MicrocosmMenuSection
basePath="/app"
currentPath={pathname}
onNavigate={(path) => router.push(path)}
onItemClick={(item, path) => analytics.track('menu_click', { key: item.key })}
filterItems={(item) => item.key !== 'mcd'}
extraItems={[{
title: 'Help', key: 'help', path: '/help',
icon: HelpCircle, badge: 'New'
}]}
/>
28. 管理员操作 Hooks
28.1 useAuctionEnd — 结束拍卖
tsx
import { useAuctionEnd } from '@microcosmmoney/auth-react'
function AdminAuction({ auctionId }: { auctionId: number }) {
const { endAuction, loading, error } = useAuctionEnd()
return <button onClick={() => endAuction(auctionId)} disabled={loading}>End Auction</button>
}
28.2 useNotifications — 通知系统
tsx
import { useNotifications, useNotificationAction } from '@microcosmmoney/auth-react'
function NotificationBell() {
const { data: notifications } = useNotifications({ unreadOnly: true })
const { markRead, markAllRead } = useNotificationAction()
return (
<div>
<span>{notifications?.length || 0} unread</span>
<button onClick={markAllRead}>Mark All Read</button>
</div>
)
}
参考
- 接入指南:
Microcosm-开发者接入指南.md - API 手册:
Microcosm-API参考手册.md - 交互式文档: https://api.microcosm.money/docs
- 参考实现: Double Helix 前端
询问 AI