app-monorepo icon indicating copy to clipboard operation
app-monorepo copied to clipboard

Determining whether the current connection is a hardware wallet or a software wallet in OneKey.

Open lihanjin opened this issue 6 months ago • 32 comments

We need a reliable method to check whether the current wallet connection is a hardware wallet or a software wallet using the OneKey SDK. The goal is to detect the wallet type so we can handle interactions appropriately based on the wallet's capabilities.

lihanjin avatar Jul 14 '25 07:07 lihanjin

In what scenarios do you need to determine whether the user is using a software wallet or a hardware wallet?

originalix avatar Jul 14 '25 08:07 originalix

In what scenarios do you need to determine whether the user is using a software wallet or a hardware wallet?

In the Tron network, hardware wallets do not support message signing, so we need to determine if the wallet is a hardware wallet in order to call the hardware wallet SDK for message signing. If it is not a hardware wallet, we do not call the hardware wallet SDK.

lihanjin avatar Jul 14 '25 08:07 lihanjin

Thanks for the feedback! I think a more reasonable approach would be for OneKey Wallet to support TronSignMessage in the SDK first — right? #7735

originalix avatar Jul 14 '25 08:07 originalix

Thanks for the feedback! I think a more reasonable approach would be for OneKey Wallet to support TronSignMessage in the SDK first — right? #7735

硬件钱包可以用这个sdk的tronSignMessage方法代替消息签名吗https://developer.onekey.so/connect-to-hardware/page-1/api-reference/tron/tronsignmessage 我看官方示例里面不支持硬件钱包消息签名

Image

lihanjin avatar Jul 14 '25 08:07 lihanjin

现在软件钱包也不支持 Tron 的 SignMessage,你们在开发时是怎么 workaround 的呢?

originalix avatar Jul 14 '25 08:07 originalix

现在软件钱包也不支持 Tron 的 SignMessage,你们在开发时是怎么 workaround 的呢?

我查阅了文档,发现软件钱包不支持 Tron 的 SignMessage。因此,我打算使用硬件钱包的 Hardware SDK 中的 tronSignMessage 方法进行签名。但在调用后发现,签名结果无法通过 Tron 网络的签名验证。

lihanjin avatar Jul 14 '25 08:07 lihanjin

现在软件钱包也不支持 Tron 的 SignMessage,你们在开发时是怎么 workaround 的呢?

我查阅了文档,发现软件钱包不支持 Tron 的 SignMessage。因此,我打算使用硬件钱包的 Hardware SDK 中的 tronSignMessage 方法进行签名。但在调用后发现,签名结果无法通过 Tron 网络的签名验证。

相同消息字符串,Hardware SDK 中的 tronSignMessage 方法 和 tronlink 的 signMessage,返回的签名结果字符串不一致

lihanjin avatar Jul 14 '25 08:07 lihanjin

由于我们的 DApp 中有一些敏感操作需要用户证明钱包属于他们,因此需要进行消息签名。但是我们发现 OneKey 无论是硬件钱包还是软件钱包,都不支持消息签名。

lihanjin avatar Jul 14 '25 09:07 lihanjin

不只是消息签名,交易签名 sign 方法在硬件钱包也是有问题的,发起 sign 方法,点击签名返回报错 User rejected the request.

Image Image Image

lihanjin avatar Jul 14 '25 09:07 lihanjin

cc @ByteZhang1024 @weatherstar

可以看下交易签名这里

originalix avatar Jul 14 '25 09:07 originalix

@lihanjin 请问具体签的是什么交易呢,contract type 具体是什么

weatherstar avatar Jul 14 '25 09:07 weatherstar

@lihanjin 请问具体签的是什么交易呢,contract type 具体是什么

@lihanjin 请问具体签的是什么交易呢,contract type 具体是什么

  1. 创建合约
  const transaction = await this.tronweb.transactionBuilder.createSmartContract(
          {
            abi,
            bytecode, 
            feeLimi,
            parameters, 
            callValue: 0,
          },
          from, 
        )
  1. 使用硬件钱包签署交易,不支持,签署返回的格式不符合 Tron 网络 sendRawTransaction https://tronweb.network/docu/docs/API%20List/trx/sendRawTransaction/ 方法所需要的格式 签名请求示例:
