开发者大毛
最近一些 web3 开发/安全群里都提到了 $FLT
空投。此次空投的项目方为 Fluence network (去中心化云平台,DePIN 概念)。空投 token 占总量 5 %,分配给在一年内为 web3 开源项目做过贡献的 ~ 110,000 个开发者。
检查资格及领取链接 https://claim.fluence.network/
理论上只有向 web3 开源项目提交过代码才有领取资格,但实际范围似乎宽泛的多。笔者周围基本上有 github 的人就有空投资格。具体有资格的 github 账户列表在这里[1]。
每个账户领取金额均为 5000 个 $FLT,在 xt.com[2] 上目前报价 ~ $16,但深度一般,价格仅能作为参考。
另一方面,根据群里的截图,场外 5000 个总价均 $1000 。
算是针对开发者的大毛了,由于项目方知名度差一些,因此相比于之前 $STRK 此次空投覆盖面似乎更广。
是钓鱼吗?
有意思的一点是,由于项目方名不见经传,且空投领取操作流程略显硬核。要本地运行脚本,大家对安全性顾虑较多,甚至一度让人怀疑这个空投是不是钓鱼网站。
此次空投的领取方式是:
-
clone 项目方提供的 github repo -
运行其中的脚本,生成领取空投的 proof -
提交 proof 领取空投
repo 本身是开源的,可以查看源码来确认其安全性。
先说结论,不是钓鱼。领取过程不会泄露以太坊私钥,不会泄露 github ssh key 私钥,但需要读取本地的 ssh key 私钥进行解密操作以验证开发者身份。
技术解析
比较简单的 github 空投发放可以使用 Oauth 进行验证,然后服务器签名发放 token。
但 Fluence 用了一个比较硬核的 web3 空投方式,即通过 github ssh key 鉴权。其流程是:
-
项目方获取到 github 账户列表,并为每个账户生成一个随机的临时 ETH 私钥。 -
使用对应github 账户的 ssh key 公钥加密这个临时 ETH 私钥。 -
开者者使用手中的 github ssh 私钥解密得到 ETH 私钥。 -
任意指定一个收取 token 的地址,用这个 ETH 私钥签名,提交 claim 交易。 -
Airdrop 合约通过 merkle proof 验证签名的地址是其在第 1 步生成的地址,并将空投发放给第 4 步开发者选择的收款地址中。
整体来说这个设计还是挺有意思的,链上进行 ssh key 验证比较麻烦,因此这里采用预生成的 ETH 私钥一一对应,从而简单的实现链上验证。
可以看到整个过程是不会泄露开发者的任何私钥信息的。唯一的风险可能在于如果项目方在 1 步骤中生成的私钥列表泄露,那么则可能导致全部空投被攻击者领取。
空投脚本在这个 repo 中:https://github.com/fluencelabs/dev-rewards
领取空投时允许通过 docker, python, bash 等多种执行方式。几种方式本质逻辑是一样的,只是实现语言和运行方式不同。另外 python 脚本包含了 1 、2 步相关的代码。
下面我们只分析领取逻辑,并以 bash 版本为例。领取空投需要运行两个 shell 脚本。
install.sh
主要作用是下载一些必须的文件,包括:
-
metadata.bin, metadata.json 完整的空投列表及加密后数据,即 1 、2 步生成的内容。这里包含了所有人的数据,文件较大。
➜ dev-rewards git:(main) ✗ ls -lh meta*
-rw-r--r-- 1 user user 937M Mar 3 10:56 metadata.bin
-rw-r--r-- 1 user user 238M Mar 3 10:59 metadata.json
-
age 可执行文件,用来进行公私钥加解密操作。 -
sha3sum 可执行文件,用来进行 Keccak256 hash 计算 -
注:两个文件下载地址均来自 github,相对可信。
proof.sh
则进行生成 claim 用的 proof。关键步骤包括:
-
用户输入 GITHUB_USERNAME
和接收空投用的ETHEREUM_ADDRESS
-
在 metadata 中查找 GITHUB_USERNAME
所对应的加密后的数据,如果能找到说明有空投资格。 -
遍历本机的 ~/.ssh
查找 ssh key,配置用户的选择,调用 age 进行数据解密 2 查到的数据,得到临时 ETH 地址私钥等信息。 -
调用 sha3sum 对 Ethereum Signed Message
格式的ETHEREUM_ADDRESS
进行 Keccak256,得到待签名的 message hash。 -
调用 openssl 使用 3 中的地址私钥对 4 中的 hash 签名。 -
输出签名、临时 ETH 地址、证明临时 ETH 地址有效性的 merkle proof(也来自 metadata)
最后回到 claim 网页,提交 6 生成的 proof 连接钱包 claim 即可。最终签名交易实际是调用 Fluence Drop (FLT-DROP) 合约[3] 的 claimTokens 方法。
这里还有一个疑问是项目方要如何才能获取到这些 github 账户的公钥?
这个 github 是对外提供的接口的,以下就是一个例子:
curl https://github.com/lmy375.keys
ssh-rsa AAAAB3NzaC1yc2...
ssh-rsa AAAAB3NzaC1yc2...
另外,由于整个验证过程的核心鉴权是通过 ssh key,所以 github 如果未上传有效的 ssh key,那么也是无法得到空投资格的。
合约详解
claimTokens
的逻辑比较简单,源码如下:
function claimTokens(
uint32 userId,
bytes32[] calldata merkleProof,
address temporaryAddress,
bytes calldata signature
) external whenClaimingIs(true) {
require(!isClaimed(userId), "Tokens already claimed");
require(lockedBalances[msg.sender].unlockTime == 0, "Tokens are already locked");
uint256 amount = currentReward();
uint256 claimedSupply_ = claimedSupply;
require(claimedSupply_ + amount <= maxClaimedSupply, "Total claimed exceeded max limit");
bytes32 leaf = keccak256(abi.encodePacked(userId, temporaryAddress));
require(MerkleProof.verify(merkleProof, merkleRoot, leaf), "Valid proof required");
bytes32 msgHash = keccak256(abi.encodePacked("x19Ethereum Signed Message:n20", msg.sender));
address signer = ECDSA.recover(msgHash, signature);
require(signer == temporaryAddress, "Invalid signature");
_setClaimed(userId);
lockedBalances[msg.sender] = LockedBalance({amount: amount, unlockTime: block.timestamp + lockupPeriod});
_totalSupply += amount;
claimedSupply = claimedSupply_ + amount;
emit Transfer(address(0x00), msg.sender, amount);
emit Claimed(userId, msg.sender, amount, leaf);
}
主要逻辑:
-
检查每个 github 账户只能领一次。 -
通过 MerkleProof 检查 userId(不是 github 账户名,而是一个整数 index)和临时 ETH 地址的有效性。 -
以 msg.sender 构造签名数据。 -
检查签名的 signer 是否为临时 ETH 地址。 -
更新相关余额数据。
其他
查看合约还能发现一些其他值得关注的信息。
-
claim 会锁定 lockupPeriod,即 60 天。早领早解锁早砸盘。
peth > view 0x6081d7F04a8c31e929f25152d4ad37c83638C62b lockupPeriod uint256
5184000
peth > timestamp 5184000
5184000 secs
= 1440.0 hours
= 60.0 days
-
claim 并不会直接领取到 FLT-DROP。解锁时间过后进行一次 transfer 可得到真正的 $FLT。解锁之前无法进行 transfer。因此如果想 OTC 出掉空投领取资格的话,则建议不要 claim。 -
Gas 成本:以 50 gwei gas price 为例,成本约 $22 左右。 -
每个 github 账户只能领取一次。每个收款地址同时只有一笔待解锁空投。因此如果有多个 github 账户并想在同一时间 claim,则只能使用不同的收款地址。 -
目前空投为 5000 个,每隔 90 天减半。 -
空投开始时间为 2024-02-28 06:04:23 结束时间为 2025-02-27 06:04:23 -
空投总量为 50000000, 目前(2024/3/13)已领约 20%。
最近针对 github 空投的项目越来越多了,可以预见未来羊毛党会开始涌入 github。是时候培养几个 github 精品号了。
参考资料
这里: https://claim.fluence.network/static/media/github-accounts.579a238639e5f9da5fd0.txt
[2]xt.com: https://www.xt.com/en/trade/flt_usdt
[3]Fluence Drop (FLT-DROP) 合约: https://etherscan.io/address/0x6081d7F04a8c31e929f25152d4ad37c83638C62b
原文始发于微信公众号(Diary of Owen):天降 $1000 ?FLT 空投详解