Loading...
Loading...
Compare original and translation side by side
deployedContracts.tsexternalContracts.tsdeployedContracts.tsexternalContracts.ts| Phase | Environment | What Happens |
|---|---|---|
| Phase 1 | Local fork | Contracts + UI on localhost. Iterate fast. |
| Phase 2 | Live network + local UI | Deploy contracts to mainnet/L2. Test with real state. Polish UI. |
| Phase 3 | Production | Deploy frontend to IPFS/Vercel. Final QA. |
| 阶段 | 运行环境 | 主要操作 |
|---|---|---|
| 阶段1 | 本地fork环境 | 在本地主机部署合约与UI,快速迭代。 |
| 阶段2 | 真实网络+本地UI | 将合约部署到主网/L2,基于真实链上状态测试,优化UI。 |
| 阶段3 | 生产环境 | 将前端部署到IPFS/Vercel,完成最终QA测试。 |
npx create-eth@latest my-dapp
cd my-dapp && yarn install
yarn fork --network base # Terminal 1: fork of real chain (or mainnet, your target chain)
yarn deploy # Terminal 2: deploy contractsAlways fork, never.yarn chaindoes everythingyarn forkdoes AND gives you real protocol state — Uniswap, USDC, Aave, whale balances, everything already deployed.yarn chaingives you an empty chain that tempts you into writing mock contracts you don't need. Don't mock what already exists onchain — just fork it.yarn chain
packages/foundry/contracts/packages/hardhat/contracts/packages/nextjs/contracts/externalContracts.tsyarn deploydeployedContracts.tsnpx create-eth@latest my-dapp
cd my-dapp && yarn install
yarn fork --network base # 终端1:创建目标链(如主网)的fork环境
yarn deploy # 终端2:部署合约始终使用fork模式,不要用。yarn chain包含yarn fork的全部功能,还能为你提供真实的链上协议状态——Uniswap、USDC、Aave、巨鲸账户余额等所有已部署的合约都能直接使用。而yarn chain会创建一条空链,诱使你编写不必要的模拟合约。对于链上已存在的资源,无需模拟,直接fork即可。yarn chain
packages/foundry/contracts/packages/hardhat/contracts/packages/nextjs/contracts/externalContracts.tsyarn deploydeployedContracts.tsyarn fork --network base # Terminal 1: fork of real chain (has Uniswap, USDC, etc.)
yarn deploy --watch # Terminal 2: auto-redeploy on changes
yarn start # Terminal 3: Next.js at localhost:3000// Read
const { data } = useScaffoldReadContract({
contractName: "YourContract",
functionName: "balanceOf",
args: [address],
watch: true,
});
// Write
const { writeContractAsync, isMining } = useScaffoldWriteContract("YourContract");
await writeContractAsync({
functionName: "swap",
args: [tokenIn, tokenOut, amount],
onBlockConfirmation: (receipt) => console.log("Done!", receipt),
});
// Events
const { data: events } = useScaffoldEventHistory({
contractName: "YourContract",
eventName: "SwapExecuted",
fromBlock: 0n,
watch: true,
});yarn fork --network base # 终端1:创建目标链的fork环境(包含Uniswap、USDC等合约)
yarn deploy --watch # 终端2:合约变更时自动重新部署
yarn start # 终端3:启动Next.js服务,访问localhost:3000// 读取合约数据
const { data } = useScaffoldReadContract({
contractName: "YourContract",
functionName: "balanceOf",
args: [address],
watch: true,
});
// 写入合约数据
const { writeContractAsync, isMining } = useScaffoldWriteContract("YourContract");
await writeContractAsync({
functionName: "swap",
args: [tokenIn, tokenOut, amount],
onBlockConfirmation: (receipt) => console.log("操作完成!", receipt),
});
// 监听合约事件
const { data: events } = useScaffoldEventHistory({
contractName: "YourContract",
eventName: "SwapExecuted",
fromBlock: 0n,
watch: true,
});formatEther()formatUnits()parseEther()parseUnits()isLoadingisMiningformatEther()formatUnits()parseEther()parseUnits()isLoadingisMininghttps://base-mainnet.g.alchemy.com/v2/YOUR_KEYscaffold.config.tsrpcOverridesalchemyApiKeyscaffold.config.ts// ❌ WRONG — key committed to public repo
rpcOverrides: {
[chains.base.id]: "https://base-mainnet.g.alchemy.com/v2/8GVG8WjDs-LEAKED",
},
// ✅ RIGHT — key stays in .env.local
rpcOverrides: {
[chains.base.id]: process.env.NEXT_PUBLIC_BASE_RPC || "https://mainnet.base.org",
},git addgit commitundefinedhttps://base-mainnet.g.alchemy.com/v2/YOUR_KEYscaffold.config.tsscaffold.config.tsrpcOverridesalchemyApiKey// ❌ 错误示例 —— 密钥会被提交到公开仓库
rpcOverrides: {
[chains.base.id]: "https://base-mainnet.g.alchemy.com/v2/8GVG8WjDs-LEAKED",
},
// ✅ 正确示例 —— 密钥仅存储在本地.env.local文件中
rpcOverrides: {
[chains.base.id]: process.env.NEXT_PUBLIC_BASE_RPC || "https://mainnet.base.org",
},git addgit commitundefined
**Your `.gitignore` MUST include:**
**SE2 handles deployer keys by default** — `yarn generate` creates a `.env` with the deployer key, and `.gitignore` excludes it. **Don't override this pattern.** Don't copy keys into scripts, config files, or deploy logs. This includes RPC keys, API keys, and any credential — not just wallet keys.
See `wallets/SKILL.md` for full key safety guide, what to do if you've already leaked a key, and safe patterns for deployment.
**你的.gitignore文件必须包含以下内容:**
**SE2默认已处理部署者密钥的安全问题** —— `yarn generate`命令会创建包含部署者密钥的.env文件,且.gitignore已默认排除该文件。**请勿修改此配置**,不要将密钥复制到脚本、配置文件或部署日志中。这包括RPC密钥、API密钥及任何凭证,而不仅仅是钱包密钥。
如需了解完整的密钥安全指南、泄露后的补救措施及安全部署模式,请查看`wallets/SKILL.md`文件。scaffold.config.tstargetNetworks: [mainnet]yarn generateyarn accountyarn deploy --network mainnetyarn verify --network mainnetscaffold.config.tstargetNetworks: [mainnet]yarn generateyarn accountyarn deploy --network mainnetyarn verify --network mainnetonlyLocalBurnerWallet: truescaffold.config.tsonlyLocalBurnerWallet: trueyarn ipfsyarn ipfs
**Vercel (fast):**
```bash
cd packages/nextjs && vercel
**Vercel(快速中心化部署):**
```bash
cd packages/nextjs && vercelpackages/
├── foundry/contracts/ # Solidity contracts
├── foundry/script/ # Deploy scripts
├── foundry/test/ # Tests
└── nextjs/
├── app/ # Pages
├── components/ # React components
├── contracts/
│ ├── deployedContracts.ts # AUTO-GENERATED (don't edit)
│ └── externalContracts.ts # YOUR external contracts (edit this)
├── hooks/scaffold-eth/ # USE THESE hooks
└── scaffold.config.ts # Main configpackages/
├── foundry/contracts/ # Solidity合约文件
├── foundry/script/ # 部署脚本
├── foundry/test/ # 测试用例
└── nextjs/
├── app/ # 页面文件
├── components/ # React组件
├── contracts/
│ ├── deployedContracts.ts # 自动生成文件(请勿编辑)
│ └── externalContracts.ts # 外部合约配置文件(可编辑)
├── hooks/scaffold-eth/ # Scaffold提供的Hooks(请使用这些)
└── scaffold.config.ts # 主配置文件┌─────────────────────────────────────────────────────────────┐
│ 1. DISCOVER Agent queries ERC-8004 IdentityRegistry │
│ → finds agents with "weather" service tag │
│ │
│ 2. TRUST Agent checks ReputationRegistry │
│ → filters by uptime >99%, quality >85 │
│ → picks best-rated weather agent │
│ │
│ 3. CALL Agent sends HTTP GET to weather endpoint │
│ → receives 402 Payment Required │
│ → PAYMENT-REQUIRED header: $0.10 USDC on Base │
│ │
│ 4. PAY Agent signs EIP-3009 transferWithAuthorization │
│ → retries request with PAYMENT-SIGNATURE │
│ → server verifies via facilitator │
│ → payment settled on Base (~$0.001 gas) │
│ │
│ 5. RECEIVE Server returns 200 OK + weather data │
│ → PAYMENT-RESPONSE header with tx hash │
│ │
│ 6. RATE Agent posts feedback to ReputationRegistry │
│ → value=95, tag="quality", endpoint="..." │
│ → builds onchain reputation for next caller │
└─────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────┐
│ 1. 发现 Agent查询ERC-8004身份注册表 │
│ → 筛选出提供「天气服务」的Agent │
│ │
│ 2. 信任 Agent查询声誉注册表 │
│ → 筛选出正常运行时间>99%、服务评分>85的Agent │
│ → 选择评分最高的天气服务Agent │
│ │
│ 3. 请求 Agent向天气服务端点发送HTTP GET请求 │
│ → 收到402 Payment Required响应 │
│ → PAYMENT-REQUIRED头信息:Base链上支付0.10 USDC │
│ │
│ 4. 支付 Agent签名EIP-3009授权转账交易 │
│ → 携带PAYMENT-SIGNATURE头信息重试请求 │
│ → 服务器通过第三方验证机构完成签名验证 │
│ → 在Base链上完成支付(手续费约0.001美元) │
│ │
│ 5. 接收 服务器返回200 OK响应及天气数据 │
│ → PAYMENT-RESPONSE头信息包含交易哈希 │
│ │
│ 6. 评级 Agent在声誉注册表提交反馈 │
│ → 评分=95,标签="quality",端点="..." │
│ → 为后续调用者积累链上声誉数据 │
└─────────────────────────────────────────────────────────────┘import { x402Fetch } from '@x402/fetch';
import { createWallet } from '@x402/evm';
import { ethers } from 'ethers';
const wallet = createWallet(process.env.AGENT_PRIVATE_KEY);
const provider = new ethers.JsonRpcProvider(process.env.BASE_RPC_URL);
const IDENTITY_REGISTRY = '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432';
const REPUTATION_REGISTRY = '0x8004BAa17C55a88189AE136b182e5fdA19dE9b63';
// 1. Discover: find agents offering weather service
const registry = new ethers.Contract(IDENTITY_REGISTRY, registryAbi, provider);
// Query events or use The Graph subgraph for indexed agent discovery
// 2. Trust: check reputation
const reputation = new ethers.Contract(REPUTATION_REGISTRY, reputationAbi, provider);
const [count, value, decimals] = await reputation.getSummary(
agentId, trustedClients, "quality", "30days"
);
// Only proceed if value/10^decimals > 85
// 3-5. Pay + Receive: x402Fetch handles the entire 402 flow
const response = await x402Fetch(agentEndpoint, {
wallet,
preferredNetwork: 'eip155:8453'
});
const weatherData = await response.json();
// 6. Rate: post feedback onchain
const reputationWriter = new ethers.Contract(REPUTATION_REGISTRY, reputationAbi, signer);
await reputationWriter.giveFeedback(
agentId, 95, 0, "quality", "weather", agentEndpoint, "", ethers.ZeroHash
);import { x402Fetch } from '@x402/fetch';
import { createWallet } from '@x402/evm';
import { ethers } from 'ethers';
const wallet = createWallet(process.env.AGENT_PRIVATE_KEY);
const provider = new ethers.JsonRpcProvider(process.env.BASE_RPC_URL);
const IDENTITY_REGISTRY = '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432';
const REPUTATION_REGISTRY = '0x8004BAa17C55a88189AE136b182e5fdA19dE9b63';
// 1. 发现:筛选提供天气服务的Agent
const registry = new ethers.Contract(IDENTITY_REGISTRY, registryAbi, provider);
// 可通过事件查询或The Graph子图实现Agent的索引式发现
// 2. 信任:查询Agent声誉
const reputation = new ethers.Contract(REPUTATION_REGISTRY, reputationAbi, provider);
const [count, value, decimals] = await reputation.getSummary(
agentId, trustedClients, "quality", "30days"
);
// 仅当value/10^decimals > 85时继续执行
// 3-5. 支付+接收:x402Fetch自动处理完整的402流程
const response = await x402Fetch(agentEndpoint, {
wallet,
preferredNetwork: 'eip155:8453'
});
const weatherData = await response.json();
// 6. 评级:在链上提交反馈
const reputationWriter = new ethers.Contract(REPUTATION_REGISTRY, reputationAbi, signer);
await reputationWriter.giveFeedback(
agentId, 95, 0, "quality", "weather", agentEndpoint, "", ethers.ZeroHash
);