跳到主要内容
返回

Blockchain 基础:Wallets、Smart Contracts、Tokens 与 dApps

计算机科学

一份实用地图,说明 wallets、smart contracts、ERC token standards,以及 dApps 如何把它们组合起来

大多数 on-chain applications 都由同一小撮零件组成:wallets、smart contracts、tokens 与 dApps。搞清楚它们如何串连,以及每一块建立什么 trust model,就足以读懂多数 Web3 architectures,而不必淹没在 cryptography 里。

这篇 note 用 Ethereum / EVM 作为框架,因为 ERC token standards 住在那里。同样的想法可以转移到其他 chains,即使名称不同。



Blockchain 基础

Blockchain 是一份由许多独立 nodes 共同同意的 shared ledger。一旦 transaction 被确认,改写历史在设计上就是昂贵的。

  • Accounts — chain 上的身份。Externally owned accounts (EOAs) 由 private keys 控制。Contract accounts 由 code 控制。
  • Transactions — 已签署的 messages,提出一次 state change:送 value、调用 contract、deploy code。
  • Consensus — 网络同意哪些 transactions 有效、以及顺序为何的方式。
  • Gas — 在 on-chain 执行工作所付的 fee。每次 write 都有成本;通过 RPC node 的 reads 通常没有。

text
Signed transaction → Mempool → Included in a block → Shared state updated

chain 是 programmable settlement layer:跟普通 database 相比又慢又贵,但当 ownership 与规则必须可公开验证时,它就有用。



Wallets

Wallet 是持有 cryptographic keys、并帮你签署 transactions 的软件(或硬件)。它不是银行账户。Chain 存 balances;wallet 存你控制某个 address 的证明。


text
Private key → Public key → Address
Private key -(signs)→ Transaction signature

  • Private key 证明控制权。任何人拿到它,就可以从该 address 移走 assets。
  • Public key / address 是别人用来送你 assets,或在 on-chain 识别你的东西。
  • Signing 代表授权一笔特定 transaction,而不广播 private key 本身。
  • Custody 是谁持有 keys。Self-custody 代表你自己持有。Custodial wallets 代表服务代表你持有。
  • Browser extensions 与 mobile wallets 主要是 keys 周围的 UX。Hardware wallets 把 private key 留在 offline,只暴露 signatures。

当 dApp 说「connect wallet」,它是在要一个 address 与一条 signing channel,而不是要你登录某间公司 database 的密码:


ts
const accounts = (await window.ethereum.request({
  method: "eth_requestAccounts",
})) as string[]

const address = accounts[0]
// address is public; the private key never leaves the wallet

Failure: 把「connect」当成 Web2 login。Phishing sites 要你签错东西,而不是输入密码。



Smart Contracts

Smart contract 是部署在 blockchain 上的 program。在 Ethereum 上通常用 Solidity 写,跑在 EVM 上。一旦 deployed,它的 code 与 storage 就住在一个 contract address。

  • Public state — 任何人都可以读 balances、ownership,常常也能读 bytecode。
  • Deterministic execution — 同样的 inputs 与 state,在诚实 nodes 上产生同样的结果。
  • Permissionless calling — 任何付得起 gas 的人都可以调用 public function,仍受 contract 自己的 access checks 约束。
  • Hard to change — upgrades 需要明确 pattern(proxy、governance、migration)。Immutable code 上没有静默 hotfix。

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract Escrow {
    address public payer;
    address public payee;
    bool public released;

    constructor(address _payee) payable {
        payer = msg.sender;
        payee = _payee;
    }

    function release() external {
        require(msg.sender == payer, "only payer");
        require(!released, "already released");
        released = true;
        payable(payee).transfer(address(this).balance);
    }
}

  • Contracts 编码规则:谁能调用什么、在什么条件下、以及 state 如何改变。
  • Smart contract 是一份 开放、按 fee 计量的 API,database 就是 chain。UI 可以撒谎;真正结算的是 contract 的 state。

Failure: 把 UI 当成 source of truth。Bugs 很贵,因为 funds 与 ownership 常常就坐在 contract 里面。



Tokens

Tokens 是由遵循共享 interfaces 的 smart contracts 表示的 assets。Wallets、explorers 与 dApps 不必为每个 project 写自定义 code 就能支持它们——这就是 ERC standards 重要的原因。

