最近一些 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 此次空投覆盖面似乎更广。
有意思的一点是,由于项目方名不见经传,且空投领取操作流程略显硬核。要本地运行脚本,大家对安全性顾虑较多,甚至一度让人怀疑这个空投是不是钓鱼网站。
此次空投的领取方式是:
repo 本身是开源的,可以查看源码来确认其安全性。
先说结论,不是钓鱼。领取过程不会泄露以太坊私钥,不会泄露 github ssh key 私钥,但需要读取本地的 ssh key 私钥进行解密操作以验证开发者身份。
比较简单的 github 空投发放可以使用 Oauth 进行验证,然后服务器签名发放 token。
但 Fluence 用了一个比较硬核的 web3 空投方式,即通过 github ssh key 鉴权。其流程是:
整体来说这个设计还是挺有意思的,链上进行 ssh key 验证比较麻烦,因此这里采用预生成的 ETH 私钥一一对应,从而简单的实现链上验证。
可以看到整个过程是不会泄露开发者的任何私钥信息的。唯一的风险可能在于如果项目方在 1 步骤中生成的私钥列表泄露,那么则可能导致全部空投被攻击者领取。
空投脚本在这个 repo 中:https://github.com/fluencelabs/dev-rewards
领取空投时允许通过 docker, python, bash 等多种执行方式。几种方式本质逻辑是一样的,只是实现语言和运行方式不同。另外 python 脚本包含了 1 、2 步相关的代码。
下面我们只分析领取逻辑,并以 bash 版本为例。领取空投需要运行两个 shell 脚本。
install.sh
主要作用是下载一些必须的文件,包括:
➜ 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
proof.sh
则进行生成 claim 用的 proof。关键步骤包括:
GITHUB_USERNAME
和接收空投用的 ETHEREUM_ADDRESS
GITHUB_USERNAME
所对应的加密后的数据,如果能找到说明有空投资格。~/.ssh
查找 ssh key,配置用户的选择,调用 age 进行数据解密 2 查到的数据,得到临时 ETH 地址私钥等信息。Ethereum Signed Message
格式的 ETHEREUM_ADDRESS
进行 Keccak256,得到待签名的 message hash。最后回到 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);
}
主要逻辑:
查看合约还能发现一些其他值得关注的信息。
peth > view 0x6081d7F04a8c31e929f25152d4ad37c83638C62b lockupPeriod uint256
5184000
peth > timestamp 5184000
5184000 secs
= 1440.0 hours
= 60.0 days
最近针对 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
【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。