招募开发者,为 Portal Wallet 提供签名支持

背景:

  1. CKB Community Fund DAO 中的所有提案,均由 Nervos DAO 的存款人在 Metaforo 上投票来决定是否给予资助。投票前,用户需要先在 Metaforo 上绑定自己的 Nervos DAO 地址,投票的权重和他们存在 Nervos DAO 中的 CKB 数量息息相关。

  2. Metaforo 上绑定 Nervos DAO 地址时,需要用到钱包的签名功能。目前只有 Neuron 钱包支持消息签名,Portal Wallet 不支持,而之前很多社区用户是用 Portal Wallet 存的 Nervos DAO,这就意味着他们无法在 Metaforo 上绑定地址,无法行使投票权。

  3. Portal Wallet 的开发者 Lay2 团队目前没有多余的精力可以投入到钱包的功能更新上,所以他们也同样希望有社区开发者能去改进 Portal Wallet。

需求

希望有社区开发者(个人/团队均可)能够自愿为 Portal Wallet 增加签名支持。

其他

  • 为 Portal Wallet 增加签名支持这件事,也可以写成一个提案,去申请 CKB Community Fund DAO 的资金支持。

  • Portal Wallet 的源代码可以在 Lay2 的 GitHub 上查看到。

2 Likes

Does someone need to basically implement support for this?

说一下我的尝试经历,想实现的朋友可以参考:

1. PWCore.provider.sign(message);

pw-core可以访问的方法。
可惜,它应该是provider本身的签名。比如,如果是连接的MetaMask钱包,那就是Eth的personal_sign签名。

2. Eth的personal_sign的签名逻辑

实现逻辑,涉及下面3个js:

  1. ethers.js/message.ts L35:对message进行哈希摘要
export function hashMessage(message: Uint8Array | string): string {
    if (typeof(message) === "string") { message = toUtf8Bytes(message); }
    return keccak256(concat([
        toUtf8Bytes(MessagePrefix),
        toUtf8Bytes(String(message.length)),
        message
    ]));
}
  1. ethers.js/signing-key.ts L64:实现了私钥的具体签名逻辑
sign(digest: BytesLike): Signature {
        assertArgument(dataLength(digest) === 32, "invalid digest length", "digest", digest);

        const [ sigDer, recid ] = secp256k1.signSync(getBytesCopy(digest), getBytesCopy(this.#privateKey), {
            recovered: true,
            canonical: true
        });

        const sig = secp256k1.Signature.fromHex(sigDer);
        return Signature.from({
            r: toBeHex("0x" + sig.r.toString(16), 32),
            s: toBeHex("0x" + sig.s.toString(16), 32),
            v: (recid ? 0x1c: 0x1b)
        });
    }

  1. ethers.js/base-wallet.ts L104:
return this.signingKey.sign(hashMessage(message)).serialized;

3. CKB 的签名逻辑

都在 neuron/sign-message.ts 中。

// L86
  private static signatureHash(message: string) {
    const buffer = Buffer.from(SignMessage.magicString + message, 'utf-8')
    const blake2b = new Blake2b()
    blake2b.updateBuffer(buffer)
    return blake2b.digest()
  }

// L41
  private static signByPrivateKey(privateKey: string, message: string): string {
    const digest = SignMessage.signatureHash(message)
    const ecPair = new ECPair(privateKey)
    const signature = ecPair.signRecoverable(digest)
    return signature
  }

4. 测试数据

Eth地址:0x309ddffb87f07afba6b69cfed4bdfaea774f6abb
对应的CKB地址:ckb1qzl58smqy32hnrq6vxjedcxe2fugvnz497h7yvwqvwel40uh4rltcqfsnh0lhpls0ta6dd5ulm2tm7h2wa8k4wcq0va7g

message:hello, world

Eth环境下的MetaMask签名结果:
0x63ca73e288a03befb6cb01a932bd08ff8da621c3365f5daee95abdeebe5258fc67c2d04986c426c305b5d66de3140b47dd3f7785c2fe8f93fb0f315b064d7af91c

pw-core的PWCore.provider.sign(message);结果:
0x63ca73e288a03befb6cb01a932bd08ff8da621c3365f5daee95abdeebe5258fc67c2d04986c426c305b5d66de3140b47dd3f7785c2fe8f93fb0f315b064d7af901

可以看出,eth和pw-core结果基本一样,区别就是最后一个byte。

5. 总结

我暂时没有思路。。。搞不定啊。。。 /(ㄒoㄒ)/~~

借此机会重构了一个工具出来:各个链的签名——就差Nervos了:Wallet Functions - RuneBox
我重新开放了PW的签名,感兴趣的可以自行测试。

1 Like

I think I found it

This specifies that the last byte of the signature should be 0xb1 or 0xc1

but also most implementations just specify “1”

(reference)

2 Likes

Update: [News] Metaforo 已支持那些通过 Portal Wallet 存 Nervos DAO 的用户参与投票

经过 Metaforo 团队的努力,那些通过 Portal Wallet(ckb.pw)存 Nervos DAO 的用户,现在也可以参与提案的投票啦!大家只需用 Portal Wallet 对应的以太坊钱包登录 Metaforo 即可(登陆后请不要绑定 CKB 地址!)。

另外,通过 CKBull 钱包存 Nervos DAO 的用户,也有变通的方法:将 CKBull 钱包的助记词,导入到 Neuron 钱包,然后参照教程绑定地址即可。


Thanks to the Metaforo team, users who deposit their CKB in Nervos DAO via Portal Wallet (ckb.pw) can now vote on proposals! They only need to log in to Metaforo with the corresponding Ethereum wallet (please do not bind the CKB address after logging in).

Moreover, there is a workaround for the CKBull users to vote on Metaforo: import the same seed phrase they use in CKBull into Neuron and then do the same sign messages steps on the tutorial.