const response = await HardwareWebSdk.tronSignTransaction(connectId, deviceId, {
  path: "m/44'/195'/0'/0/0",  // TRON BIP44 path for the hardware wallet
  transaction: {
    refBlockBytes: 'ddf1',
    refBlockHash: 'd04764f22469a0b8', 
    timestamp: Date.now(),  
    expiration: Date.now() + 60 * 5 * 1000,  
    contract: [
      {
        type: 'SmartContract',  
        parameter: {
          value: parameters,   
          data: bytecode,   
        },
        feeLimit,               
        callValue: 0,          
      }
    ]
  }
});
  1. 使用软件钱包导入硬件钱包签署交易,不支持,点击签名返回报错 User rejected the request. 签名请求示例:
window.$onekey.tron.tronWeb.trx.sign(transaction)
window.$onekey.tron.tronWeb.trx.signTransaction(transaction)

lihanjin avatar Jul 14 '25 09:07 lihanjin

@lihanjin 抱歉硬件这边暂时还不支持 CreateSmartContract contract type

weatherstar avatar Jul 14 '25 10:07 weatherstar

@lihanjin 抱歉硬件这边暂时还不支持 CreateSmartContract contract type

tronSignMessage 是不是也有问题,相同消息字符串,Hardware SDK 中的 tronSignMessage 方法 和 tronlink 的 signMessage,返回的签名结果字符串不一致

lihanjin avatar Jul 14 '25 10:07 lihanjin

@originalix 想问一下 Hardware Web SDK 中的 tronSignMessage 方法 和 tronlink 的 signMessage是一样的吗

lihanjin avatar Jul 15 '25 01:07 lihanjin

不完全一样,两者在处理消息方式上存在差异:

  • OneKey 硬件钱包在调用 tronSignMessage 时,会对传入的原始消息做一次 sha256,然后对哈希值进行签名。

  • TronLink 的 signMessage 方法则是直接签名传入的消息(比如已经是 sha256 后的结果)

因此,如果希望在 TronLink 中复现与 OneKey 硬件钱包相同的签名结果,可以尝试对 rawMessage(例如 "Hello World")做一次 sha256

originalix avatar Jul 15 '25 02:07 originalix

不完全一样,两者在处理消息方式上存在差异:

  • OneKey 硬件钱包在调用 tronSignMessage 时,会对传入的原始消息做一次 sha256,然后对哈希值进行签名。
  • TronLink 的 signMessage 方法则是直接签名传入的消息(比如已经是 sha256 后的结果)

因此,如果希望在 TronLink 中复现与 OneKey 硬件钱包相同的签名结果,可以尝试对 rawMessage(例如 "Hello World")做一次 sha256

 const messageHex = crypto.createHash('sha256').update('Hello').digest('hex')
    const response = await HardwareWebSdk.searchDevices()
    const result = await HardwareWebSdk.tronSignMessage(
      response.payload?.[0]?.connectId,
      response.payload?.[0]?.deviceId,
      {
        path: "m/44'/195'/0'/0/0",
        messageHex,
      },
    )

    const signature = result.payload.signature

是这样处理吗

lihanjin avatar Jul 15 '25 02:07 lihanjin

  • 使用 TronLink 的时候才需要 hash 一次
  • 调用硬件直接把 Hello 用 utf-8 encode 后传入

originalix avatar Jul 15 '25 03:07 originalix

不完全一样,两者在处理消息方式上存在差异:

  • OneKey 硬件钱包在调用 tronSignMessage 时,会对传入的原始消息做一次 sha256,然后对哈希值进行签名。
  • TronLink 的 signMessage 方法则是直接签名传入的消息(比如已经是 sha256 后的结果)

因此,如果希望在 TronLink 中复现与 OneKey 硬件钱包相同的签名结果,可以尝试对 rawMessage(例如 "Hello World")做一次 sha256

   const messageHex = Buffer.from('helloword').toString('hex')
        const response = await HardwareWebSdk.searchDevices()
        const result = await HardwareWebSdk.tronSignMessage(
          response.payload?.[0]?.connectId,
          response.payload?.[0]?.deviceId,
          {
            path: "m/44'/195'/0'/0/0",
            messageHex,
          },
        )
858ced0301fa3532553c6c91b4606e29423166f3cfe319644ffa1eb37eaf41ba477351a54fb6a07b3dc8328f42b0b1abb4a7e2343c4a940a93f69642dd741e631b 
const message = crypto.createHash('sha256').update('helloword').digest('hex')
const result = await this.provider?.signMessage(message)
0x89f210327d0b442ae94deaa4840301d4f849adcd04e60ef7ecf3990a53688c701ed5975d3b13d7eb4ba4174066a0c4fa503c23185d6462dd1df2dfd9088073db1b

试了一下,这两个签名还是不太一样

lihanjin avatar Jul 15 '25 03:07 lihanjin

