JOVANA
Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

去中心化应用、钱包与签名

去中心化应用,不过是一个接到链上代码的网站。本文讲清你的钱包如何为请求签名、为什么读取免费而写入要花燃料,以及一次代币授权究竟交出了什么。

一个应用的两半

想象一个普通的网上银行。你在浏览器里看到一块精致的界面——按钮、余额、一个转账键——但真正的钱住在银行的服务器上,锁在公司的数据库背后。那块界面只是一扇友好的窗,望向一个你看不见、也掌控不了的金库。

去中心化应用保留了那扇友好的窗,却把金库换掉了。它的前端是一个普通网站,可以住在任何服务器上(甚至你的笔记本电脑);而*逻辑与资金*则坐落在以太坊这类公链上的智能合约里。所以一个 dApp 其实是两半:一半是你看着的前端,一半是无法伪造、也无法关停的链上代码。前端明天就算消失,合约——以及你的资金——也会一如既往地照常运转。

钱包,是你的签名笔

你的钱包并不是存放硬币的地方——那些数字住在链上。钱包真正的工作,是守护一个秘密:你的私钥。把这把私钥想成一支只有你握着的签名笔,它写出的签名,地球上没有任何人能够伪造。当一个 dApp 想让你做某件事时,你的钱包就用这支笔为请求签名,证明这道指令确实出自你手。

这支笔背后的密码学,是数字签名。它的奇妙之处在于单向:你的私钥造出一个签名,任何人都能拿它来核对你的公开地址,可无论怎么核对,都永远不会反推出私钥本身。于是整个网络都能确认*「没错,这个账户的主人确实授权了此事」*,却从不曾窥见你的秘密。先签名,签好的请求便能安全地穿行于开放的互联网。

读取免费,写入花燃料

你与合约的每一次互动,都落进两个篮子中的一个,而二者之别,决定了你究竟要不要打开钱包。读取是向链发问——*我的余额是多少?这件物品归谁?*——它什么也不改变。任何节点都能用手头已有的数据作答,所以读取既即时又免费;无需签名,也无需付费。这正是为什么页面一加载,dApp 就能显示你的余额,而你还什么都没批准。

写入则是另一个篮子:它*改变共享状态*——转出代币、投下一票、铸造一件物品。一次写入必须由网络上每一个节点重新运行并达成一致,再被永久存下,因此它不可能免费。它必须是一笔签了名的交易,并附带一笔燃料费,为这场全球性的运算付账。读取是图书管理员瞥一眼书架;写入则是馆里所有人同时改写各自那一本书。

READ  (a question)            WRITE (a change)
  cost: free                    cost: gas fee
  signature: none               signature: required
  speed: instant                speed: wait for a block
  example: getBalance()         example: transfer(to, 10)

Flow of a write:
  front-end drafts tx  ->  wallet shows it  ->  YOU sign
        ->  broadcast  ->  a validator includes it in a block
        ->  every node re-runs it  ->  state updated forever
读取是免费地发问;写入会改变世界,且要花燃料。

代币授权:交出一份支出额度

有一个动作常让新手栽跟头。多数合约无法伸进你的钱包、把你的代币掏出来——而这是刻意如此设计的。于是,当一个 dApp 需要*代你*转移代币时(比如一个交易应用,要把一种币换成另一种),你得先签一笔单独的交易,叫作授权。它告诉代币合约:*「允许这个另外的合约,最多花掉我 N 枚代币。」*

// Solidity: the approval lives in the TOKEN contract
function approve(address spender, uint amount) public {
    allowance[msg.sender][spender] = amount;  // set a limit
}

// Later the dApp's contract may pull tokens, but only
// up to the limit you set:
//   transferFrom(you, someoneElse, amount <= allowance)

// approve(dApp, 50)            -> safe, capped at 50
// approve(dApp, UNLIMITED)     -> convenient, but risky
一次授权设定了一个支出上限;dApp 此后最多可拉走这么多。

授权是真正有用的——它让一个应用顺畅地行事,不必每一步都来烦你签名。但症结在于额度。为了省去你日后的弹窗,许多 dApp 会索要一份无上限的额度,而人们往往不看就一路点过。倘若那个支出合约日后被发现存在缺陷、或心怀恶意,这份长期有效的许可,恰恰就是让它能抽干已授权代币的那把钥匙。补救之道很简单:尽量只授权你实际要花的数额,并撤销那些你不再使用的旧额度。

把它们串起来

  1. 打开 dApp。它的前端加载后,免费*读取*链上数据来显示你的余额——此刻还没有钱包弹窗。
  2. 点击一个动作。前端*起草*一笔交易(比如一次兑换),并把它递给你的钱包——它自己无法发送。
  3. 读一读,再签名。你的钱包显示这份请求和燃料预估;你的签名把它变成一笔有效且经授权的交易。
  4. 网络结清它。这笔签好的写入被广播、被打包进区块、被每个节点重新运行,并永久记录到链上。

整套模式就是这样。一个 dApp 是前端加链上代码;你的钱包是那支签名的笔;读取是免费的发问,写入是付费的改动;而一次授权,是一份值得仔细设定的支出额度。接下来,我们要看代币本身——那些标准,让一个合约发行的一种币或一件藏品,能被每个钱包和应用瞬间认得、知道如何处理。