天降 $1000 ?FLT 空投详解

开发者大毛

最近一些 web3 开发/安全群里都提到了 $FLT 空投。此次空投的项目方为 Fluence network (去中心化云平台,DePIN 概念)。空投 token 占总量 5 %,分配给在一年内为 web3 开源项目做过贡献的 ~ 110,000 个开发者。

检查资格及领取链接 https://claim.fluence.network/

天降 00 ?FLT 空投详解

理论上只有向 web3 开源项目提交过代码才有领取资格,但实际范围似乎宽泛的多。笔者周围基本上有 github 的人就有空投资格。具体有资格的 github 账户列表在这里[1]

每个账户领取金额均为 5000 个 $FLT,在 xt.com[2] 上目前报价 ~ $16,但深度一般,价格仅能作为参考。

天降 00 ?FLT 空投详解

另一方面,根据群里的截图,场外 5000 个总价均 $1000 。

天降 00 ?FLT 空投详解

算是针对开发者的大毛了,由于项目方知名度差一些,因此相比于之前 $STRK 此次空投覆盖面似乎更广。

是钓鱼吗?

有意思的一点是,由于项目方名不见经传,且空投领取操作流程略显硬核。要本地运行脚本,大家对安全性顾虑较多,甚至一度让人怀疑这个空投是不是钓鱼网站。

天降 00 ?FLT 空投详解

此次空投的领取方式是:

  1. clone 项目方提供的 github repo
  2. 运行其中的脚本,生成领取空投的 proof
  3. 提交 proof 领取空投

repo 本身是开源的,可以查看源码来确认其安全性。

先说结论,不是钓鱼。领取过程不会泄露以太坊私钥,不会泄露 github ssh key 私钥,但需要读取本地的 ssh key 私钥进行解密操作以验证开发者身份。

技术解析

比较简单的 github 空投发放可以使用 Oauth 进行验证,然后服务器签名发放 token。

但 Fluence 用了一个比较硬核的 web3 空投方式,即通过 github ssh key 鉴权。其流程是:

  1. 项目方获取到 github 账户列表,并为每个账户生成一个随机的临时 ETH 私钥。
  2. 使用对应github 账户的 ssh key 公钥加密这个临时 ETH 私钥。
  3. 开者者使用手中的 github ssh 私钥解密得到 ETH 私钥。
  4. 任意指定一个收取 token 的地址,用这个 ETH 私钥签名,提交 claim 交易。
  5. 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。关键步骤包括:

  1. 用户输入 GITHUB_USERNAME 和接收空投用的 ETHEREUM_ADDRESS
  2. 在 metadata 中查找 GITHUB_USERNAME 所对应的加密后的数据,如果能找到说明有空投资格。
  3. 遍历本机的 ~/.ssh 查找 ssh key,配置用户的选择,调用 age 进行数据解密 2 查到的数据,得到临时 ETH 地址私钥等信息。
  4. 调用 sha3sum 对 Ethereum Signed Message 格式的 ETHEREUM_ADDRESS 进行 Keccak256,得到待签名的 message hash。
  5. 调用 openssl 使用 3 中的地址私钥对 4 中的 hash 签名。
  6. 输出签名、临时 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);
}

主要逻辑:

  1. 检查每个 github 账户只能领一次。
  2. 通过 MerkleProof 检查 userId(不是 github 账户名,而是一个整数 index)和临时 ETH 地址的有效性。
  3. 以 msg.sender 构造签名数据。
  4. 检查签名的 signer 是否为临时 ETH 地址。
  5. 更新相关余额数据。

其他

查看合约还能发现一些其他值得关注的信息。

  • 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 精品号了。

参考资料

[1]

这里: 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 空投详解

版权声明:admin 发表于 2024年3月14日 上午11:30。
转载请注明:天降 $1000 ?FLT 空投详解 | CTF导航

相关文章