# 研究了一下Stargate是怎么实现的

By [dragonbro](https://paragraph.com/@dragonbro) · 2023-03-31

---

[https://github.com/stargate-protocol/stargate/blob/main/whitepaper/Delta-Solving.The.Bridging-Trilemma.pdf](https://github.com/stargate-protocol/stargate/blob/main/whitepaper/Delta-Solving.The.Bridging-Trilemma.pdf)

跨链桥的不可能三角：

1.  即时确定性，从A链提交的向B链的跨链请求能够被立即响应
    
2.  统一流动性，如果跨链桥对于每两条链都要单独创建一个池子，那么池子总数会随着链的数量呈平方增长
    
3.  原生资产，而不是再印一种跨链桥承兑的资产
    

目前的跨链桥大都放弃了第三条，本质上是自己印一种中间资产来承兑，跨到目标链之后还要再swap一次，而这个中间资产可能流动性很差。有一些跨链桥本质上是钱庄，两边都是原生资产，中间靠中心化核对和承兑，不知道属于放弃了哪一条。stargate提出了一种基于layerzero的跨链桥算法，能够保证你提交的任意一笔转账，要么因为目标链没有足够额度而直接被拒绝，要么必然能转账成功。证明用的是数学归纳法，即对于初始情况（第一笔转账），证明了结论必然成立，并且对于任意已知的历史H，新增的一笔转账也能使结论成立，那么由归纳法可知，结论必然成立。我们更关心的是具体如何实现，下边我用论文里的例子拆解一下。 需要补充说明：为了让模型尽量简洁，以下讨论时我们忽略了跨链手续费和gas fee，并认为智能合约和跨链通信是绝对安全可信的。实际上，跨链桥应当积累手续费，并在池子比例极端的情况下，向此时的流动性提供者发放奖励，或动态调整手续费以鼓励让桥恢复平衡的行为。我们假定要在XYZ三条链上部署Stargate，对于X链，我们会设置一些变量，Y链和Z链同理： **初始流动性 lp\_x**，向跨链桥存入的初始资产，只会在发生存取款行为时改变，不会在发生跨链活动时改变； **权重 w\_xy，w\_xz，要理解成是看待其他链的权重**，权重越高代表向相应链的额度越高，权重总和是1； **总资产 a\_x**，是经过了存取款、跨链行为之后，**剩余的资产**，初始情况下a\_x = lp\_x； **可跨链资产 b\_xy，b\_yz，意思是最大可充值的额度，也就是目标链上能被提走的额度**，如果跨链需求大于它，会被拒绝，比如b\_xy=10，意思就是在x链发起向y的跨链，最多可以跨10； **最近一次被知道的额度 lkb\_yx，lkb\_zx**，名字有点抽象，实际上就是跨链桥里能被相应的链支配的资产额度，或者**对于某一条链，最多能被提走的额度**，lkb\_yx=20，意思就是y链想发起向x的跨链，最多可以跨20； **信用 c\_xy，c\_xz，是在跨链过程中产生的相对于其他链的欠款**，会随着每次跨链提币同步，计入lkb的资产端。 在每一笔跨链完成后，对于任一条链，可被支配总额lkb与向其他链的负债c的总和即为总资产。我们把“从S链向D链跨一笔大小为t的资产”称为一次跨链操作，跨链桥在执行此操作时，遵循以下算法过程：

1.  检查目标链是否有足够资金可供这笔跨链需求，若b\_sd < t 则拒绝此交易；
    
2.  使用lp和w计算出对每一条链的目标额度。对于存入的跨链资产，优先补满全部的目标额度，在不存在赤字之后，再按照w来分配多余的额度。
    
3.  按照可被提款的比例来分配本地对于其他各条链的负债
    
4.  更新资产负债表，向目标链发送数据
    
5.  目标链更新资产负债表，转出跨链的资产
    

接下来是具体例子： 三条链X，Y，Z的初始状态： 初始资产都是100，全部是LP存进来的钱 X链初始权重 w\_xy = 0.5，w\_xz = 0.5，可充值额度 b\_xy = 60，b\_xz = 50 被跨链额度 lkb\_yx = 50，lkb\_zx = 50，债务 c\_xy = 0，c\_xz = 0 YZ不赘述第一笔跨链，向X存入40，从Y提走40，算法会执行以下步骤：

1.  X可以支配Y的额度60 > 40，这笔跨链能够实现，不会拒绝
    
2.  从X可支配Y的额度中扣除40，b\_xy = 20
    
3.  X此时可以被YZ支配的资产都是50，已经达到了初始额度，所以存款按照weight来分配，记为X欠了YZ各20，c\_xy = 20，c\_xz = 20
    
4.  X链把向Y的负债计入资产，也就是X可以被Y支配的额度 lkb\_yx = 70，向Y链发送同步信息
    
5.  Y链更新账本，Y可支配X的额度 b\_yx = 70，并把本地资产发送给目标用户，更新本地资产 lkb\_xy = 20
    

执行完以上步骤后，用户实现了向X存入40，从Y提走40。跨链桥上X的账本变成了：可被Y支配70，可被Z支配50，向Z负债20，合计140；Y的账本变成了：可支配X 70，可支配Z 50，可被X支配20，可被Y支配40，合计60。Z链上的账本没有变化。第二笔跨链，向Y存入30，从Z提走30，以下是算法步骤：

1.  Y可以支配Z的额度 b\_yz = 50 > 30，所以不会拒绝
    
2.  从Y可支配Z的额度扣除30，剩余 b\_yz = 20
    
3.  **由于Y可被X支配的初始额度是60，现在只剩20，存款会优先补充这个额度，此处记为Y增加了30对X的负债，c\_yx = 30**
    
4.  Y向Z发送同步，Z可支配Y额度 lkb\_yz = 20，Z向用户转账30
    

执行完以上步骤后，Y多了30向X的负债，Z减少了30的资产。第三笔跨链，向Y存20，从X取20：

1.  Y可以支配X的额度 b\_yx = 70 > 20，不会拒绝，扣除20，b\_yx = 50
    
2.  由于Y可被X支配的初始额度是60，现在剩20+30=50，还差10，存款会优先补充这个额度；存款是20，补了10，剩下的10会按照weight来分配，所以最后Y向X的负债 c\_yx = 30 + 10 + 6 = 46，Y向Z的负债 c\_yz = 4
    
3.  Y向X的负债并入X的可支配资产，向X发送同步消息，此时lkb\_xy = 20 + 46 = 66
    
4.  X收到信息，修改可支配Y的资产 b\_xy = 66，并向用户转账20，此时lkb\_yx = 70 - 20 = 50
    

执行完以上步骤后，Y对X的负债并入了资产，对Z产生了负债；X增加了可支配X的资产。总的来说，这个算法靠一笔转入、一次链间发送消息和一笔转出，实现了多链转账系统，还是挺不错的。

---

*Originally published on [dragonbro](https://paragraph.com/@dragonbro/stargate)*