ERC-20 是 fungible tokens 的标准:每一单位都可以互换。心智模型是 balances,不是独特物品。approve + transferFrom 是 protocol 代表你花 tokens 的方式。


solidity
interface IERC20 {
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

ERC-721 是 unique tokens 的标准。每个 tokenId 都是自己的 asset,只有一个 owner。Collectibles、tickets 与 on-chain deeds 是常见用途。同一份 contract 里的两个 tokens,只要 IDs 不同,就 不可互换。

ERC-1155 让一份 contract 管理多种 token types——fungible、non-fungible,或两者都有——并支持 batch transfers。Games 与 marketplaces 在单一 collection 混了 gold coins(fungible)、unique swords(supply 为一)与 limited skins(supply 为 N)时,往往偏好它。更少 deployments,更便宜的 batch operations。

StandardFungibilityIdentity modelCommon uses
ERC-20FungibleAmount per addressCurrencies, points, governance
ERC-721Non-fungibleOne owner per tokenIdCollectibles, tickets, unique rights
ERC-1155MixedBalance per address per idGames, multi-asset collections

三者仍然只是 smart contracts。ERC number 是共享 interface,让 tooling 能一致地对待它们。



Decentralized Applications (dApps)

dApp 是 critical logic 或 ownership 住在 on-chain 的应用。

  • 一个 frontend(常常是普通 web app)负责 UX
  • 一个 wallet 负责 identity 与 transaction signing
  • Smart contracts 作为 assets 与规则的 source of truth
  • 一个 RPC provider,让 frontend 能读 chain state 并广播已签署的 transactions

text
User → Wallet
User → dApp Frontend
dApp Frontend -(read state)→ RPC Node
dApp Frontend -(request signature)→ Wallet
Wallet -(signed tx)→ RPC Node → Blockchain → Smart Contracts

  • Reads 可以免费且频繁。Writes 需要 signature 与 gas。
  • 许多 dApps 仍使用中心化零件——indexers、APIs、IPFS gateways、admin keys。「Decentralized」是一条光谱。真正重要的是:哪些部分失败或审查时,不会夺走用户的 assets。


它们如何组合

许多产品共用的一条具体流程:


text
User → dApp UI: Open app
dApp UI → Wallet: eth_requestAccounts
Wallet → dApp UI: address
dApp UI → Blockchain: balanceOf(address)
Blockchain → dApp UI: token balance
User → dApp UI: Deposit
dApp UI → Wallet: approve(protocol, amount)
Wallet → Blockchain: signed approve tx
dApp UI → Wallet: deposit(amount)
Wallet → Blockchain: signed deposit tx
Blockchain → dApp UI: updated state

  • User 打开 dApp 并 connect wallet。App 得知他们的 address。
  • UI 通过 RPC 读取 balances 与 ownership(balanceOf、ownerOf)。
  • 要 deposit 一笔 ERC-20,他们先 approve contract 作为 spender,再调用 deposit——两次 signatures、两笔 transactions,除非被更高层 pattern batch。
  • Smart contract 更新 on-chain state。UI 从 chain 或 indexer 刷新。

ts
import { parseAbi, parseUnits } from "viem"

const amount = parseUnits("100", 6) // 100 USDC (6 decimals)

await walletClient.writeContract({
  address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
  abi: parseAbi(["function approve(address spender, uint256 amount) returns (bool)"]),
  functionName: "approve",
  args: ["0xProtocolAddress", amount],
})

await walletClient.writeContract({
  address: "0xProtocolAddress",
  abi: parseAbi(["function deposit(uint256 amount)"]),
  functionName: "deposit",
  args: [amount],
})

把那笔 ERC-20 换成 ERC-721 mint,或 ERC-1155 batch claim,wallet / contract / RPC 的形状仍然一样。变的只有 token interface 与 contract 的业务规则。



要点

  • Wallet 持有 keys,不是 ledger 本身——custody 讲的是谁能签。
  • Smart contract 是公开、按 fee 计量的 logic,其 state 结算 ownership。
  • ERC-20、ERC-721 与 ERC-1155 的主要差别在 fungibility,以及 identity 如何建模。
  • dApp 组合 frontend、wallet signatures、RPC 与 contracts——对 assets 来说,source of truth 是 chain,不是 UI。

其他一切——L2s、account abstraction、indexers、bridges——都建立在这个底座上。


Recap Q&A

阅读下一篇笔记
常用 Algorithms