• Web钱包私钥导出新旧两种地址格式(加班到深夜修改的一个功能点)


    前言:

    这个问题是中午的时候,被用户反馈,当时还不觉得有问题。

    调到最后发现一个小坑是:私钥地址,带0x和不带0x是有区别的。我们的Web钱包不要带0x,否则会还原出另一个新地址。

    1. jssdk修改

    (1)用私钥还原地址

    /** 新地址
     * Get address from private key.
     * @param {string} privateKeyHex the private key hexstring
     * @param {string} prefix address prefix
     * @return {string} address
     */
    export const getAddressFromPrivateKey = (privateKeyHex, prefix) => {
      return getAddressFromPubKey(getPubKeyHexFromPrivateKey(privateKeyHex), prefix)
    }
    
    // 旧地址 Legacy
    export const getAddressFromPrivateKeyLegacy = (privateKeyHex, prefix) => {
      return getAddressFromPublicKeyLegacy(getPubKeyHexFromPrivateKey(privateKeyHex), prefix)
    }
    
    
    /** 新方法
     * Gets address from pubKey with hex format.
     * @param {string} publicKey publicKey hexstring
     * @param {string} prefix address prefix
     * @return {string} address
     */
    export const getAddressFromPubKey = (publicKey, prefix) => {
        publicKey = publicKey.slice(0, 2) === '0x' ? publicKey.slice(2) : publicKey
        const publicKey1 = Buffer.from(publicKey, 'hex')
        publicKey = Buffer.from(secp256k1.publicKeyConvert(new Uint8Array(publicKey1), false)).slice(1)
        const hash = createKeccakHash('keccak256').update(publicKey).digest()
        return encodeAddressToBech32(hash.slice(-20).toString('hex'), prefix)
    }
    
    // 旧的方法Legacy
    export const getAddressFromPublicKeyLegacy = (publicKeyHex, prefix) => {
      // const pubKey = ec.keyFromPublic(publicKeyHex, "hex")
      // const pubPoint = pubKey.getPublic()
      // const compressed = pubPoint.encodeCompressed()
      // const hexed = ab2hexstring(compressed)
      const hash = sha256ripemd160(publicKeyHex) // https://git.io/fAn8N
      const address = encodeAddress(hash, prefix)
      return address
    }
    
    export const encodeAddress = (value, prefix = "ex", type = "hex") => {
      const words = bech32.toWords(Buffer.from(value, type))
      return bech32.encode(prefix, words)
    }
    

      

    (2)新旧两种地址在转账交易类型

    设置账户信息,也要体现两种地址

        /**
         * @param {string} privateKey
         * @param {string} prefix
         * @return {OKEXChainClient}
         */
        async setAccountInfo(privateKey, prefix = "ex", isPrivatekeyOld = 0) {
            if(!privateKey) {
                const address = await wallet.getAddress();
                if (!address) throw new Error("invalid privateKey: " + privateKey)
                await this.setAccountInfoByWallet(address);
                return this;
            }
            if (privateKey !== this.privateKey) {
                let address = crypto.getAddressFromPrivateKey(privateKey, prefix)
                if (isPrivatekeyOld) {
                    address = crypto.getAddressFromPrivateKeyLegacy(privateKey, prefix)
                }
                if (!address) throw new Error("invalid privateKey: " + privateKey)
                if (address === this.address) return this
                this.privateKey = privateKey
                this.address = address
                const data = await this.getAccount(address)
                this.account_number = this.getAccountNumberFromAccountInfo(data)
            }
            return this
        }
    

      

    构造两种交易:"tendermint/PubKeySecp256k1” 和"ethermint/PubKeyEthSecp256k1",及两种不同的签名。

    // PrivatekeyHex
        if (typeof privateKeyHexOrSigner === 'string') {
          const jsonStr = JSON.stringify(signMsg)
          const signBytes = Buffer.from(jsonStr)
          const privateKey = Buffer.from(privateKeyHexOrSigner, "hex")
          const signature = isPrivatekeyOldAddress ? crypto.signPrivateKeyOldAddress(signBytes.toString("hex"), privateKey)
              : crypto.sign(signBytes.toString("hex"), privateKey)
          const pubKey = crypto.encodePubKeyToCompressedBuffer(crypto.getPubKeyFromPrivateKey(privateKey))
          signatures = [{
            pub_key: {
              type: isPrivatekeyOldAddress ? "tendermint/PubKeySecp256k1" : "ethermint/PubKeyEthSecp256k1",
              value:pubKey},
            signature: signature,
          }]
        }
    
    
    /** 旧签名
     * Generates a signature (64 byte <r,s>) for a transaction based on given private key.
     * @param {string} signBytesHex - Unsigned transaction sign bytes hexstring.
     * @param {string | Buffer} privateKey - The private key.
     * @return {Buffer} Signature. Does not include tx.
     */
    export const signPrivateKeyOldAddress = (signBytesHex, privateKey) => {
      const msgHash = sha256(signBytesHex)
      const msgHashHex = Buffer.from(msgHash, "hex")
      const signature = ecc.sign(msgHashHex, Buffer.from(privateKey, "hex")) // enc ignored if buffer
      return signature
    }
    
    /** 新签名
     * Sign msg with privateKey and Msg in hex format.
     * @param {string} msgHex msg in hex format.
     * @param {string} privateKey - The private key in hex format.
     * @return {Buffer} Signature.
     */
    export const sign = (msgHex, privateKey) => {
      const msg = Buffer.from(msgHex, "hex")
      const msgHash = createKeccakHash('keccak256').update(msg).digest()
      const signature = ecc.sign(msgHash, Buffer.from(privateKey, "hex")) // enc ignored if buffer
      return signature
    }
    

      

    2. Web前端修改

    (1)还原地址处

      validatePrivateKey = async () => {
        try {
          let { privateKey, password } = this.state;
          privateKey = privateKey.replace(/^(0x)/, '');
          if (!/^[\d|a-f]{64}$/.test(privateKey)) {
            throw new Error('not pass the reg');
          }
          const oldAddress = crypto.getAddressFromPrivateKeyLegacy(privateKey);
          const newAddress = crypto.getAddressFromPrivateKey(privateKey);
          const oldBalance = await this.fetchAcount(oldAddress);
          const newBalance = await this.fetchAcount(newAddress);
          this.setState({
            isValidatedPrivateKey: true,
            buttonLoading: false,
            isNone: false,
            oldAddress,
            newAddress: crypto.convertBech32ToHex(newAddress)[0],
            oldBalance: calc.showFloorTruncation(oldBalance),
            newBalance: calc.showFloorTruncation(newBalance),
            step: 2,
          });
          const keyStore = crypto.generateKeyStore(privateKey, password);
          walletUtil.setUserInSessionStroage(privateKey, keyStore);
          this.props.commonAction.setPrivateKey(privateKey);
          // util.go(DesktopTypeMenu.current ? DesktopTypeMenu.current.url : void 0);
        } catch (e) {
          this.setState({
            isValidatedPrivateKey: false,
            buttonLoading: false,
            isNone: false,
          });
        }
      };
    

      

    // 保留最后的尊严,哈哈哈
      selectPathType = (type) => {
        window.localStorage.setItem(env.envConfig.privatekeyPathType, type);
        if (type === 'old') {
          window.localStorage.setItem(
            env.envConfig.privatekeyOldPathPrivatekey,
            this.state.privateKey
          );
        } else {
          window.localStorage.setItem(
            env.envConfig.privatekeyOldPathPrivatekey,
            ''
          );
        }
        this.setState({
          pathType: type,
        });
      };
    

      

    账户部分

    setUserInSessionStroageByWalletConnect(addr) {
        const user = {
          addr,
        };
        window.localStorage.setItem(env.envConfig.dexUser, JSON.stringify(user));
        window.OK_GLOBAL.senderAddr = addr;
        window.OK_GLOBAL.isLogin = true;
      },
    // 重点是
      setUserInSessionStroage(privateKey, keyStore) {
        const privatekeyPathType = window.localStorage.getItem(
          env.envConfig.privatekeyPathType
        );
        let addr = crypto.getAddressFromPrivateKey(privateKey);
        if (privatekeyPathType === 'old') {
          addr = crypto.getAddressFromPrivateKeyLegacy(privateKey);
        }
        const user = {
          addr,
          info: keyStore,
        };
        window.localStorage.setItem(env.envConfig.dexUser, JSON.stringify(user));
        window.OK_GLOBAL.senderAddr = addr;
        window.OK_GLOBAL.generalAddr = crypto.convertBech32ToHex(addr)[0];
        window.OK_GLOBAL.isLogin = true;
      },
    

      

    还有URL部分,涉及到跨域。

    export const DEFAULT = window.okGlobal.mainDomain || 'https://www.okx.com';
    
    export function getApiUrl(apiUrl = DEFAULT) {
      const protocol = window.location.protocol;
      if (/file/.test(protocol) || window.location.hostname === '127.0.0.1')
        return apiUrl;
      return `${window.location.protocol}//${window.location.host}`;
    }
    
    export function getCurrentApiUrl() {
      // let url = getApiUrl();
      let url = 'https://www.okx.com';
      const currentNode = storage.get('currentNode');
      if (currentNode && currentNode.httpUrl) url = currentNode.httpUrl;
      return url;
    }
    

      

    (2)发送交易处

    const isPrivatekeyOld = oldPrivate ? 1 : 0;
        okexchainClient
          .setAccountInfo(privateKey, 'ex', isPrivatekeyOld)
          .then(() => {
            okexchainClient
              .sendSendTransaction(
                address,
                amountStr,
                symbol,
                note,
                null,
                isPrivatekeyOld
              )
              .then((res) => {
                if (res.result.code) {
                  this._transferErr(
                    toLocale(`error.code.${res.result.code}`) ||
                      toLocale('trans_fail')
                  );
                } else {
                  this._transferSuccess(onSuccess);
                }
              })
              .catch(() => {
                this._transferErr(toLocale('trans_fail'));
              });
          });
    

      

  • 相关阅读:
    BZOJ4552 Tjoi2016&Heoi2016排序 【二分+线段树】*
    BZOJ4547 Hdu5171 小奇的集合 【矩阵快速幂优化递推】
    BZOJ1113 Poi2008 海报PLA【单调栈】【水】
    BZOJ1510 POI2006 Kra-The Disks 【模拟】
    BZOJ 2530 Poi2011 Party 【枚举】
    BZOJ4292 PA2015 Równanie 【暴力水题】
    BZOJ1801 Ahoi2009 chess 中国象棋 【DP+组合计数】*
    【干货】高精度模板【加,减,乘,快速幂】
    BZOJ1220 HNOI2002 跳蚤 【容斥原理+高精度】*
    BZOJ1412 ZJOI2009 狼和羊的故事 【网络流-最小割】
  • 原文地址:https://www.cnblogs.com/zccst/p/15885654.html
Copyright © 2020-2023  润新知