hash 函数跟以太坊那个一致的,是 keccak256

somebodyLi avatar Jul 15 '25 03:07 somebodyLi

  • 使用 TronLink 的时候才需要 hash 一次
  • 调用硬件直接把 Hello 用 utf-8 encode 后传入

那 onekey硬件的签名怎么验证,tronweb.trx.verifyMessage(messageHex, signature, address) 验证无法通过

lihanjin avatar Jul 15 '25 03:07 lihanjin

现在签名一致了吗?

somebodyLi avatar Jul 15 '25 03:07 somebodyLi

现在签名一致了吗?

还是不一致,这个不好测试,因为onekey硬件钱包没办法导出,tronlink和onekey的地址不一样,onekey的签名结果应该怎么效验,tronweb.trx.verifyMessage(messageHex, signature, address) 验证无法通过

lihanjin avatar Jul 15 '25 03:07 lihanjin

拿 tronlink 签名接口用的参数(hash 后的消息)和 OneKey的签名验签,传入验签接口,验下试试。测试的话,可以生成一组测试助记词,同时导入到软件中,这样方便对比

somebodyLi avatar Jul 15 '25 03:07 somebodyLi

这个 Tron 的 SignMessageV1 协议本身有问题,我们早期实现的版本也因此有点拧巴,后面我们会支持 V2。

somebodyLi avatar Jul 15 '25 03:07 somebodyLi

拿 tronlink 签名接口用的参数(hash 后的消息)和 OneKey的签名验签传入验签接口验下试试。测试的话,可以生成一组测试助记词,同时导入到软件中,这样方便对比

试了也不行,有具体的代码示例吗

lihanjin avatar Jul 15 '25 05:07 lihanjin

      // 签名验证方法,兼容 onekey 硬件钱包 tronSignMessage
     // 原始消息
     const rawMessage = 'helloworld'
     // 将 message 转换为十六进制字符串
      const hexMessage = this.tronweb.toHex(rawMessage)

    // 去掉 signature 前缀 '0x'
    let cleanSignature = signature.replace(/^0x/, '')

    // 获取签名的第二个字节(用于检查签名格式)
    const signaturePrefix = cleanSignature.substring(128, 130)

    // 根据签名的前缀修改签名
    if (signaturePrefix === '01') {
      cleanSignature = cleanSignature.substring(0, 128) + '1c' // 如果是 "01",修改签名为 "1c"
    } else if (signaturePrefix === '00') {
      cleanSignature = cleanSignature.substring(0, 128) + '1b' // 如果是 "00",修改签名为 "1b"
    }

    // 尝试用消息和签名进行验证
    const verificationResult = await this.tronweb.trx
      .verifyMessage(hexMessage.replace(/^0x/, ''), cleanSignature, this.account, true)
      .catch(() => {})

    // 如果第一次验证失败,使用哈希后的消息重试验证,硬件钱包走的这里的逻辑
    if (!verificationResult) {
      const hexMessage2 = this.tronweb.toHex(rawMessage).replace(/^0x/, '')
      const messageByteArray = this.tronweb.utils.code.hexStr2byteArray(hexMessage2) // 将消息转为字节数组
      const hashedMessage = this.tronweb.sha3(messageByteArray).replace(/^0x/, '') // 对消息进行 sha3 哈希处理
      verificationResult = await this.tronweb.trx
        .verifyMessage(hashedMessage, cleanSignature, this.account, true)
        .catch(() => {})
      // 验证通过
      console.log('🚀 ~ TronAdapter ~ signMessage ~ isValid:', verificationResult)
    } 

已解决,兼容Onekey硬件钱包验签,如果第一次失败,需要对消息进行 sha3 哈希处理 在验证一次

lihanjin avatar Jul 15 '25 08:07 lihanjin

这个 Tron 的 SignMessageV1 协议本身有问题,我们早期实现的版本也因此有点拧巴,后面我们会支持 V2。

签名问题解决了,有没有办法识别用户是 onekey 连接钱包 还是 tronlink连接钱包 。 有没有办法判断当前连接的地址是硬件钱包的地址还是插件钱包的地址

lihanjin avatar Jul 15 '25 08:07 lihanjin

暂时没法识别,只能在 Tron 链添加 wallet api 来识别

originalix avatar Jul 15 '25 09:07 originalix

暂时没法识别,只能在 Tron 链添加 wallet api 来识别

有没有办法判断当前连接的地址是硬件钱包还是插件钱包

lihanjin avatar Jul 15 '25 09:07 lihanjin