有一天,一名用户联系了 rabbit.io 客服,声称在一次交易后,他收到了 1 XLM 而不是 1,000 USDC。
这看起来是一笔严重的损失。1 个 Lumen 的价值远低于 1 美元:目前,XLM 的交易价格约为 0.22 美元。以这种方式损失几乎全部金额对任何人来说都是触目惊心的。
自然地,我们立即开始调查此案。如果事实证明是因为我们的过错导致发送了错误的金额或错误的资产,我们会立即采取行动,确保用户收到正确的资金。
但事实证明,故事要有趣得多。
我们的系统运行完全符合预期。1,000 USDC 已发送至用户提供的地址,我们这边没有出现任何错误或故障。然而,在 Stellar 网络中存在一个微妙的架构细节,如果你忽略了它,它真的能将 1,000 USDC 变成 1 XLM。
让我解释一下这是如何发生的。
rabbit.io 的这位客户并不是新手。相反,他是一位经验丰富的加密货币用户,他刻意将资金存储在非托管钱包中,而不是交易所。然而,他的大部分经验都来自基于 EVM 的网络。
在以太坊的世界里,用户习惯了一个简单的模型:发送到你地址的任何代币都会成功到达。在最坏的情况下,你只需要在钱包界面手动添加该代币即可。甚至当钱包应用根本不支持某个特定代币时,你也可以将助记词导入到支持该代币的另一个钱包中。
Stellar 的运作方式则大不相同。
它的架构与以太坊、币安智能链(BSC)或 Polygon 根本不同。甚至地址的概念也不一样。在 EVM 网络中,地址实际上是免费的。而在 Stellar 中,在账本(ledger)上创建一个地址需要花费 1 XLM。
而这正是我们的客户在交易后在钱包中看到的准确金额——1 XLM。
Stellar 与基于 EVM 的网络之间最重要的区别在于资产的接收方式。
在 Stellar 中,钱包必须在入账前明确批准任何新代币。例如,为了首次接收 USDC,Stellar 账户必须向 USDC 发行方创建一条信任线(trustline)。创建信任线需要锁定 0.5 XLM 作为准备金,以确保相应的账本条目安全。
最初,如果将代币发送到没有现有信任线的地址,交易将直接失败。全额资金将保留在发送方手中。
从 Stellar Protocol 15 开始,随着可申领余额(claimable balances)的引入,这一行为发生了改变。其目标是提高易用性,并允许将代币发送到甚至尚未“准备好”的账户。
当我们向客户没有 USDC 信任线的 Stellar 地址发送 USDC 时,协议按如下方式处理了该交易:
换句话说,资金被记录在账本上并留在那里,等待某人明确申领。谁被允许申领由交易条件定义。默认情况下,发送方和接收方都有资格申领。
但是接收方账户上的 1 XLM 是从哪里来的呢?答案是:来自我们——尽管我们从未刻意发送过它。
以下是此类交易实际处理的过程:
第一步:发送方发起 USDC 转账并签署具有以下参数的交易:
在此阶段,发送方默认同意支付处理交易所需的任何金额的 XLM。在实践中,用户很少关注这个细节,因为 Stellar 上的交易费用通常微不足道。
第二步:Stellar 执行一系列基本验证,检查操作是否可以执行:
综合这些条件,意味着直接支付是不可能的。
第三步:Stellar 没有直接拒绝交易,而是激活了可申领余额机制。
为此,网络:
然而,为了将接收方列为潜在申领人,接收方的账户必须存在于网络上。在交易时,该账户仅存在于接收方的钱包应用内部,尚未在 Stellar 账本上创建。
在这些条件下,账户作为同一笔交易的一部分被创建。
如前所述,在 Stellar 上创建账户不是免费的。创建账户所需的 1 XLM 从操作源头扣除,即从发送方的余额中扣除:
这 1 XLM 是执行交易成本的一部分——我们在签署交易时默认接受了这一成本。从技术上讲,它最终留在接收方的余额中,但接收方实际上无法使用它。特别地,接收方不能拿走这笔金额的一半来创建 USDC 信任线并申领资金。
如果接收方的账户已经存在于网络上,只是缺乏 USDC 信任线,则不需要额外的 1 XLM。在这种情况下,接收方根本不会看到钱包有任何可见的变化。
第一步是让接收方为 USDC 资产签署一个 changeTrust 操作。为了使此操作成功,钱包必须拥有至少 0.5 XLM 的可用余额,这在创建信任线时会被锁定为准备金。
我们的客户没有任何可用的 XLM。更准确地说,账户中唯一的 XLM 是由于交易而出现在那里的 1 XLM——但该金额作为基础准备金被完全锁定,无法使用。
因此,我们建议了一个简单的变通方法:将少量任何可用的加密货币兑换成 Lumen。完成此操作后,客户终于有了足够的可用 XLM 在他的钱包中创建信任线。
一旦建立了 USDC 信任线,用户就能够申领这 1,000 USDC。在这种情况下,相关各方都有了一个圆满的结局。
我们客户遇到的情况并非个例。他非常幸运,使用的是完全由自己控制的非托管钱包。这正是问题相对容易解决的原因。
我之所以想起这个故事,是因为就在几天前,我读到了另一个用户涉及的一个非常类似的案例。金额完全一样——1,000 USDC——但情况使得问题解决起来要困难得多。
三天前,LinkedIn 上在 Uphold 首席执行官 Simon McLoughlin 的最新动态下出现了一条评论,一位 Uphold 用户描述了以下情况:
鉴于症状如此吻合,我相信其根本问题是完全一样的。
最有可能的情况是,Uphold 根据需求生成充值地址,而用户发送资金的 XLM 地址尚未在 Stellar 账本上创建。这可以解释为什么交易导致账户上出现了 1 XLM。然而,1,000 USDC 并没有出现,解决这种情况需要 Uphold 手动为该地址创建一条 USDC 信任线。
为什么客服拒绝提供帮助?
我的猜测是安全架构。任何处理加密货币的业务都会在钱包安全方面投入巨资。看起来 Uphold 没有在预期的标准充值流程之外实现创建信任线的流程。在满足所有内部安全要求的同时追溯性地添加此类功能,交易所花费的成本可能远超用户损失的 1,000 USDC。
截至今天,首席执行官动态下的那条评论已被删除。我不知道是用户自己删除的还是被交易所删除的。我希望问题已经得到解决,用户选择了自行删除评论。但如果评论是被 Uphold 删除的,那将是一个令人不安的信号。
这些问题不应该被悄悄掩埋。相反,它们值得关注——这样其他用户就不会重蹈覆辙。这就是为什么我决定在这里分享我们的故事和 Uphold 用户的故事。
如果涉及的钱包中至少有一个——无论是发送方还是接收方——完全由资金所有者控制,情况就相对简单:
然而,当涉及托管钱包时——例如中心化交易所(CEX)钱包——事情就会变得复杂得多。
托管服务没有义务通过手动干预其钱包基础设施来修正用户的错误,特别是如果这样做会引入额外的运营或安全风险。因此,你可能会被拒绝提供协助,尽管资金在技术上仍然存在于账本上。
尽管如此,仍值得一试。只要交易所控制着私钥,资金就有机会找回。
如果你发现自己处于这种境地:
最终,最好的解决方案仍然是预防。成为自己的托管人有很多优势,但也伴随着高度的责任。发送加密货币时,对细节的关注至关重要,因为有些错误犯起来容易,修正起来却难得多。