Full Code of ontio/OWallet for AI

master 434b97d71cb4 cached
141 files
754.2 KB
195.1k tokens
259 symbols
1 requests
Download .txt
Showing preview only (812K chars total). Download the full file or copy to clipboard to get everything.
Repository: ontio/OWallet
Branch: master
Commit: 434b97d71cb4
Files: 141
Total size: 754.2 KB

Directory structure:
gitextract_cdm3kmul/

├── .browserslistrc
├── .editorconfig
├── .eslintrc.js
├── .github/
│   └── workflows/
│       └── publish.yml
├── .gitignore
├── LICENSE
├── README.md
├── README_cn.md
├── babel.config.js
├── build/
│   ├── after-sign.js
│   └── entitlements.mac.plist
├── package.json
├── public/
│   └── index.html
├── src/
│   ├── App.vue
│   ├── assets/
│   │   ├── fonts/
│   │   │   └── avenirnextregular.otf
│   │   └── icons/
│   │       └── icon.icns
│   ├── background.js
│   ├── components/
│   │   ├── Breadcrumb.vue
│   │   ├── Common/
│   │   │   ├── CommonSignShared.vue
│   │   │   ├── Oep4Home.vue
│   │   │   ├── Oep4Selection.vue
│   │   │   ├── SelectWallet.vue
│   │   │   └── SignSendTx.vue
│   │   ├── CommonWallet/
│   │   │   ├── CommonReceive.vue
│   │   │   ├── CommonRedeem.vue
│   │   │   ├── CommonTokenSwap.vue
│   │   │   ├── SendConfirm.vue
│   │   │   └── SendHome.vue
│   │   ├── Dapps.vue
│   │   ├── Dashboard.vue
│   │   ├── Exchange/
│   │   │   ├── Changelly/
│   │   │   │   └── Changelly.vue
│   │   │   └── Cryptonex/
│   │   │       └── Cryptonex.vue
│   │   ├── Home.vue
│   │   ├── Identitys/
│   │   │   ├── Create/
│   │   │   │   ├── BasicInfo.vue
│   │   │   │   └── ConfirmInfo.vue
│   │   │   ├── CreateIdentity.vue
│   │   │   ├── IdentityView.vue
│   │   │   ├── Import/
│   │   │   │   └── BasicInfo.vue
│   │   │   └── ImportIdentity.vue
│   │   ├── Identitys.vue
│   │   ├── JsonWallet/
│   │   │   ├── Create/
│   │   │   │   ├── BasicInfo.vue
│   │   │   │   └── ConfirmInfo.vue
│   │   │   ├── CreateJsonWallet.vue
│   │   │   ├── Import/
│   │   │   │   └── BasicInfo.vue
│   │   │   ├── ImportJsonWallet.vue
│   │   │   └── View/
│   │   │       └── Details.vue
│   │   ├── LedgerWallet/
│   │   │   ├── Import/
│   │   │   │   ├── BasicInfo.vue
│   │   │   │   └── ConnectLedger.vue
│   │   │   ├── ImportLedgerWallet.vue
│   │   │   └── LoginLedger.vue
│   │   ├── Modals/
│   │   │   ├── Loading.vue
│   │   │   └── SetPath.vue
│   │   ├── Node/
│   │   │   ├── Node.vue
│   │   │   ├── NodeApply/
│   │   │   │   ├── Register.vue
│   │   │   │   └── RegisterSuccess.vue
│   │   │   ├── NodeAuthorize/
│   │   │   │   ├── AuthorizationMgmt.vue
│   │   │   │   ├── AuthorizeLogin.vue
│   │   │   │   ├── NewAuthorization.vue
│   │   │   │   ├── NodeList.vue
│   │   │   │   ├── Sesameseed/
│   │   │   │   │   ├── AuthorizationMgmtSesameseed.vue
│   │   │   │   │   ├── AuthorizeLoginSesameseed.vue
│   │   │   │   │   ├── NewAuthorizationSesameseed.vue
│   │   │   │   │   └── SesameseedVars.js
│   │   │   │   └── StakeHistory.vue
│   │   │   ├── NodeManagement/
│   │   │   │   ├── MyNode.vue
│   │   │   │   ├── NodeStakeAuthorization.vue
│   │   │   │   └── NodeStakeManagement.vue
│   │   │   ├── NodeStake/
│   │   │   │   ├── NodeInfo.vue
│   │   │   │   ├── NodeStakeInfo.vue
│   │   │   │   ├── NodeStakeIntro.vue
│   │   │   │   └── NodeStakeRegister.vue
│   │   │   └── Vote/
│   │   │       ├── Create.vue
│   │   │       ├── Detail.vue
│   │   │       ├── List.vue
│   │   │       ├── Login.vue
│   │   │       └── index.vue
│   │   ├── RedeemInfoIcon.vue
│   │   ├── Setting.vue
│   │   ├── SharedWallet/
│   │   │   ├── Create/
│   │   │   │   ├── BasicInfo.vue
│   │   │   │   ├── ConfirmSigNum.vue
│   │   │   │   └── CreateSuccess.vue
│   │   │   ├── CreateSharedWallet.vue
│   │   │   ├── Import/
│   │   │   │   ├── InputPass.vue
│   │   │   │   └── QuerySharedWallet.vue
│   │   │   ├── ImportSharedWallet.vue
│   │   │   ├── PAX/
│   │   │   │   ├── PaxMgmt.vue
│   │   │   │   ├── SignProcess.vue
│   │   │   │   └── StartProcess.vue
│   │   │   ├── PendingTxHome.vue
│   │   │   ├── SharedWalletDetail.vue
│   │   │   ├── SharedWalletHome.vue
│   │   │   ├── SharedWalletSend.vue
│   │   │   ├── Transfer/
│   │   │   │   ├── InputPassword.vue
│   │   │   │   ├── PendingConfirm.vue
│   │   │   │   ├── PendingTxSign.vue
│   │   │   │   ├── SendAsset.vue
│   │   │   │   └── SendConfirm.vue
│   │   │   ├── Tx/
│   │   │   │   ├── SharedTxMgmt.vue
│   │   │   │   ├── SignSharedTx.vue
│   │   │   │   └── StartSharedTx.vue
│   │   │   └── View/
│   │   │       ├── Details.vue
│   │   │       └── SharedWalletCopayer.vue
│   │   ├── TopLeftNav.vue
│   │   └── Wallets.vue
│   ├── core/
│   │   ├── asyncHelper.js
│   │   ├── consts.js
│   │   ├── dbService.js
│   │   ├── fileHelper.js
│   │   ├── lang.js
│   │   ├── network.js
│   │   ├── nodes.json
│   │   ├── ontLedger.js
│   │   ├── ontLedgerNew.js
│   │   ├── runtime.js
│   │   └── utils.js
│   ├── lang/
│   │   ├── en.js
│   │   ├── index.js
│   │   └── zh.js
│   ├── main.js
│   ├── router/
│   │   └── index.js
│   └── store/
│       ├── index.js
│       └── modules/
│           ├── CreateIdentity.js
│           ├── CreateJsonWallet.js
│           ├── CreateSharedWallet.js
│           ├── CurrentWallet.js
│           ├── Identities.js
│           ├── ImportSharedWallet.js
│           ├── LedgerConnector.js
│           ├── LedgerWallet.js
│           ├── LoadingModal.js
│           ├── NodeAuthorization.js
│           ├── NodeAuthorizationSesameseed.js
│           ├── NodeStake.js
│           ├── Oep4s.js
│           ├── PaxMgmt.js
│           ├── Setting.js
│           ├── Tokens.js
│           ├── Vote.js
│           ├── Wallets.js
│           └── index.js
└── vue.config.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .browserslistrc
================================================
> 1%
last 2 versions
not dead


================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true


================================================
FILE: .eslintrc.js
================================================
module.exports = {
  root: true,
  env: {
    node: true
  },
  'extends': [
    'plugin:vue/essential',
    'eslint:recommended'
  ],
  parserOptions: {
    parser: 'babel-eslint'
  },
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-unused-vars': 'off',
    'no-empty': 'off',
    'no-empty-pattern': 'off',
  }
}


================================================
FILE: .github/workflows/publish.yml
================================================
name: Release on Tag

on:
  push:
    tags:
      - '*' # Listen for any tag push events

jobs:
  build-and-release:
    runs-on: macos-latest

    # permissions: # Add this permissions block
    #   contents: write
    #   packages: write
    #   issues: write
    #   pull-requests: write

    permissions: write-all

    steps:
    # Check out the code
    - name: Checkout code
      uses: actions/checkout@v3

    # Set up Node.js and Yarn environment
    - name: Setup Node.js and Yarn
      uses: actions/setup-node@v3
      with:
        node-version: '16'
        cache: 'yarn'

    - name: 🔐 Setup Temporary Keychain and Import Certificate
      run: |
        KEYCHAIN_NAME="temp.keychain"
        NODE_PATH=$(which node)
        echo "Found Node executable at: $NODE_PATH"

        # 1. Create a new temporary keychain
        security create-keychain -p ${{ secrets.KEYCHAIN_PASSWORD }} $KEYCHAIN_NAME

        # 2. Set the new keychain as the default for the session
        security default-keychain -s $KEYCHAIN_NAME
        security unlock-keychain -p ${{ secrets.KEYCHAIN_PASSWORD }} $KEYCHAIN_NAME

        # 3. Increase the keychain search timeout
        security set-keychain-settings -t 3600 $KEYCHAIN_NAME

        # 4. Decode the P12 file content from the secret and save it to a file
        echo "${{ secrets.DEV_ID_CERTIFICATE_P12 }}" | base64 --decode > dev_cert.p12


        # 6. Set the partition list to ensure automated tools can access the key
        #    This is crucial for CI environments.
        CERT_ID='Developer ID Application: Ontology Foundation Ltd (29B4VVVVKM)' # <-- Replace with your exact Identity name

        #security set-key-partition-list -S apple-tool: -S apple: -k $KEYCHAIN_NAME -p ${{ secrets.KEYCHAIN_PASSWORD }} $KEYCHAIN_NAME
        curl https://www.apple.com/certificateauthority/DeveloperIDG2CA.cer -o DeveloperIDG2CA.cer
        sudo security add-trusted-cert -d -r unspecified -k $KEYCHAIN_NAME DeveloperIDG2CA.cer
        rm -f DeveloperIDG2CA.cer

        # 5. Import the certificate and private key into the new keychain
        security import dev_cert.p12 -k $KEYCHAIN_NAME -P "${{ secrets.P12_PASSWORD }}" -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/xcodebuild -T $NODE_PATH
        echo "import success!"
        security set-key-partition-list -S apple-tool:,apple: -s -k ${{ secrets.KEYCHAIN_PASSWORD }} $KEYCHAIN_NAME
        echo "partition list success"


        # Set the temporary keychain as the default for the session
        security default-keychain -s $KEYCHAIN_NAME
        echo "default keychain success"

        # Unlock the keychain
        security unlock-keychain -p ${{ secrets.KEYCHAIN_PASSWORD }} $KEYCHAIN_NAME

        # Set lock timeout to the maximum (3600 seconds) and ensure it's always searched
        security set-keychain-settings -l -u -t 3600 $KEYCHAIN_NAME
        if security find-identity -p codesigning $KEYCHAIN_NAME | grep -q "$CERT_ID"; then
        echo "✅ SUCCESS: Code Signing Identity '$CERT_ID' found in the temporary keychain."
        else
        echo "❌ FAILURE: Code Signing Identity '$CERT_ID' NOT found. Codesign will likely fail."
        exit 1 # Exit the job immediately if the identity isn't found
        fi




    # Install dependencies
    - name: Install dependencies
      run: |
        yarn install

    # # Build all packages (macOS, Linux, and Windows)
    - name: Build macos packages
      env:
        APPLE_ID: ${{ secrets.APPLE_ID }}
        TEAM_ID: ${{ secrets.TEAM_ID }}
        PASSWORD: ${{ secrets.PASSWORD }}
      run: |
        yarn build:mac

    - name: Build Windows App
      # if: matrix.os == 'windows-latest'
      run: |
        yarn build:win

    - name: Build Linux App
      # if: matrix.os == 'ubuntu-latest'
      run: |
        yarn build:linux

    # - name: Create Release v1
    #   id: create_release
    #   uses: actions/create-release@latest
    #   env:
    #     GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
    #   with:
    #     tag_name: ${{ github.ref }}
    #     release_name: Release ${{ github.ref }}
    #     body: |
    #       Change Log
    #       - TODO
    #     draft: false
    #     prerelease: false


    # --- Cleanup ---
    - name: 🗑️ Clean Up Keychain and Files
      if: always() # Ensure cleanup runs even on failure
      run: |
        security delete-keychain temp.keychain
        rm dev_cert.p12


    - name: Generate Checksums
      run: |
        brew install coreutils
        #echo "# OWallet ${{ github.ref_name }}" > CHECKSUMS.md
        echo "" > CHECKSUMS.md
        echo "CHANGELOG: $(git log -1 --format=%s ${{ github.ref_name }})" >> CHECKSUMS.md
        echo "## SHA256 Checksums" >> CHECKSUMS.md
        echo "| File | SHA256 Checksum |" >> CHECKSUMS.md
        echo "|------|----------------|" >> CHECKSUMS.md
        # find dist_electron/ -type f -name OWallet\*.AppImage -o -name OWallet\*.dmg -o -name OWallet\*.exe -o -name OWallet\*.deb -exec sh -c '
        #   for file; do
        #     echo "| $(basename "$file") | \`$(sha256sum "$file" | cut -d " " -f1)\` |" >> CHECKSUMS.md
        #   done
        # ' sh {} +
        echo "| $(ls dist_electron/OWallet-*.deb | sed -e 's#dist_electron/##') | \`$(sha256sum dist_electron/OWallet-*.deb | cut -d " " -f1)\` |" >> CHECKSUMS.md
        echo "| $(ls dist_electron/OWallet-*.exe | sed -e 's#dist_electron/##') | \`$(sha256sum dist_electron/OWallet-*.exe | cut -d " " -f1)\` |" >> CHECKSUMS.md
        echo "| $(ls dist_electron/OWallet-*.AppImage | sed -e 's#dist_electron/##') | \`$(sha256sum dist_electron/OWallet-*.AppImage | cut -d " " -f1)\` |" >> CHECKSUMS.md
        for dmg in dist_electron/OWallet-*.dmg; do
          echo "| $(basename "$dmg") | \`$(sha256sum "$dmg" | cut -d " " -f1)\` |" >> CHECKSUMS.md
        done

    - name: Create Release v2
      uses: softprops/action-gh-release@v1
      with:
        name: Release ${{ github.ref_name }}
        body_path: CHECKSUMS.md
        files: |
          dist_electron/*.deb
          dist_electron/*.AppImage
          dist_electron/*.dmg
          dist_electron/*.exe



================================================
FILE: .gitignore
================================================
.DS_Store
node_modules
/dist
.sign

# local env files
.env.local
.env.*.local

# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

#Electron-builder output
/dist_electron

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2018 Ontology

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
[中文版](./README_cn.md)



<h1 align="center">OWallet - a comprehensive Ontology desktop wallet</h1>
<h4 align="center">Version 0.10.0</h4>

## Introduction

OWallet is a comprehensive Ontology desktop wallet. OWallet supports standard wallet management, shared wallet management based on multi-signature technology, and will also connect with various hard wallets such as Ledger, Trezor, and so on. In the next phase, OWallet will integrate more applications, providing developers with smart contract compilation, invocation, and other comprehensive services.

Support Windows/MacOS/Linux,get it [Here](https://github.com/ontio/OWallet/releases),also welcome to join [our community on Discord](https://discord.gg/4TQujHj).

Core features of OWallet are as follows:

* Create wallet/import wallet using keystore,mnemonic phrase,WIF private key,HEX private key
* Support shared wallet based on multi-signature technology
* Ledger support
* View balance and record
* Send ONG and ONT
* Withdraw (redeem) ONG
* Node stake and stake authorization management
* ONT ID support
* Integrate gateway provided by changelly and cryptonex

![](images/OWallet.jpg)


## Get started

1. Clone the repo

```
git clone https://github.com/ontio/OWallet.git
```

2. Install packages
**yarn** is recommended.
```
yarn
```

3. Run in Development

```
yarn serve
```

4. Build

```
yarn build
```

## Install released app

Please download the latest version that is compatiable with your platform.

## Default keystore.db file path

Default points to:

* %APPDATA% on `Windows`

* $XDG_CONFIG_HOME or ~/.config on `Linux`

* ~/Library/Application Support on `macOS`


================================================
FILE: README_cn.md
================================================
[English Version](./README.md)



<h1 align="center">OWallet - 本体综合性桌面版钱包 </h1>
<h4 align="center">Version 0.10.0</h4>

## 总体介绍

OWallet是本体综合性桌面版钱包,支持标准的钱包管理、基于多重签名技术的共享钱包管理,同时将连接Ledger、Trezor多种硬件钱包。未来,OWallet将持续集成更加丰富的应用功能,为开发者提供智能合约编译、运行等综合性服务。

支持Windows/MacOS/Linux,下载请到[这里](https://github.com/ontio/OWallet/releases),也欢迎加入我们的[技术讨论社区](https://discord.gg/4TQujHj)!

OWallet核心功能如下:

* 创建钱包/导入钱包(支持使用Keystore,助记词,WIF私钥,明文私钥)
* 支持共享钱包(基于多重签名技术)
* 支持硬件钱包Ledger
* 查看余额和交易明细
* 发送ONG和ONT
* 提取ONG
* 节点质押和质押授权管理
* 支持ONT ID功能
* 集成changelly和cryptonex网关

![](images/OWallet.jpg)


## 如何开始

1. 克隆repo

```
git clone https://github.com/ontio/OWallet.git
```

2. 安装依赖
推荐使用**yarn**

```
yarn
```

3. 开发模式运行

```
yarn serve
```

4. 打包

```
yarn build
```

## 安装发布的客户端

请下载适合于您的操作系统的最新版本客户端。


## keystore.db文件的默认保存路径

在不同系统上指向如下位置:

* %APPDATA% on `Windows`

* $XDG_CONFIG_HOME or ~/.config on `Linux`

* ~/Library/Application Support on `macOS`


================================================
FILE: babel.config.js
================================================
module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  plugins: [
    ["import", { libraryName: "ant-design-vue", libraryDirectory: "es", style: "css" }]
  ]
}


================================================
FILE: build/after-sign.js
================================================
// build/after-sign.js

const { execSync } = require("child_process");
const path = require("path");
const fs = require("fs");

const DEV_ID = "Developer ID Application: Ontology Foundation Ltd (29B4VVVVKM)";
const ENTITLEMENTS = "build/entitlements.mac.plist";

function run(cmd) {
  console.log(`\n> ${cmd}`);
  execSync(cmd, { stdio: "inherit" });
}

exports.default = async function afterSign(context) {

  
  if (context.electronPlatformName !== "darwin") {
    console.log("!Skipping afterSign: not macOS build.");
    return;
  }
  if (process.env.CI !== 'true' || process.env.GITHUB_ACTIONS!=='true') {
    return
  }

  const appPath = path.join(
    context.appOutDir,
    `${context.packager.appInfo.productFilename}.app`
  );
  if (!fs.existsSync(appPath)) {
    console.error("!!App not found:", appPath);
    return;
  }

  console.log(`\nStarting manual signing for: ${appPath}`);

  console.log("[1/6] Signing Electron Framework Libraries...");
  const libsPath = path.join(
    appPath,
    "Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries"
  );
  if (fs.existsSync(libsPath)) {
    const libs = fs.readdirSync(libsPath).filter((f) => f.endsWith(".dylib"));
    for (const lib of libs) {
      const libPath = path.join(libsPath, lib);
      run(
        `codesign -fs "${DEV_ID}" --options runtime --timestamp -v "${libPath}"`
      );
    }
  }

  console.log("[2/6] Signing Binaries of Helpers and Squirrel...");
  const crashpadHandler = path.join(
    appPath,
    "Contents/Frameworks/Electron Framework.framework/Versions/A/Helpers/chrome_crashpad_handler"
  );
  const shipIt = path.join(
    appPath,
    "Contents/Frameworks/Squirrel.framework/Versions/A/Resources/ShipIt"
  );
  if (fs.existsSync(crashpadHandler))
    run(
      `codesign -fs "${DEV_ID}" --options runtime --timestamp -v "${crashpadHandler}"`
    );
  if (fs.existsSync(shipIt))
    run(
      `codesign -fs "${DEV_ID}" --options runtime --timestamp -v "${shipIt}"`
    );

  console.log("[3/6] Signing Frameworks...");
  const frameworks = [
    "Electron Framework.framework",
    "Squirrel.framework",
    "Mantle.framework",
    "ReactiveObjC.framework",
  ];
  for (const fw of frameworks) {
    const fwPath = path.join(appPath, "Contents/Frameworks", fw);
    if (fs.existsSync(fwPath)) {
      run(
        `codesign -fs "${DEV_ID}" --options runtime --timestamp -v "${fwPath}"`
      );
    }
  }

  console.log("[4/6] Signing Helper Apps...");
  const helpers = [
    "OWallet Helper.app",
    "OWallet Helper (Renderer).app",
    "OWallet Helper (Plugin).app",
    "OWallet Helper (GPU).app",
  ];
  for (const helper of helpers) {
    const helperPath = path.join(appPath, "Contents/Frameworks", helper);
    if (fs.existsSync(helperPath)) {
      console.log(`Signing executables in ${helperPath}`);
      const helperExePath = path.join(helperPath, "Contents/MacOS");
      const exes = fs.existsSync(helperExePath)
        ? fs.readdirSync(helperExePath)
        : [];
      for (const exe of exes) {
        run(
          `codesign -fs "${DEV_ID}" --options runtime --timestamp -v "${path.join(
            helperExePath,
            exe
          )}"`
        );
      }
      console.log(`Signing helper app itself ${helperPath}`);
      run(
        `codesign -fs "${DEV_ID}" --options runtime --timestamp --deep --entitlements ${ENTITLEMENTS} -v "${helperPath}"`
      );
    }
  }

  console.log("[5/6] Signing Main Binary...");
  const mainExePath = path.join(appPath, "Contents/MacOS/OWallet");
  if (fs.existsSync(mainExePath)) {
    run(
      `codesign -fs "${DEV_ID}" --options runtime --timestamp --deep -v --entitlements ${ENTITLEMENTS} "${mainExePath}"`
    );
  }

  console.log("[6/6] Signing .app...");
  run(
    `codesign -fs "${DEV_ID}" --options runtime --timestamp --deep --entitlements ${ENTITLEMENTS} -v "${appPath}"`
  );

  console.log("\nVerifying Signature...");
  run(`codesign -vvv --deep --strict "${appPath}"`);
  run(`codesign -dvv "${appPath}"`);

  console.log("\nManual signing completed successfully!");

  console.log("\nSubmitting to Apple for notarization...");

  const ZIP_FILE = path.join(
    context.appOutDir,
    `${context.packager.appInfo.productFilename}.zip`
  );
  run(`ditto -c -k --keepParent "${appPath}" "${ZIP_FILE}"`);
  run(
    `xcrun notarytool submit --apple-id ${process.env.APPLE_ID} --team-id ${process.env.TEAM_ID} --password ${process.env.PASSWORD}  --wait  "${ZIP_FILE}"`
  );
  console.log("Notarization complete.");

  run(`xcrun stapler staple "${appPath}"`);
  console.log("\nSigning & notarization finished successfully!");
};


================================================
FILE: build/entitlements.mac.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" 
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
</dict>
</plist>


================================================
FILE: package.json
================================================
{
  "name": "owallet",
  "homepage": "http://ont.io",
  "version": "v0.10.4",
  "author": "Ontology Foundation Ltd. <devops@ont.io>",
  "description": "OWallet is a comprehensive Ontology desktop wallet",
  "license": "Apache-2.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service electron:serve",
    "build": "vue-cli-service electron:build -mlw --publish=never",
    "build:mac": "vue-cli-service electron:build -m --publish=never",
    "build:linux": "vue-cli-service electron:build -l --publish=never",
    "build:win": "vue-cli-service electron:build -w --publish=never",
    "postinstall": "electron-builder install-app-deps",
    "postuninstall": "electron-builder install-app-deps"
  },
  "main": "background.js",
  "dependencies": {
    "@electron/remote": "^2.1.2",
    "@ledgerhq/hw-transport-node-hid": "^5.19.1",
    "@xkeshi/vue-qrcode": "^1.0.0",
    "ant-design-vue": "^1.1.9",
    "axios": "^0.21.1",
    "bignumber.js": "^7.2.1",
    "bootstrap": "^4.1.1",
    "caniuse-lite": "^1.0.30001749",
    "clipboard": "^2.0.1",
    "core-js": "^3.6.5",
    "dateformat": "^3.0.3",
    "delay": "^4.4.0",
    "elliptic": "^6.5.4",
    "font-awesome": "^4.7.0",
    "lodash": "^4.17.21",
    "nedb": "^1.8.0",
    "node-hid": "^2.1.1",
    "numeral": "^2.0.6",
    "ontology-ts-sdk": "^1.1.14-alpha.5",
    "opn": "^5.4.0",
    "popper.js": "^1.14.3",
    "sass": "^1.83.1",
    "usb": "1.7.1",
    "vee-validate": "^2.2.15",
    "vue": "^2.7.0",
    "vue-axios": "^2.1.1",
    "vue-clipboard2": "^0.2.1",
    "vue-electron": "^1.0.6",
    "vue-i18n": "^8.0.0",
    "vue-router": "^3.2.0",
    "vuedraggable": "^2.16.0",
    "vuex": "^3.4.0"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^4.4.0",
    "@vue/cli-plugin-eslint": "^4.4.0",
    "@vue/cli-plugin-router": "^4.4.0",
    "@vue/cli-plugin-vuex": "^4.4.0",
    "@vue/cli-service": "^4.4.0",
    "babel-eslint": "^10.1.0",
    "babel-plugin-import": "^1.11.0",
    "electron": "^33.0.0",
    "electron-devtools-installer": "^3.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^6.2.2",
    "jquery": "^3.3.1",
    "sass-loader": "^10.0.0",
    "vue-cli-plugin-electron-builder": "^2.0.0",
    "vue-template-compiler": "^2.6.11"
  },
  "resolutions": {
    "usb": "1.7.1",
    "node-hid": "2.1.1",
    "app-builder-bin": "3.5.13",
    "electron-builder": "23.6.0"
  }
}


================================================
FILE: public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title><%= process.env.VUE_APP_TITLE %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= process.env.VUE_APP_TITLE %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>


================================================
FILE: src/App.vue
================================================
<template>
  <div id="app">
    <top-left-nav v-if="$route.name !== 'Home'"></top-left-nav>

    <div class="container-fluid">
      <router-view></router-view>
    </div>

      <loading-modal></loading-modal>
  </div>
</template>

<script>
  import 'bootstrap/dist/css/bootstrap.min.css'
  import 'bootstrap/dist/js/bootstrap.min.js'
  import TopLeftNav from "./components/TopLeftNav"
  import LoadingModal from './components/Modals/Loading'

  export default {
    name: 'ont-wallet-test',
    components: {TopLeftNav, LoadingModal},
    watch: {
      '$route': 'hideLoadingPage'
    },
    created() {
      if(!localStorage.getItem('net')) { // initialize the network as MAIN_NET
          localStorage.setItem('net', 'MAIN_NET');
      }
    },
    methods: {
      hideLoadingPage() {
        this.$store.dispatch('hideLoadingModals')
      }
    }
  }
</script>



<style lang="scss">
  /* CSS */
  @font-face {
    font-family: SourceSansPro;
    src: url('./assets/fonts/SourceSansPro-Semibold.ttf');
  }

  @font-face {
    font-family: AvenirNext-Bold;
    src: url('./assets/fonts/AvenirNextBold.ttf');
  }
  @font-face {
    font-family: AvenirNext-Medium;
    src: url('./assets/fonts/AvenirNextMedium.ttf');
  }
  @font-face {
    font-family: AvenirNext-Regular;
    src: url('./assets/fonts/avenirnextregular.otf');
  }

  body {
      p {
        margin:0;
    }
  }



  .loading {
    text-align: center;
    background: rgba(0, 0, 0, 0.05);
    width: 100%;
    height: 100%;
  }

  .container-fluid {
    padding-left: 5.13rem !important;
    padding-top: 4rem;
  }

  .font-regular {
    font-family: AvenirNext-Regular;
    color: #000000;
    font-size: 0.88rem;
  }

  .font-gray {
    color: #6F7781;
  }

  .font-medium {
    font-family: AvenirNext-Medium;
    color: #5E6369;
    font-size: 0.88rem;
  }

  .font-medium-black {
    font-family: AvenirNext-Medium;
    color: #000000;
    font-size: 0.88rem;
  }

  .font-bold {
    font-family: AvenirNext-Bold;
    color: #5E6369;
    font-size: 14px;
  }

  .font-title {
    font-size:18px;
    font-family: AvenirNext-Regular,AvenirNext;
    font-weight:400;
    color:rgba(0,0,0,1);
  }


  /* Button CSS */
  .btn-container {
    width: 540px;
    margin: 25px auto;
  }

  .btn-next,
  .btn-cancel {
    min-width: 6.25rem !important;
    height: 2.13rem !important;
    font-family: AvenirNext-Medium !important;
    font-size: 14px !important;
    text-align: center !important;
  }

  .btn-cancel {
    background: #F5F7FB !important;
    border-radius: 0 !important;
    color: #5E6369 !important;
    border: none !important;
  }
  .btn-cancel:hover {
      background: #E4E6EA !important;
  }

  .btn-next {
    background: #196BD8 !important;
    color: #ffffff !important;
    border-radius: 0 !important;
    border: none !important;
  }
  .btn-next:hover {
      background: #619AE5 !important;
  }

  .btn-add {
    width: 80px !important;
    height: 34px !important;
    background: #FBE45A !important;
    border-radius: 0 !important;
    font-family: 'AvenirNext-Bold' !important;
    border: none !important;
    font-size: 18px !important;
  }

  .btn-add:hover {
    border: 1px solid #FBE45A !important;
  }

  .btn-cancel span, .btn-next span {
    width: 100%;
  }

  .input {
    border-radius: 0 !important;
    background: #FFFFFF !important;
    border: 1px solid #DFE2E9 !important;
    height: 34px !important;
  }

  .error-input {
    border-color:red !important;
  }

  .footer-btns {
    position: fixed;
    bottom: 0;
    width: calc(100% - 4rem);
    height: 85px;
    left: 4rem;
    background: #FFFFFF;
    box-shadow: 0 -1px 6px 0 #F2F2F2;
    z-index: 1000;
  }

  .footer-btn-container {
    width: 540px;
    margin: 20px auto;
  }

  .footer-btn-container :last-child {
    float: right;
  }

  .ant-spin-text {
    color: white !important;
    text-shadow: none !important;
  }

  /* .ant-spin-dot i {
    background-color: white !important;
  } */

  .v-validate-span-errors {
    color: red;
    font-size: 12px;
    display: block;
  }

  .refresh-icon {
    display: inline-block;
    background-image: url('./assets/refresh.svg');
    background-size: cover;
  }
  .add-icon {
    background-image: url('./assets/add.svg');
    display:inline-block;
    background-size: cover;
  }
  /* .add-icon:hover {
    background-image: url('./assets/add-hover.png');
  } */

  .common-icon {
    width:20px;
    height:20px;
    border-radius: 50%;
    background-color:#F4F4F6;
    cursor: pointer;
  }
  .common-icon:hover {
    background-color:#E4E6EA;
  }

  .copy-icon {
    display: inline-block;
    margin-left: 10px;
    background-image: url('./assets/copy_new.svg');
    background-size: cover;
    position: relative;
    top: 5px;
}

  .asset-container {
    height:40vh;
    overflow:auto;
  }

.asset-container::-webkit-scrollbar {
    -webkit-appearance: none;
}

.asset-container::-webkit-scrollbar:vertical {
    width: 10px;
    height:15px;
}

.asset-container::-webkit-scrollbar-thumb {
    border-radius: 4px;
    border: 2px solid white; /* should match background, can't be transparent */
    background-color:#dddddd;
}

 .wallet-balance {
    font-size: 16px;
    color: #000000;
    font-family: 'AvenirNext-Bold';
    position: relative;
    margin-top: 30px;
    display:flex;
    justify-content: space-between;
    padding-bottom: 5px;
    border-bottom:1px solid #F4F4F6;
  }

  .wallet-balance :first-child {
    float: left;
    margin-right: 20px;
  }


  .asset-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    /* margin-top: 10px; */
    /* padding-right:20px; */
    width:100%;
    height:40px;
    border-bottom:1px solid #F4F4F6;
  }

  .asset-ong {
    height: 2.56rem;
    line-height: 2.56rem;
    margin-top: 12px;
  }

  .asset-label {
    font-family: AvenirNext-Medium;
    font-size: 0.88rem;
    color: #515457;
    float: left;
    margin-right: 12px;
  }

  .asset-amount {
    font-family: AvenirNext-Medium;
    font-size: 18px;
    color: #000000;
  }

  .asset-value {
    padding-left: 3rem;
    font-family: AvenirNext-Medium;
    font-size: 14px;
    color: #000000;
    margin-bottom: 20px;
  }

  .asset-btn {
    border-radius: 0;
    background: #196BD8;
    font-family: AvenirNext-Medium;
    font-size: 14px;
    color: #FFFFFF;
    margin-right: 20px;
    margin-bottom: 20px;
    border: none;
    width:120px;
    height: 34px;
  }
  .asset-btn > i {
      margin-right:4px;
  }

  .claim-ong-container {
    display:flex;
    justify-content: space-between;
    align-items: flex-end;
    padding-bottom:10px;
    border-bottom: 1px solid #F4F4F6;
    margin-bottom:20px;
  }

  .claim-ong-item {
    margin-bottom: 10px;
    position: relative;
  }

  .claim-ong-item :first-child {
    font-family: AvenirNext-Medium;
    font-size: 12px;
    color: #515457;
    margin-right: 8px;
    width: 100px;
    display: block;
    float: left;
  }

  .claim-ong-item :nth-child(2) {
    font-family: AvenirNext-Medium;
    font-size: 12px;
    color: #000000;
    float: left;
  }
  .redeem-container {
    display: flex;
    align-items: center;
  }

  .btn-redeem {
    border: none;
    color: #227EEC;
    font-size: 14px;
    font-family: AvenirNext-Medium;
    font-weight: 500;
    padding-right: 0;
  }
  .btn-redeem:hover {
    color:#619AE5;
  }

  .tx-item {
    display: flex;
    justify-content: space-between;
    margin-bottom:14px;
    font-family: AvenirNext-Medium;
    font-size: 12px;
    width:100%;
    cursor: pointer;
  }

  .tx-item:hover span {
    color:#196BD8 !important;
  }

  .tx-item :first-child {
    flex: 0.6;
    overflow: hidden;
    text-overflow: ellipsis;
    color: #6F7781;
  }

  .tx-item :last-child {
    flex:0.4;
    text-align: right;
    font-family: AvenirNext-Medium;
    font-size: 12px;
    color: #000000;
  }

.left-footer {
  margin-top:20px;
}
.negative-margin-top {
    margin-top:-4rem;
}

.ant-tabs-tab-active {
    color: #000000;
}

.app-container {
    width: 550px;
	margin: 0 auto;
	margin-top: 20px;
}
</style>


================================================
FILE: src/background.js
================================================
'use strict'

import { app, protocol, BrowserWindow, Menu } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
require('@electron/remote/main').initialize()
const isDevelopment = process.env.NODE_ENV !== 'production'

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win

// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
  { scheme: 'app', privileges: { secure: true, standard: true } }
])

function createWindow() {
  // Create the browser window.
  win = new BrowserWindow({
    useContentSize: true,
    width: 1110,
    minWidth: 1110,
    height: 675,
    minHeight: 635,
    webPreferences: {
      // Use pluginOptions.nodeIntegration, leave this alone
      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
      webSecurity: false,
      enableRemoteModule: true,
      // TODO: Expose only necessary modules.
      contextIsolation: false,
    }
  })
  require('@electron/remote/main').enable(win.webContents);

  const menu = Menu.buildFromTemplate(template)
  Menu.setApplicationMenu(menu)

  if (process.env.WEBPACK_DEV_SERVER_URL) {
    // Load the url of the dev server if in development mode
    win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
    if (!process.env.IS_TEST) win.webContents.openDevTools()
  } else {
    createProtocol('app')
    // Load the index.html when not in development
    win.loadURL('app://./index.html')
  }

  win.on('closed', () => {
    win = null
  })
}

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (win === null) {
    createWindow()
  }
})

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {
  if (isDevelopment && !process.env.IS_TEST) {
    // Install Vue Devtools
    try {
      await installExtension(VUEJS_DEVTOOLS)
    } catch (e) {
      console.error('Vue Devtools failed to install:', e.toString())
    }
  }
  createWindow()
})

// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
  if (process.platform === 'win32') {
    process.on('message', (data) => {
      if (data === 'graceful-exit') {
        app.quit()
      }
    })
  } else {
    process.on('SIGTERM', () => {
      app.quit()
    })
  }
}

// Menu template
const template = [
  {
    label: 'Edit ( 操作 )',
    submenu: [{
      label: 'Select All ( 全选 )',
      accelerator: 'CmdOrCtrl+A',
      role: 'selectall'
    }, {
      label: 'Copy ( 复制 )',
      accelerator: 'CmdOrCtrl+C',
      role: 'copy'
    }, {
      label: 'Cut ( 剪切 )',
      accelerator: 'CmdOrCtrl+X',
      role: 'cut'
    }, {
      label: 'Paste ( 粘贴 )',
      accelerator: 'CmdOrCtrl+V',
      role: 'paste'
    }, {
      label: 'Reload ( 重新加载 )',
      accelerator: 'CmdOrCtrl+R',
      click: function (item, focusedWindow) {
        if (focusedWindow) {
          // on reload, start fresh and close any old
          // open secondary windows
          if (focusedWindow.id === 1) {
            BrowserWindow.getAllWindows().forEach(function (win) {
              if (win.id > 1) {
                win.close()
              }
            })
          }
          focusedWindow.reload()
        }
      }
    },
      {
        label: 'Quit ( 退出 )',
        accelerator: 'CmdOrCtrl+Q',
        role: 'quit'
      },
  ]
  },
  {
    label: 'Window ( 窗口 )',
    role: 'window',
    submenu: [{
      label: 'Minimize ( 最小化 )',
      accelerator: 'CmdOrCtrl+M',
      role: 'minimize'
    }, {
      label: 'Close ( 关闭 )',
      accelerator: 'CmdOrCtrl+W',
      role: 'close'
    }, {
      label: 'Developer Tools (切换开发者工具)',
      accelerator: (function () {
        if (process.platform === 'darwin') {
          return 'Alt+Command+I'
        } else {
          return 'Ctrl+Shift+I'
        }
      })(),
      click: function (item, focusedWindow) {
        if (focusedWindow) {
          focusedWindow.toggleDevTools()
        }
      }
    }, {
      type: 'separator'
    }]
  }
]


================================================
FILE: src/components/Breadcrumb.vue
================================================
<style scoped>
    .breadcrumb-container {
        height:4rem;
        padding:1.1rem 0 1.1rem 15px;
        padding-left:5.13rem;
        width:100%;
        position: fixed;
        top:0;
        left:0;
        background:rgba(255,255,255,1);
        z-index: 100;
    }
    .back-icon-container {
        height: 1.7rem;
        line-height: 1.7rem;
        padding-right: 18px;
        border-right: 1px solid #dddddd;
        float: left;
        cursor: pointer;
        color: #1C76DD;
        font-size: 18px;
    }
    .back-icon-container:hover {
        color:#619AE5;
    }
    .back-icon {
        display: inline-block;
        height:10px;
        width:18px;
        background:url(../assets/back.png) center center;
        background-size: cover;
        line-height: 1.7rem;
    }
    .breadcrumb-routes {
        float: left;
        margin-left: 18px;
        height:1.7rem;
        line-height: 1.7rem;    
    }
    .breadcrumb-routes a {
        color: #A5A7A9;
        font-size:16px;
        font-family: AvenirNext-Bold;

    }
    .breadcrumb-current {
        float:left;
        height:1.7rem;
        line-height: 1.7rem;
        margin-left: 18px;
        color: #000000;
        font-size:14px; 
        font-family: AvenirNext-Bold;
    }
    .left-icon {
        font-size: 16px;
        color: #A5A7A9;
        margin-left: 10px;
    }
</style>
<template>
    <div class="breadcrumb-container">
        <div class="back-icon-container" @click="back">
            <span class="fa fa-long-arrow-left"></span>
        </div>
        <div class="breadcrumb-routes" v-for="route in routes" :key="route.path">
            <router-link :to="route.path">{{route.name}}</router-link>
            <a-icon type="right" class="left-icon" />
        </div>
        <div class="breadcrumb-current">
            {{current}}
        </div>
    </div>
</template>

<script>
export default {
    name:'Breadcrumb',
    props:['routes', 'current'],
    methods:{
        back() {
            this.$emit('backEvent');
            // this.$router.back();
        }
    }
}
</script>




================================================
FILE: src/components/Common/CommonSignShared.vue
================================================
<style scoped>
.sign-container {
    display: flex;
}
.label {
    width:200px;
     margin-right:10px;
}
.sign-content {
    flex:1;

}

</style>
<template>
    <div class="sign-container">
        <p class="label">{{$t('sharedTx.signTx')}}</p>

        <div class="sign-content">
            <div v-if="wallet.type === 'CommonWallet'">
                <a-input type="password" class="input-pass" :placeholder="$t('pax.inputPassword')" v-model="password"></a-input>
            </div>

            <div class="ledger-status" v-if="wallet.type === 'HardwareWallet'">
                <div class="font-bold" style="margin-bottom: 15px;">{{$t('ledgerWallet.connectApp')}}</div>
                <span class="font-medium-black">{{$t('ledgerWallet.status')}}: </span>
                <span class="font-medium">{{ledgerStatus}} </span>
                <p>{{$t('pax.ledgerSignMultiTimes')}}</p>
            </div>
        </div>
    </div>
</template>

<script>
import {mapState} from 'vuex'
import {DEFAULT_SCRYPT} from '../../core/consts'
import {decryptWallet} from '../../core/utils'
import {legacySignWithLedger} from '../../core/ontLedger'
import {Crypto, Transaction, TransactionBuilder, TxSignature, utils, RestClient} from 'ontology-ts-sdk'

export default {
    name: 'SignSharedTx',
    props: ['wallet'],
    data() {
        const sharedWallet = JSON.parse(sessionStorage.getItem('sharedWallet'));
        return {
            password: '',
            sharedWallet
        }
    },
    mounted(){
        if(this.wallet.type === 'HardwareWallet') {
            this.$store.dispatch('getLedgerStatus')
        }
    },
    beforeDestroy() {
        clearInterval(this.intervalId);
        this.$store.dispatch('stopGetLedgerStatus')
    },
    computed:{
        ...mapState({
            ledgerStatus: state => state.LedgerConnector.ledgerStatus,
            ledgerPk : state => state.LedgerConnector.publicKey,
            ledgerWallet: state => state.LedgerConnector.ledgerWallet,
        })
    },
    methods: {
        async signSharedTx(isFirstSign, tx) {
            if(this.wallet.type === 'CommonWallet' && !this.password
            || this.wallet.type === 'HardwareWallet' && !this.ledgerPk) {
                return;
            }
            const M = this.sharedWallet.requiredNumber;
            const pks = this.sharedWallet.coPayers.map(p => new Crypto.PublicKey(p.publickey))
           const txTemp = Transaction.deserialize(tx)
            if (this.wallet.type === 'CommonWallet') {
                const pri = decryptWallet({
                    key: this.wallet.wallet.key,
                    address: this.wallet.address,
                    salt: this.wallet.wallet.salt
                    }, this.password);
                if (!pri) {
                    return;
                }
                TransactionBuilder.signTx(txTemp, M, pks, pri)
            } else {
                txTemp.payer = new Crypto.Address(this.wallet.sharedWalletAddress);
                let res;
                try {
                    res = await legacySignWithLedger(txTemp.serializeUnsignedData())
                } catch(err) {
                    this.ledgerStatus = '';
                    this.$store.dispatch('hideLoadingModals')
                    alert(err.message)
                    return;
                }
                const sig = new TxSignature();
                sig.M = M;
                sig.pubKeys = pks;
                if(isFirstSign) {
                    sig.sigData = ['01' + res];
                    txTemp.sigs.push(sig);
                } else {
                    const sigVal = '01' + res;
                    txTemp.sigs[0].sigData.push(sigVal);
                }

            }
            this.$emit('sharedTxSigned', txTemp.serialize())
        }
    }
}
</script>


================================================
FILE: src/components/Common/Oep4Home.vue
================================================
<style scoped>
.content-container {
    display: flex;
    padding:10px;
  }

  .left-half {
    flex-basis: 50%;
    padding-right: 40px;

  }
  .oep4-container {
      max-height:360px;
      overflow-y:auto;
  }

  .right-half {
    flex-basis: 50%;
  }
  .home-title {
      display: flex;
      align-items: center;
      margin-bottom:20px;
  }
  .home-title p {
      font-size: 20px;
      font-weight: 500;
      margin:0;
      margin-right:15px;
  }
  .oep4-item {
      margin-bottom: 15px;
  }

  .oep4-item div {
      display: flex;
      align-items: center;
  }
   .asset-label {
    font-family: AvenirNext-Medium;
    font-size: 16px;
    color: #515457;
    float: left;
    margin-right: 12px;
  }

  .asset-amount {
    font-family: AvenirNext-Medium;
    font-size: 16px;
    color: #000000;
  }
  .asset-scriptHash {
    font-family: AvenirNext-Medium;
    font-size: 14px;
    color: #000000;
  }
  .oep4-btns {
      margin-top:30px;
  }
   .asset-btn {
    border-radius: 0;
    background: #196BD8;
    font-family: AvenirNext-Medium;
    font-size: 14px;
    color: #FFFFFF;
    width: 100px;
    height: 34px;
    margin-right: 40px;
    margin-bottom: 60px;
    border: none;
  }

  .txList-header {
    padding-bottom: 5px;
    border-bottom: 1px solid #DFE2E9;
    position: relative;
  }

  .txList-header :first-child {
    font-family: AvenirNext-Bold;
    font-size: 14px;
    color: #000000;
    text-align: center;
  }

  .txList-header :last-child {
    width: 64px;
    height: 64px;
    display: block;
    float: right;
    background: url('../../assets/transaction.png');
    background-size: contain;
    top: -20px;
    right: 0;
    position: absolute;
  }
  .tx-item {
    float: left;
    margin: 5px 0;
    cursor: pointer;
  }

  .tx-item :first-child {
    width: 65%;
    display: inline-block;
    overflow: hidden;
    text-overflow: ellipsis;
    font-family: AvenirNext-Medium;
    font-size: 12px;
    color: #6F7781;
  }

  .tx-item :last-child {
    width: 30%;
    text-align: right;
    float: right;
    display: block;
    font-family: AvenirNext-Medium;
    font-size: 12px;
    color: #000000;
  }
.check-more {
    font-family: AvenirNext-Medium;
    font-size: 12px;
    color: #227EEC;
    text-align: center;
    cursor: pointer;
    width:100%;
    float:left;
  }
</style>

<template>
    <div>
        <breadcrumb :current="$t('sharedWalletHome.send')" :routes="routes"
                v-on:backEvent="handleBack"></breadcrumb>

        <div class="content-container">
            <div class="left-half">
                <div class="oep4-container">
                    <div class="home-title">
                        <p>OEP-4 Tokens</p>
                        <a-icon class="refresh-icon" type="reload" @click="refresh"/>
                    </div>

                    <div class="oep4-item" v-for="(token,index) of oep4s.filter(token.net === net)" :key="index">
                        <div class="font-medium-black">{{token.symbol}} - {{token.name}}</div>
                        <div class="oep4-balance">
                            <span class="asset-label">{{$t('commonWalletHome.balance')}}: </span>
                            <span class="asset-amount">{{token.balance}}</span>
                        </div>
                        <div class="">
                            <span class="asset-label">{{$t('commonWalletHome.scriptHash')}}: </span>
                            <span class="asset-scriptHash">{{token.scriptHash}}</span>
                        </div>
                    </div>

                    <a-button @click="handleAdd">{{$t('commonWalletHome.add')}}</a-button>
                </div>
                <div class="oep4-btns">
                    <a-button class="asset-btn" type="primary" @click="sendAsset">
                        <i class="arrow-up"></i>
                        {{$t('sharedWalletHome.send')}}
                    </a-button>
                    <a-button class="asset-btn" type="primary" @click="commnReceive">
                        <i class="arrow-down"></i>
                        {{$t('sharedWalletHome.receive')}}
                    </a-button>
                </div>
            </div>
            <div class="right-half">
                <div class="completed-tx">
                    <div class="txList-header">
                        <span>{{$t('sharedWalletHome.completedTx')}}</span>
                        <span class="transfer-icon"></span>
                    </div>
                    <div v-for="(tx,index) in completedTx.slice(0,10)" :key="tx.txHash+index" class="tx-item"
                        @click="showTxDetail(tx.txHash)">
                        <span>{{tx.txHash}}</span>
                        <span>{{tx.amount}} {{tx.asset}}</span>
                    </div>
                    <div class="check-more" v-if="completedTx.length > 6" @click="checkMoreTx">
                        {{$t('sharedWalletHome.checkMore')}}>>
                    </div>
                </div>
            </div>
          </div>

        <a-modal
            :title="$t('commonWalletHome.addOep4')"
            :visible="showModal"
            @ok="handleAddOep4"
            @cancel="handleCancel">
            <div>
                <div>
                    <p>{{$t('commonWalletHome.enterScripthash')}}</p>
                    <a-input class="input" v-model="scriptHash"  ></a-input>
                </div>
            </div>
        </a-modal>
    </div>
</template>

<script>
import Breadcrumb from '../Breadcrumb'
import {mapState} from 'vuex'
import { TEST_NET } from '../../core/consts'
import { open } from '../../core/utils'

export default {
    name: 'Oep4Home',
    data() {
        const net = localStorage.getItem('net')
        return {
            showModal: false,
            scriptHash: '',
            net: net
        }
    },
    components:{
        Breadcrumb
    },
    mounted() {
        this.refresh()
    },
    computed:{
        ...mapState({
            oep4s: state => state.Oep4s.oep4s,
            completedTx: state => state.Oep4s.completedTx,
            address: state => state.CurrentWallet.wallet.address,
            currentWallet: state => state.CurrentWallet.wallet
        }),
        routes: function() {
            const address = this.$store.state.CurrentWallet.wallet.address;
            let path = '';
            if(address === this.$store.state.CurrentWallet.wallet.address) {
                path = '/dashboard'
            } else {
                path = '/sharedWallet/home'
            }
            return [{name: this.$store.state.CurrentWallet.wallet.name, path}]
        }
    },
    methods: {
        refresh() {
            this.$store.dispatch('queryBalanceForOep4', this.address)
            this.$store.dispatch('queryTxForOep4', {address: this.address, oep4s: this.oep4s})
        },
        handleBack() {
            this.$router.push({name: 'Wallets'})
        },
        handleAdd() {
            this.showModal = true;
        },
        handleCancel() {
            this.showModal = false;
            this.scriptHash = ''
        },
        handleAddOep4(){
            if(!this.scriptHash || this.scriptHash.trim().length !== 40) {
                this.$message.error(this.$t('commonWalletHome.invalidScriptHash'))
                return;
            }
            for(let i = 0 ; i < this.oep4s.length; i++) {
                if(this.oep4s[i].scriptHash === this.scriptHash) {
                    this.$message.warning(this.$t('commonWalletHome.oep4Exists'))
                    return;
                }
            }
            this.$store.dispatch('showLoadingModals')
            this.$store.dispatch('addOep4Token', {
                scriptHash: this.scriptHash,
                address: this.address
            }).then(res => {
                this.$store.dispatch('hideLoadingModals')
                if(res === 'ADD_SUCCESS') {
                    this.showModal = false;
                    this.scriptHash = '';
                    this.$message.success(this.$t('commonWalletHome.addOep4Success'))
                } else if(res === 'NO_CONTRACT') {
                    this.$message.success(this.$t('commonWalletHome.noOep4Contract'))
                } else if (res === 'NETWORK_ERROR') {
                    this.$message.success(this.$t('commonWalletHome.networkError'))
                }
            })
        },
        sendAsset() {
            this.$store.commit('CLEAR_CURRENT_TRANSFER');
            if(this.address === this.currentWallet.address) {
                this.$router.push({name: 'CommonSendHome'})
            } else {
                this.$store.commit('UPDATE_TRANSFER_REDEEM_TYPE', {type: false});
                this.$router.push({path:'/sharedWallet/sendTransfer'})
            }
        },
        commnReceive() {
            this.$router.push({path: '/commonWalletReceive/commonWallet'})
        },
        showTxDetail(txHash) {
            let url = `https://explorer.ont.io/transaction/${txHash}`
            if (this.net === 'TEST_NET') {
                url += '/testnet'
            }
            open(url)
        },
        checkMoreTx() {
        let url = `https://explorer.ont.io/address/${this.address}/10/1`
            if (this.net === 'TEST_NET') {
                url += '/testnet'
            }
            open(url)
        },
    }
}
</script>



================================================
FILE: src/components/Common/Oep4Selection.vue
================================================
<style scoped>
.selection-container {
    height:370px;
    margin-top:-15px;
}
.pages {
    margin:0 auto;
    margin-top:20px;
    text-align: center;
}
.selection-item {
    display: flex;
    justify-content: space-between;
    padding: 7px 0;
    border-bottom:1px solid #DFE2E9;
}
.selection-item p {
    margin: 0;
    font-size:14px;
    font-family:PingFangSC-Regular;
    font-weight:400;
    color:rgba(0,0,0,1);
}
.oep4-info {
    font-size: 12px;
}
.oep4-info p {
    margin:0;
}
</style>
<template>
    <div>
        <a-modal
            :title="$t('common.selectOep4')"
            :visible="visible"
            @cancel="handleClose"
            :footer="null"
            :width="400">

                <div>
                    <div class="selection-container">
                        <div v-for="item of oep4s" :key="item.contract_hash" class="selection-item">
                            <p>{{item.symbol}}</p>
                            <!-- <a-checkbox :checked="item.selected" @change="onChangeSelection(item)"></a-checkbox> -->
                            <a-switch :checked="item.selected" @change='onChangeSelection(item)'/>
                        </div>
                    </div>

                    <a-pagination v-model="page_number" :total="total"  @change="handlePageChange" class="pages"/>
                </div>

        </a-modal>
    </div>
</template>
<script>
/*
从后台获取oep4列表,本地缓存用户选择的记录,对比合约hash,显示选择状态,要有分页;
每次更新选择,触发mutation更新store并更新缓存;
*/
import {mapState} from 'vuex'
export default {
    name: 'Oep4Selection',
    props: ['visible'],
    data() {
        return {
            oep4s: [],
            page_size: 10,
            page_number: 1,
            total: 0,
        }
    },

     mounted() {
    },

    computed: {
        ...mapState({

        })

    },
    watch: {
        visible: function(newVal) {
           this.fetchOep4List();
        }
    },
    methods: {
        handleClose() {
            this.page_number = 1;
            this.$emit('closeOep4Selection')
        },
        onChangeSelection(item) {
            item.selected = !item.selected;
            this.$store.commit('UPDATE_OEP4_TOKEN', {oep4: item})
        },
        handlePageChange(page) {
            this.page_number = page;
            this.fetchOep4List();
        },
        fetchOep4List() {
            this.$store.dispatch('showLoadingModals')
            this.$store.dispatch('fetchOep4Selections', {
                    page_size: this.page_size,
                    page_number: this.page_number
                }).then(res => {
                    console.log('result')
                    const {list, total } = res;
                    this.total = total;
                    this.oep4s = list.map(item => Object.assign({}, {
                        contract_hash: item.contract_hash,
                        decimal: item.decimals,
                        symbol: item.symbol,
                        selected: item.selected
                    }))
                })
        }

    }
}
</script>


================================================
FILE: src/components/Common/SelectWallet.vue
================================================
<template>
	<div class="select-container">
		<a-select :options="normalWalletAndLedgerWallet"
			class="select-ontid"
			:placeholder="$t('createIdentity.selectCommonWallet')"
			@change="handleChangeWallet">
		</a-select>

		<!-- <a-radio-group @change="changePayerWallet"
			v-model="walletType"
			class="change-payer-radio">
			<a-radio value="commonWallet"
				class="payer-radio-item">{{$t('createIdentity.commonWallet')}}</a-radio>
			<a-radio value="ledgerWallet"
				class="payer-radio-item">{{$t('createIdentity.ledgerWallet')}}</a-radio>

			<div v-if="walletType === 'commonWallet'">
				<a-select :options="normalWalletAndLedgerWallet"
					class="select-ontid"
					:placeholder="$t('createIdentity.selectCommonWallet')"
					@change="handleChangeWallet">
				</a-select>
			</div>

			<div v-if="walletType === 'ledgerWallet'">

				<div class="payer-ledger-status">
					<div class="font-bold"
						style="margin-bottom: 10px;">{{$t('ledgerWallet.connectApp')}}</div>
					<span class="font-medium-black">{{$t('ledgerWallet.status')}}: </span>
					<span class="font-medium">{{ledgerStatus}} </span>
				</div>

			</div>

		</a-radio-group> -->
	</div>
</template>
<script>
import { mapState } from "vuex";
import {WALLET_TYPE}  from '../../core/consts'

export default {
	name: "SelectWallet",
	data: () => ({
		walletType: "commonWallet"
	}),
	props: {
		walletSelected: {}
	},
	created() {
		// this.$store.dispatch("fetchWalletsFromDb");
	},
	beforeDestroy() {
		// this.$store.dispatch("stopGetLedgerStatus");
	},
	computed: {
		...mapState({
			ledgerStatus: state => state.LedgerConnector.ledgerStatus,
			ledgerPk: state => state.LedgerConnector.publicKey,
			ledgerWallet: state => state.LedgerConnector.ledgerWallet
		}),
		normalWalletAndLedgerWallet: {
			get() {
				const NormalList = this.$store.state.Wallets.NormalWallet.slice();
				const LedgerList = this.$store.state.Wallets.HardwareWallet.slice();

				const list1 = NormalList.map(i => {
					return Object.assign({}, i, {
						label: i.label + " " + i.address,
						value: i.address
					});
				});

				const list2 = LedgerList.map(i => {
					return Object.assign({}, i, {
						type: WALLET_TYPE.HardwareWallet,
						label: i.label + " " + i.address + " (Ledger)",
						value: i.address
					});
				});
				list2.sort((a,b)=>{
					if (b.timestamp !== a.timestamp) {
						return b.timestamp - a.timestamp;
					} else {
						return b.acct - a.acct;
					}
				})

				return [...list1, ...list2];
			}
		}
	},
	watch: {
		// ledgerPk(newV, oldV) {
		// 	if (newV) {
		// 		const wallet = this.ledgerWallet;
		// 		this.$emit("walletSelected", {
		// 			walletType: this.walletType,
		// 			wallet
		// 		});
		// 	}
		// }
	},
	methods: {
		// changePayerWallet(e) {
		// 	this.walletType = e.target.value;
		// 	if (e.target.value === "ledgerWallet") {
		// 		this.$store.dispatch("getLedgerStatus");
        //     } else {
		// 		this.$store.dispatch('stopGetLedgerStatus')
		// 	}
        //     this.$emit("walletSelected", {
		// 		walletType: this.walletType,
		// 		wallet: null
		// 	});
		// },
		handleChangeWallet(value) {
			const wallet = this.normalWalletAndLedgerWallet.find(v => {
				return v.address === value;
			});
			this.$emit("walletSelected", {
				walletType: wallet.type === WALLET_TYPE.HardwareWallet ? "ledgerWallet" : "commonWallet",
				wallet
			});
		}
	}
};
</script>
<style lang="scss" scoped>
.label {
    
}
.change-payer-radio {
    width: 100%;
}
.payer-radio-item {
    margin-bottom: 10px;
}
</style>

================================================
FILE: src/components/Common/SignSendTx.vue
================================================
<style scoped>

</style>
<template>
    <div>
    <a-modal
        :title="$t('nodeStake.signWithWallet')"
        :visible="visible"
        @ok="handleWalletSignOK"
        @cancel="handleWalletSignCancel">
          <div v-if="wallet.key">
              <p>{{$t('nodeStake.enterWalletPass')}}</p>
              <a-input class="input" v-model="walletPassword" :plaecholder="$t('nodeStake.password')" type="password"></a-input>
          </div>
          <div v-if="!wallet.key">
            <div class="font-bold" style="margin-bottom: 10px;">{{$t('ledgerWallet.connectApp')}}</div>
                    <span class="font-medium-black">{{$t('ledgerWallet.status')}}: </span>
                    <span class="font-medium">{{ledgerStatus}} </span>
          </div>
    </a-modal>
    </div>
</template>
<script>
import {mapState} from 'vuex'
import delay from 'delay'
import {DEFAULT_SCRYPT} from '../../core/consts'
import { getRestClient } from '../../core/utils'
import {legacySignWithLedger, checkPublicKeyIsInTheConnectedLedger} from '../../core/ontLedger'
import {Crypto, TransactionBuilder, TxSignature, utils, RestClient, WebsocketClient, Transaction, OntAssetTxBuilder} from 'ontology-ts-sdk'
// common component to sign tx or messages with wallet or ledger.

export default {
    name: 'SignSendTx',
    // props:['tx', 'wallet', 'visible',],
    props: {
        tx: {
            required: true
        },
        wallet: {
            required: true
        },
        visible: {
            required: true,
            type: Boolean
        },
        sendAfterSign: {
            required: false,
            type: Boolean,
            default: true
        }

    },
    mounted(){

    },
    watch: {
        visible(newV, oldV) {
            if(newV) {
                if(!this.wallet.key) {//common wallet
                    this.$store.dispatch('getLedgerStatus')
                }
            } else {
                this.$store.dispatch('stopGetLedgerStatus')
            }
        }
    },
    beforeDestroy() {
        this.$store.dispatch('stopGetLedgerStatus')
    },
    data(){
        return {
            walletPassword: ''
        }
    },
    computed:{
        ...mapState({
            ledgerStatus: state => state.LedgerConnector.ledgerStatus,
            ledgerPk : state => state.LedgerConnector.publicKey,
            ledgerWallet: state => state.LedgerConnector.ledgerWallet,
        })
    },
    methods: {
        handleWalletSignCancel() {
            this.walletPassword = '';
            this.$emit('signClose')
        },
        async handleWalletSignOK() {
            const tx = this.tx;
            if (this.wallet.key && !this.walletPassword) {
                //common wallet
                this.$message.error(this.$t("nodeStake.passwordEmpty"));
                return;
            }
            if (this.wallet.key) {
                this.$store.dispatch("showLoadingModals");
                const enc = new Crypto.PrivateKey(this.wallet.key);
                let pri;
                try {
                    pri = enc.decrypt(
                        this.walletPassword,
                        new Crypto.Address(this.wallet.address),
                        this.wallet.salt,
                        DEFAULT_SCRYPT
                    );
                } catch (err) {
                    console.log(err);
                    this.$store.dispatch("hideLoadingModals");
                    this.$message.error(this.$t("common.pwdErr"));
                    return;
                }
                if(typeof tx === 'string') {
                    const signature =  pri.sign(tx)
                    this.$store.dispatch("hideLoadingModals");
                    this.$emit('afterSign', signature) // 返回签名message结果
                    this.walletPassword = ''
                } else {
                    TransactionBuilder.signTransaction(tx, pri);
                    this.sendTx(tx);
                    this.walletPassword = ''
                }

            } else {
                //ledger sign
                if (this.ledgerWallet.address) {
                    this.$store.dispatch("showLoadingModals");
                    this.$store.dispatch('stopGetLedgerStatus')
                    await delay(1000);
                    console.log(this.wallet);
                    // 当前连接的Ledger需要和之前导入钱包的Ledger是同一个
                    try {
                        await checkPublicKeyIsInTheConnectedLedger(this.wallet.acct || 0, this.wallet.neo, this.wallet.publicKey)
                    } catch (err) {
                        this.$store.dispatch("hideLoadingModals");
                        this.$store.dispatch('getLedgerStatus')
                        return;
                    }
                    let txData
                    if(typeof tx === 'string') {
                        txData =  tx
                        // ledger 签名message特殊处理,放到tx的payload里. 先构造个占位的tx
                        const addr = new Crypto.Address(this.wallet.address)
                        const txTemp = OntAssetTxBuilder.makeTransferTx('ONT', addr, addr, '1', '500', '20000', addr)
                        txTemp.payload.code = tx;
                        const pk = new Crypto.PublicKey(this.wallet.publicKey);
                        const txSig = new TxSignature();
                        txSig.M = 1;
                        txSig.pubKeys = [pk];
                        txData = txTemp.serializeUnsignedData();
                        legacySignWithLedger(txData, this.wallet.neo, this.wallet.acct || 0).then(res => {
                            // console.log('txSigned: ' + res);
                            const sign = "01" + res; //ECDSAwithSHA256
                            txSig.sigData = [sign];
                            txTemp.sigs = [txSig];
                            this.$store.dispatch("hideLoadingModals");
                            this.$emit('afterSign', txTemp.serialize()) // 返回签名message结果
                            },
                            err => {
                                this.sending = false;
                                console.log(err)
                                this.$store.dispatch("hideLoadingModals");
                                this.$message.error(this.$t('ledgerWallet.signFailed'))
                            }
                        ).finally(() => {
                          this.$store.dispatch('getLedgerStatus')
                        });
                    } else {
                        const pk = new Crypto.PublicKey(this.wallet.publicKey);
                        const txSig = new TxSignature();
                        txSig.M = 1;
                        txSig.pubKeys = [pk];
                        tx.payer = new Crypto.Address(this.wallet.address);
                        txData = tx.serializeUnsignedData();
                        legacySignWithLedger(txData, this.wallet.neo, this.wallet.acct || 0).then(res => {
                            // console.log('txSigned: ' + res);
                            const sign = "01" + res; //ECDSAwithSHA256
                            txSig.sigData = [sign];
                            tx.sigs = [txSig];
                            this.sendTx(tx);
                            },
                            err => {
                                console.log(err)
                                this.sending = false;
                                this.$store.dispatch("hideLoadingModals");
                                this.$message.error(this.$t('ledgerWallet.signFailed'))
                            }
                        ).finally(() => {
                          this.$store.dispatch('getLedgerStatus')
                        });
                    }
                } else {
                    this.$store.dispatch("hideLoadingModals");
                    this.$message.warning(this.$t("ledgerWallet.connectApp"));
                }
            }
            },
            sendTx(tx){
                if(!this.sendAfterSign) {
                    this.$emit('afterSign', tx)
                    return;
                }
                this.walletPassword = '';
                const client = getRestClient();
                // const client = new WebsocketClient();
                // client.sendRawTransaction(tx.serialize(), false, true).then(res => {
                client.sendRawTransaction(tx.serialize()).then(res => {
                console.log(res)
                this.$store.dispatch("hideLoadingModals");
                if (res.Error === 0) {
                    this.$message.success(this.$t('common.transSentSuccess'))
                } else if (res.Error === -1) {
                    if(res.Result.indexOf('balance insufficient') > -1 ) {
                        this.$message.error(this.$t('common.balanceInsufficient'))
                    } else if(res.Result.indexOf('cover gas cost') > -1){
                        this.$message.error(this.$t('common.ongNoEnough'))
                    } else {
                        // this.$message.error(res.Result)
                        console.log(res.Result)
                        const msg = typeof res.Result === 'string' ? res.Result : JSON.stringify(res.Result)
                        this.$message.error(this.$t('common.txFailed') + ' '+ msg)
                    }
                    return;
                } else {
                    this.$message.error(res.Result)
                    return;
                }
                this.$emit('txSent')
                const title = this.$t('common.transSentSuccess')
                setTimeout(() => {
                    this.$success({
                        title: title,
                        content: 'Transaction hash: ' + utils.reverseHex(tx.getHash())
                    })
                }, 100)
                }).catch(err => {
                    console.log(err)
                    this.$message.error(this.$t('common.networkError'))
                })
            },
    }
}
</script>


================================================
FILE: src/components/CommonWallet/CommonReceive.vue
================================================
<style scoped>
.content-container {
    width:540px;
    margin:20px auto;
}
.label {
    font-family: AvenirNext-Bold;
    font-size: 14px;
    color: #000000;
    margin-bottom:30px;
}
.qrcode {
    text-align:center;
    margin-bottom:40px;
}
.address-item {
    margin-bottom: 20px;
}
.address-item  :first-child{
    width:40%;
    float: left;
    font-family: AvenirNext-Regular;
    font-size: 14px;
    color: #000000;
}

.value-item {
    width:60%;
    float:right;
}
.value-item :first-child {
    width:280px;
    display: block;
    float: left;
    word-break: break-all;
}
.font-regular {
    font-family: AvenirNext-Regular;
    font-size: 14px;
    color: #000000;
}
.copy-icon {
    width:18px;
    height:18px;
    display: inline-block;
    margin-left: 10px;
    background: url('../../assets/copy.png') center center;
    background-size: cover;
    cursor: pointer;
    margin-top:10px;
}
</style>
<template>
    <div>
        <breadcrumb :current="$t('commonWalletHome.receive')" :routes="routes" v-on:backEvent="backToWallets"></breadcrumb>
        <div class="content-container">
            <p class="label">{{$t('commonWalletHome.walletQrCode')}}</p>
            <div class="qrcode">
                <vue-qrcode :value="address" :options="{size:200}"></vue-qrcode>
            </div>
            <div class="address-item clearfix">
                <span>{{$t('commonWalletHome.walletAddress')}}</span>
                <div class="value-item">
                    <span class="font-regular">{{address}}</span>
                    <span class="copy-icon" @click="copy(address)"></span>
                </div>
            </div>
            <div class="address-item clearfix" v-if="pk">
                <span>{{$t('commonWalletHome.publicKey')}}</span>
                <div class="value-item">
                    <span class="font-regular">{{pk}}</span>
                    <span class="copy-icon" @click="copy(pk)"></span>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
import Breadcrumb from '../Breadcrumb'
import VueQrcode from '@xkeshi/vue-qrcode'
export default {
    name:'CommonReceive',
    components:{
        Breadcrumb,
        VueQrcode
    },
    data() {
        const type = this.$route.params.walletType
        let wallet, walletName, routes, address, pk;
        if(type === 'commonWallet') {
            wallet = JSON.parse(sessionStorage.getItem('currentWallet'))
            walletName = wallet.label
            routes = [{name: walletName, path:'/dashboard'}]
            address = wallet.address
            pk = wallet.publicKey
        } else {
            wallet = JSON.parse(sessionStorage.getItem('sharedWallet'))
            walletName = wallet.sharedWalletName
            routes = [{name: walletName, path:'/sharedWallet/home'}]
            address = wallet.sharedWalletAddress
            pk = ''
        }

        return {
            address,
            pk,
            walletName,
            routes,
        }
    },
    mounted() {

    },
    methods: {
        backToWallets() {
            this.$router.push({name:'Wallets'})
        },
        copy(value) {
            this.$copyText(value);
            this.$message.success(this.$t('common.copied'))
        }
    }
}
</script>


================================================
FILE: src/components/CommonWallet/CommonRedeem.vue
================================================
<style scoped>
.container {
    width:540px;
    margin:4rem auto;
}
.label {
    font-family: AvenirNext-Bold;
    font-size: 20px;
    color: #5E6369;
}
.input-pass {
    margin-top:12px;
    padding-left: 4rem;
}
.connect-ledger-app {
    margin-top: 20px;
    margin-left: 4rem;
}

.ledger-status {
    margin-top:10px;
    margin-left: 4rem;
}
</style>
<template>
    <div>
        <breadcrumb :current="$t('commonWalletHome.redeem')" :routes="routes"
                v-on:backEvent="backToWallets"></breadcrumb>
        <div class="container">
            <div class="label">
                {{$t('commonWalletHome.redeemCharge')}}
            </div>
            <div class="input-pass" v-if="type=== 'commonWallet'">
                <a-input type="password" class="input" :placeholder="$t('commonWalletHome.inputPass')" v-model="password"></a-input>
            </div>
            <div v-if="type === 'hardwareWallet'" class="connect-ledger-app font-medium">
                {{$t('ledgerWallet.connectApp')}}
            </div>
            <div v-if="ledgerStatus" class="ledger-status ">
                <span class="font-medium-black">{{$t('ledgerWallet.status')}}: </span>
                <span class="font-medium">{{ledgerStatus}} </span>
            </div>
        </div>
        <div class="footer-btns">
            <div class="footer-btn-container">
                <a-button type="default" class="btn-cancel" @click="cancel">{{$t('commonWalletHome.cancel')}}</a-button>
                <a-button type="primary" class="btn-next" @click="submit" :disabled="sending">
                    {{$t('commonWalletHome.submit')}}
                    </a-button>
            </div>
        </div>

    </div>
</template>

<script>
import Breadcrumb from '../Breadcrumb'
import {legacySignWithLedger} from '../../core/ontLedger'
import {RestClient, Crypto,OntAssetTxBuilder, TransactionBuilder, utils, TxSignature} from 'ontology-ts-sdk'
import { TEST_NET, MAIN_NET, ONT_CONTRACT, ONT_PASS_NODE, DEFAULT_SCRYPT, GAS_PRICE, GAS_LIMIT } from '../../core/consts'
import {mapState} from 'vuex'
import {getDeviceInfo, getPublicKey, checkPublicKeyIsInTheConnectedLedger} from '../../core/ontLedger'
import {BigNumber} from 'bignumber.js'
import { getRestClient } from '../../core/utils'
export default {
    name: 'CommonRedeem',
    components: {
        Breadcrumb
    },
    mounted: function () {
    const currentWallet = JSON.parse(sessionStorage.getItem('currentWallet'));
      if(currentWallet.key) {
          return;
      }
      let that = this;
      that.getDevice()
      this.intervalId = setInterval(() => {
        that.getDevice()
      }, this.interval)
    },
    beforeDestroy(){
      clearInterval(this.intervalId)
    },
    data() {
        const net = localStorage.getItem('net');
        const type = this.$route.params.walletType
        const currentWallet = JSON.parse(sessionStorage.getItem('currentWallet'))
        const routes = [{name: currentWallet.label, path:'/dashboard'}]
        return {
            currentWallet,
            routes,
            type,
            password:'',
            interval:10000,
            invervalId:'',
            publicKey:'',
            ledgerStatus:'',
            sending: false
        }
    },
    computed:{
        ...mapState({
            redeem: state => state.CurrentWallet.redeem
        })
    },
    methods: {
        backToWallets() {
            this.$router.push({name: 'Wallets'})
        },
        cancel() {
            this.$router.push('/dashboard')
        },
        getDevice() {
        if(this.publicKey) {
            return;
        }
            getDeviceInfo().then(res => {
                console.log('device: ' + res)
                this.device = res;
                this.getPublicKey()
            }).catch(err => {
                console.log(err)
                this.publicKey = '';
                if (err === 'NOT_FOUND') {
                    this.ledgerStatus = this.$t('common.ledgerNotOpen')
                } else if (err === 'NOT_SUPPORT') {
                    this.ledgerStatus = this.$t('common.ledgerNotSupported')
                } else {
                    this.ledgerStatus = this.$t('common.pluginDevice')
                }
            })
      },
      getPublicKey() {
        if(this.publicKey) {
            return;
        }
        getPublicKey().then(res => {
          console.log('pk info: ' + res);
          this.publicKey = res
          this.ledgerStatus = this.$t('common.readyToSubmit')
        }).catch(err => {
          this.ledgerStatus = err.message
        })
      },
      sendTx(tx) {
          const restClient = getRestClient();
          restClient.sendRawTransaction(tx.serialize()).then(res => {
            console.log(res)
            this.$store.dispatch('hideLoadingModals')
            if (res.Error === 0) {
                this.$message.success(this.$t('common.transSentSuccess'))
            } else if (res.Error === -1) {
                const err = res.Result.indexOf('cover gas cost') > -1 ? this.$t('common.ongNoEnough') : res.Result
                this.$message.error(err)
                return;
            } else {
                this.$message.error(res.Result)
                return;
            }
            const title = this.$t('common.transSentSuccess')
            this.$router.push({path:'/dashboard'})
            setTimeout(() => {
                this.$success({
                    title: title,
                    content: 'Transaction hash: ' + utils.reverseHex(tx.getHash())
                })
            }, 100)
        }).catch(err => {
                    console.log(err)
                    this.$message.error(this.$t('common.networkError'))
                })
      },
        async submit() {
            if(this.type === 'commonWallet' &&!this.password) {
                this.$message.error(this.$t('commonWalletHome.emptyPass'))
                return;
            }
            this.sending = true;
            const from = new Crypto.Address(this.currentWallet.address);
            const to = from;
            const value = new BigNumber(this.redeem.claimableOng);
            const amount = value.multipliedBy(1e9).toString();
            const tx = OntAssetTxBuilder.makeWithdrawOngTx(from, to, amount, from, GAS_PRICE, GAS_LIMIT);
            if(this.type === 'commonWallet') {
                this.$store.dispatch('showLoadingModals')
                const enc = new Crypto.PrivateKey(this.currentWallet.key)
                let pri;
                try {
                    pri = enc.decrypt(this.password, from, this.currentWallet.salt, DEFAULT_SCRYPT)
                } catch (err) {
                    console.log(err);
                    this.$store.dispatch('hideLoadingModals')
                    this.$message.error(this.$t('common.pwdErr'))
                    this.sending = false;
                    return;
                }
                TransactionBuilder.signTransaction(tx, pri);
                this.sendTx(tx);
            } else {
                if(this.publicKey) {
                    const neo = this.currentWallet.neo;
                    const acct = this.currentWallet.acct;
                    await checkPublicKeyIsInTheConnectedLedger(acct, neo, this.currentWallet.publicKey);
                    this.$store.dispatch('showLoadingModals')
                    this.sending = true;
                    this.ledgerStatus = this.$t('common.waitForSign')
                    const pk = new Crypto.PublicKey(this.currentWallet.publicKey);
                    const txSig = new TxSignature();
                    txSig.M = 1;
                    txSig.pubKeys = [pk];
                    tx.payer = from;
                    const txData = tx.serializeUnsignedData();
                    legacySignWithLedger(txData, neo, acct).then(res => {
                    // console.log('txSigned: ' + res);
                        const sign = '01' + res; //ECDSAwithSHA256
                        txSig.sigData = [sign]
                        tx.sigs = [txSig];
                        this.sendTx(tx);
                    }, err => {
                        this.sending = false;
                        this.ledgerStatus = '';
                        this.$store.dispatch('hideLoadingModals')
                        alert(err.message)
                    })
                } else {
                    this.$message.warning(this.$t('ledgerWallet.connectApp'))
                }


            }
        }
    }
}
</script>




================================================
FILE: src/components/CommonWallet/CommonTokenSwap.vue
================================================
<style scoped>

  .content-container {
    display: flex;
    margin-top: 40px;
  }

  .left-half {
    flex-basis: 50%;
    padding:10px 15px;
  }

  .right-half {
    flex-basis: 50%;
    padding: 10px 20px;
  }
  .swap-btns {
      width:70%;
      margin:30px auto;
  }
  .swap-btns :last-child {
      float: right;
  }
  .error-amount {
      border-color:red !important;
  }
</style>
<template>
    <div>
        <breadcrumb :current="$t('commonWalletHome.swap')" :routes="routes"
                v-on:backEvent="backToWallets"></breadcrumb>
        <div class="content-container">
            <div class="left-half">
                <p class="font-regular">{{$t('commonWalletHome.swapText')}}</p>
                <p class="font-regular">{{$t('commonWalletHome.stepFollow')}}</p>
                <p class="font-medium">{{$t('commonWalletHome.step1')}}</p>
                <p class="font-medium">{{$t('commonWalletHome.step2')}}</p>
                <p class="font-medium">{{$t('commonWalletHome.step3')}}</p>
            </div>
            <div class="right-half">
                <p class="font-medium-black">{{$t('commonWalletHome.swapAmount')}}</p>
                <a-input class="input" v-model="amount"
                @change="validateAmount" :class="validAmount? '': 'error-amount'"
                ></a-input>
                <p class="font-regular">{{$t('commonWalletHome.nep5Balance')}}
                    <span class="font-medium-black">{{nep5Ont}}</span> </p>
                <p class="font-medium-black">{{$t('commonWalletHome.password')}}</p>
                <a-input class="input" v-model="password" type="password"
                @change="validatePass" :class="validPassword? '': 'error-amount'"
                ></a-input>
                <div class="swap-btns">
                     <a-button type="default" class="btn-cancel" @click="cancel">{{$t('commonWalletHome.cancel')}}</a-button>
                     <a-button type="primary" class="btn-next" @click="submit" :disabled="sending">{{$t('commonWalletHome.swap')}}</a-button>
                </div>
            </div>
        </div>
    </div>
</template>
<script>
import Breadcrumb from '../Breadcrumb'
import {mapState} from 'vuex'
import {varifyPositiveInt} from '../../core/utils.js'
import {SWAP_ADDRESS, DEFAULT_SCRYPT} from '../../core/consts'
import {Crypto, SDK} from 'ontology-ts-sdk'

export default {
    name: 'CommonTokenSwap',
    data() {
        const currentWallet = JSON.parse(sessionStorage.getItem('currentWallet'))
        const routes = [{name: currentWallet.label, path:'/dashboard'}]
        return {
            currentWallet,
            routes,
            amount: 0,
            password:'',
            sending:false,
            validAmount:true,
            validPassword:true,
            nep5Ont: 0
        }
    },
    components: {
        Breadcrumb
    },
    computed: {
    },
    mounted(){
        this.getNep5Balance();
    },
    methods: {
        getNep5Balance() {
            const NEO_TRAN = 100000000;
            SDK.getNeoBalance(this.currentWallet.address).then(res => {
                if(res.result) {
                    const nep5Ont = res.result / NEO_TRAN
                    this.nep5Ont = nep5Ont;
                } else {
                    this.nep5Ont = 0;
                }
            })
        },
        backToWallets() {
            this.$router.push({name: 'Wallets'})
        },
        cancel() {
            this.$router.push('/dashboard')
        },
        validateAmount(){
            if(!this.amount || !varifyPositiveInt(this.amount)) {
                this.validAmount = false;
                return;
            }
            if(Number(this.amount) > Number(this.nep5Ont)) {
                this.validAmount = false;
                return;
            }
            this.validAmount = true;
        },
        validatePass(){
            if(!this.password ) {
                this.validPassword = false
                return;
            }
            this.validPassword = true;
        },
        submit() {
            if(!this.amount || !this.validAmount) {
                this.$message.error(this.$t('commonWalletHome.validAmount'))
                return;
            }
            if(!this.password) {
                this.$message.error(this.$t('commonWalletHome.emptyPass'))
                return;
            }
            const from = this.currentWallet.address
            const to = SWAP_ADDRESS
            const value = this.amount;
            const encKey = this.currentWallet.key;
            const salt = this.currentWallet.salt;
            // must transform password to base when call Ont.SDK's api
            const password = Buffer.from(this.password).toString('base64');
            const params = DEFAULT_SCRYPT;
            const resp =  SDK.neoTransfer(from, to, value, encKey,password,salt,'', params)
            if(resp.then) {
                resp.then(res => {
                    if(res.result) {
                        const title = this.$t('common.transSentSuccess')
                        this.$router.push({name:'Dashboard'})
                        setTimeout(() => {
                            this.$success({
                                title: title,
                                content: 'NEP5 Transaction hash: ' + res.result
                            })
                        }, 100)
                    } else {
                        this.$message.error(this.$t('common.networkErr'))
                    }
                })
            } else {
                if(resp.error === 53000 ) {
                    this.$message.error(this.$t('common.pwdErr'))
                    return;
                }
            }

        }
    }
}
</script>


================================================
FILE: src/components/CommonWallet/SendConfirm.vue
================================================
<style scoped>
  .confirm-container {

  }

  .drag-item {
    cursor: pointer;
  }

  .label-container {
    position: relative;
  }

  .label {
    font-weight: bold;
    font-family: 'AvenirNext-Bold';
    color: #5E6369;
    font-size: 1.25rem;
    margin: 0;
  }

  .asset-table {
    padding: 5px 50px;
  }

  .asset-item {
    border-bottom: 1px solid #dddddd;
    padding: 10px 20px;
  }

  .asset-item span {
    width: 30%;
    display: inline-block;
    text-align: left;
  }

  .asset-item :nth-child(2) {
    width: 69%;
    display: inline-block;
    text-align: right
  }

  .select-sponsor {
    margin-left: 20px;
    width: 80%;
    margin-bottom: 15px;
  }

  .circle {
    display: inline-block;
    text-align: center;
    border: 1px solid #dddddd;
    border-radius: 50%;
    width: 1.5rem;
    height: 1.5rem;
    line-height: 1.5rem;
    background: #FBE45A;
  }

  .confirm-btns {
    position: fixed;
    bottom: 0;
    left: 4rem;
    height: 5.3rem;
    width: calc(100% - 4rem);
    /* z-index: 1000; */
    box-shadow: 0 -1px 6px 0 #F2F2F2;
    background: #ffffff;
  }

  .fee {
    padding-left: 20px;
    padding-top: 10px;
    margin-bottom: 50px;
  }

  .sponsor-select {
    padding-left: 4rem;
  }

  .sponsor-label {
    margin-bottom: 20px;
  }

  .sponsor-label :last-child {
    float: right;
  }

  .drag-container {
    margin-top: 20px;
    padding-left: 4rem;
  }

  .payer-item {
    height: 30px;
  }

  .payer-item:hover {
    background: #F5F7FB;
  }

  .payer-item:hover span {
    color: #196BD8 !important;
  }

  .payer-item :nth-child(2) {
    margin-left: 14px;
  }

  .payer-item :nth-child(3) {
    float: right;
    margin-right: 14px;
  }

  .btns-container {
    width: 500px;
    margin: 20px auto;
  }

  .btns-container :last-child {
    float: right;
  }

  .label {
    font-weight: bold;
    font-family: 'AvenirNext-Bold';
    color: #5E6369;
    font-size: 1.25rem;
    margin: 0;
  }

  .input-content {
    padding-left: 4rem;
  }

  .input-check {
    margin-top: 12px;
    margin-bottom: 20px;
    font-family: AvenirNext-Medium;
    font-size: 14px;
    color: #000000;
  }

</style>

<template>
    <div class="confirm-container clearfix">
            <p class="label">{{$t('sharedWalletHome.send')}}</p>

        <div class="asset-table">
            <div class="asset-item">
                <span class="font-medium">{{$t('sharedWalletHome.amount')}}</span>
                <span class="font-medium-black">{{transfer.amount}} {{transfer.asset}}</span>

            </div>
            <div class="asset-item">
                <span class="font-medium">{{$t('sharedWalletHome.recipient')}}</span>
                <span class="font-medium-black">{{transfer.to}}</span>
            </div>
            <div class="fee font-medium-black">{{$t('sharedWalletHome.fee')}}: {{transfer.gas}} ONG</div>
        </div>

       <p class="label">{{$t('sharedWalletHome.confirmation')}}</p>
        <div class="input-content">
            <div>
                <a-checkbox @change="onChange" :checked="checked" class="input-check">{{$t('sharedWalletHome.agreeToSend')}}</a-checkbox>

                <a-input type="password" class="input"  v-if="isCommonWallet"
                :placeholder="$t('sharedWalletHome.inputPassToTransfer')"
                v-model="password"></a-input>

                <p class="font-medium" v-if="!isCommonWallet">{{$t('ledgerWallet.connectApp')}}</p>
                <p v-if="ledgerStatus">
                   <span class="font-medium-black">{{$t('ledgerWallet.status')}}: </span>
                    <span class="font-medium">{{ledgerStatus}}</span>
                </p>
            </div>
        </div>


        <div class="confirm-btns">
            <div class="btns-container">
                <a-button type="default" class="btn-cancel" @click="back">{{$t('sharedWalletHome.back')}}</a-button>
                <a-button type="primary" class="btn-next" @click="submit" :disabled="sending">{{$t('sharedWalletHome.submit')}}</a-button>
            </div>

        </div>
    </div>
</template>
<script>
import {mapState} from 'vuex'
import {legacySignWithLedger} from '../../core/ontLedger'
import {Oep4} from 'ontology-ts-sdk'
import { TEST_NET, MAIN_NET, ONT_CONTRACT, ONT_PASS_NODE, DEFAULT_SCRYPT } from '../../core/consts'
import {Crypto, OntAssetTxBuilder, TransactionBuilder, utils, RestClient, TxSignature} from 'ontology-ts-sdk'
import axios from 'axios';
import {getDeviceInfo, getPublicKey, checkPublicKeyIsInTheConnectedLedger} from '../../core/ontLedger'
// import $ from 'jquery'
import {BigNumber} from 'bignumber.js'
import { getRestClient } from '../../core/utils'

export default {
  name: 'SendConfirm',
  mounted: function () {
      const currentWallet = JSON.parse(sessionStorage.getItem('currentWallet'));
      if(currentWallet.key) {
          return;
      }
      this.getDevice()
      let that = this;
      this.intervalId = setInterval(() => {
        that.getDevice()
      }, this.interval)
    },
    beforeDestroy(){
      clearInterval(this.intervalId)
    },
  data() {
    const net = localStorage.getItem('net');
    const currentWallet = JSON.parse(sessionStorage.getItem('currentWallet'));
    return {
      interval:10000,
      invervalId: '',
      currentWallet,
      checked: false,
      password: '',
      isCommonWallet: currentWallet.key ? true: false,
      ledgerStatus: '',
      publicKey: '',
      sending: false
    }
  },
  computed: {
    ...mapState({
      transfer: state => state.CurrentWallet.transfer
    })
  },
  methods: {
    back() {
      this.$emit('backEvent')
    },
    onChange() {
      this.checked = !this.checked;
    },
    getDevice() {
        if(this.publicKey) {
            return;
        }
        getDeviceInfo().then(res => {
          console.log('device: ' + res)
          this.device = res;
          this.getPublicKey()
        }).catch(err => {
          console.log(err)
          this.publicKey = '';
          if (err === 'NOT_FOUND') {
            this.ledgerStatus = this.$t('common.ledgerNotOpen')
          } else if (err === 'NOT_SUPPORT') {
            this.ledgerStatus = this.$t('common.ledgerNotSupported')
          } else {
            this.ledgerStatus = this.$t('common.pluginDevice')
          }
        })
      },
      getPublicKey() {
        if(this.publicKey) {
            return;
        }
        getPublicKey().then(res => {
          console.log('pk info: ' + res);
          this.publicKey = res
          this.ledgerStatus = this.$t('common.readyToSubmit')
        }).catch(err => {
          this.ledgerStatus = this.$t('common.pluginDevice');
          // this.ledgerStatus = err.message
        })
      },
      sendTx(tx){
          const restClient = getRestClient();
          restClient.sendRawTransaction(tx.serialize()).then(res => {
          console.log(res)
          this.$store.dispatch('hideLoadingModals')
          if (res.Error === 0) {
            this.$message.success(this.$t('common.transSentSuccess'))
          } else if (res.Error === -1) {
            const err = res.Result.indexOf('cover gas cost') > -1 ? this.$t('common.ongNoEnough') : res.Result
            this.$message.error(err)
            return;
          } else {
            this.$message.error(res.Result)
            return;
          }
          this.$emit('sendConfirmSubmit')
          const title = this.$t('common.transSentSuccess')
          setTimeout(() => {
              this.$success({
                  title: title,
                  content: 'Transaction hash: ' + utils.reverseHex(tx.getHash())
              })
          }, 100)
        }).catch(err => {
          console.log(err)
          this.$message.error(this.$t('common.networkError'))
        })
      },
    async submit() {
      if (this.isCommonWallet && (!this.password || !this.checked)) {
        this.$message.warning(this.$t('common.confirmPwdTips'))
        return;
      }
      if(!this.isCommonWallet && !this.checked) {
          this.$message.warning(this.$t('common.confirmTips'))
          return;
      }
      const asset = this.transfer.asset;
      const from = new Crypto.Address(this.currentWallet.address);
      const to = new Crypto.Address(this.transfer.to);
      const gasLimit = '20000';
      const gas = (new BigNumber(this.transfer.gas)).multipliedBy(1e9);
      const gasPrice = gas.div(parseInt(gasLimit)).toString();

      let tx;
      if(asset === 'ONT' || asset === 'ONG') {
        const amount = asset === 'ONT' ? this.transfer.amount : (new BigNumber(this.transfer.amount).multipliedBy(1e9)).toString();
         tx = OntAssetTxBuilder.makeTransferTx(asset, from, to, amount, gasPrice, gasLimit);
      } else if (this.transfer.scriptHash) {
        const contractAddr = new Crypto.Address(utils.reverseHex(this.transfer.scriptHash));
        const oep4 = new Oep4.Oep4TxBuilder(contractAddr);
        const val = new BigNumber(this.transfer.amount).multipliedBy(Math.pow(10, this.transfer.decimal));
        console.log(val)
        const amount = val.toString()
        console.log(amount)
         tx = oep4.makeTransferTx(from, to, amount, gasPrice, gasLimit, from);
      }

      if (this.isCommonWallet) {
        this.$store.dispatch('showLoadingModals')
        const enc = new Crypto.PrivateKey(this.currentWallet.key)
        let pri;
        try {
          pri = enc.decrypt(this.password, new Crypto.Address(this.currentWallet.address), this.currentWallet.salt, DEFAULT_SCRYPT)
        } catch (err) {
          this.sending = false;
          console.log(err);
          this.$store.dispatch('hideLoadingModals')
          this.$message.error(this.$t('common.pwdErr'))
          return;
        }
        TransactionBuilder.signTransaction(tx, pri);
        this.sendTx(tx)
      } else {
        if(this.publicKey) {
            const neo = this.currentWallet.neo;
            const acct = this.currentWallet.acct;
            await checkPublicKeyIsInTheConnectedLedger(acct, neo, this.currentWallet.publicKey);
            this.sending = true;
            this.ledgerStatus = this.$t('common.waitForSign')
            this.$store.dispatch('showLoadingModals')
            const pk = new Crypto.PublicKey(this.currentWallet.publicKey);
            const txSig = new TxSignature();
            txSig.M = 1;
            txSig.pubKeys = [pk];
            tx.payer = from;
            const txData = tx.serializeUnsignedData();
            legacySignWithLedger(txData, neo, acct).then(res => {
            // console.log('txSigned: ' + res);
            const sign = '01' + res; //ECDSAwithSHA256
            txSig.sigData = [sign]
            tx.sigs = [txSig];
            this.sendTx(tx);
            }, err => {
                this.sending = false;
                this.ledgerStatus = '';
                this.$store.dispatch('hideLoadingModals')
                alert(err.message)
            })
        } else {
            this.$message.warning(this.$t('ledgerWallet.connectApp'))
        }
      }
    }

  }
}
</script>


================================================
FILE: src/components/CommonWallet/SendHome.vue
================================================
<template>
  <div>
    <breadcrumb :current="$t('sharedWalletHome.send')" :routes="routes"
                v-on:backEvent="backToWallets"></breadcrumb>

    <div class="send-container">
      <div class="steps">
        <a-steps :current="current">
          <a-step/>
          <a-step/>
        </a-steps>
      </div>

      <send-asset
        v-on:cancelEvent="handleCancel"
        v-on:sendAssetNext="handleSendAssetNext"
        v-if="current ===0">
      </send-asset>

      <send-confirm
        v-on:backEvent="handleConfirmBack"
        v-on:sendConfirmSubmit="handleSubmit"
        v-if="current === 1">
      </send-confirm>
    </div>
  </div>
</template>

<script>
  import Breadcrumb from '../Breadcrumb'
  import SendAsset from '../SharedWallet/Transfer/SendAsset'
  import SendConfirm from '../CommonWallet/SendConfirm'

  export default {
    name: 'CommonSendHome',
    components: {
      Breadcrumb,
      SendAsset,
      SendConfirm
    },
    data() {
      const currentWallet = JSON.parse(sessionStorage.getItem('currentWallet'))
      return {
        walletName: currentWallet.label,
        routes: [{name: currentWallet.label, path: '/dashboard'}],
        current: 0
      }
    },
    methods: {
      backToWallets() {
        this.$router.push({name: 'Wallets'})
      },
      handleCancel() {
        this.$router.go(-1);
      },
      handleSendAssetNext() {
        this.current = 1;
      },
      handleConfirmBack() {
        this.current = 0;
      },
      handleSubmit() {
        this.$router.go(-1);
      }

    }
  }
</script>

<style scoped>
  .send-container {
    width: 600px;
    margin: 0 auto;
    padding-bottom: 5.3rem;
  }

  .steps {
    height: 68px;
    padding: 0 4rem;
  }
</style>


================================================
FILE: src/components/Dapps.vue
================================================

<style scoped>
.dapps-container {
    padding: 20px 20px;
}
.dapp-item {
    margin: 15px;
    cursor: pointer;
    background: #f5f7fb;
    font-family: AvenirNext-Medium;
    font-size: 18px;
    color: #515457;
    line-height: 24px;
    height:15rem;
    border: 1px solid #f5f7fb;
}
.dapp-item:hover {
    border:1px solid #196BD8;
}

.dapp-title {
    padding: 15px;
    border-bottom: 1px solid #cccccc;
    display: flex;
    justify-content: flex-start;
    align-items: center;
}
.dapp-title > img {
    width: 30px;
    height: 30px;
    margin-right: 10px;
}

.dapp-content {
    padding: 15px;
    text-overflow: ellipsis;
    overflow: hidden;
    font-size: 14px;
}
</style>

<template>
    <div class="negative-margin-top dapps-container">
        <a-row>
            <a-col :md="8" :lg="8" :xl="6">
                <div @click="handleExchangeChangelly" class="dapp-item">
                    <div class="dapp-title">
                        <img :src="require('../assets/changelly.png')" alt />
                        <span>{{$t('exchange.changelly')}}</span>
                    </div>
                    <p class="dapp-content">Cryptocurrency Exchange Platform</p>
                </div>
            </a-col>
            <a-col :md="8" :lg="8" :xl="6">
                <div
                    @click="handleExchangeCryptonex"
                    class="dapp-item"
                    :title="$t('exchange.cryptonex')"
                >
                    <div class="dapp-title">
                        <img :src="require('../assets/cryptonex.png')" alt />
                        <span>{{$t('exchange.cryptonex')}}</span>
                    </div>
                    <p class="dapp-content">
                        Buy Bitcoin, Ethereum, Cryptonex
                        Quick online purchase using a bank card
                    </p>
                </div>
            </a-col>
            <!-- <a-col :md="8" :lg="8" :xl="6">
                <div
                    class="dapp-item"
                    @click="handleDappSesameseed"
                >
                    <div class="dapp-title">
                        <img :src="require('../assets/sesameseed.png')" alt />
                        <span>{{$t('dapps.sesameSeed')}}</span>
                    </div>
                    <p class="dapp-content">{{$t('dapps.sesameseedDesc')}}</p>
                </div>
            </a-col> -->
            <a-col :md="8" :lg="8" :xl="6">
                <div
                    class="dapp-item"
                    @click="handleOntidMgmt"
                >
                    <div class="dapp-title">
                        <img :src="require('../assets/ontid.svg')" alt />
                        <span>ONT ID</span>
                    </div>
                    <p class="dapp-content">{{$t('dapps.ontidMgmt')}}</p>
                </div>
            </a-col>
        </a-row>
    </div>
</template>

<script>
import axios from "axios";
import { isNumber, isNullOrUndefined } from "util";
import { open } from "../core/utils";

export default {
    name: "Dapps",
    components: {},
    data() {
        return {
            result: [],
            results: [],
            coin_short: "",
            coin_long: "",
            price: "",
            mcap: "",
            vol: "",
            dailychange: "",
            filteredlist: "",
            interval: 60000,
            loading: true
        };
    },
    mounted: function() {
        this.$confirm({
            title: this.$t('dapps.notification'),
            content: this.$t('dapps.userPolicy'),
            onOk() {},
            onCancel: () => {
                this.$router.back();
            }
        })
    },
    computed: {},
    beforeDestroy() {
        clearInterval(this.interval);
    },
    created: function() {
        this.getImageData();
    },
    methods: {
        handleExchangeChangelly() {
            // this.$router.push({ name: "Changelly" });
            const changellyURL =
                "https://widget.changelly.com?currencies=&from=btc&to=ont&amount=1&address=&fiat=true&fixedTo=false&theme=default&ref_id=su5srryl1mhz4fno&merchant_id=su5srryl1mhz4fno";
            open(changellyURL);
        },
        handleExchangeCryptonex() {
            // this.$router.push({ name: "Cryptonex" });
            const cryptonexURL = "https://wallet.cryptonex.org/member/sign-in";
            open(cryptonexURL);
        },
        handleDappSesameseed() {
            this.$router.push({name: 'AuthorizeLoginSesameseed'});
        },
        handleOntidMgmt() {
            this.$router.push({name:'Identitys'})
        },
        formatPrice(value) {
            if (isNumber(value)) {
                let val = (value / 1)
                    .toFixed(2)
                    .replace(/\B(?=(\d{3})+(?!\d))/g, ",");
                return "$" + val;
            } else return value;
        },
        setColor: num => {
            return num > 0 ? "color:green;" : "color:red;";
        },
        reorderArray(array, initialIndex, destinationIndex) {
            const itemOfInterest = array[initialIndex];
            array.splice(initialIndex, 1);
            array.splice(destinationIndex, 0, itemOfInterest);

            return array;
        },
        getPrices() {
            this.loading = true;
            const url = "http://coincap.io/front";
            this.axios
                .get(url)
                .then(response => {
                    if (response.status === 200 && response.data) {
                        const pricelist = response.data;

                        const filteredlist = pricelist.map(t => {
                            const coin_short = t.short;
                            const coin_long = t.long;
                            const price = t.price;
                            const mcap = t.mktcap;
                            const vol = t.volume;
                            const dailychange = t.cap24hrChange;

                            return {
                                coin_short,
                                coin_long,
                                price,
                                mcap,
                                vol,
                                dailychange
                            };
                        });

                        try {
                            // Find ONT in list and re-order it to top of the list
                            let ONTindex = filteredlist.findIndex(
                                filteredlist =>
                                    filteredlist.coin_long == "Ontology"
                            );
                            const reorderedArray = this.reorderArray(
                                filteredlist,
                                ONTindex,
                                0
                            );
                            this.results = reorderedArray;

                            this.loading = false;
                        } catch (err) {
                            this.results = filteredlist;
                            console.log(err);
                        }
                    } else {
                        console.log(response);
                    }
                })
                .catch(err => {
                    this.loading = false;
                    console.log(err);
                });
        },
        test: function(from, to) {
            this.splice(to, 0, this.splice(from, 1)[0]);
        },
        getImageData: function() {
            let self = this;

            this.axios
                .get("https://min-api.cryptocompare.com/data/all/coinlist")
                .then(response => {
                    if (response.status === 200 && response.data) {
                        this.imageData = response.data.Data;
                        this.getPrices();
                    }
                })
                .catch(err => {
                    this.getPrices();
                    console.error(err);
                });
        },
        getCoinImage: function(short) {
            try {
                if (short.length > 0) {
                    return (
                        "https://www.cryptocompare.com" +
                        this.imageData[short].ImageUrl
                    );
                } else {
                    return "";
                }
            } catch (err) {
              //
            }
        },
        refresh() {
            this.$store.dispatch("showLoadingModals");
            setTimeout(() => {
                this.$store.dispatch("hideLoadingModals");
            }, 8000);
            this.getPrices();
        }
    }
};
</script>


================================================
FILE: src/components/Dashboard.vue
================================================
<style scoped>
  .header-header {
    height: 4rem;
    padding: 1.1rem 0;
    width: 100%;

  }

  .home-container {
    padding: 0 20px;
    height: 100%;
  }

  .content-container {
    display: flex;
  }

  .left-half {
    flex:1;
    padding-right: 67px;
  }

  .right-half {
    flex:1;
  }

  .asset {
    margin: 20px auto;
    display: flex;
    flex-direction: row;
    justify-content: space-around
  }

  .claim-btn {
    text-align: center;
  }

  .rule {
    text-align: center;
  }

  .owners-table {

  }

  .table-item {
    margin: 10px 0;
  }

  .table-item :first-child {
    width: 72px;
    overflow: hidden;
    display: inline-block;
    text-overflow: ellipsis;
  }

  .table-item :last-child {
    float: right;
  }

  .wallet-info {
    position: relative;
    font-family: AvenirNext-Regular;
    font-size: 0.88rem;
  }

  .wallet-info p {
    margin-bottom: 4px;
  }

  .wallet-type {
    position: absolute;
    width: 4rem;
    height: 4rem;
    background: url('../assets/commonwallet.png') center center;
    background-size: cover;
    right: 0;
    top: -12px;
  }

  .copayer-header {
    padding-bottom: 5px;
    border-bottom: 1px solid #DFE2E9;
  }

  .copayer-header :last-child {
    float: right;
    font-family: AvenirNext-Bold;
    font-size: 14px;
    color: #6F7781;
  }

  .copayer-header :first-child {
    font-family: AvenirNext-Bold;
    font-size: 14px;
    color: #000000;
  }

  .check-more {
    font-family: AvenirNext-Medium;
    font-size: 12px;
    color: #227EEC;
    text-align: center;
    cursor: pointer;
    width:100%;
    float:left;
  }
  .check-more:hover {
    color:#619AE5;
  }

  .txList-header {
    padding-bottom: 5px;
    border-bottom: 1px solid #F4F4F6;
    position: relative;
    margin-bottom:10px;
  }

  .txList-header :first-child {
    font-family: AvenirNext-Bold;
    font-size: 14px;
    color: #000000;
    text-align: center;
  }

  /* .txList-header :last-child {
    width: 64px;
    height: 64px;
    display: block;
    float: right;
    background: url('../assets/transaction.png');
    background-size: contain;
    top: -20px;
    right: 0;
    position: absolute;
  } */

  .pending-tx {
    margin-bottom: 50px;
    height: 30%;
    overflow: scroll;
  }



  .wallet-pk {
    word-break: break-all;
  }



  .commonWallet-btn {
    width: 70px;
    height: 28px;
    border-radius: 0;
    background: #FBE45A;
    padding: 0;
    font-family: AvenirNext-Medium;
    font-size: 14px;
    color: #5E6369;
    border: none;
  }
  .btn-swap {
    margin-left: 30px;
  }


.nep5-label :first-child{
  display: block;
  height:16px;
}
.nep5-label :last-child {
  font-size: 12px;
}

.oep4-container  {
  display: flex;
  margin-bottom:30px;
  align-items:center;
}
.icon-add-oep4 {
  margin-left: 20px;
  font-size: 20px;
  cursor: pointer;
}
.left-footer {
  margin-top:20px;
}
</style>
<template>
  <div class="home-container">
    <breadcrumb :current="currentWallet.label" v-on:backEvent="handleBack"></breadcrumb>
    <div class="wallet-info">
      <p class="font-regular">
        {{$t('sharedWalletHome.address')}}: <span class="font-gray">{{address}}</span>
        <span class="common-icon copy-icon" @click="copy(address)"></span>
      </p>
    </div>
    <div class="content-container">

      <div class="left-half">
        <div class="wallet-balance">
          <div>
            <span>{{$t('sharedWalletHome.balance')}}</span>
            <span class="common-icon  refresh-icon" @click="refresh(true)"></span>
          </div>
          <span class="common-icon add-icon" @click="addOep4"></span>

        </div>
        <div class="asset-container">
          <div class="asset-item">
            <span class="asset-label">ONT</span>
            <span class="asset-amount">{{balance.ont}}</span>
          </div>
          <!-- <div class="asset-value">${{balance.ontValue}}</div> -->

          <div class="asset-item">
            <span class="asset-label">ONG</span>
            <span class="asset-amount">{{balance.ong}}</span>
          </div>

          <div class="asset-item" v-for="item of oep4s" :key="item.contract_hash">
            <span class="asset-label">{{item.symbol}}</span>
            <span class="asset-amount">{{item.balance}}</span>
          </div>

          <!-- <div class="asset-value">{{'$900'}}</div> -->
          <!-- <div class="asset-ong" v-if="currentWallet.key">
            <div class="asset-label nep5-label">
              <span>ONT</span>
              <span>(NEP-5)</span>
            </div>
            <span class="asset-amount">{{nep5Ont}}</span>
            <a-button type="default" class="commonWallet-btn btn-swap"
          @click="toSwap">{{$t('commonWalletHome.swap')}}</a-button>
          </div> -->

        </div>

        <div class="left-footer">
          <div class="claim-ong-container">
            <div class="claim-ong">
              <div class="claim-ong-item ">
                <span>{{$t('commonWalletHome.claimableOng')}}: </span>
                <span>{{balance.unboundOng}}</span>
              </div>
              <div class="claim-ong-item ">
                <span>{{$t('commonWalletHome.unboundOng')}}: </span>
                <span>{{balance.waitBoundOng}}</span>
              </div>
            </div>
            <div class="redeem-container">
              <a-button type="default" class="btn-redeem"
              @click="redeemOng">{{$t('commonWalletHome.redeem')}}</a-button>
              <redeem-info-icon></redeem-info-icon>
            </div>
          </div>

          <div>
            <a-button class="asset-btn" type="primary" @click="sendAsset">
              <i class="fa fa-paper-plane"></i>
              {{$t('sharedWalletHome.send')}}
            </a-button>
            <a-button class="asset-btn" type="primary" @click="commonReceive">
              <i class="fa fa-qrcode"></i>
              {{$t('sharedWalletHome.receive')}}
            </a-button>
          </div>
        </div>

      </div>

      <div class="right-half">

        <div class="completed-tx">
          <div class="txList-header">
            <span>{{$t('sharedWalletHome.completedTx')}}</span>
            <!-- <span class="transfer-icon"></span> -->
          </div>
          <div v-for="(tx,index) in completedTx" :key="tx.txHash+index" class="tx-item"
               @click="showTxDetail(tx.txHash)">
            <span>{{tx.txHash.substring(0, 40) + '...'}}</span>
            <span>{{tx.amount}} {{tx.asset}}</span>
          </div>
          <div class="check-more" v-if="completedTx.length > 6" @click="checkMoreTx">
            {{$t('sharedWalletHome.checkMore')}}
            <i class="fa fa-chevron-right icon-arrow"></i>
          </div>
        </div>

      </div>
    </div>

    <a-modal
        :title="$t('redeemInfo.info')"
        v-model="redeemInfoVisible"
        @ok="handleModalOk"
        >
          <p class="font-regular"><span class="font-medium"></span> {{$t('redeemInfo.noClaimableOng')}}</p>
      </a-modal>

    <oep4-selection :visible="showOep4Selection" @closeOep4Selection="closeOep4Selection" ></oep4-selection>

  </div>
</template>

<script>
  import {mapState} from 'vuex'
  import {TEST_NET, MAIN_NET, ONT_CONTRACT, ONT_PASS_NODE} from '../core/consts'
  import {Crypto, OntAssetTxBuilder, RestClient, SDK} from 'ontology-ts-sdk'
  import axios from 'axios';
  import Breadcrumb from './Breadcrumb'
import { BigNumber } from 'bignumber.js';
import RedeemInfoIcon from './RedeemInfoIcon'
import Oep4Selection from './Common/Oep4Selection'
import { open, getRestClient, getTransactionListUrl, getBalanceUrl } from '../core/utils'
const ONG_GOVERNANCE_CONTRACT = 'AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK'

  export default {
    name: 'Dashboard',
    components: {
      Breadcrumb,
      RedeemInfoIcon,
      Oep4Selection
    },
    data() {
      const currentWallet = JSON.parse(sessionStorage.getItem('currentWallet'));
      const net = localStorage.getItem('net');
      const network = net && net === 'TEST_NET' ? this.$t('common.testNet') : this.$t('common.mainNet');

      return {
        currentWallet,
        publicKey: currentWallet.publicKey,
        address: currentWallet.address,
        amount: 0,
        toAddress: '',
        transactions: '',
        asset: 'ONT',
        network: network,
        completedTx: [],
        intervalId: '',
        interval:15000,
        redeemInfoVisible: false,
        requestStart: false,
        showOep4Selection: false
      }
    },
    created() {
      this.$store.commit('CLEAR_NATIVE_BALANCE')
      this.$store.commit('CLEAR_OEP4S_BALANCES')
    },
    mounted: function () {
      //UPDATE_CURRENT_WALLET
      const wallet = {
            address: this.address,
            name: this.currentWallet.label
          }
      this.$store.commit('UPDATE_CURRENT_WALLET', {wallet})
      this.refresh(true)
      // this.$store.dispatch('queryBalanceForOep4', this.currentWallet.address)
      this.intervalId = setInterval(() => {
          this.refresh(false)
      }, this.interval)
    },
    computed: {
      ...mapState({
        nep5Ont : state => state.CurrentWallet.nep5Ont,
        balance: state => state.CurrentWallet.balance,
        oep4s: state => state.Tokens.oep4WithBalances
      })
    },
    beforeDestroy(){
        clearInterval(this.intervalId)
        this.$store.commit('UPDATE_NEP5_ONT', {nep5Ont:0})
    },
    methods: {
      handleBack() {
        this.$router.push({name: 'Wallets'})
      },
      async getTransactions() {
        const url = getTransactionListUrl(this.address);
        try {
          const res = await this.httpService(url)
          const txlist = res.result;
            const completed = []
            for(const t of txlist) {
              for(const tx of t.transfers) {
                const asset = tx.asset_name.toUpperCase()
                // if(tx.to_address === ONG_GOVERNANCE_CONTRACT && asset === 'ONG') {
                //   continue;
                // }
                let amount = asset === 'ONT' ? parseInt(tx.amount) : tx.amount;
                if (tx.from_address === this.address) {
                    amount = '-' + amount;
                } else {
                  amount = '+' + amount;
                }
                completed.push({
                  txHash: t.tx_hash,
                  asset,
                  amount: amount
                })
              }

            }
            this.completedTx = completed.slice(0,10);
            return completed; // fetch tx history succeed
        } catch(err) {
          console.log(err);
          this.$message.error(this.$t('dashboard.getTransErr'))
          return false; // fetch tx history failed
        }
        /* return this.axios.get(url + '/api/v1/explorer/address/' + this.address + '/10/1').then(response => {
          if (response.status === 200 && response.data && response.data.Result) {
            const txlist = response.data.Result.TxnList;
            const completed = []
            for(const t of txlist) {
              // if(t.TransferList.length === 1 && t.TransferList[0].ToAddress === ONG_GOVERNANCE_CONTRACT) {
              //   continue;
              // }
              for(const tx of t.TransferList) {
                const asset = tx.AssetName.toUpperCase()
                if(tx.ToAddress === ONG_GOVERNANCE_CONTRACT && asset === 'ONG' && Number(tx.Amount) == 0.01) {
                  continue;
                }
                let amount = asset === 'ONT' ? parseInt(tx.Amount) : tx.Amount;
                if (tx.FromAddress === this.address) {
                    amount = '-' + amount;
                } else {
                  amount = '+' + amount;
                }
                completed.push({
                  txHash: t.TxnHash,
                  asset,
                  amount: amount
                })
              }

            }
            this.completedTx = completed;
            return true; // fetch tx history succeed
          } else {
            console.log(response)
            return true;
          }
        }).catch(err => {
          console.log(err);
          this.$message.error(this.$t('dashboard.getTransErr'))
          return false; // fetch tx history failed
        }) */
      },
      getUnclaimOng() {
        const restClient = getRestClient();
        restClient.getAllowance('ong', new Crypto.Address(ONT_CONTRACT), new Crypto.Address(this.address)).then(res => {
          console.log(res.Result)
          this.unclaimOng = new BigNumber(res.Result).div(1e9);
        }).catch(err => {
          this.$message.error(this.$t('common.networkErr'))
        })
      },
      getBalance() {
        return this.$store.dispatch('getNativeBalance', {address: this.address}).then(res => {
          if(!res){
            this.$message.error(this.$t('dashboard.getBalanceErr'))
          }
          return res;
        })
      },
      getOep4Balances() {
        this.$store.dispatch('fetchTokenBalances', {address: this.address}).then(res => {
          if(!res) {
            this.$message.error(this.$t('dashboard.getBalanceErr'))
          }
          return res;
        })
      },
      getNep5Balance() {
        const NEO_TRAN = 100000000;
        SDK.getNeoBalance(this.currentWallet.address).then(res => {
          let nep5Ont = 0;
          if(res.result) {
            nep5Ont = res.result / NEO_TRAN
          }
          this.$store.commit('UPDATE_NEP5_ONT', {nep5Ont})
        })
      },
      getExchangeCurrency() {
        const currency = 'ont'
        const goaltype = 'USD'
        const amount = this.balance.ont;
        const url = `https://service.onto.app/S3/api/v1/onto/exchangerate/reckon/${currency}/${goaltype}/${amount}`;
        axios.get(url).then(res => {
          console.log(res)
          if (res.data.Result) {
            this.balance.ontValue = res.data.Result.Money
          }
        })
      },
      refresh(showLoading) {
        // this.$store.dispatch('showLoadingModals')
        // const that = this
        // setTimeout(() => {
        //     that.$store.dispatch('hideLoadingModals')
        // }, 500)
        if(showLoading) {
          this.$store.dispatch('showLoadingModals')
        }
        if(this.requestStart) {
          return;
        }
        this.requestStart = true;
        Promise.all([
          this.getBalance(),
          this.getTransactions(),
          this.getOep4Balances(),
        ]).then(res => {
          console.log(res)
          this.requestStart = false;
          this.$store.dispatch('hideLoadingModals')
        })

        // this.getNep5Balance();
      },
      sendAsset() {
        if(Number(this.balance.ong) < 0.01) {
          this.$message.warning(this.$t('common.ongNoEnough'))
          return;
        }
        this.$store.commit('CLEAR_CURRENT_TRANSFER');

        this.$router.push({name: 'CommonSendHome'})
      },
      commonReceive() {
        this.$router.push({path: '/commonWalletReceive/commonWallet'})
      },
      redeemOng() {
          if(this.balance.unboundOng == 0) {
            this.redeemInfoVisible = true;
            return;
          }
          const redeem = {
              claimableOng : this.balance.unboundOng,
              balance: this.balance.ong
          }
        this.$store.commit('UPDATE_CURRENT_REDEEM', {redeem: redeem})
        if(this.currentWallet.key) {
            this.$router.push({path:'/commonWalletRedeem/commonWallet'})
        } else {
            this.$router.push({path: '/commonWalletRedeem/hardwareWallet'})
        }
      },
      goBack() {
        this.$router.push({name: 'Wallets'})
      },
      checkMoreTx() {
        let url = `https://explorer.ont.io/address/${this.address}/10/1`
        if (this.network === 'TestNet') {
          url += '/testnet'
        }
        open(url)
      },
      showTxDetail(txHash) {
        let url = `https://explorer.ont.io/transaction/${txHash}`
        if (this.network === 'TestNet') {
          url += '/testnet'
        }
        open(url)
      },
      copy(value) {
            this.$copyText(value);
            this.$message.success(this.$t('common.copied'))
      },
      toSwap() {
        this.$router.push({name: 'CommonTokenSwap'})
      },
      handleModalOk() {
        this.redeemInfoVisible = false;
      },
      checkMoreOep4() {
        this.$router.push({name: 'Oep4Home'})
      },
      addOep4() {
        this.showOep4Selection = true;
      },
      closeOep4Selection() {
        this.showOep4Selection = false;
        this.$store.dispatch('showLoadingModals')
        this.$store.dispatch('fetchTokenBalances', {address: this.address})
      }
    }
  }
</script>


================================================
FILE: src/components/Exchange/Changelly/Changelly.vue
================================================
<style scoped>
.changelly-container {
  position: relative;
  padding-bottom: 75%;
  height: 0;
  overflow: hidden;
}
.changelly-container iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
</style>
<template>
    <div>
      <breadcrumb  :current="$t('exchange.exchange')" v-on:backEvent="handleRouteBack"></breadcrumb>
      <!-- Remove this div and enable this.loadPage in mounted() to open in a new window -->
      <!-- <div class="changelly"
        <iframe src="https://widget.changelly.com?currencies=&from=btc&to=ont&amount=1&address=&fiat=true&fixedTo=false&theme=default&ref_id=su5srryl1mhz4fno&merchant_id=su5srryl1mhz4fno" width="100%" height="600" class="changelly" scrolling="no" onLoad="function v(e){var t=e.target,n=t.parentNode,r=t.contentWindow,a=function(){return r.postMessage({width:n.offsetWidth},'https://widget.changelly.com')};window.addEventListener('resize',a),a()};v.apply(this, arguments);" style="overflow-y: hidden; border: none">Can't load widget</iframe>
      </div> -->
      </div>
</template>

<script>
import Breadcrumb from "../../Breadcrumb";
const changellyURL =
  "https://widget.changelly.com?currencies=&from=btc&to=ont&amount=1&address=&fiat=true&fixedTo=false&theme=default&ref_id=su5srryl1mhz4fno&merchant_id=su5srryl1mhz4fno";
const { BrowserWindow } = require('@electron/remote')
const open = require('open')
export default {
  name: "Changelly",
  mounted() {
    //Changelly page set to load as iframe in current window, if new browser
    //window is preferred, enable method this.loadPage() below and remove reference
    //to iFrame in <div> above
    this.loadPage()
  },
  data() {
    return {};
  },
  components: {
    Breadcrumb
  },
  methods: {
    handleRouteBack() {
      this.$router.push({ name: "Exchange" });
    },
    loadPage() {
      open(changellyURL)
      // let win = new BrowserWindow({ width: 1000, height: 550, center: true });
      // win.on("closed", () => {
      //   win = null;
      // });
      // win.loadURL(changellyURL);
    }
  }
};
</script>

================================================
FILE: src/components/Exchange/Cryptonex/Cryptonex.vue
================================================
<style scoped>
.cryptonex-container {
  position: relative;
  padding-bottom: 75%;
  height: 0;
  overflow: hidden;
}
.cryptonex-container iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
</style>
<template>
    <div>
      <breadcrumb  :current="$t('exchange.exchange')" v-on:backEvent="handleRouteBack"></breadcrumb>
   </div>
</template>

<script>
import Breadcrumb from "../../Breadcrumb";
const cryptonexURL = "https://wallet.cryptonex.org/member/sign-in";
const { BrowserWindow } = require('@electron/remote');

export default {
  name: "Cryptonex",
  mounted() {
    this.loadPage()
  },
  data() {
    return {};
  },
  components: {
    Breadcrumb
  },
  methods: {
    handleRouteBack() {
      this.$router.push({ name: "Exchange" });
    },
    loadPage() {
      let win = new BrowserWindow({ width: 1024, height: 768, center: true });
      win.on("closed", () => {
        win = null;
        this.$router.push({ name: "Exchange" });
      });
      win.loadURL(cryptonexURL);
    }
  }
};
</script>

================================================
FILE: src/components/Home.vue
================================================

<style scoped>
  @import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro');

  .row-home {
    margin-left: -5.13rem;
  }

  .row-home .col-10 {
    padding: 0;
  }

  .img-home-page {
    width: 100%;
    height: 100%;
  }

  .div-slogan {
    margin-top: 30vh;
    text-align:left;
  }

  .go-to-wallets {
    width: 10rem;
    height: 2.5rem;
    line-height: 1.8rem;
    background-color: #196BD8;
    font-family: AvenirNext-Medium;
    font-size: 14px;
    color: #FFFFFF;
    text-align: center;
    border-radius: 0;
    margin-top: 15vh;
  }

  .div-footer-version {
    text-align: center;
    position: absolute;
    bottom:10px;
    margin-left: auto;
    margin-right: auto;
    left: 0;
    right:0;
  }
  .div-footer-version P {
    margin:0;
  }
  .home-img {
    width:100%;
    height:100%;
    background:url('../assets/home/background@1.5x.png') center center;
    background-size:cover;
  }
  .home-container {
    position:fixed;
    width:100%;
    height: 100%;
    margin-top: -4rem;
  }
  .home-slogan :first-child {
    font-family: AvenirNext-Medium;
    font-size: 16px;
    color: #000000;
    text-align: left;
    margin: 0;
  }
  .home-slogan :last-child {
    font-family: AvenirNext-Regular;
    margin: 0;
  }
  .bg-container {
    position: relative;
  }
  .home-upgrade {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 10px;
    text-align: center;
    border:1px solid #FBE45A;
    background:#FBE45A;
    font-family: AvenirNext-Regular;
  }
  .home-upgrade a {
    color: #196BD8;
  }
  .home-upgrade a:hover {
    color: rgb(50, 120, 211);
  }
</style>
<template>
  <div class="row row-home home-container">
    <div class="col-10 bg-container">
      <!-- <img class="img-home-page" src="./../assets/home/background@1.5x.png" alt=""> -->
      <div class="home-img"></div>
      <div class="home-upgrade" v-if="latest_url">
        <!-- <a-alert message="Warning" type="warning" showIcon /> -->
        {{$t('common.versionUpdate')}}
        <a @click="handleUpdate">{{$t('common.getLatestVersion')}}</a>
      </div>
    </div>
    <div class="col-2 text-center">
      <div class="div-slogan home-slogan">
          <p>OWallet</p>
          <p>A comprehensive Ontology desktop wallet.</p>
      </div>
      <div>
        <router-link class="btn btn-default go-to-wallets text-center" to="Wallets">
          <div>ENTER →</div>
        </router-link>
      </div>

      <div class="div-footer-version">
        <p>Version: {{version}}</p>
        <p>Powered by Ontology</p>
      </div>
    </div>


  </div>
</template>

<script>
  import {mapState} from 'vuex'
  import {TEST_NET, MAIN_NET} from '../core/consts'
  import axios from 'axios';
  import pkg from '../../package.json'
  const { BrowserWindow } = require('@electron/remote')
  import { open } from '../core/utils'
import {Modal} from 'ant-design-vue'
  export default {
    name: 'Home',
    data() {
      return {
        version: pkg.version,
        latest_url: ''
      }
    },
    mounted() {
      this.$store.dispatch('showLoadingModals');
      const url = 'https://api.github.com/repos/ontio/OWallet/releases/latest';
      const version = this.version;
      axios.get(url).then(res => {
        this.$store.dispatch('hideLoadingModals');
        if (res.data && res.data.tag_name !== version){
          console.log('not latest')
          this.latest_url = res.data.html_url
          Modal.confirm({
                centered: true,
                okText: this.$t('common.toUpdate'),
                cancelText: this.$t('common.cancel'),
                title: this.$t('dapps.notification'),
                content: this.$t('common.availableNewVersion'),
                onOk() {open(res.data.html_url)},
                onCancel(){}
            })
        }
      }).catch(err => {
        console.log(err);
        this.$store.dispatch('hideLoadingModals');
      })
    },
    methods: {
      handleUpdate() {
        const url = this.latest_url;
        open(url);
        // let win = new BrowserWindow({width: 800, height: 600, center: true});
        // win.on('closed', () => {
        //   win = null
        // })

        // // Load a remote URL
        // win.loadURL(url)
      }
    }
  }
</script>



================================================
FILE: src/components/Identitys/Create/BasicInfo.vue
================================================
<template>
  <div>
    <div class="basic-label">
      <a-input class="input" :placeholder="$t('createIdentity.label')" v-model="label"
          v-validate="{required: true}" name="label"
      ></a-input>
      <span class="v-validate-span-errors" v-show="errors.has('label')">{{ errors.first('label') }}</span>

      <a-input type="password" class="input input-password"
               v-validate="{required: true ,min:6}" name="password"
               v-model="password" :placeholder="$t('createIdentity.password')"></a-input>
      <span class="v-validate-span-errors" v-show="errors.has('password')">{{ errors.first('password') }}</span>

      <a-input type="password" class="input input-repassword"
               v-validate="{required: true , min:6, is:password}" :data-vv-as="$t('FormField.passwordConfirmation')" name="rePassword"
               v-model="rePassword" :placeholder="$t('createIdentity.rePassword')"></a-input>
      <span class="v-validate-span-errors" v-show="errors.has('rePassword')">{{ errors.first('rePassword') }}</span>

      <div class="create-select-wallet">
        <p class="font-medium-black">{{$t('createIdentity.selectWallet')}}</p>
        <a-radio-group @change="changePayerWallet" v-model="payerWalletType" class="change-payer-radio">
          <a-radio value="commonWallet">{{$t('createIdentity.commonWallet')}}</a-radio>
          <a-radio value="ledgerWallet">{{$t('createIdentity.ledgerWallet')}}</a-radio>
          <div v-if="payerWalletType === 'commonWallet'">
           <a-select :options="localCommonWallet" class="select-payer-wallet"
           :placeholder="$t('createIdentity.selectCommonWallet')"
            @change="handleChangePayer">
           </a-select>
           <a-input type="password" class="input" v-model="payerPassword" :placeholder="$t('createIdentity.payerPassword')"></a-input>
          </div>

          <div v-if="payerWalletType === 'ledgerWallet'">

            <div class="payer-ledger-status">
              <div class="font-bold" style="margin-bottom: 15px;">{{$t('ledgerWallet.connectApp')}}</div>
              <span class="font-medium-black">{{$t('ledgerWallet.status')}}: </span>
              <span class="font-medium">{{ledgerStatus}} </span>
            </div>

          </div>

        </a-radio-group>


      </div>
    </div>

    <div class="basic-pk-btns">
      <div class="btn-container">
        <a-button type="default" @click="cancel" class="btn-cancel">{{$t('createIdentity.cancel')}}</a-button>
        <a-button type="primary" @click="next" class="btn-next">{{$t('createIdentity.next')}}</a-button>
      </div>
    </div>
  </div>
</template>

<script>
  import {mapState} from 'vuex'
  import {Wallet, Account, Crypto, TransactionBuilder, TxSignature, RestClient} from "ontology-ts-sdk"
  import FileHelper from "../../../core/fileHelper"
  import dbService from '../../../core/dbService'
  import {DEFAULT_SCRYPT, TEST_NET, MAIN_NET} from '../../../core/consts'
import {legacySignWithLedger} from '../../../core/ontLedger'
import { getRestClient } from '../../../core/utils'

  export default {
    name: 'BasicInfo',
    data() {
      const net = localStorage.getItem('net');
      return {
        label: "",
        password: "",
        rePassword: "",
        createSuccess: false,
        payerWalletType: 'commonWallet',
        payerWallet: '',
        localCommonWallet:[],
        payerPassword: ''
      }
    },
    mounted(){
      this.updateLocalCommonWallets()
      this.$store.dispatch('getLedgerStatus')
    },
    beforeDestroy(){
      this.$store.dispatch('stopGetLedgerStatus')
    },
    computed: {
      ...mapState({
        ledgerStatus: state => state.LedgerConnector.ledgerStatus,
        ledgerPk : state => state.LedgerConnector.publicKey,
        ledgerWallet: state => state.LedgerConnector.ledgerWallet
      })
    },
    methods: {
      updateLocalCommonWallets() {
            var that = this;
                const localpayers = []
                dbService.find({type:'CommonWallet'}, function (err, accounts) {
                    if (err) {
                        console.log(err)
                        return;
                    }

                    for (let ac of accounts) {
                      localpayers.push(Object.assign({}, ac.wallet,
                      {value:ac.address, label:ac.wallet.label + ' ' + ac.address}))
                    }
                    that.localCommonWallet = localpayers
                })
        },
      next() {
        if(this.payerWalletType === 'commonWallet' && !this.payerWallet) {
          this.$message.error(this.$t('createIdentity.selectOneWallet'))
          return;
        }
        if(this.payerWalletType === 'commonWallet' && this.payerWallet && !this.payerPassword) {
          this.$message.error(this.$t('createIdentity.enterPassword'))
          return;
        }
        let payer;
        if(this.payerWalletType === 'commonWallet') {
          payer = new Crypto.Address(this.payerWallet.address)
        } else {
          payer = new Crypto.Address(this.ledgerWallet.address)
        }
        this.$validator.validateAll().then(result => {
          if(result) {
            let privateKey = Crypto.PrivateKey.random()
            let body = {
              label: this.label,
              privateKey: privateKey,
              password: this.password,
              payer: payer
            }
            this.$store.dispatch('createIdentityWithPrivateKey', body).then(res => {
              console.log(res)
              const tx = res;
              // const tx = Object.assign({}, res);
              this.$store.dispatch('showLoadingModals')
              if(this.payerWalletType === 'commonWallet') {
                const enc = new Crypto.PrivateKey(this.payerWallet.key)
                let pri;
                try {
                  pri = enc.decrypt(this.payerPassword, new Crypto.Address(this.payerWallet.address), this.payerWallet.salt, DEFAULT_SCRYPT)
                } catch (err) {
                  console.log(err);
                  this.$message.error(this.$t('common.pwdErr'))
                  this.$store.dispatch('hideLoadingModals')
                  return;
                }
                TransactionBuilder.addSign(tx, pri);
                this.sendTx(tx)
              } else {
                if(this.ledgerPk) {
                  this.$store.dispatch('showLoadingModals')
                  const pk = new Crypto.PublicKey(this.ledgerWallet.publicKey);
                  const txSig = new TxSignature();
                  txSig.M = 1;
                  txSig.pubKeys = [pk];
                  const txData = tx.serializeUnsignedData();
                  legacySignWithLedger(txData).then(res => {
                  // console.log('txSigned: ' + res);
                  const sign = '01' + res; //ECDSAwithSHA256
                  txSig.sigData = [sign]
                  tx.sigs.push(txSig);
                  this.sendTx(tx);
                  }, err => {
                      this.ledgerStatus = '';
                      this.$store.dispatch('hideLoadingModals')
                      alert(err.message)
                  })
              } else {
                  this.$message.warning(this.$t('ledgerWallet.connectApp'))
              }
              }
            })


          }
        })
      },
      sendTx(tx){
        const restClient = getRestClient();
          restClient.sendRawTransaction(tx.serialize()).then(res => {
          console.log(res)
          this.$store.dispatch('hideLoadingModals')
          console.log('hide')

          if (res.Error === 0) {
            this.$message.success(this.$t('common.transSentSuccess'))
          } else if (res.Error === -1) {
            this.$message.error(this.$t('common.ongNoEnough'))
            return;
          } else {
            this.$message.error(res.Result)
            return;
          }
          this.$store.commit('ADD_CREATE_IDENTITY_STEP')
          // const title = this.$t('common.transSentSuccess')
          // setTimeout(() => {
          //     this.$success({
          //         title: title,
          //         content: 'Transaction hash: ' + utils.reverseHex(tx.getHash())
          //     })
          // }, 100)
        }).catch(err => {
                    console.log(err)
                    this.$message.error(this.$t('common.networkError'))
                })
      },
      cancel() {
        this.$router.push({name: 'Identitys'})
      },
      changePayerWallet(e) {
        this.payerWalletType = e.target.value
      },
      handleChangePayer(value) {
        this.payerWallet = this.localCommonWallet.find((v)=>{return v.address === value})
      }
    }
  }
</script>

<style>
  .basic-label {
    width: 540px;
    margin: 2px auto;
  }

  .input-password {
    margin-top: 30px;
  }

  .input-repassword {
    margin-top: 10px;
  }

  .copayer-label {
    margin-left: 172px;
    margin-top: 40px;
  }

  .basic-pks {
    width: 540px;
    margin: 0px auto;
  }

  .pk-item {
    margin-bottom: 15px;
  }

  .pk-item :first-child {
    width: 150px;
    margin-right: 20px;
    display: inline-block;
  }

  .pk-item :nth-child(2) {
    width: 318px;
  }

  .delete-icon {
    height: 34px;
    width: 34px;
    /* display: inline-block; */
    background: url('../../../assets/delete.png') center center;
    background-size: contain;
    float: right;
    margin-right: 10px;
    cursor: pointer;
  }

  .basic-pk-box {
    border: 1px solid #dddddd;
    width: 100%;
    height: 300px;
    padding: 10px;
    position: relative;
  }

  .basic-pk-add {
    border-top: 1px solid #dddddd;
    width: calc(100% - 20px);
    position: absolute;
    bottom: 10px;
    left: 10px;
    padding-top: 10px;
  }

  .basic-pk-item {
    width: 100%;
    float: left;
  }

  .basic-pk-item span {
    margin-right: 10px;
  }

  .basic-add-item {
    display: inline-block;
    width: 40%;
  }

  .basic-add-item input {
    width: 80%;
  }

  .basic-pk-btns {
    position: fixed;
    bottom: 0;
    width: calc(100% - 4rem);
    height: 85px;
    left: 4rem;
    background: #FFFFFF;
    box-shadow: 0 -1px 6px 0 #F2F2F2;
    z-index: 1000;
  }

  .basic-pk-btns button:first-child {
    float: left;
  }

  .basic-pk-btns :nth-child(2) {
    float: right;
  }

  .basic-pk-btns :nth-child(3) {
    float: right;
    margin-right: 20px;
  }

  .error-input {
    border-color: red;
  }
  .create-select-wallet {
    margin-top: 15px;
  }
  .select-payer-wallet {
    width:100%;
    margin-bottom:10px;
    margin-top:15px;
  }
  .change-payer-radio {
    width:100%;
  }
  .payer-ledger-status {
    margin-top:10px;
    padding: 5px 10px;
  }
</style>



================================================
FILE: src/components/Identitys/Create/ConfirmInfo.vue
================================================
<template>
  <div class="container json-confirm-container">
    <p><b>{{$t('createIdentity.label')}}: </b> {{label}}</p>
    <p><b>{{$t('createIdentity.ontid')}}: </b> {{ ontid }}</p>


    <div class="confirm-btns">
      <div class="confirm-btn-container">
        <a-button type="default" class="btn-cancel" @click="back">{{ $t('createJsonWallet.back') }}</a-button>
        <a-button type="primary" class="btn-next" @click="next">{{ $t('createJsonWallet.next') }}</a-button>
      </div>
    </div>
  </div>
</template>

<script>
  import {mapState} from 'vuex'
  import {Crypto, Wallet, Account} from 'ontology-ts-sdk'
  import FileHelper from "../../../core/fileHelper"
  import dbService from '../../../core/dbService'
  import {WALLET_TYPE,DEFAULT_SCRYPT} from '../../../core/consts'
  import en from '../../../lang/en'
  import zh from '../../../lang/zh'

  export default {
    name: 'ConfirmInfo',
    data() {
      const langType = localStorage.getItem('user_lang') || 'en';
      const lang = langType === 'en' ? en : zh;
      return {
        lang: lang,
        processing: false
      }
    },
    computed: {
      ...mapState({
        label: state => state.CreateIdentity.label,
        ontid: state => state.CreateIdentity.ontid,
        identity: state => state.CreateIdentity.identity,
        tx: state => state.CreateIdentity.tx
      })
    },
    beforeDestroy() {
      console.log('clear')
      this.$store.commit('INIT_CREATE_IDENTITY')
    },
    methods: {
      back() {
        this.$store.commit('SUB_CREATE_IDENTITY_STEP')
      },
      downloadWallet() {
        const commonWallet = this.account
        let wallet = Wallet.create(commonWallet.label || "")
        console.log(wallet)
        wallet.scrypt.n = 16384;
        const account = Account.parseJsonObj(commonWallet)
        wallet.addAccount(account)
        FileHelper.downloadFile(wallet.toJsonObj(), commonWallet.label);
      },
      next() {
        this.$store.dispatch('showLoadingModals')
        //Download file
        // FileHelper.downloadFile(this.downloadContent)

        //save to db
        const wallet = {
          type : 'Identity',
          address: this.ontid,
          wallet: this.identity
        }
        dbService.insert(wallet, (err, newDoc) => {
          if (err) {
            console.log(err)
            this.$store.dispatch('hideLoadingModals')
            this.$message.error(this.$t('common.savedbFailed'))
          }
          // console.log(newDoc)
        })

        this.$store.commit('INIT_CREATE_IDENTITY')
        this.$message.success(this.$t('createIdentity.createSuccess'))
        this.$router.push({name: 'Identitys'})
      }
    }
  }
</script>

<style scoped>
  .json-confirm-container {
    width: 36rem;
  }

  .confirm-btns {
    position: fixed;
    bottom: 0;
    width: calc(100% - 4rem);
    height: 85px;
    left: 4rem;
    background: #FFFFFF;
    box-shadow: 0 -1px 6px 0 #F2F2F2;
    z-index: 1000;
  }

  .confirm-btn-container {
    width: 540px;
    margin: 20px auto;
  }

  .confirm-btn-container :last-child {
    float: right;
  }
  .backup-text {
    text-align: center;
    padding: 20px;
    border: 1px solid #dddddd;
    font-size: 16px;
  }
  .backup-text p {
    margin:0;
    font-size:16px !important;
  }

</style>


================================================
FILE: src/components/Identitys/CreateIdentity.vue
================================================
<template>
  <div>
    <breadcrumb :current="$t('createIdentity.create')" v-on:backEvent="back"></breadcrumb>
    <div class="shared-container">
      <a-steps :current="current" class="create-steps">
        <a-step v-for="item in steps" :key="item.title"/>
      </a-steps>
      <div class="steps-content">
        <basic-info v-if="current === 0"></basic-info>
        <confirm-info v-if="current === 1"></confirm-info>
      </div>
    </div>
  </div>

</template>

<script>
  import BasicInfo from './Create/BasicInfo'
  import ConfirmInfo from './Create/ConfirmInfo'
  import Breadcrumb from '../Breadcrumb'
  import {mapState} from 'vuex';

  export default {
    name: 'createIdentity',
    data() {
      return {
        steps: [{
          title: this.$t('createIdentity.basicInfo'),
          content: 'First-content',
        }, {
          title: this.$t('createIdentity.confirmInfo'),
          content: 'Second-content',
        }]
      }
    },
    computed: {
      ...mapState({
        current: state => state.CreateIdentity.currentStep,
      })
    },
    components: {
      BasicInfo,
      ConfirmInfo,
      Breadcrumb
    },
    methods: {
      back() {
        this.$router.push({name: 'Identitys'})
      }
    }
  }
</script>

<style scoped>
  .shared-container {
  }

  .steps-content {
  }

  .steps-action {
    margin-top: 24px;
  }

  .create-steps {
    width: 520px;
    height: 4rem;
    margin: 2px auto;
  }
</style>


================================================
FILE: src/components/Identitys/IdentityView.vue
================================================
<template>
  <div class="common-detail-container">
    <div >
      <div class="div-shared-wallet-sign">
        <span>{{ $t('identitys.identity')}}</span>
      </div>
      <div class="div-wallet-name">{{identity.label}}</div>
      <!--<img class="img-wallet-edit" src="./../assets/edit.png" alt="">-->
      <div class="div-wallet-address">
        <div>{{$t('identitys.ontid')}} :</div>
        {{identity.ontid}}
      </div>
    </div>
    <div v-show="addressCopied" class="copied-label">Copied</div>
    <img class="img-wallet-copy" src="../../assets/copy.png" @click="copyAddress(identity)" alt="">
    <div class="common-topRight-btns">
      <a-dropdown >
        <a-menu slot="overlay" >
          <a-menu-item key="1" >
            <span @click="handleExportIdentity()">{{$t('common.exportIdentity')}}</span>
          </a-menu-item>
          <a-menu-item key="2">
            <span  @click="deleteIdentity()">{{$t('common.deleteIdentity')}}</span>
          </a-menu-item>
        </a-menu>
        <a-button style="margin-left: 8px">
          {{$t('common.more')}}<a-icon type="down" />
        </a-button>
      </a-dropdown>
    </div>

    <a-modal
        :title="modalTitle"
        :visible="passModal"
        @ok="handleValidatePassword"
        @cancel="handleCancel">
          <div>
              <p class="font-medium">
                {{option==='EXPORT_ONTID' ? $t('wallets.exportOntid') : '' }}
                 {{identity.ontid}}</p>
              <div >
                <p>{{$t('common.enterIdentityPassword')}}</p>
                <a-input class="input" v-model="password" :plaecholder="$t('common.password')" type="password"></a-input>
              </div>
          </div>
    </a-modal>

    <a-modal
        :title="$t('common.exportIdentity')"
        v-model="showIdentityKeystore"
        @ok="handleShowKeystoreOk"
        >
        <div class="identity-keystore">
          <p class="font-medium">{{keystore}}</p>
        </div>
    </a-modal>
  </div>
</template>

<script>
  import {Wallet, Account, Crypto, Identity} from 'ontology-ts-sdk';
  import dbService from '../../core/dbService'
  import { formatScryptParams } from '../../core/utils'
	export default {
    name: "IdentityView",
    props: ['identity'],
    data() {
      return {
        addressCopied: false,
        modalTitle: this.$t('common.authentication'),
        passModal: false,
        password: '',
        showIdentityKeystore: false,
        keystore: '',
        option: ''
      }
    },
    methods: {
      copyAddress(identity) {
        this.$copyText(identity.ontid)
        this.addressCopied = true
        this.$nextTick(function () {
          setInterval(this.addressCopiedDisabled, 3000);
        })
      },
      addressCopiedDisabled() {
        this.addressCopied = false
      },
      handleExportIdentity() {
        this.passModal = true;
        this.option = 'EXPORT_ONTID'
      },
      deleteIdentity() {
        this.passModal = true;
        this.option = 'DELETE_ONTID'
      },
      handleCancel() {
        this.passModal = false;
        this.password = '';
      },
      handleValidatePassword() {
        if(!this.password ) {
          this.$message.error(this.$t('common.enterIdentityPassword'))
          return;
        }
        this.$store.dispatch('showLoadingModals')
        const controlData = this.identity.controls[0];
        const enc = new Crypto.PrivateKey(controlData.key)
        let pri;
        const scrypt = this.identity.scrypt ||
        {
            n : 4096,
            p : 8,
            r : 8,
            dkLen : 64
        }
        const params = formatScryptParams(scrypt);
        try {
          pri = enc.decrypt(this.password, new Crypto.Address(controlData.address), controlData.salt, params)
        } catch (err) {
          console.log(err);
          this.$store.dispatch('hideLoadingModals')
          this.$message.error(this.$t('common.pwdErr'))
          return;
        }
        if(this.option === 'DELETE_ONTID') {
          this.handleDelete();
        } else if (this.option === 'EXPORT_ONTID') {
          this.passModal = false;
          this.showIdentityKeystore = true;
          const keystore = {
            type : 'I',
            label : this.identity.label,
            algorithm : 'ECDSA',
            scrypt,
            key : this.identity.controls[0].key,
            salt: this.identity.controls[0].salt,
            address: this.identity.controls[0].address,
            parameters : {
                curve : 'secp256r1'
            }
          };
            this.keystore = JSON.stringify(keystore);
          this.$store.dispatch('hideLoadingModals')
        }
        this.password = '';
        pri.key = '';
      },
      handleDelete() {
        // remove from db
        const that = this;
        const type = 'Identity'
        const commitType = 'DELETE_IDENTITY';
        dbService.remove({type:type, address: this.identity.ontid}, {}, function(err, numRemoved) {
          if(err) {
            that.$store.dispatch('hideLoadingModals')
            that.$message.error(that.$t('wallets.deleteIdentityFailed'));
            return;
          }
           // remove from store
          that.$store.commit(commitType, {ontid: that.identity.ontid})
          that.$store.dispatch('hideLoadingModals')
          that.$message.success(that.$t('wallets.deleteIdentitySuccess'))
          that.passModal = false;
        })
      },

      handleShowKeystoreOk() {
        this.keystore = '';
        this.showIdentityKeystore = false;
      }

    }
  }
</script>

<style scoped>
  .common-detail-container {

  }
  .div-shared-wallet-sign {
    margin-top: 0.88rem;
    font-family: AvenirNext-Medium;
    font-size: 14px;
    color: #196BD8;
    cursor: default;
  }

  .div-wallet-name {
    margin-top: 1.75rem;
    font-family: AvenirNext-Medium;
    font-size: 18px;
    color: #515457;
    line-height: 24px;
    word-wrap: break-word;
  }

  .img-wallet-edit {
    position: absolute;
    top: 4.13rem;
    right: 1.41rem;
  }

  .div-wallet-address {
    font-family: AvenirNext-Regular;
    font-size: 13px;
    color: #B2B2B3;
    position:absolute;
    bottom:10px;
    cursor: default;
  }

  .img-wallet-copy {
    position: absolute;
    bottom:15px;
    right: 1.29rem;
  }

  .copied-label {
    position: absolute;
    top: 9rem;
    right: 2.69rem;
    background-color: #8a9098;
    border-radius: 2px;
    padding: 3px 4px;
    font-size: 10px;
    font-weight: 100;
    color: white;
  }
  .common-export-btn {
    height: 34px;
    width:78px;
    background:#5EA2FF;
    font-family: AvenirNext-Regular;
    font-size: 16px;
    color: #FFFFFF;
    border: 1px solid #FFFFFF;
    border-radius: 0;
    position: absolute;
    top: 0px;
    right: 20px;
  }
  .common-topRight-btns {
    position:absolute;
    top:10px;
    right:10px;
  }
</style>


================================================
FILE: src/components/Identitys/Import/BasicInfo.vue
================================================
<template>
  <div class="container json-import-container">
    <ul class="nav nav-pills import-identity-nav-pills" id="pills-tab" role="tablist">
      <li class="nav-item active">
        <a class="nav-link" id="import-identity-keystore-pills-tab" data-toggle="pill" href="#import-identity-keystore-pills"
           role="tab"
           aria-controls="import-identity-keystore-pills" aria-selected="false" @click="activeTab('keystore')">{{ $t('importIdentity.keystoreImport') }}</a>
      </li>
    </ul>

    <div class="tab-content" id="pills-tabContent">
      <div class="tab-pane fade show active" id="import-identity-keystore-pills" role="tabpanel"
           aria-labelledby="import-identity-keystore-pills-tab">

        <textarea class="import-identity-keystore" id="import-identity-keystore" rows="6"
                  v-validate="{required: true} " name="keystore"
                  :placeholder="$t('importIdentity.keystore')" v-model="keystore"></textarea>
        <span class="v-validate-span-errors" v-show="errors.has('keystore')">{{ errors.first('keystore') }}</span>

        <a-input type="password" class="input input-password"
                 v-validate="{required: true ,min:6}" :data-vv-as="$t('FormField.password')" name="keystorePassword"
                 v-model="keystorePassword" :placeholder="$t('importIdentity.ontidPassword')"></a-input>
        <span class="v-validate-span-errors" v-show="errors.has('keystorePassword')">{{ errors.first('keystorePassword') }}</span>
      </div>
    </div>

    <div class="basic-pk-btns">
      <div class="btn-container">
        <a-button type="default" @click="cancel" class="btn-cancel">{{$t('createIdentity.cancel')}}</a-button>
        <a-button type="primary" @click="next" class="btn-next">{{$t('createIdentity.next')}}</a-button>
      </div>
    </div>
  </div>
</template>

<script>
  import {mapState} from 'vuex'
  import {Wallet, Account, Crypto, Identity, OntidContract, RestClient, SDK} from "ontology-ts-sdk"
  import FileHelper from "../../../core/fileHelper"
  import dbService from '../../../core/dbService'
  import {DEFAULT_SCRYPT, TEST_NET, MAIN_NET} from '../../../core/consts'
  // import $ from 'jquery'
import { getNodeUrl, getRestClient, formatScryptParams } from '../../../core/utils';

  export default {
    name: 'BasicInfo',
    data() {
      const net = localStorage.getItem('net');
      return {
        tabName: 'keystore', // keystore

        keystore: '',
        keystoreLabel: '',
        keystorePassword: ''
      }
    },
    methods: {
      activeTab(tabName) {
        this.tabName = tabName
      },
      next() {
        if (this.tabName === 'keystore') {
          this.$validator.validateAll({
            keystore: this.keystore,
            keystorePassword: this.keystorePassword
          }).then(result => {
            if (result) {
              this.$store.dispatch('showLoadingModals')
              this.importIdentityForKeystore()
            }
          })
        }
      },
      validateKeystore(keystore) {
        if(!keystore.key || !keystore.address || !keystore.salt) {
          return false;
        } else {
          return true;
        }
      },
      async importIdentityForKeystore() {
        console.log('keystore:[' + this.keystore + ']; keystorePassword:[' + this.keystorePassword + ']')
        //import identity
        let keystore;
        try {
          keystore = JSON.parse(this.keystore)
        } catch(err) {
          this.$store.dispatch('hideLoadingModals')
          this.$message.error(this.$t('importIdentity.invalidKeystore'))
          return;
        }
        if(!this.validateKeystore(keystore)) {
          this.$store.dispatch('hideLoadingModals')
          this.$message.error(this.$t('importIdentity.invalidKeystore'))
          return;
        }
        let identity = new Identity();
        try {
            const encryptedPrivateKeyObj = new Crypto.PrivateKey(keystore.key);
            const addr = new Crypto.Address(keystore.address);
            const label = keystore.label || 'Identity'
            const salt = keystore.salt
            //must call if use
            let password = SDK.transformPassword(this.keystorePassword)
            let params = keystore.scrypt ? formatScryptParams(keystore.scrypt) : null;
            identity = Identity.importIdentity(label, encryptedPrivateKeyObj, password, addr, salt, params);
            identity = identity.toJsonObj();
            //Fix: keystore里需要加上scrypt参数
            identity.scrypt = keystore.scrypt;
        } catch (err) {
            this.$message.error(this.$t('importIdentity.passError'))
            this.$store.dispatch('hideLoadingModals')
            return;
        }
        const tx = OntidContract.buildGetDDOTx(identity.ontid)
        const restClient = getRestClient()
        const res = await restClient.sendRawTransaction(tx.serialize(), true)
          if(res.Error === 0 && res.Result) {
            this.saveToDb(identity)
          } else {
            const restUrl = getNodeUrl()
            const doc = await OntidContract.getDocumentJson(identity.ontid, restUrl)
            const id = doc.publicKey.find(item => item.id.split('#')[0] === identity.ontid)
            debugger
            if(id) {
                this.saveToDb(identity)
            } else {
                this.$message.error(this.$t('importIdentity.ontidNotExist'))
                this.$store.dispatch('hideLoadingModals')
                return;
            }
          }
      },
      saveToDb(identity) {
        const that = this;
        const wallet = {
          type: 'Identity',
          address: identity.ontid,
          wallet: identity
        }
        dbService.insert(wallet, function (err, newDoc) {
          if (err) {
            console.log(err)
            that.$message.warning(that.$t('importIdentity.ontidExist'))
            that.$store.dispatch('hideLoadingModals')
            return;
          }

          that.$message.success(that.$t('importIdentity.importSuccess'))
          that.$router.push({name: 'Identitys'})
        })
      },
      cancel() {
        this.$router.push({name: 'Identitys'})
      }
    }
  }
</script>

<style>
  .json-import-container {
    width: 36rem;
  }

  .import-identity-nav-pills > li.nav-item {
    width: 100%;
    text-align: center;
    height: 2rem;
    margin-bottom: 30px;
    font-family: AvenirNext-Medium;
    font-size: 14px;
  }

  .import-identity-nav-pills > li.nav-item > a {
    color: black;
  }

  .import-identity-nav-pills .nav-link:hover {
    color: #196BD8;
  }

  .import-identity-nav-pills .nav-link.active {
    color: #196BD8;
    background-color: transparent;
    border-radius: 0;
    border-bottom: #196BD8 solid 1px;
  }

  .input-password {
    margin-top: 30px;
  }

  .import-identity-keystore {
    width: 100%;
    resize: none;
    margin-top: 30px;
    padding: 12px 20px;
    border: 1px solid #DFE2E9;
  }

  textarea::-webkit-input-placeholder {
    color: #C9CBCF;
    font-family: AvenirNext-Regular;
    font-size: 14px;
  }

  .basic-pk-btns {
    position: fixed;
    bottom: 0;
    width: calc(100% - 4rem);
    height: 85px;
    left: 4rem;
    background: #FFFFFF;
    box-shadow: 0 -1px 6px 0 #F2F2F2;
    z-index: 1000;
  }

  .basic-pk-btns button:first-child {
    float: left;
  }

  .basic-pk-btns :nth-child(2) {
    float: right;
  }

  .basic-pk-btns :nth-child(3) {
    float: right;
    margin-right: 20px;
  }

  .error-input {
    border-color: red;
  }
</style>



================================================
FILE: src/components/Identitys/ImportIdentity.vue
================================================
<template>
  <div>
    <breadcrumb :current="$t('importIdentity.import')" v-on:backEvent="back"></breadcrumb>
    <div class="shared-container">
      <div class="steps-content">
        <basic-info></basic-info>
      </div>
    </div>
  </div>

</template>

<script>
  import BasicInfo from './Import/BasicInfo'
  import Breadcrumb from '../Breadcrumb'
  import {mapState} from 'vuex';

  export default {
    name: 'ImportIdentity',
    data() {
      return {
        steps: [{
          title: this.$t('importIdentity.basicInfo'),
          content: 'First-content',
        }]
      }
    },
    components: {
      BasicInfo,
      Breadcrumb
    },
    methods: {
      back() {
        this.$router.push({name: 'Identitys'})
      }
    }
  }
</script>


================================================
FILE: src/components/Identitys.vue
================================================
<template>
  <div class="negative-margin-top">
    <ul class="nav nav-pills wallets-nav-pills" id="pills-tab" role="tablist">
      <li class="nav-item">
        <a class="nav-link active" id="pills-home-tab" data-toggle="pill" href="#pills-home" role="tab"
           aria-controls="pills-home" aria-selected="true">{{ $t('identitys.pageTit') }}</a>
      </li>
    </ul>

    <div class="tab-content" id="pills-tabContent">

      <div class="tab-pane fade show active" id="pills-home" role="tabpanel" aria-labelledby="pills-home-tab">
        <div class="d-flex flex-wrap align-content-start center">
          <div class="normalWallet" v-for="w in allIdentitys" :key="w.address">
            <identity-view :identity="w"></identity-view>
          </div>

          <div class="div-create-wallet" :class="[viewBtn?'div-create-wallet-bg-color':'']"
               v-on:mouseenter="viewAllBtn(true)" v-on:mouseleave="viewAllBtn(false)">
            <div class="div-create" v-show="viewBtn">
              <router-link class="btn btn-default btn-create" :to="{name: 'CreateIdentity'}">{{$t('identitys.createIdentity')}}</router-link>
            </div>
            <div class="div-join" v-show="viewBtn">
              <router-link class="btn btn-default btn-create" :to="{name: 'ImportIdentity'}">{{$t('identitys.importIdentity')}}</router-link>
            </div>
            <img class="img-wallet-create" v-show="!viewBtn" src="./../assets/create-wallet.png" alt="">
          </div>
        </div>
      </div>

    </div>
  </div>
</template>

<script>
import {mapState} from 'vuex'
import IdentityView from './Identitys/IdentityView'

	export default {
    name: "Identitys",
    components:{
      IdentityView
    },
    data() {
      const net = localStorage.getItem('net')
      const network = net === 'TEST_NET' ? this.$t('common.testNet') : this.$t('common.mainNet');

      return {
        network: network,
        viewBtn: false,
      }
    },
    mounted() {
      this.$store.dispatch('fetchIdentitiesFromDb')
    },
    computed: {
      ...mapState({
        allIdentitys : state => state.Identities.Identities
      })
    },
    methods: {
      copyAddress(wallet) {
        this.$copyText(wallet.address)
      },
      viewAllBtn(bool) {
        this.viewBtn = bool
      }
    }
	}
</script>

<style scoped>
  .nav-item > a {
    color: #A5A7A9;
  }

  .nav-item > a:hover {
    color: #196BD8;
  }

  .wallets-nav-pills .nav-link.active {
    color: #196BD8;
    background-color: transparent;
    border-radius: 0;
  }

  .wallets-nav-pills {
    line-height: 4rem;
    font-family: AvenirNext-Medium;
    font-size: 0.88rem;
    padding: 0 1.7rem;
  }

  .nav-link {
    padding: 0 1.7rem;
  }

  .nav-pills .show > .nav-link {
    color: #196BD8;
    background-color: transparent;
  }

  .center {
    padding: 1.88rem 3rem;
    position: relative;
  }

  .normalWallet,
  .div-create-wallet {
    width: 24.63rem;
    height: 13.19rem;
    margin-right: 1.75rem;
    margin-left:1.75rem;
    margin-bottom: 2.75rem;
  }

  .normalWallet {
    background-color: #F5F7FB;
    padding: 0 1.25rem;
    position: relative;
  }

  .normalWallet:hover {
    cursor: pointer;
  }

  .div-create-wallet {
    background-color: #F5F7FB;
    font-family: AvenirNext-Medium;
    position: relative;
  }

  .div-create-wallet-bg-color {
    background-color: #498FEF;
  }

  .img-wallet-create {
    position: absolute;
    top: 50%;
    left: 50%;
    margin-left: -30px;
    margin-top: -30px;
  }

  .div-create-wallet > div > a {
    font-size: 0.88rem;
  }

  .btn-create {
    width: 8.25rem;
    height: 2.13rem;
    color: white;
    border: white solid 1px;
    border-radius: 0;
  }

  .div-create {
    padding: 0px;
    margin: 3.5rem auto 2rem;
    text-align: center;
  }

  .div-join {
    padding: 0px;
    margin: 2rem auto;
    text-align: center;
  }
</style>


================================================
FILE: src/components/JsonWallet/Create/BasicInfo.vue
================================================
<template>
  <div>
    <div class="basic-label">
      <a-input class="input" :placeholder="$t('createJsonWallet.label')" v-model="label"
          v-validate="{required: true}" name="label"
      ></a-input>
      <span class="v-validate-span-errors" v-show="errors.has('label')">{{ errors.first('label') }}</span>

      <a-input type="password" class="input input-password"
               v-validate="{required: true ,min:6}" name="password"
               v-model="password" :placeholder="$t('createJsonWallet.password')"></a-input>
      <span class="v-validate-span-errors" v-show="errors.has('password')">{{ errors.first('password') }}</span>

      <a-input type="password" class="input input-repassword"
               v-validate="{required: true , min:6, 'confirmed':password}" :data-vv-as="$t('FormField.passwordConfirmation')" name="rePassword"
               v-model="rePassword" :placeholder="$t('createJsonWallet.rePassword')"></a-input>
      <span class="v-validate-span-errors" v-show="errors.has('rePassword')">{{ errors.first('rePassword') }}</span>
    </div>

    <div class="basic-pk-btns">
      <div class="btn-container">
        <a-button type="default" @click="cancel" class="btn-cancel">{{$t('createJsonWallet.cancel')}}</a-button>
        <a-button type="primary" @click="next" class="btn-next">{{$t('createJsonWallet.next')}}</a-button>
      </div>
    </div>
  </div>
</template>

<script>
  import {mapState} from 'vuex'
  import {Wallet, Account, Crypto} from "ontology-ts-sdk"
  import FileHelper from "../../../core/fileHelper"
  import dbService from '../../../core/dbService'

  export default {
    name: 'BasicInfo',
    data() {
      return {
        label: "",
        password: "",
        rePassword: "",
        createSuccess: false
      }
    },
    methods: {
      next() {
        this.$validator.validateAll().then(result => {
          if(result) {
            let privateKey = Crypto.PrivateKey.random()
            const wif = privateKey.serializeWIF();
            let body = {
              label: this.label,
              privateKey: privateKey,
              password: this.password,
              wif: wif
            }
            this.$store.dispatch('createJsonWalletWithPrivateKey', body).then(res => {
              // console.log(res)
            })

            this.$store.commit('ADD_CREATE_JSON_STEP')
          }
        })
      },
      cancel() {
        this.$router.push({name: 'Wallets'})
      }
    }
  }
</script>

<style>
  .basic-label {
    width: 540px;
    margin: 2px auto;
  }

  .input-password {
    margin-top: 30px;
  }

  .input-repassword {
    margin-top: 10px;
  }

  .copayer-label {
    margin-left: 172px;
    margin-top: 40px;
  }

  .basic-pks {
    width: 540px;
    margin: 0px auto;
  }

  .pk-item {
    margin-bottom: 15px;
  }

  .pk-item :first-child {
    width: 150px;
    margin-right: 20px;
    display: inline-block;
  }

  .pk-item :nth-child(2) {
    width: 318px;
  }

  .delete-icon {
    height: 34px;
    width: 34px;
    /* display: inline-block; */
    background: url('../../../assets/delete.png') center center;
    background-size: contain;
    float: right;
    margin-right: 10px;
    cursor: pointer;
  }

  .basic-pk-box {
    border: 1px solid #dddddd;
    width: 100%;
    height: 300px;
    padding: 10px;
    position: relative;
  }

  .basic-pk-add {
    border-top: 1px solid #dddddd;
    width: calc(100% - 20px);
    position: absolute;
    bottom: 10px;
    left: 10px;
    padding-top: 10px;
  }

  .basic-pk-item {
    width: 100%;
    float: left;
  }

  .basic-pk-item span {
    margin-right: 10px;
  }

  .basic-add-item {
    display: inline-block;
    width: 40%;
  }

  .basic-add-item input {
    width: 80%;
  }

  .basic-pk-btns {
    position: fixed;
    bottom: 0;
    width: calc(100% - 4rem);
    height: 85px;
    left: 4rem;
    background: #FFFFFF;
    box-shadow: 0 -1px 6px 0 #F2F2F2;
    z-index: 1000;
  }

  .basic-pk-btns button:first-child {
    float: left;
  }

  .basic-pk-btns :nth-child(2) {
    float: right;
  }

  .basic-pk-btns :nth-child(3) {
    float: right;
    margin-right: 20px;
  }

  .error-input {
    border-color: red;
  }
</style>



================================================
FILE: src/components/JsonWallet/Create/ConfirmInfo.vue
================================================
<template>
  <div class="container json-confirm-container">
    <p><b>{{$t('createJsonWallet.labelN')}}: </b> {{label}}</p>
    <p><b>{{$t('createJsonWallet.addressN')}}: </b> {{ address }}</p>
    <p><b>{{$t('createJsonWallet.pubKeyN')}}: </b> {{publicKey}}</p>
    <p><b>{{$t('createJsonWallet.signatureSchemeN')}}: </b> SHA256withECDSA </p>
    <p><b>{{$t('createJsonWallet.priavteKeywif')}}: </b> {{wif}}</p>

    <div class="backup-text">
      <p class="font-medium-black">
        <span></span>
         <a-icon type="warning" /> {{$t('createJsonWallet.backupWallet')}}</p>
         <a-button type="primary" @click="downloadWallet">{{$t('createJsonWallet.download')}}</a-button>
    </div>
    <div class="confirm-btns">
      <div class="confirm-btn-container">
        <a-button type="default" class="btn-cancel" @click="back">{{ $t('createJsonWallet.back') }}</a-button>
        <a-button type="primary" class="btn-next" @click="next">{{ $t('createJsonWallet.next') }}</a-button>
      </div>
    </div>
  </div>
</template>

<script>
  import {mapState} from 'vuex'
  import {Crypto, Wallet, Account} from 'ontology-ts-sdk'
  import FileHelper from "../../../core/fileHelper"
  import dbService from '../../../core/dbService'
  import {WALLET_TYPE,DEFAULT_SCRYPT} from '../../../core/consts'
  import en from '../../../lang/en'
  import zh from '../../../lang/zh'

  export default {
    name: 'ConfirmInfo',
    data() {
      const langType = localStorage.getItem('user_lang') || 'en';
      const lang = langType === 'en' ? en : zh;
      return {
        lang: lang,
        processing: false
      }
    },
    mounted() {
      this.downloadWallet()
    },
    beforeDestroy() {
      console.log('clear')
      this.$store.commit('INIT_JSON_WALLET')
    },
    computed: {
      ...mapState({
        label: state => state.CreateJsonWallet.label,
        account: state => state.CreateJsonWallet.account,
        downloadContent: state => state.CreateJsonWallet.downloadContent,
        address: state => state.CreateJsonWallet.address,
        publicKey: state => state.CreateJsonWallet.publicKey,
        wif: state => state.CreateJsonWallet.wif
      })
    },
    methods: {
      back() {
        this.$store.commit('SUB_CREATE_JSON_STEP')
      },
      downloadWallet() {
        const commonWallet = this.account
        let wallet = Wallet.create(commonWallet.label || "")
        console.log(wallet)
        wallet.scrypt.n = 16384;
        const account = Account.parseJsonObj(commonWallet)
        wallet.addAccount(account)
        FileHelper.downloadFile(wallet.toJsonObj(), commonWallet.label);
      },
      next() {
        this.$store.dispatch('showLoadingModals')
        //Download file
        // FileHelper.downloadFile(this.downloadContent)

        //save to db
        const wallet = {
          type : WALLET_TYPE.CommonWallet,
          address: this.address,
          wallet: this.account
        }
        const that = this;
        // Add verification to make sure wallet data is right before saving
        const pri = Crypto.PrivateKey.deserializeWIF(this.wif);
        const pk = pri.getPublicKey();
        const addTmp = Crypto.Address.fromPubKey(pk);
        if (addTmp.toBase58() !== this.account.address) {
          this.$message.error(this.$t('createJsonWallet.createFail'));
          this.back();
          return;
        }
        dbService.insert(wallet, function (err, newDoc) {
          if (err) {
            console.log(err)
            that.$store.dispatch('hideLoadingModals')
            that.$message.error('common.savedbFailed')
            return;
          }
          // console.log(newDoc)
          that.$store.dispatch('hideLoadingModals')
          that.$store.commit('INIT_JSON_WALLET')
          that.$message.success(that.$t('createJsonWallet.createSuccess'))
          that.$router.push({name: 'Wallets'})
        })
      }
    }
  }
</script>

<style lang="scss" scoped>
  .json-confirm-container {
    width: 36rem;
    padding: 15px;
    border:1px solid #dddddd;
    p {
        margin-bottom: 10px;
        word-break: break-all;
    }
  }


  .confirm-btns {
    position: fixed;
    bottom: 0;
    width: calc(100% - 4rem);
    height: 85px;
    left: 4rem;
    background: #FFFFFF;
    box-shadow: 0 -1px 6px 0 #F2F2F2;
    z-index: 1000;
  }

  .confirm-btn-container {
    width: 540px;
    margin: 20px auto;
  }

  .confirm-btn-container :last-child {
    float: right;
  }
  .backup-text {
    text-align: center;
    p {
        text-align: left;
    }
    /* padding: 20px; */
    /* border: 1px solid #dddddd; */
    font-size: 16px;
  }
  .backup-text p {
    margin-bottom: 15px;
    font-size:16px !important;
  }

</style>


================================================
FILE: src/components/JsonWallet/CreateJsonWallet.vue
================================================
<template>
  <div>
    <breadcrumb :current="$t('createJsonWallet.create')" v-on:backEvent="back"></breadcrumb>
    <div class="shared-container">
      <a-steps :current="current" class="create-steps">
        <a-step v-for="item in steps" :key="item.title"/>
      </a-steps>
      <div class="steps-content">
        <basic-info v-if="current === 0"></basic-info>
        <confirm-info v-if="current === 1"></confirm-info>
      </div>
    </div>
  </div>

</template>

<script>
  import en from '../../lang/en'
  import zh from '../../lang/zh'
  import BasicInfo from './Create/BasicInfo'
  import ConfirmInfo from './Create/ConfirmInfo'
  import Breadcrumb from '../Breadcrumb'
  import {mapState} from 'vuex';

  export default {
    name: 'CreateJsonWallet',
    data() {
      const langType = localStorage.getItem('user_lang') || 'en';
      const lang = langType === 'en' ? en : zh;
      return {
        lang: lang,
        steps: [{
          title: lang.createJsonWallet.basicInfo,
          content: 'First-content',
        }, {
          title: lang.createJsonWallet.confirmInfo,
          content: 'Second-content',
        }]
      }
    },
    computed: {
      ...mapState({
        current: state => state.CreateJsonWallet.currentStep,
      })
    },
    components: {
      BasicInfo,
      ConfirmInfo,
      Breadcrumb
    },
    methods: {
      back() {
        this.$router.push({name: 'Wallets'})
      }
    }
  }
</script>

<style scoped>
  .shared-container {
  }

  .steps-content {
  }

  .steps-action {
    margin-top: 24px;
  }

  .create-steps {
    width: 520px;
    height: 4rem;
    margin: 2px auto;
  }
</style>


================================================
FILE: src/components/JsonWallet/Import/BasicInfo.vue
================================================
<style scoped>
.json-import-container {
  width: 48rem;
  padding-bottom: 100px;
}

.import-json-nav-pills>li.nav-item {
  width: 25%;
  text-align: center;
  height: 2rem;
  margin-bottom: 30px;
  font-family: AvenirNext-Medium;
  font-size: 14px;
}

.import-json-nav-pills>li.nav-item>a {
  color: black;
}

.import-json-nav-pills .nav-link:hover {
  color: #196BD8;
}

.import-json-nav-pills .nav-link.active {
  color: #196BD8;
  background-color: transparent;
  border-radius: 0;
  border-bottom: #196BD8 solid 1px;
}

.upload-dat-file {
  margin-top: 25px;
  position: relative;
  display: inline-block;
  background: #FBE45A;
  border: 1px solid #FBE45A;
  padding: 4px 12px;
  overflow: hidden;
  color: black !important;
  text-decoration: none;
  text-indent: 0;
  line-height: 1.5rem;
  height: 2.13rem;
}

.upload-dat-file input {
  background: #FBE45A;
  border: 1px solid #FBE45A;
  color: black !important;
  ;
  position: absolute;
  font-size: 100px;
  right: 0;
  top: 0;
  margin-top: 0;
  opacity: 0;
  line-height: 1.5rem;
  height: 2.13rem;
}

.upload-dat-file input:hover,
.upload-dat-file:hover {
  background: #FBE45A;
  border-color: black;
  color: black !important;
  ;
  text-decoration: none;
  cursor: pointer !important;
  ;
}

.input-wif {
  margin-top: 30px;
}

.input-password {
  margin-top: 30px;
}

.input-repassword {
  margin-top: 6px;
}

.import-json-mnemonic {
  width: 100%;
  resize: none;
  margin-top: 30px;
  padding: 12px 20px;
  border: 1px solid #DFE2E9;
}

textarea::-webkit-input-placeholder {
  color: #C9CBCF;
  font-family: AvenirNext-Regular;
  font-size: 14px;
}

.basic-pk-btns {
  position: fixed;
  bottom: 0;
  width: calc(100% - 4rem);
  height: 85px;
  left: 4rem;
  background: #FFFFFF;
  box-shadow: 0 -1px 6px 0 #F2F2F2;
  z-index: 1000;
}

.basic-pk-btns button:first-child {
  float: left;
}

.basic-pk-btns :nth-child(2) {
  float: right;
}

.basic-pk-btns :nth-child(3) {
  float: right;
  margin-right: 20px;
}

.error-input {
  border-color: red;
}

.nav-item a {
  font-size: 14px !important;
}

.tip {
  font-size: 14px;
}
</style>
<template>
  <div class="container json-import-container">
    <ul class="nav nav-pills import-json-nav-pills" id="pills-tab" role="tablist">
      <li class="nav-item">
        <a class="nav-link active" id="import-json-wif-pills-tab" data-toggle="pill" href="#import-json-wif-pills"
          role="tab" aria-controls="import-json-wif-pills" aria-selected="true" @click="activeTab('wif')">{{
            $t('createJsonWallet.priavteKeywif') }}</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" id="import-json-dat-pills-tab" data-toggle="pill" href="#import-json-dat-pills" role="tab"
          aria-controls="import-json-dat-pills" aria-selected="true" @click="activeTab('dat')">{{
            $t('createJsonWallet.keystoreDat') }}</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" id="import-json-mnemonic-pills-tab" data-toggle="pill" href="#import-json-mnemonic-pills"
          role="tab" aria-controls="import-json-mnemonic-pills" aria-selected="false" @click="activeTab('mnemonic')">{{
            $t('createJsonWallet.mnemonic') }}</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" id="import-json-private-key-pills-tab" data-toggle="pill"
          href="#import-json-private-key-pills" role="tab" aria-controls="import-json-private-key-pills"
          aria-selected="true" @click="activeTab('pk')">{{ $t('createJsonWallet.privateKey64Hex') }}</a>
      </li>
    </ul>

    <div class="tab-content" id="pills-tabContent">
      <div class="tab-pane fade show active" id="import-json-wif-pills" role="tabpanel"
        aria-labelledby="import-json-wif-pills-tab">
        <a-input class="input" :placeholder="$t('importJsonWallet.label')" v-validate="{ required: true }"
          name="wifLabel" :data-vv-as="$t('FormField.label')" v-model="wifLabel"></a-input>
        <span class="v-validate-span-errors" v-show="errors.has('wifLabel')">{{ errors.first('wifLabel') }}</span>

        <a-input class="input input-wif" v-validate="{ required: true }" name="wif" v-model="wif"
          :placeholder="$t('importJsonWallet.wifTip')"></a-input>
        <span class="v-validate-span-errors" v-show="errors.has('wif')">{{ errors.first('wif') }}</span>

        <a-input type="password" class="input input-password" v-validate="{ required: true, min: 6 }"
          :data-vv-as="$t('FormField.password')" name="wifPassword" v-model="wifPassword"
          :placeholder="$t('importJsonWallet.setPassword')"></a-input>
        <span class="v-validate-span-errors" v-show="errors.has('wifPassword')">{{ errors.first('wifPassword') }}</span>
        <a-input type="password" class="input input-repassword" v-validate="{ required: true, min: 6, is: wifPassword }"
          :data-vv-as="$t('FormField.passwordConfirmation')" name="wifRePassword" v-model="wifRePassword"
          :placeholder="$t('importJsonWallet.rePassword')"></a-input>
        <span class="v-validate-span-errors" v-show="errors.has('wifRePassword')">{{ errors.first('wifRePassword')
          }}</span>
      </div>
      <div class="tab-pane fade" id="import-json-private-key-pills" role="tabpanel"
        aria-labelledby="import-json-private-key-pills-tab">
        <a-input class="input" :placeholder="$t('importJsonWallet.label')" v-model="pkLabel"></a-input>
        <a-input class="input input-wif" v-validate="{ required: true, length: 64 }"
          :data-vv-as="$t('FormField.privateKey')" name="pk" v-model="pk"
          :placeholder="$t('importJsonWallet.privateKeyTip')"></a-input>
        <span class="v-validate-span-errors" v-show="errors.has('pk')">{{ errors.first('pk') }}</span>
        <a-input type="password" class="input input-password" v-validate="{ required: true, min: 6 }"
          :data-vv-as="$t('FormField.password')" name="pkPassword" v-model="pkPassword"
          :placeholder="$t('importJsonWallet.setPassword')"></a-input>
        <span class="v-validate-span-errors" v-show="errors.has('pkPassword')">{{ errors.first('pkPassword') }}</span>
        <a-input type="password" class="input input-repassword" v-validate="{ required: true, min: 6, is: pkPassword }"
          :data-vv-as="$t('FormField.passwordConfirmation')" name="pkRePassword" v-model="pkRePassword"
          :placeholder="$t('createJsonWallet.rePassword')"></a-input>
        <span class="v-validate-span-errors" v-show="errors.has('pkRePassword')">{{ errors.first('pkRePassword')
          }}</span>
      </div>

      <div class="tab-pane fade" id="import-json-dat-pills" role="tabpanel" aria-labelledby="import-json-dat-pills-tab">

        <a class="upload-dat-file">{{ datPath }}
          <input type="file" @change="onFileChange" id="datFile">
        </a>

        <!-- <p>
          <a-icon type="info-circle-o" class="redeem-info-icon" />
          <span class="tip">{{$t('importJsonWallet.importFirstDefault')}}</span>
        </p> -->

        <div v-show="datWallet?.accounts?.length > 0">
          <div v-for="(account, index) in datWallet.accounts" :key="account.address" style="margin-top: 20px;">
            <a-space direction="vertical" style="width: 100%">
              <span>Address: {{ account.address }}</span>
              <a-input class="input" :placeholder="$t('importJsonWallet.label')"
                @change="(e) => datLabelChange(e, index)" name="datLabel"></a-input>
              <a-input type="password" class="input" name="datPassword" @change="(e) => datPasswordChange(e, index)"
                :placeholder="$t('importJsonWallet.datImportPassword')"></a-input>
            </a-space>
          </div>

        </div>

      </div>

      <div class="tab-pane fade" id="import-json-mnemonic-pills" role="tabpanel"
        aria-labelledby="import-json-mnemonic-pills-tab">
        <a-input class="input" :placeholder="$t('importJsonWallet.label')" v-model="mnemonicLabel"></a-input>

        <textarea class="import-json-mnemonic" id="import-json-mnemonic" rows="6" v-validate="{ required: true }"
          :data-vv-as="$t('FormField.mnemonic')" name="mnemonic" :placeholder="$t('importJsonWallet.mnemonic')"
          v-model="mnemonic"></textarea>
        <span class="v-validate-span-errors" v-show="errors.has('mnemonic')">{{ errors.first('mnemonic') }}</span>

        <a-input type="password" class="input input-password" v-validate="{ required: true, min: 6 }"
          :data-vv-as="$t('FormField.password')" name="mnemonicPassword" v-model="mnemonicPassword"
          :placeholder="$t('importJsonWallet.setPassword')"></a-input>
        <span class="v-validate-span-errors" v-show="errors.has('mnemonicPassword')">{{ errors.first('mnemonicPassword')
          }}</span>
        <a-input type="password" class="input input-repassword"
          v-validate="{ required: true, min: 6, is: mnemonicPassword }"
          :data-vv-as="$t('FormField.passwordConfirmation')" name="mnemonicRePassword" v-model="mnemonicRePassword"
          :placeholder="$t('importJsonWallet.rePassword')"></a-input>
        <span class="v-validate-span-errors" v-show="errors.has('mnemonicRePassword')">{{
          errors.first('mnemonicRePassword') }}</span>
      </div>
    </div>
    <a-modal :title="$t('importJsonWallet.confirmImport')" :visible="confirmModal" @ok="handleConfirmOk"
      @cancel="handleConfirmCancel">
      <div>
        <p class="font-medium">
          {{ $t('importJsonWallet.confirmImportExist') }}
        </p>
      </div>
    </a-modal>

    <div class="basic-pk-btns">
      <div class="btn-container">
        <a-button type="default" @click="cancel" class="btn-cancel">{{ $t('importJsonWallet.cancel') }}</a-button>
        <a-button type="primary" @click="next" class="btn-next">{{ $t('importJsonWallet.next') }}</a-button>
      </div>
    </div>
  </div>
</template>

<script>
import { mapState } from 'vuex'
import { Wallet, Account, Crypto } from "ontology-ts-sdk"
import FileHelper from "../../../core/fileHelper"
import dbService from '../../../core/dbService'
import { DEFAULT_SCRYPT } from '../../../core/consts'
// import $ from 'jquery'
import { isHexString, convertScryptParams } from '../../../core/utils'

export default {
  name: 'BasicInfo',
  data() {
    return {
      tabName: 'wif', // dat | pk | wif | mnemonic

      pk: '',
      pkLabel: '',
      pkPassword: '',
      pkRePassword: '',

      datPath: this.$t('importJsonWallet.datFile'),
      dat: '',
      datWallet: [],
      datLabel: [],
      datPassword: [],

      wif: '',
      wifLabel: '',
      wifPassword: '',
      wifRePassword: '',

      mnemonic: '',
      mnemonicLabel: '',
      mnemonicPassword: '',
      mnemonicRePassword: '',
      mnemonicAccount: '',
      confirmModal: false,
      updatingWallet: ''
    }
  },

  beforeDestroy() {
    console.log('clear')
  },
  methods: {
    activeTab(tabName) {
      this.tabName = tabName
    },
    next() {
      if (this.tabName === 'pk') {
        this.$validator.validateAll({
          pk: this.pk,
          pkPassword: this.pkPassword,
          pkRePassword: this.pkRePassword
        }).then(result => {
          console.log(result)
          if (result) {
            this.$store.dispatch('showLoadingModals')
            this.importAccountForPK()
          }
        })
      } else if (this.tabName === 'dat') {
        // this.$validator.validateAll({
        //   datPassword: this.datPassword,
        //   datLabel: this.datLabel
        // }).then(result => {
        if (!this.dat) {
          this.$message.error(this.$t('importJsonWallet.invalidDatFile'))
          return;
        }
        // if (result) {
        this.$store.dispatch('showLoadingModals')
        this.importAccountForDat()
        // }
        // })
      } else if (this.tabName === 'wif') {
        this.$validator.validateAll({
          wifLabel: this.wifLabel,
          wif: this.wif,
          wifPassword: this.wifPassword,
          wifRePassword: this.wifRePassword
        }).then(result => {
          if (result) {
            this.$store.dispatch('showLoadingModals')
            this.importAccountForWif()
          }
        })
      } else {
        this.$validator.validateAll({
          mnemonic: this.mnemonic,
          mnemonicPassword: this.mnemonicPassword,
          mnemonicRePassword: this.mnemonicRePassword
        }).then(result => {
          if (result) {
            this.$store.dispatch('showLoadingModals')
            this.importAccountForMnemonic()
          }
        })
      }
    },
    importAccountForPK() {
      let body = {
        label: this.pkLabel,
        privateKey: new Crypto.PrivateKey(this.pk),
        password: this.pkPassword
      }
      if (!isHexString(this.pk)) {
        this.$message.error(this.$t('importJsonWallet.invalidPrivateKey'))
        this.$store.dispatch('hideLoadingModals')
        return;
      }
      this.$store.dispatch('createJsonWalletWithPrivateKey', body).then(res => {
        this.saveToDb(res)
      })
    },
    onFileChange() {
      // Custom upload button copywriting.
      // let uploadFile = $("#datFile").val();
      // $(".fileerrorTip").html("").hide();
      let uploadFile = document.getElementById("datFile").value;
      let arr = uploadFile.split('\\');
      let fileName = arr[arr.length - 1];
      let files = document.getElementById("datFile").files
      this.dat = files[0]
      console.log('this.dat', this.dat);
      if (!this.dat) {
        return
      }
      this.datPath = this.$t('importJsonWallet.selectedDatFile') + fileName

      FileHelper.readWalletFile(this.dat).then(res => {
        console.log('res', res);
        let wallet;
        try {
          wallet = JSON.parse(res)
          console.log('wallet', wallet);
          if (!wallet.scrypt || !wallet.accounts || wallet.accounts.length < 1) {
            throw new Error();
          }

          let accounts = [];
          for (const acct of wallet.accounts) {
            if (acct && acct.key && acct.address && acct.salt) {
              accounts.push(acct)
            }
          }
          wallet.accounts = accounts
          if (wallet.accounts.length < 1) {
            throw new Error();
          }
          this.datWallet = wallet


        } catch (err) {
          console.log(err)
          this.$store.dispatch('hideLoadingModals')
          this.$message.error(this.$t('importJsonWallet.invalidDatFile'))
          return;
        }


      })

    },

    datLabelChange(e, index) {
      this.datLabel[index] = e.target.value
    },
    datPasswordChange(e, index) {
      this.datPassword[index] = e.target.value
    },

    importAccountForDat() {
      let successAmount = 0;
      console.log('this.datWallet', this.datWallet);

      this.datWallet.accounts.forEach((account, index) => {
        if (!this.datPassword[index]) {
          return
        }
        if (!this.datLabel[index]) {
          return
        }

        try {
          const enc = new Crypto.PrivateKey(account.key);
          const address = new Crypto.Address(account.address)
          let scrypt = convertScryptParams(this.datWallet.scrypt)
          let pri;
          pri = enc.decrypt(this.datPassword[index], address, account.salt, scrypt)
          account.label = this.datLabel[index];
          //Fix: 使导入的wallet的scrypt参数保持一致,都使用 n = 16384
          if (this.datWallet.scrypt && this.datWallet.scrypt.n !== 16384) {
            account = Account.create(pri, this.datPassword[index], this.datLabel[index], DEFAULT_SCRYPT)
            account = account.toJsonObj();
          }
          this.saveToDb(account);
        } catch (err) {
          console.log(err)
          return;
        }
        successAmount++


      });
      this.$store.dispatch('hideLoadingModals')
      if(successAmount==0){
        this.$message.error('Import failed.')
        return
      }
      this.$message.success(`A total of ${ successAmount} addresses succeed to import.`)

    },
    importAccountForWif() {
      let privateKey;
      try {
        privateKey = Crypto.PrivateKey.deserializeWIF(this.wif);
      } catch (err) {
        this.$message.error(this.$t('basicInfo.errWif'))
        this.$store.dispatch('hideLoadingModals')
        return;
      }

      let body = {
        label: this.wifLabel,
        privateKey: privateKey,
        password: this.wifPassword
      }
      this.$store.dispatch('createJsonWalletWithPrivateKey', body).then(res => {
        this.saveToDb(res)
      })
    },
    importAccountForMnemonic() {
      // 助记词导入
      let account
      try {
        account = Account.importWithMnemonic(this.mnemonicLabel, this.mnemonic, this.mnemonicPassword, DEFAULT_SCRYPT)
      } catch (err) {
        this.$store.dispatch('hideLoadingModals')
        this.$message.error(this.$t('basicInfo.InvalidMnemonic'))
      }
      this.mnemonicAccount = account.toJsonObj()
      this.saveToDb(this.mnemonicAccount)
    },
    saveToDb(account) {
      account.isDefault = true;
      const that = this;
      const wallet = {
        type: 'CommonWallet',
        address: account.address,
        wallet: account
      }
      dbService.insert(wallet, function (err, newDoc) {
        if (err) {
          console.log(err)
          // that.$message.warning('The wallet already exists in local.')
          that.$store.dispatch('hideLoadingModals')
          that.confirmModal = true;
          that.updatingWallet = wallet;
          return;
        }
        // console.log(newDoc)
        that.$message.success(that.$t('importJsonWallet.success'))
        that.$router.push({ name: 'Wallets' })
      })
    },
    cancel() {
      this.$router.push({ name: 'Wallets' })
    },
    handleConfirmOk() {
      if (this.updatingWallet) {
        dbService.update({ address: this.updatingWallet.address }, { $set: { wallet: this.updatingWallet.wallet } }, {},
          (err, numReplaced) => {
            if (err) {
              this.$store.dispatch('hideLoadingModals')
              this.$message.error(this.$t('importJsonWallet.saveDbFailed'))
              return;
            }
            this.$message.success(this.$t('importJsonWallet.success'))
            this.$router.push({ name: 'Wallets' })
          })
      }
    },
    handleConfirmCancel() {
      this.confirmModal = false;
    }
  }
}
</script>


================================================
FILE: src/components/JsonWallet/ImportJsonWallet.vue
================================================
<template>
  <div>
    <breadcrumb :current="$t('importJsonWallet.create')" v-on:backEvent="back"></breadcrumb>
    <div class="shared-container">
      <div class="steps-content">
        <basic-info></basic-info>
      </div>
    </div>
  </div>

</template>

<script>
  import en from '../../lang/en'
  import zh from '../../lang/zh'
  import BasicInfo from './Import/BasicInfo'
  import Breadcrumb from '../Breadcrumb'
  import {mapState} from 'vuex';

  export default {
    name: 'ImportJsonWallet',
    data() {
      const langType = localStorage.getItem('user_lang') || 'en';
      const lang = langType === 'en' ? en : zh;
      return {
        lang: lang,
        steps: [{
          title: lang.importJsonWallet.basicInfo,
          content: 'First-content',
        }]
      }
    },
    components: {
      BasicInfo,
      Breadcrumb
    },
    methods: {
      back() {
        this.$router.push({name: 'Wallets'})
      }
    }
  }
</script>


================================================
FILE: src/components/JsonWallet/View/Details.vue
================================================
<template>
  <div class="common-detail-container">
    <div>
      <div class="div-shared-wallet-sign">
        <span>{{ isCommonWallet ? $t('common.normalWallet') : $t('common.hardwareWallet') }}</span>
        <p class="neo-compatile" v-if="!isCommonWallet && wallet.neo">{{$t('common.neoCompatible')}}</p>
      </div>
      <div class="div-wallet-name" @click="toWalletHome(wallet)">{{wallet.label}}</div>
      <!--<img class="img-wallet-edit" src="./../assets/edit.png" alt="">-->
      <div class="div-wallet-address">
        <div>{{$t('common.walletAddress')}}:</div>
        {{wallet.address}}
      </div>
    </div>
    <div v-show="addressCopied" class="copied-label">Copied</div>
    <img class="img-wallet-copy" src="../../../assets/copy.png" @click="copyAddress(wallet)" alt="">
    <div class="common-topRight-btns">
      <span class="common-delete-icon" @click="deleteWallet()" v-if="!isCommonWallet"></span>
      <a-dropdown v-if="isCommonWallet">
        <a-menu slot="overlay" >
          <a-menu-item key="1" @click="handleExportWallet()">
            <span >{{$t('common.exportDat')}}</span>
          </a-menu-item>
          <a-menu-item key="2" @click="handleExportWIF()">
            <span  >{{$t('common.exportWIF')}}</span>
          </a-menu-item>
          <a-menu-item key="3" @click="handleChangePassword()">
            <span  >{{$t('common.changePassword')}}</span>
          </a-menu-item>
          <a-menu-item key="4" @click="deleteWallet()">
            <span  >{{$t('common.deleteWallet')}}</span>
          </a-menu-item>
        </a-menu>
        <a-button style="margin-left: 8px">
          {{$t('common.more')}}<a-icon type="down" />
        </a-button>
      </a-dropdown>
    </div>

    <a-modal
        :title="modalTitle"
        :visible="passModal"
        @ok="handleValidatePassword"
        @cancel="handleCancel">
          <div>
              <p class="font-medium">
                {{option==='TO_DELETE' ? $t('wallets.deleteingWallet') : '' }}
                {{option === 'TO_EXPORT' ? $t('wallets.exportingWallet') : ''}}
                {{option === 'EXPORT_WIF' ? $t('wallets.exportingWIF') : ''}}
                 {{wallet.address}}</p>
          
Download .txt
gitextract_cdm3kmul/

├── .browserslistrc
├── .editorconfig
├── .eslintrc.js
├── .github/
│   └── workflows/
│       └── publish.yml
├── .gitignore
├── LICENSE
├── README.md
├── README_cn.md
├── babel.config.js
├── build/
│   ├── after-sign.js
│   └── entitlements.mac.plist
├── package.json
├── public/
│   └── index.html
├── src/
│   ├── App.vue
│   ├── assets/
│   │   ├── fonts/
│   │   │   └── avenirnextregular.otf
│   │   └── icons/
│   │       └── icon.icns
│   ├── background.js
│   ├── components/
│   │   ├── Breadcrumb.vue
│   │   ├── Common/
│   │   │   ├── CommonSignShared.vue
│   │   │   ├── Oep4Home.vue
│   │   │   ├── Oep4Selection.vue
│   │   │   ├── SelectWallet.vue
│   │   │   └── SignSendTx.vue
│   │   ├── CommonWallet/
│   │   │   ├── CommonReceive.vue
│   │   │   ├── CommonRedeem.vue
│   │   │   ├── CommonTokenSwap.vue
│   │   │   ├── SendConfirm.vue
│   │   │   └── SendHome.vue
│   │   ├── Dapps.vue
│   │   ├── Dashboard.vue
│   │   ├── Exchange/
│   │   │   ├── Changelly/
│   │   │   │   └── Changelly.vue
│   │   │   └── Cryptonex/
│   │   │       └── Cryptonex.vue
│   │   ├── Home.vue
│   │   ├── Identitys/
│   │   │   ├── Create/
│   │   │   │   ├── BasicInfo.vue
│   │   │   │   └── ConfirmInfo.vue
│   │   │   ├── CreateIdentity.vue
│   │   │   ├── IdentityView.vue
│   │   │   ├── Import/
│   │   │   │   └── BasicInfo.vue
│   │   │   └── ImportIdentity.vue
│   │   ├── Identitys.vue
│   │   ├── JsonWallet/
│   │   │   ├── Create/
│   │   │   │   ├── BasicInfo.vue
│   │   │   │   └── ConfirmInfo.vue
│   │   │   ├── CreateJsonWallet.vue
│   │   │   ├── Import/
│   │   │   │   └── BasicInfo.vue
│   │   │   ├── ImportJsonWallet.vue
│   │   │   └── View/
│   │   │       └── Details.vue
│   │   ├── LedgerWallet/
│   │   │   ├── Import/
│   │   │   │   ├── BasicInfo.vue
│   │   │   │   └── ConnectLedger.vue
│   │   │   ├── ImportLedgerWallet.vue
│   │   │   └── LoginLedger.vue
│   │   ├── Modals/
│   │   │   ├── Loading.vue
│   │   │   └── SetPath.vue
│   │   ├── Node/
│   │   │   ├── Node.vue
│   │   │   ├── NodeApply/
│   │   │   │   ├── Register.vue
│   │   │   │   └── RegisterSuccess.vue
│   │   │   ├── NodeAuthorize/
│   │   │   │   ├── AuthorizationMgmt.vue
│   │   │   │   ├── AuthorizeLogin.vue
│   │   │   │   ├── NewAuthorization.vue
│   │   │   │   ├── NodeList.vue
│   │   │   │   ├── Sesameseed/
│   │   │   │   │   ├── AuthorizationMgmtSesameseed.vue
│   │   │   │   │   ├── AuthorizeLoginSesameseed.vue
│   │   │   │   │   ├── NewAuthorizationSesameseed.vue
│   │   │   │   │   └── SesameseedVars.js
│   │   │   │   └── StakeHistory.vue
│   │   │   ├── NodeManagement/
│   │   │   │   ├── MyNode.vue
│   │   │   │   ├── NodeStakeAuthorization.vue
│   │   │   │   └── NodeStakeManagement.vue
│   │   │   ├── NodeStake/
│   │   │   │   ├── NodeInfo.vue
│   │   │   │   ├── NodeStakeInfo.vue
│   │   │   │   ├── NodeStakeIntro.vue
│   │   │   │   └── NodeStakeRegister.vue
│   │   │   └── Vote/
│   │   │       ├── Create.vue
│   │   │       ├── Detail.vue
│   │   │       ├── List.vue
│   │   │       ├── Login.vue
│   │   │       └── index.vue
│   │   ├── RedeemInfoIcon.vue
│   │   ├── Setting.vue
│   │   ├── SharedWallet/
│   │   │   ├── Create/
│   │   │   │   ├── BasicInfo.vue
│   │   │   │   ├── ConfirmSigNum.vue
│   │   │   │   └── CreateSuccess.vue
│   │   │   ├── CreateSharedWallet.vue
│   │   │   ├── Import/
│   │   │   │   ├── InputPass.vue
│   │   │   │   └── QuerySharedWallet.vue
│   │   │   ├── ImportSharedWallet.vue
│   │   │   ├── PAX/
│   │   │   │   ├── PaxMgmt.vue
│   │   │   │   ├── SignProcess.vue
│   │   │   │   └── StartProcess.vue
│   │   │   ├── PendingTxHome.vue
│   │   │   ├── SharedWalletDetail.vue
│   │   │   ├── SharedWalletHome.vue
│   │   │   ├── SharedWalletSend.vue
│   │   │   ├── Transfer/
│   │   │   │   ├── InputPassword.vue
│   │   │   │   ├── PendingConfirm.vue
│   │   │   │   ├── PendingTxSign.vue
│   │   │   │   ├── SendAsset.vue
│   │   │   │   └── SendConfirm.vue
│   │   │   ├── Tx/
│   │   │   │   ├── SharedTxMgmt.vue
│   │   │   │   ├── SignSharedTx.vue
│   │   │   │   └── StartSharedTx.vue
│   │   │   └── View/
│   │   │       ├── Details.vue
│   │   │       └── SharedWalletCopayer.vue
│   │   ├── TopLeftNav.vue
│   │   └── Wallets.vue
│   ├── core/
│   │   ├── asyncHelper.js
│   │   ├── consts.js
│   │   ├── dbService.js
│   │   ├── fileHelper.js
│   │   ├── lang.js
│   │   ├── network.js
│   │   ├── nodes.json
│   │   ├── ontLedger.js
│   │   ├── ontLedgerNew.js
│   │   ├── runtime.js
│   │   └── utils.js
│   ├── lang/
│   │   ├── en.js
│   │   ├── index.js
│   │   └── zh.js
│   ├── main.js
│   ├── router/
│   │   └── index.js
│   └── store/
│       ├── index.js
│       └── modules/
│           ├── CreateIdentity.js
│           ├── CreateJsonWallet.js
│           ├── CreateSharedWallet.js
│           ├── CurrentWallet.js
│           ├── Identities.js
│           ├── ImportSharedWallet.js
│           ├── LedgerConnector.js
│           ├── LedgerWallet.js
│           ├── LoadingModal.js
│           ├── NodeAuthorization.js
│           ├── NodeAuthorizationSesameseed.js
│           ├── NodeStake.js
│           ├── Oep4s.js
│           ├── PaxMgmt.js
│           ├── Setting.js
│           ├── Tokens.js
│           ├── Vote.js
│           ├── Wallets.js
│           └── index.js
└── vue.config.js
Download .txt
SYMBOL INDEX (259 symbols across 31 files)

FILE: build/after-sign.js
  constant DEV_ID (line 7) | const DEV_ID = "Developer ID Application: Ontology Foundation Ltd (29B4V...
  constant ENTITLEMENTS (line 8) | const ENTITLEMENTS = "build/entitlements.mac.plist";
  function run (line 10) | function run(cmd) {

FILE: src/background.js
  function createWindow (line 18) | function createWindow() {

FILE: src/components/Node/NodeAuthorize/Sesameseed/SesameseedVars.js
  constant CONTRACT_HASH (line 1) | const CONTRACT_HASH = 'a63c33d2209854feafbf40685a33d4846ee82556'
  constant SESAMESEED_NODE_ADDRESS (line 2) | const SESAMESEED_NODE_ADDRESS = 'ANRRE8xKwKzuaCeAjP6eZYDnVi7n2x6byE'

FILE: src/core/asyncHelper.js
  function asyncWrap (line 1) | function asyncWrap (promise) {

FILE: src/core/consts.js
  constant GAS_PRICE (line 2) | const GAS_PRICE = '500';
  constant GAS_LIMIT (line 3) | const GAS_LIMIT = '20000';
  constant ONT_CONTRACT (line 5) | const ONT_CONTRACT = '0000000000000000000000000000000000000001';
  constant TEST_NET (line 6) | const TEST_NET = 'http://polaris1.ont.io';
  constant MAIN_NET (line 7) | const MAIN_NET = 'http://dappnode1.ont.io';
  constant TEST_NET_LIST (line 9) | const TEST_NET_LIST = [
  constant MAIN_NET_LIST (line 17) | const MAIN_NET_LIST = [
  constant ONT_PASS_NODE (line 24) | const ONT_PASS_NODE = 'https://service-test.onto.app'
  constant ONT_PASS_NODE_PRD (line 26) | const ONT_PASS_NODE_PRD = 'https://service.onto.app'
  constant ONT_PASS_URL (line 28) | const ONT_PASS_URL = {
  constant WALLET_TYPE (line 50) | const WALLET_TYPE = {
  constant DEFAULT_SCRYPT (line 56) | const DEFAULT_SCRYPT = {
  constant SWAP_ADDRESS (line 63) | const SWAP_ADDRESS = 'AFmseVrdL9f9oyCzZefL9tG6UbvhPbdYzM'
  constant NODE_DETAIL (line 65) | const NODE_DETAIL = 'https://explorer.ont.io/nodes/detail/'
  constant NODE_NAME_LIST (line 66) | const NODE_NAME_LIST = 'https://ont.io/api/v1/candidate/info/All'
  constant OFF_CHAIN_NODES (line 67) | const OFF_CHAIN_NODES = {
  constant QUERY_NODE_INFO_API (line 72) | const QUERY_NODE_INFO_API = {
  constant UPDATE_NODE_INFO_API (line 78) | const UPDATE_NODE_INFO_API = {
  constant UPDATE_LEDGER_NODE_INFO_API (line 84) | const UPDATE_LEDGER_NODE_INFO_API = {
  constant NODE_CURRENT_STAKES (line 90) | const NODE_CURRENT_STAKES = {
  constant PAX_API (line 95) | const PAX_API = {
  constant PAX_SC_HASH (line 106) | const PAX_SC_HASH = {
  constant VOTE_ROLE (line 111) | const VOTE_ROLE = {
  constant VALIDATE_DICTIONARY (line 117) | const VALIDATE_DICTIONARY = {

FILE: src/core/fileHelper.js
  method downloadFile (line 3) | downloadFile(json, fileName) {
  method readWalletFile (line 14) | readWalletFile($file) {

FILE: src/core/lang.js
  method setLang (line 2) | setLang(lang) {
  method getLang (line 5) | getLang(defaultLang) {

FILE: src/core/network.js
  constant WS_PORT (line 18) | const WS_PORT = '20335'
  function initNetwork (line 20) | function initNetwork() {
  function reconnect (line 37) | function reconnect() {
  function getClient (line 50) | function getClient() {

FILE: src/core/ontLedger.js
  constant VALID_STATUS (line 9) | const VALID_STATUS = 0x9000
  constant MSG_TOO_BIG (line 10) | const MSG_TOO_BIG = 0x6d08
  constant APP_CLOSED (line 11) | const APP_CLOSED = 0x6e00
  constant TX_DENIED (line 12) | const TX_DENIED = 0x6985
  constant TX_PARSE_ERR (line 13) | const TX_PARSE_ERR = 0x6d07
  class OntLedger (line 56) | class OntLedger {
    method constructor (line 60) | constructor(path) {
    method init (line 68) | static async init() {
    method list (line 79) | static async list() {
    method open (line 87) | async open() {
    method close (line 100) | close() {
    method getPublicKey (line 110) | async getPublicKey(acct = 0, neo) {
    method getDeviceInfo (line 123) | getDeviceInfo() {
    method send (line 138) | async send(params, msg, statusList) {
    method getSignature (line 164) | async getSignature(data, acct = 0, neo = false) {

FILE: src/core/ontLedgerNew.js
  constant STATUS_CODES (line 4) | const STATUS_CODES = {
  constant MAX_PAYLOAD (line 28) | const MAX_PAYLOAD = 255;
  constant LEDGER_CLA (line 29) | const LEDGER_CLA = 0x80;
  constant P1_NON_CONFIRM (line 30) | const P1_NON_CONFIRM = 0x00;
  constant P1_CONFIRM (line 31) | const P1_CONFIRM = 0x01;
  constant P2_MORE (line 32) | const P2_MORE = 0x80;
  constant P2_EXTEND (line 33) | const P2_EXTEND = 0x00;
  constant INS (line 35) | const INS = {
  class OntLedgerNew (line 42) | class OntLedgerNew {
    method constructor (line 43) | constructor(transport, scrambleKey = "ONT") {
    method #sendToDevice (line 51) | async #sendToDevice(path, instruction, msgBuffer) {
    method pathToBuffer (line 111) | pathToBuffer(path) {
    method getSignFromRelay (line 142) | getSignFromRelay(reply) {
    method getVersion (line 160) | async getVersion() {
    method checkVersion (line 187) | async checkVersion() {
    method getPublicKey (line 199) | async getPublicKey(path, showAddress = false) {
    method signMessage (line 236) | async signMessage(path, msg) {
    method signOffchainMessage (line 282) | async signOffchainMessage(path, msg) {
    method _convertTransportError (line 294) | _convertTransportError(error) {

FILE: src/core/runtime.js
  function getBalance (line 12) | async function getBalance(addr) {
  function getUnboundOng (line 26) | async function getUnboundOng(addr) {
  function getGrantOng (line 35) | async function getGrantOng(addr) {
  function invokeTx (line 43) | async function invokeTx(tx) {
  function invokeReadTx (line 48) | async function invokeReadTx(tx) {

FILE: src/core/utils.js
  function open (line 25) | function open(url) {
  function varifyPositiveInt (line 38) | function varifyPositiveInt(value) {
  function varifyOngValue (line 45) | function varifyOngValue(value) {
  function varifyOpe4Value (line 52) | function varifyOpe4Value(value, decimal) {
  function isHexString (line 63) | function isHexString(str) {
  function getNodeUrl (line 68) | function getNodeUrl() {
  function getRestClient (line 82) | function getRestClient() {
  function convertNumber2Str (line 88) | function convertNumber2Str(num, decimal = 0, division) {
  function convertStr2Number (line 96) | function convertStr2Number(str, decimal = 0) {
  function decryptWallet (line 101) | function decryptWallet(wallet, password, scrypt = DEFAULT_SCRYPT) {
  function validateAddress (line 115) | function validateAddress(address) {
  function convertScryptParams (line 125) | function convertScryptParams({n, r, p, dkLen}) {
  function getExplorerUrl (line 170) | function getExplorerUrl() {
  function getTransactionListUrl (line 176) | function getTransactionListUrl(address, page_size = 10, page_number =1) {
  function getBalanceUrl (line 182) | function getBalanceUrl(address, token_type = 'NATIVE') {
  function getTokenListUrl (line 188) | function getTokenListUrl(token_type = 'oep4', page_size = 10, page_numbe...
  function getTokenBalanceUrl (line 194) | function getTokenBalanceUrl(token_type, address) {
  function validateKeystorePath (line 200) | function validateKeystorePath(path) {
  function formatScryptParams (line 215) | function formatScryptParams(scrypt) {
  function splitPath (line 224) | function splitPath(path) {
  function convertPathToBuffer (line 240) | function convertPathToBuffer(path) {

FILE: src/main.js
  method data (line 36) | data () {

FILE: src/store/modules/CreateIdentity.js
  method ADD_CREATE_IDENTITY_STEP (line 12) | ADD_CREATE_IDENTITY_STEP(state, payload) {
  method SUB_CREATE_IDENTITY_STEP (line 15) | SUB_CREATE_IDENTITY_STEP(state, payload) {
  method CREATE_IDENTITY (line 20) | CREATE_IDENTITY(state, payload) {
  method INIT_CREATE_IDENTITY (line 26) | INIT_CREATE_IDENTITY(state, payload) {
  method createIdentityWithPrivateKey (line 36) | createIdentityWithPrivateKey({commit}, body) {

FILE: src/store/modules/CreateJsonWallet.js
  method ADD_CREATE_JSON_STEP (line 14) | ADD_CREATE_JSON_STEP(state, payload) {
  method SUB_CREATE_JSON_STEP (line 17) | SUB_CREATE_JSON_STEP(state, payload) {
  method CREATE_JSON_WALLET (line 22) | CREATE_JSON_WALLET(state, payload) {
  method INIT_JSON_WALLET (line 30) | INIT_JSON_WALLET(state, payload) {
  method createJsonWalletWithPrivateKey (line 42) | createJsonWalletWithPrivateKey({commit}, body) {

FILE: src/store/modules/CreateSharedWallet.js
  method CREATE_SHARED_WALLET (line 16) | CREATE_SHARED_WALLET(state, payload) {
  method UPDATE_CREATE_SHARED_LABEL (line 21) | UPDATE_CREATE_SHARED_LABEL(state, payload) {
  method UPDATE_REQUIRED_SIG_NUMBER (line 24) | UPDATE_REQUIRED_SIG_NUMBER(state, payload) {
  method ADD_CREATE_SHARED_STEP (line 27) | ADD_CREATE_SHARED_STEP(state, payload) {
  method SUB_CREATE_SHARED_STEP (line 30) | SUB_CREATE_SHARED_STEP(state, payload) {
  method UPDATE_CREATE_SHARED_COPAYERS (line 35) | UPDATE_CREATE_SHARED_COPAYERS(state, payload) {
  method CLEAR_CREATE_SHARED_STATE (line 38) | CLEAR_CREATE_SHARED_STATE(state,payload) {
  method createSharedWallet (line 51) | createSharedWallet({ commit, dispatch }, body) {

FILE: src/store/modules/CurrentWallet.js
  method UPDATE_CURRENT_WALLET (line 51) | UPDATE_CURRENT_WALLET(state, payload){
  method UPDATE_TRANSFER (line 54) | UPDATE_TRANSFER(state, payload) {
  method UPDATE_LOCAL_COPAYERS (line 57) | UPDATE_LOCAL_COPAYERS(state, payload) {
  method UPDATE_PENDINGTX (line 60) | UPDATE_PENDINGTX(state, payload) {
  method UPDATE_CURRENT_SIGNER (line 63) | UPDATE_CURRENT_SIGNER(state, payload) {
  method UPDATE_NATIVE_BALANCE (line 66) | UPDATE_NATIVE_BALANCE(state, payload) {
  method CLEAR_NATIVE_BALANCE (line 69) | CLEAR_NATIVE_BALANCE(state, payload) {
  method CLEAR_CURRENT_TRANSFER (line 72) | CLEAR_CURRENT_TRANSFER(state, payload) {
  method UPDATE_CURRENT_REDEEM (line 88) | UPDATE_CURRENT_REDEEM(state, payload) {
  method UPDATE_NEP5_ONT (line 91) | UPDATE_NEP5_ONT(state, payload) {
  method UPDATE_TRANSFER_REDEEM_TYPE (line 94) | UPDATE_TRANSFER_REDEEM_TYPE(state, payload) {
  method clearTransferBalance (line 102) | clearTransferBalance({commit}) {
  method getNativeBalance (line 105) | getNativeBalance({commit}, {address}) {

FILE: src/store/modules/Identities.js
  method FETCH_IDENTITIES (line 8) | FETCH_IDENTITIES(state, payload) {
  method DELETE_IDENTITY (line 11) | DELETE_IDENTITY(state, payload) {
  method fetchIdentitiesFromDb (line 20) | async fetchIdentitiesFromDb({ commit }, pk) {

FILE: src/store/modules/ImportSharedWallet.js
  method ADD_IMPORT_SHARED_STEP (line 11) | ADD_IMPORT_SHARED_STEP(state, payload) {
  method SUB_IMPORT_SHARED_STEP (line 14) | SUB_IMPORT_SHARED_STEP(state, payload) {
  method UPDATE_LOCAL_COPAYERS (line 19) | UPDATE_LOCAL_COPAYERS(state, payload) {
  method UPDATE_SHARED_WALLET (line 22) | UPDATE_SHARED_WALLET(state, payload) {
  method CLEAR_IMPORT_SHARED_STATE (line 25) | CLEAR_IMPORT_SHARED_STATE(state, payload) {

FILE: src/store/modules/LedgerConnector.js
  function formatLedgerStatus (line 7) | function formatLedgerStatus(status) {
  function getDevice (line 12) | function getDevice(commit, state) {
  function getLedgerPublicKey (line 38) | function getLedgerPublicKey(commit, state) {
  function getLedgerWallet (line 53) | function getLedgerWallet(commit, pk) {
  method UPDATE_LEDGER_DEVICE_INFO (line 74) | UPDATE_LEDGER_DEVICE_INFO(state, payload){
  method UPDATE_LEDGER_PUBLICKEY (line 77) | UPDATE_LEDGER_PUBLICKEY(state, payload) {
  method UPDATE_LEDGER_STATUS (line 80) | UPDATE_LEDGER_STATUS(state, payload) {
  method UPDATE_LEDGER_CONNECTOR_INTERVALID (line 83) | UPDATE_LEDGER_CONNECTOR_INTERVALID(state, payload) {
  method UPDATE_LEDGER_CONNECTOR_WALLET (line 86) | UPDATE_LEDGER_CONNECTOR_WALLET(state, payload) {
  constant LEDGER_CONNECTOR_INTERVAL (line 91) | const LEDGER_CONNECTOR_INTERVAL = 'ledger_connector_intervalId'
  method getLedgerStatus (line 94) | getLedgerStatus({dispatch,commit,state}, interval) {
  method stopGetLedgerStatus (line 103) | stopGetLedgerStatus({commit, state}) {

FILE: src/store/modules/LedgerWallet.js
  method LOGIN_WITH_LEDGER (line 11) | LOGIN_WITH_LEDGER(state, payload) {
  method someAsyncTask (line 18) | someAsyncTask({ commit }) {
  method loginWithLedger (line 22) | loginWithLedger({ commit }, pk) {
  method createLedgerWalletWithPk (line 33) | createLedgerWalletWithPk({commit}, body) {

FILE: src/store/modules/LoadingModal.js
  method SHOW_LOADING_MODALS (line 7) | SHOW_LOADING_MODALS(state) {
  method HIDE_LOADING_MODALS (line 10) | HIDE_LOADING_MODALS(state) {
  method showLoadingModals (line 16) | showLoadingModals({commit}) {
  method hideLoadingModals (line 20) | hideLoadingModals({commit}) {

FILE: src/store/modules/NodeAuthorization.js
  function matchNodeName (line 16) | async function matchNodeName(list) {
  function fetchRoundBlocks (line 53) | async function fetchRoundBlocks() {
  function delay (line 66) | function delay(s) {
  function formatAuthorizationInfo (line 73) | function formatAuthorizationInfo(info) {
  method UPDATE_CURRENT_PEER (line 132) | UPDATE_CURRENT_PEER(state, payload) {
  method UPDATE_PEER_ATTRS (line 143) | UPDATE_PEER_ATTRS(state, payload) {
  method UPDATE_CURRENT_NODE (line 156) | UPDATE_CURRENT_NODE(state, payload) {
  method UPDATE_AUTHORIZATION_INFO (line 159) | UPDATE_AUTHORIZATION_INFO(state, payload) {
  method UPDATE_SPLIT_FEE (line 178) | UPDATE_SPLIT_FEE(state, payload) {
  method UPDATE_COUNTDOWN_BLOCK (line 181) | UPDATE_COUNTDOWN_BLOCK(state, payload) {
  method UPDATE_NODE_LIST (line 184) | UPDATE_NODE_LIST(state, payload) {
  method UPDATE_POS_LIMIT (line 187) | UPDATE_POS_LIMIT(state, payload) {
  method UPDATE_PEER_UNBOUND_ONG (line 190) | UPDATE_PEER_UNBOUND_ONG(state, payload) {
  method UPDATE_STAKE_HISTORY (line 193) | UPDATE_STAKE_HISTORY(state, payload) {
  method UPDATE_STAKE_AUTHORIZATION_WALLET (line 196) | UPDATE_STAKE_AUTHORIZATION_WALLET(state, payload) {
  method UPDATE_PEER_POOL_MAP (line 199) | UPDATE_PEER_POOL_MAP(state, payload) {
  method CLEAR_STAKE_HISTORY (line 202) | CLEAR_STAKE_HISTORY(state, payload) {
  method UPDATE_SORTED_NODE_LIST (line 205) | UPDATE_SORTED_NODE_LIST(state, {list}) {
  method fetchPeerItem (line 211) | async fetchPeerItem({commit}, pk){
  method fetchPeerAttributes (line 235) | async fetchPeerAttributes({commit}, pk) {
  method fetchAuthorizationInfo (line 243) | async fetchAuthorizationInfo({commit}, {pk, address}) {
  method fetchSplitFee (line 252) | async fetchSplitFee({commit}, address) {
  method searchStakeHistory (line 264) | async searchStakeHistory({commit, dispatch, state}, {address}) {
  method fetchAllSortedNodeList (line 314) | async fetchAllSortedNodeList({commit, dispatch}) {
  method fetchNodeList (line 349) | async fetchNodeList({commit, dispatch, state}, {pageSize, pageNum}) {
  method fetchNodeListNew (line 393) | async fetchNodeListNew({commit, dispatch}, {pageSize, pageNum}) {
  method fetchBlockCountdown (line 435) | async fetchBlockCountdown({commit}) {
  method fetchPosLimit (line 455) | async fetchPosLimit({commit}) {
  method fetchPeerUnboundOng (line 467) | async fetchPeerUnboundOng({commit}, address) {

FILE: src/store/modules/NodeAuthorizationSesameseed.js
  method UPDATE_CURRENT_SS_PEER (line 12) | UPDATE_CURRENT_SS_PEER(state, payload) {
  method fetchSSPerInfo (line 21) | async fetchSSPerInfo({ commit }, address) {

FILE: src/store/modules/NodeStake.js
  method UPDATE_STAKE_IDENTITY (line 30) | UPDATE_STAKE_IDENTITY(state, payload) {
  method UPDATE_STAKE_WALLET (line 33) | UPDATE_STAKE_WALLET(state, payload) {
  method UPDATE_NODE_PUBLICKEY (line 36) | UPDATE_NODE_PUBLICKEY(state, payload) {
  method UPDATE_NODE_STATUS (line 39) | UPDATE_NODE_STATUS(state, payload) {
  method UPDATE_STAKE_STATUS (line 42) | UPDATE_STAKE_STATUS(state, payload) {
  method UPDATE_STAKE_DETAIL (line 49) | UPDATE_STAKE_DETAIL(state, payload) {
  method UPDATE_MENU_TAB_INDEX (line 52) | UPDATE_MENU_TAB_INDEX(state, index) {
  function formatStatusText (line 57) | function formatStatusText(status){
  function getStatus (line 62) | function getStatus(status) {
  method fetchStakeDetail (line 157) | fetchStakeDetail({commit}, {address, public_key}){
  method fetchNodeInfo (line 175) | async fetchNodeInfo({ }, public_key) {
  method updateNodeInfo (line 185) | async updateNodeInfo({ }, info) {
  method updateLedgerNodeInfo (line 191) | async updateLedgerNodeInfo({ }, info) {
  method newStakeInfo (line 197) | async newStakeInfo({ }, info) {

FILE: src/store/modules/Oep4s.js
  method ADD_OEP4 (line 25) | ADD_OEP4(state, payload) {
  method UPDATE_OEP4S (line 30) | UPDATE_OEP4S(state, payload) {
  method UPDATE_OEP4_TX_LIST (line 33) | UPDATE_OEP4_TX_LIST(state, payload) {
  method addOep4Token (line 39) | async addOep4Token({commit, dispatch, state}, {scriptHash, address})  {
  method registerOep4Info (line 64) | async registerOep4Info({commit, dispatch}, scriptHash) {
  method queryOep4Name (line 81) | async queryOep4Name({commit}, scriptHash) {
  method queryOep4Symbol (line 94) | async queryOep4Symbol({ commit }, scriptHash) {
  method queryOep4Decimal (line 107) | async queryOep4Decimal({ commit }, scriptHash) {
  method queryOep4Balance (line 120) | async queryOep4Balance({commit}, {scriptHash, address, decimal=0}) {
  method queryBalanceForOep4 (line 135) | async queryBalanceForOep4({commit, dispatch, state}, address) {
  method queryTxForOep4 (line 164) | async queryTxForOep4({commit, dispatch}, {address,oep4s}) {

FILE: src/store/modules/PaxMgmt.js
  method UPDATE_UNPROCESS_LIST (line 14) | UPDATE_UNPROCESS_LIST(state, {list}) {
  method UPDATE_PROCESSING_LIST (line 17) | UPDATE_PROCESSING_LIST(state, {list}) {
  method UDPATE_CURRENT_SIGNER (line 20) | UDPATE_CURRENT_SIGNER(state, {signer}) {

FILE: src/store/modules/Setting.js
  method UPDATE_SETTING_NETWORK (line 10) | UPDATE_SETTING_NETWORK(state, payload) {
  method NETWORK_CONNECTED (line 13) | NETWORK_CONNECTED(state, payload) {
  method NETWORK_DISCONNECTED (line 16) | NETWORK_DISCONNECTED(state, payload) {

FILE: src/store/modules/Tokens.js
  method UPDATE_OEP4_TOKENS (line 26) | UPDATE_OEP4_TOKENS(state, {oep4s}) {
  method UPDATE_OEP4_TOKEN (line 31) | UPDATE_OEP4_TOKEN(state, {oep4}) {
  method UPDATE_OEP4_BALANCES (line 52) | UPDATE_OEP4_BALANCES(state, {balances}) {
  method CLEAR_OEP4S_BALANCES (line 55) | CLEAR_OEP4S_BALANCES(state) {
  method fetchOep4Selections (line 61) | async fetchOep4Selections({commit, state}, {page_size, page_number}) {
  method fetchTokenBalances (line 82) | async fetchTokenBalances({commit,state}, {address}) {

FILE: src/store/modules/Vote.js
  constant VOTE_STATUS_TEXT (line 36) | const VOTE_STATUS_TEXT = {
  constant MY_VOTED (line 43) | const MY_VOTED = {
  function formatVoteInfo (line 99) | function formatVoteInfo(infos) {
  method UPDATE_VOTE_WALLET (line 195) | UPDATE_VOTE_WALLET(state, { voteWallet }) {
  method UPDATE_VOTE_ROLE (line 198) | UPDATE_VOTE_ROLE(state, { role }) {
  method UPDATE_ALL_VOTES (line 201) | UPDATE_ALL_VOTES(state, { votes }) {
  method UPDATE_ADMIN_VOTES (line 204) | UPDATE_ADMIN_VOTES(state, { votes }) {
  method UPDATE_VOTE_WALLET_TYPE (line 207) | UPDATE_VOTE_WALLET_TYPE(state, { type }) {
  method UPDATE_CURRENT_VOTE (line 210) | UPDATE_CURRENT_VOTE(state, { vote }) {
  method UPDATE_MY_WEIGHT (line 213) | UPDATE_MY_WEIGHT(state, { weight }) {
  method UPDATE_ALL_VOTERS (line 216) | UPDATE_ALL_VOTERS(state, { all_voters }) {
  method UPDATE_CURRENT_VOTE_RECORDS (line 219) | UPDATE_CURRENT_VOTE_RECORDS(state, { records }) {
  method UPDATE_VOTE_CONTRACT (line 222) | UPDATE_VOTE_CONTRACT(state, contract_hash) {
  method fetchVoteContract (line 228) | async fetchVoteContract({commit}) {
  method getVoteRole (line 238) | async getVoteRole({ commit, dispatch, state }, { address }) {
  method getAllVotes (line 318) | async getAllVotes({ commit, dispatch, state }, {showLoading}) {
  method getAdminVotes (line 395) | async getAdminVotes({ commit, dispatch, state }) {
  method submitVote (line 409) | submitVote({ commit, state }, { type, hash }) {
  method stopVote (line 422) | stopVote({ commit, dispatch, state }, { hash }) {
  method createVote (line 434) | createVote({ commit, dispatch, state }, { vote }) {
  method setVoters (line 451) | async setVoters({ commit, dispatch, state }, { hash, voters }) {
  method getVoters (line 476) | async getVoters({ commit, state }, { hash }) {
  method isVoter (line 498) | async isVoter({ commit, dispatch, state }, { hash }) {
  method getVotedInfo (line 509) | async getVotedInfo({ commit, state }, { hash, address }) {
  method getVotedRecords (line 535) | async getVotedRecords({ commit, dispatch, state }, { hash }) {
  method setCurrentVote (line 572) | setCurrentVote({ commit }, { vote }) {
  method updateCurrentVote (line 575) | async updateCurrentVote({ commit, state }, { hash }) {

FILE: src/store/modules/Wallets.js
  method FETCH_WALLETS (line 10) | FETCH_WALLETS(state, payload) {
  method DELETE_COMMON_WALLET (line 15) | DELETE_COMMON_WALLET(state, payload) {
  method DELETE_SHARED_WALLET (line 21) | DELETE_SHARED_WALLET(state, payload) {
  method DELETE_HARDWARE_WALLET (line 27) | DELETE_HARDWARE_WALLET(state, payload) {
  method fetchWalletsFromDb (line 36) | async fetchWalletsFromDb({ commit }, pk) {
Condensed preview — 141 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (830K chars).
[
  {
    "path": ".browserslistrc",
    "chars": 30,
    "preview": "> 1%\nlast 2 versions\nnot dead\n"
  },
  {
    "path": ".editorconfig",
    "chars": 147,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert_final_newline = true\ntrim_"
  },
  {
    "path": ".eslintrc.js",
    "chars": 435,
    "preview": "module.exports = {\n  root: true,\n  env: {\n    node: true\n  },\n  'extends': [\n    'plugin:vue/essential',\n    'eslint:rec"
  },
  {
    "path": ".github/workflows/publish.yml",
    "chars": 6207,
    "preview": "name: Release on Tag\n\non:\n  push:\n    tags:\n      - '*' # Listen for any tag push events\n\njobs:\n  build-and-release:\n   "
  },
  {
    "path": ".gitignore",
    "chars": 276,
    "preview": ".DS_Store\nnode_modules\n/dist\n.sign\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nnpm-debug.log*\nyarn-debug.log"
  },
  {
    "path": "LICENSE",
    "chars": 1065,
    "preview": "MIT License\n\nCopyright (c) 2018 Ontology\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
  },
  {
    "path": "README.md",
    "chars": 1643,
    "preview": "[中文版](./README_cn.md)\n\n\n\n<h1 align=\"center\">OWallet - a comprehensive Ontology desktop wallet</h1>\n<h4 align=\"center\">Ve"
  },
  {
    "path": "README_cn.md",
    "chars": 932,
    "preview": "[English Version](./README.md)\n\n\n\n<h1 align=\"center\">OWallet - 本体综合性桌面版钱包 </h1>\n<h4 align=\"center\">Version 0.10.0</h4>\n\n"
  },
  {
    "path": "babel.config.js",
    "chars": 179,
    "preview": "module.exports = {\n  presets: [\n    '@vue/cli-plugin-babel/preset'\n  ],\n  plugins: [\n    [\"import\", { libraryName: \"ant-"
  },
  {
    "path": "build/after-sign.js",
    "chars": 4635,
    "preview": "// build/after-sign.js\n\nconst { execSync } = require(\"child_process\");\nconst path = require(\"path\");\nconst fs = require("
  },
  {
    "path": "build/entitlements.mac.plist",
    "chars": 324,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \n\"http://www.apple.com/DTDs/"
  },
  {
    "path": "package.json",
    "chars": 2369,
    "preview": "{\n  \"name\": \"owallet\",\n  \"homepage\": \"http://ont.io\",\n  \"version\": \"v0.10.4\",\n  \"author\": \"Ontology Foundation Ltd. <dev"
  },
  {
    "path": "public/index.html",
    "chars": 601,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE="
  },
  {
    "path": "src/App.vue",
    "chars": 8116,
    "preview": "<template>\n  <div id=\"app\">\n    <top-left-nav v-if=\"$route.name !== 'Home'\"></top-left-nav>\n\n    <div class=\"container-f"
  },
  {
    "path": "src/background.js",
    "chars": 4750,
    "preview": "'use strict'\n\nimport { app, protocol, BrowserWindow, Menu } from 'electron'\nimport { createProtocol } from 'vue-cli-plug"
  },
  {
    "path": "src/components/Breadcrumb.vue",
    "chars": 2103,
    "preview": "<style scoped>\n    .breadcrumb-container {\n        height:4rem;\n        padding:1.1rem 0 1.1rem 15px;\n        padding-le"
  },
  {
    "path": "src/components/Common/CommonSignShared.vue",
    "chars": 3822,
    "preview": "<style scoped>\n.sign-container {\n    display: flex;\n}\n.label {\n    width:200px;\n     margin-right:10px;\n}\n.sign-content "
  },
  {
    "path": "src/components/Common/Oep4Home.vue",
    "chars": 9426,
    "preview": "<style scoped>\n.content-container {\n    display: flex;\n    padding:10px;\n  }\n\n  .left-half {\n    flex-basis: 50%;\n    pa"
  },
  {
    "path": "src/components/Common/Oep4Selection.vue",
    "chars": 3052,
    "preview": "<style scoped>\n.selection-container {\n    height:370px;\n    margin-top:-15px;\n}\n.pages {\n    margin:0 auto;\n    margin-t"
  },
  {
    "path": "src/components/Common/SelectWallet.vue",
    "chars": 3545,
    "preview": "<template>\n\t<div class=\"select-container\">\n\t\t<a-select :options=\"normalWalletAndLedgerWallet\"\n\t\t\tclass=\"select-ontid\"\n\t\t"
  },
  {
    "path": "src/components/Common/SignSendTx.vue",
    "chars": 10065,
    "preview": "<style scoped>\n\n</style>\n<template>\n    <div>\n    <a-modal\n        :title=\"$t('nodeStake.signWithWallet')\"\n        :visi"
  },
  {
    "path": "src/components/CommonWallet/CommonReceive.vue",
    "chars": 3297,
    "preview": "<style scoped>\n.content-container {\n    width:540px;\n    margin:20px auto;\n}\n.label {\n    font-family: AvenirNext-Bold;\n"
  },
  {
    "path": "src/components/CommonWallet/CommonRedeem.vue",
    "chars": 8566,
    "preview": "<style scoped>\n.container {\n    width:540px;\n    margin:4rem auto;\n}\n.label {\n    font-family: AvenirNext-Bold;\n    font"
  },
  {
    "path": "src/components/CommonWallet/CommonTokenSwap.vue",
    "chars": 5773,
    "preview": "<style scoped>\n\n  .content-container {\n    display: flex;\n    margin-top: 40px;\n  }\n\n  .left-half {\n    flex-basis: 50%;"
  },
  {
    "path": "src/components/CommonWallet/SendConfirm.vue",
    "chars": 11079,
    "preview": "<style scoped>\n  .confirm-container {\n\n  }\n\n  .drag-item {\n    cursor: pointer;\n  }\n\n  .label-container {\n    position: "
  },
  {
    "path": "src/components/CommonWallet/SendHome.vue",
    "chars": 1749,
    "preview": "<template>\n  <div>\n    <breadcrumb :current=\"$t('sharedWalletHome.send')\" :routes=\"routes\"\n                v-on:backEven"
  },
  {
    "path": "src/components/Dapps.vue",
    "chars": 8750,
    "preview": "\n<style scoped>\n.dapps-container {\n    padding: 20px 20px;\n}\n.dapp-item {\n    margin: 15px;\n    cursor: pointer;\n    bac"
  },
  {
    "path": "src/components/Dashboard.vue",
    "chars": 16749,
    "preview": "<style scoped>\n  .header-header {\n    height: 4rem;\n    padding: 1.1rem 0;\n    width: 100%;\n\n  }\n\n  .home-container {\n  "
  },
  {
    "path": "src/components/Exchange/Changelly/Changelly.vue",
    "chars": 2073,
    "preview": "<style scoped>\n.changelly-container {\n  position: relative;\n  padding-bottom: 75%;\n  height: 0;\n  overflow: hidden;\n}\n.c"
  },
  {
    "path": "src/components/Exchange/Cryptonex/Cryptonex.vue",
    "chars": 1050,
    "preview": "<style scoped>\n.cryptonex-container {\n  position: relative;\n  padding-bottom: 75%;\n  height: 0;\n  overflow: hidden;\n}\n.c"
  },
  {
    "path": "src/components/Home.vue",
    "chars": 4287,
    "preview": "\n<style scoped>\n  @import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro');\n\n  .row-home {\n    margin-left"
  },
  {
    "path": "src/components/Identitys/Create/BasicInfo.vue",
    "chars": 10737,
    "preview": "<template>\n  <div>\n    <div class=\"basic-label\">\n      <a-input class=\"input\" :placeholder=\"$t('createIdentity.label')\" "
  },
  {
    "path": "src/components/Identitys/Create/ConfirmInfo.vue",
    "chars": 3304,
    "preview": "<template>\n  <div class=\"container json-confirm-container\">\n    <p><b>{{$t('createIdentity.label')}}: </b> {{label}}</p>"
  },
  {
    "path": "src/components/Identitys/CreateIdentity.vue",
    "chars": 1460,
    "preview": "<template>\n  <div>\n    <breadcrumb :current=\"$t('createIdentity.create')\" v-on:backEvent=\"back\"></breadcrumb>\n    <div c"
  },
  {
    "path": "src/components/Identitys/IdentityView.vue",
    "chars": 6912,
    "preview": "<template>\n  <div class=\"common-detail-container\">\n    <div >\n      <div class=\"div-shared-wallet-sign\">\n        <span>{"
  },
  {
    "path": "src/components/Identitys/Import/BasicInfo.vue",
    "chars": 7546,
    "preview": "<template>\n  <div class=\"container json-import-container\">\n    <ul class=\"nav nav-pills import-identity-nav-pills\" id=\"p"
  },
  {
    "path": "src/components/Identitys/ImportIdentity.vue",
    "chars": 762,
    "preview": "<template>\n  <div>\n    <breadcrumb :current=\"$t('importIdentity.import')\" v-on:backEvent=\"back\"></breadcrumb>\n    <div c"
  },
  {
    "path": "src/components/Identitys.vue",
    "chars": 3903,
    "preview": "<template>\n  <div class=\"negative-margin-top\">\n    <ul class=\"nav nav-pills wallets-nav-pills\" id=\"pills-tab\" role=\"tabl"
  },
  {
    "path": "src/components/JsonWallet/Create/BasicInfo.vue",
    "chars": 4218,
    "preview": "<template>\n  <div>\n    <div class=\"basic-label\">\n      <a-input class=\"input\" :placeholder=\"$t('createJsonWallet.label')"
  },
  {
    "path": "src/components/JsonWallet/Create/ConfirmInfo.vue",
    "chars": 4730,
    "preview": "<template>\n  <div class=\"container json-confirm-container\">\n    <p><b>{{$t('createJsonWallet.labelN')}}: </b> {{label}}<"
  },
  {
    "path": "src/components/JsonWallet/CreateJsonWallet.vue",
    "chars": 1656,
    "preview": "<template>\n  <div>\n    <breadcrumb :current=\"$t('createJsonWallet.create')\" v-on:backEvent=\"back\"></breadcrumb>\n    <div"
  },
  {
    "path": "src/components/JsonWallet/Import/BasicInfo.vue",
    "chars": 18399,
    "preview": "<style scoped>\n.json-import-container {\n  width: 48rem;\n  padding-bottom: 100px;\n}\n\n.import-json-nav-pills>li.nav-item {"
  },
  {
    "path": "src/components/JsonWallet/ImportJsonWallet.vue",
    "chars": 960,
    "preview": "<template>\n  <div>\n    <breadcrumb :current=\"$t('importJsonWallet.create')\" v-on:backEvent=\"back\"></breadcrumb>\n    <div"
  },
  {
    "path": "src/components/JsonWallet/View/Details.vue",
    "chars": 13074,
    "preview": "<template>\n  <div class=\"common-detail-container\">\n    <div>\n      <div class=\"div-shared-wallet-sign\">\n        <span>{{"
  },
  {
    "path": "src/components/LedgerWallet/Import/BasicInfo.vue",
    "chars": 13717,
    "preview": "<template>\n  <div class=\"container ledger-import-container\">\n    <div>\n      <a-input class=\"input\" :placeholder=\"$t('im"
  },
  {
    "path": "src/components/LedgerWallet/Import/ConnectLedger.vue",
    "chars": 1955,
    "preview": "<template>\n  <div class=\"div-ledger-info\">\n    <div class=\"div-ledger-info-tit\">\n      <strong>{{ $t(\"ledgerWallet.info\""
  },
  {
    "path": "src/components/LedgerWallet/ImportLedgerWallet.vue",
    "chars": 1132,
    "preview": "<template>\n  <div>\n    <breadcrumb\n      :current=\"$t('importLedgerWallet.import')\"\n      v-on:backEvent=\"back\"\n    ></b"
  },
  {
    "path": "src/components/LedgerWallet/LoginLedger.vue",
    "chars": 4066,
    "preview": "<template>\n  <div id=\"wrapper\">\n    <main>\n      <div class=\"left-side\">\n        <router-link to=\"Wallets\" class=\"backBt"
  },
  {
    "path": "src/components/Modals/Loading.vue",
    "chars": 1821,
    "preview": "<template>\n<div>\n  <transition name=\"fade\">\n    <!-- transition seems not working -->\n  <div v-if=\"showLoading\">\n       "
  },
  {
    "path": "src/components/Modals/SetPath.vue",
    "chars": 2837,
    "preview": "<template>\n  <div class=\"modal modal_wapper fade\" id=\"setPathModal\" v-if=\"value\">\n    <div class=\"modal-dialog\" role=\"do"
  },
  {
    "path": "src/components/Node/Node.vue",
    "chars": 4566,
    "preview": "<style scoped>\n.node-container {\n    position: relative;\n    width:100%;\n    padding:22px 20px;\n}\n.center-content {\n    "
  },
  {
    "path": "src/components/Node/NodeApply/Register.vue",
    "chars": 11081,
    "preview": "<template>\n<div>\n\t<div v-if=\"!registerSucceed\">\n\t\t<breadcrumb :current=\"$t('nodeApply.newNodeApply')\"\n\t\t\tv-on:backEvent="
  },
  {
    "path": "src/components/Node/NodeApply/RegisterSuccess.vue",
    "chars": 1360,
    "preview": "<template>\n    <div class=\"success-container\">\n        <img :src=\"require('../../../assets/success.svg')\" alt=\"\">\n      "
  },
  {
    "path": "src/components/Node/NodeAuthorize/AuthorizationMgmt.vue",
    "chars": 14490,
    "preview": "<style scoped>\n.content-container {\n    display: flex;\n  }\n\n  .left-half {\n    flex-basis: 55%;\n    padding-right: 20px;"
  },
  {
    "path": "src/components/Node/NodeAuthorize/AuthorizeLogin.vue",
    "chars": 4032,
    "preview": "<style scoped>\n.auth-login {\n    width:540px;\n    margin:20px auto;\n}\n.select-wallet {\n    width:100%;\n}\n.change-payer-r"
  },
  {
    "path": "src/components/Node/NodeAuthorize/NewAuthorization.vue",
    "chars": 5214,
    "preview": "<style scoped>\n.content-container {\n    width:540px;\n    margin:20px auto;\n}\n.content-container div {\n    margin-bottom:"
  },
  {
    "path": "src/components/Node/NodeAuthorize/NodeList.vue",
    "chars": 8462,
    "preview": "<style scoped>\n.block-clock {\n    width:540px;\n    height: 80px;\n    margin:15px auto;\n    border:1px solid #dddddd;\n}\n."
  },
  {
    "path": "src/components/Node/NodeAuthorize/Sesameseed/AuthorizationMgmtSesameseed.vue",
    "chars": 9546,
    "preview": "<style scoped>\n.content-container {\n  display: flex;\n}\n\n.left-half {\n  flex-basis: 55%;\n  padding-right: 20px;\n}\n\n.right"
  },
  {
    "path": "src/components/Node/NodeAuthorize/Sesameseed/AuthorizeLoginSesameseed.vue",
    "chars": 5502,
    "preview": "<style scoped>\n.auth-login {\n    width:540px;\n    margin:20px auto;\n}\n.select-wallet {\n    width:100%;\n}\n.change-payer-r"
  },
  {
    "path": "src/components/Node/NodeAuthorize/Sesameseed/NewAuthorizationSesameseed.vue",
    "chars": 5297,
    "preview": "<style scoped>\n.content-container {\n  width: 540px;\n  margin: 20px auto;\n}\n.content-container div {\n  margin-bottom: 15p"
  },
  {
    "path": "src/components/Node/NodeAuthorize/Sesameseed/SesameseedVars.js",
    "chars": 148,
    "preview": "export const CONTRACT_HASH = 'a63c33d2209854feafbf40685a33d4846ee82556'\nexport const SESAMESEED_NODE_ADDRESS = 'ANRRE8xK"
  },
  {
    "path": "src/components/Node/NodeAuthorize/StakeHistory.vue",
    "chars": 7137,
    "preview": "<style scoped>\n.detail-link {\n    text-align: center;\n    cursor: pointer;\n}\n.detail-link i {\n    font-size:20px;\n}\n\n.au"
  },
  {
    "path": "src/components/Node/NodeManagement/MyNode.vue",
    "chars": 5216,
    "preview": "<template>\n\t<div class=\"nodes-container\">\n\t\t<breadcrumb :current=\"$t('myNode.myNode')\"\n\t\t\tv-on:backEvent=\"back\"></breadc"
  },
  {
    "path": "src/components/Node/NodeManagement/NodeStakeAuthorization.vue",
    "chars": 13656,
    "preview": "<style scoped>\n.content-container {\n    padding: 10px 10px;\n}\n.header-text {\n    font-size:16px;\n}\n\n.stake-content {\n   "
  },
  {
    "path": "src/components/Node/NodeManagement/NodeStakeManagement.vue",
    "chars": 2505,
    "preview": "<style scoped>\n.btn-new-stake {\n    width:200px !important;\n    float: right;\n    margin-right: 10px;\n    top: -50px;\n}\n"
  },
  {
    "path": "src/components/Node/NodeStake/NodeInfo.vue",
    "chars": 7267,
    "preview": "<template>\n<div>\n    <!-- <div v-if=\"!stakeWallet.key\" class=\"ledger-not-support\">\n        <p>{{$t('nodeInfo.ledgerWalle"
  },
  {
    "path": "src/components/Node/NodeStake/NodeStakeInfo.vue",
    "chars": 20720,
    "preview": "<style scoped>\n.nodeStake-container {\n  width: 540px;\n  margin: 0px auto;\n  padding-top:20px;\n}\n.detail-item {\n  margin-"
  },
  {
    "path": "src/components/Node/NodeStake/NodeStakeIntro.vue",
    "chars": 7068,
    "preview": "<style scoped>\n.intro-content {\n  width: 540px;\n  margin: 0rem auto;\n}\n.btn-known {\n  margin: 20px auto;\n  text-align: c"
  },
  {
    "path": "src/components/Node/NodeStake/NodeStakeRegister.vue",
    "chars": 9758,
    "preview": "<style scoped>\n.nodeStake-container {\n  width: 540px;\n  margin: 20px auto;\n}\n.detail-item {\n  margin-bottom: 15px;\n}\n.de"
  },
  {
    "path": "src/components/Node/Vote/Create.vue",
    "chars": 7536,
    "preview": "<template>\n\t<div>\n\t\t<breadcrumb :routes=\"routes\"\n\t\t\t:current=\"$t('vote.new')\"\n\t\t\tv-on:backEvent=\"back\"></breadcrumb>\n\t\t<"
  },
  {
    "path": "src/components/Node/Vote/Detail.vue",
    "chars": 12385,
    "preview": "<template>\n\t<div>\n\t\t<breadcrumb :routes=\"routes\"\n\t\t\t:current=\"$t('vote.votingDetail')\"\n\t\t\tv-on:backEvent=\"back\"></breadc"
  },
  {
    "path": "src/components/Node/Vote/List.vue",
    "chars": 10574,
    "preview": "<template>\n\t<div>\n        <breadcrumb :routes=\"routes\" :current=\"$t('vote.votingTopics')\" v-on:backEvent=\"back\"></breadc"
  },
  {
    "path": "src/components/Node/Vote/Login.vue",
    "chars": 5401,
    "preview": "<template>\n    <div>\n        <breadcrumb :routes=\"routes\" :current=\"$t('vote.login')\" v-on:backEvent=\"back\"></breadcrumb"
  },
  {
    "path": "src/components/Node/Vote/index.vue",
    "chars": 156,
    "preview": "<template>\n    <div>\n        <router-view></router-view>\n    </div>\n</template>\n<script>\nexport default {\n    name: 'Nod"
  },
  {
    "path": "src/components/RedeemInfoIcon.vue",
    "chars": 1086,
    "preview": "<style scoped>\n.redeem-info-icon {\n    margin-left: 10px;\n  font-size: 16px;\n  cursor: pointer;\n  color:#D0D2D9;\n}\n.rede"
  },
  {
    "path": "src/components/Setting.vue",
    "chars": 4899,
    "preview": "<template>\n  <div class=\"setting-container\">\n    <breadcrumb :current=\"$t('setting.name')\" v-on:backEvent=\"handleBack\"><"
  },
  {
    "path": "src/components/SharedWallet/Create/BasicInfo.vue",
    "chars": 7202,
    "preview": "<template>\n    <div class=\"basic-container\">\n        <div class=\"basic-label\">\n            <a-input class=\"input\" :class"
  },
  {
    "path": "src/components/SharedWallet/Create/ConfirmSigNum.vue",
    "chars": 5115,
    "preview": "<template>\n  <div class=\"basic-container\">\n    <p class=\"confirm-label wallet-label\" style=\"margin-bottom:40px;\">{{label"
  },
  {
    "path": "src/components/SharedWallet/Create/CreateSuccess.vue",
    "chars": 985,
    "preview": "<template>\n<div>\n    <div class=\"content\">\n        <a-alert :message=\"$t('createSharedWallet.success')\" type=\"success\" s"
  },
  {
    "path": "src/components/SharedWallet/CreateSharedWallet.vue",
    "chars": 1730,
    "preview": "<style scoped>\n.shared-container {\n}\n  .steps-content {\n  }\n\n  .steps-action {\n    margin-top: 24px;\n  }\n\n  .create-step"
  },
  {
    "path": "src/components/SharedWallet/Import/InputPass.vue",
    "chars": 5738,
    "preview": "<style scoped>\n\n\n.wallet-info {\n    margin-bottom: 20px;\n}\n.wallet-info-item label {\n    font-weight: bold;\n}\n\n.choose-l"
  },
  {
    "path": "src/components/SharedWallet/Import/QuerySharedWallet.vue",
    "chars": 3430,
    "preview": "<style scoped>\n.query-input {\n    width:540px;\n    margin:20px auto;\n}\n.result-item {\n    float:left;\n    width:100%;\n}\n"
  },
  {
    "path": "src/components/SharedWallet/ImportSharedWallet.vue",
    "chars": 1128,
    "preview": "<style scoped>\n\n.import-steps {\n    width:540px;\n    margin:0 auto;\n    height: 4rem;\n}\n</style>\n<template>\n<div>\n    <b"
  },
  {
    "path": "src/components/SharedWallet/PAX/PaxMgmt.vue",
    "chars": 13936,
    "preview": "<style scoped>\n.pax-container {\n    text-align: center;\n    position: relative;\n}\n.btn-ethScan {\n    position: absolute;"
  },
  {
    "path": "src/components/SharedWallet/PAX/SignProcess.vue",
    "chars": 13275,
    "preview": "<style scoped>\n.sign-container {\n    width:700px;\n    margin:20px auto;\n}\n.label-container {\n    position: relative;\n}\n."
  },
  {
    "path": "src/components/SharedWallet/PAX/StartProcess.vue",
    "chars": 11630,
    "preview": "<style scoped>\n.start-container {\n    width: 700px;\n    margin:20px auto;\n}\n.drag-item {\n    cursor: pointer;\n}\n.label-c"
  },
  {
    "path": "src/components/SharedWallet/PendingTxHome.vue",
    "chars": 1604,
    "preview": "<style scoped>\n.pending-container {\n    width:600px;\n    margin:4rem auto;\n}\n</style>\n\n<template>\n    <div>\n        <bre"
  },
  {
    "path": "src/components/SharedWallet/SharedWalletDetail.vue",
    "chars": 169,
    "preview": "\n\n\n<template>\n    <div>\n        <router-view></router-view>\n    </div>\n</template>\n<script>\nexport default {\n    name: '"
  },
  {
    "path": "src/components/SharedWallet/SharedWalletHome.vue",
    "chars": 19786,
    "preview": "<style scoped>\n.header-header {\n  height: 4rem;\n  padding: 1.1rem 0;\n  width: 100%;\n}\n.home-container {\n  padding: 0 20p"
  },
  {
    "path": "src/components/SharedWallet/SharedWalletSend.vue",
    "chars": 2782,
    "preview": "<style scoped>\n    .send-container {\n        width:600px;\n        margin:0 auto;\n        padding-bottom:5.3rem;\n        "
  },
  {
    "path": "src/components/SharedWallet/Transfer/InputPassword.vue",
    "chars": 10640,
    "preview": "<style scoped>\n.label {\n    font-weight: bold;\n    font-family: 'AvenirNext-Bold';\n    color: #5E6369;\n    font-size:1.2"
  },
  {
    "path": "src/components/SharedWallet/Transfer/PendingConfirm.vue",
    "chars": 6732,
    "preview": "<style scoped>\n.confirm-container {\n    height: 400px;\n    padding-bottom: 20px;\n    overflow:auto;\n}\n\n.label-container "
  },
  {
    "path": "src/components/SharedWallet/Transfer/PendingTxSign.vue",
    "chars": 8511,
    "preview": "<style scoped>\n.label {\n    font-weight: bold;\n    font-family: 'AvenirNext-Bold';\n    color: #5E6369;\n    font-size:1.2"
  },
  {
    "path": "src/components/SharedWallet/Transfer/SendAsset.vue",
    "chars": 8107,
    "preview": "<style scoped>\n.label {\n    font-weight: bold;\n    position: relative;\n    font-family: 'AvenirNext-Bold';\n    color: #5"
  },
  {
    "path": "src/components/SharedWallet/Transfer/SendConfirm.vue",
    "chars": 7388,
    "preview": "<style scoped>\n.confirm-container {\n\n}\n.drag-item {\n    cursor: pointer;\n}\n.label-container {\n    position: relative;\n}\n"
  },
  {
    "path": "src/components/SharedWallet/Tx/SharedTxMgmt.vue",
    "chars": 2858,
    "preview": "<style scoped>\n.pax-container {\n    text-align: center;\n    position: relative;\n}\n</style>\n<template>\n    <div>\n        "
  },
  {
    "path": "src/components/SharedWallet/Tx/SignSharedTx.vue",
    "chars": 5947,
    "preview": "<style scoped>\n.tx-container {\n    padding:20px 60px;\n    text-align: left;\n}\n.tx-title {\n    font-size: 18px;\n    font-"
  },
  {
    "path": "src/components/SharedWallet/Tx/StartSharedTx.vue",
    "chars": 5768,
    "preview": "<style scoped>\n.tx-container {\n    padding:20px 60px;\n    text-align: left;\n}\n.tx-title {\n    font-size: 18px;\n    font-"
  },
  {
    "path": "src/components/SharedWallet/View/Details.vue",
    "chars": 3917,
    "preview": "<template>\n  <div>\n    <div @click=\"toSharedWalletHome(wallet)\">\n      <div class=\"div-shared-wallet-sign\">{{ $t('common"
  },
  {
    "path": "src/components/SharedWallet/View/SharedWalletCopayer.vue",
    "chars": 3831,
    "preview": "<style scoped>\n.wallet-info {\n    margin-bottom: 20px;\n}\n.wallet-info-item label {\n    font-weight: bold;\n}\n\n.choose-loc"
  },
  {
    "path": "src/components/TopLeftNav.vue",
    "chars": 4766,
    "preview": "<template>\n  <div>\n    <div class=\"left-nav text-center\">\n      <router-link class=\"logo-div\" to=\"Home\">\n        <img cl"
  },
  {
    "path": "src/components/Wallets.vue",
    "chars": 9874,
    "preview": "<template>\n  <div class=\"negative-margin-top\">\n    <ul class=\"nav nav-pills wallets-nav-pills\" id=\"pills-tab\" role=\"tabl"
  },
  {
    "path": "src/core/asyncHelper.js",
    "chars": 129,
    "preview": "export default function asyncWrap (promise) {\n  return promise.then(data => {\n    return [null, data]\n  }).catch(err => "
  },
  {
    "path": "src/core/consts.js",
    "chars": 5683,
    "preview": "// export const GAS_PRICE = '0';for test\nexport const GAS_PRICE = '500';\nexport const GAS_LIMIT = '20000';\n\nexport const"
  },
  {
    "path": "src/core/dbService.js",
    "chars": 1697,
    "preview": "// import path, { resolve } from 'path'\nimport electron from 'electron'\n// const app = electron.remote.app;\nimport { app"
  },
  {
    "path": "src/core/fileHelper.js",
    "chars": 821,
    "preview": "\nexport default {\n    downloadFile(json, fileName) {\n        let content = new Blob([JSON.stringify(json)], { type: \"tex"
  },
  {
    "path": "src/core/lang.js",
    "chars": 328,
    "preview": "export default {\n    setLang(lang) {\n        window.localStorage.setItem('user_lang', lang)\n    },\n    getLang(defaultLa"
  },
  {
    "path": "src/core/network.js",
    "chars": 1017,
    "preview": "import {WebsocketClient} from 'ontology-ts-sdk';\nimport store from '../store'\nimport { MAIN_NET_LIST, TEST_NET_LIST } fr"
  },
  {
    "path": "src/core/nodes.json",
    "chars": 5002,
    "preview": "[\n    {\n        \"name\": \"Dubhe\",\n        \"pk\": \"02bcdd278a27e4969d48de95d6b7b086b65b8d1d4ff6509e7a9eab364a76115af7\",\n   "
  },
  {
    "path": "src/core/ontLedger.js",
    "chars": 8340,
    "preview": "import LedgerNode from '@ledgerhq/hw-transport-node-hid'\nimport asyncWrap from './asyncHelper'\nimport { utils, Crypto } "
  },
  {
    "path": "src/core/ontLedgerNew.js",
    "chars": 8626,
    "preview": "import { convertPathToBuffer } from \"./utils\";\nimport i18n from '../lang'\n\nconst STATUS_CODES = {\n  SW_DENY: 0x6985,\n  S"
  },
  {
    "path": "src/core/runtime.js",
    "chars": 1207,
    "preview": "import {get} from 'lodash'\nimport {\n  Crypto\n} from 'ontology-ts-sdk';\n\n\nimport {\n  getClient\n} from './network';\n\n\nexpo"
  },
  {
    "path": "src/core/utils.js",
    "chars": 6200,
    "preview": "import {\n  TEST_NET,\n  MAIN_NET,\n  MAIN_NET_LIST,\n  DEFAULT_SCRYPT,\n  TEST_NET_LIST\n} from './consts'\nimport axios from "
  },
  {
    "path": "src/lang/en.js",
    "chars": 33617,
    "preview": "export default {\n  common: {\n    testNet: 'TestNet',\n    mainNet: 'MainNet',\n    copied: 'Copied!',\n    confirmPwdTips: "
  },
  {
    "path": "src/lang/index.js",
    "chars": 304,
    "preview": "import Vue from \"vue\";\nimport VueI18n from \"vue-i18n\";\nimport en from \"./en\";\nimport zh from \"./zh\";\nimport LangStorage "
  },
  {
    "path": "src/lang/zh.js",
    "chars": 22413,
    "preview": "export default {\n  common: {\n    testNet: 'TestNet',\n    mainNet: 'Main Net',\n    copied: '已复制!',\n    confirmPwdTips: '请"
  },
  {
    "path": "src/main.js",
    "chars": 3420,
    "preview": "import Vue from 'vue'\nimport axios from 'axios'\nimport VueAxios from 'vue-axios'\n\nimport App from './App'\nimport router "
  },
  {
    "path": "src/router/index.js",
    "chars": 8433,
    "preview": "import Vue from 'vue'\nimport Router from 'vue-router'\n\nVue.use(Router)\n\nexport default new Router({\n    routes: [{\n     "
  },
  {
    "path": "src/store/index.js",
    "chars": 189,
    "preview": "import Vue from 'vue'\nimport Vuex from 'vuex'\n\nimport modules from './modules'\n\nVue.use(Vuex)\n\nexport default new Vuex.S"
  },
  {
    "path": "src/store/modules/CreateIdentity.js",
    "chars": 1554,
    "preview": "import { Wallet, Identity, Crypto, OntidContract, TransactionBuilder } from \"ontology-ts-sdk\";\nimport {GAS_PRICE, GAS_LI"
  },
  {
    "path": "src/store/modules/CreateJsonWallet.js",
    "chars": 1565,
    "preview": "import { Wallet, Account, Crypto } from \"ontology-ts-sdk\";\n\nconst state = {\n  currentStep: 0,\n  label: '',\n  address: ''"
  },
  {
    "path": "src/store/modules/CreateSharedWallet.js",
    "chars": 2556,
    "preview": "import axios from 'axios';\nimport { ONT_PASS_NODE, ONT_PASS_NODE_PRD, ONT_PASS_URL } from '../../core/consts'\nimport dbS"
  },
  {
    "path": "src/store/modules/CurrentWallet.js",
    "chars": 3401,
    "preview": "import axios from 'axios'\nimport {\n  getBalanceUrl\n } from '../../core/utils'\n\nconst state = {\n    wallet : {\n        //"
  },
  {
    "path": "src/store/modules/Identities.js",
    "chars": 894,
    "preview": "import dbService, { dbFind } from '../../core/dbService';\n\nconst state = {\n    Identities: []\n}\n\nconst mutations = {\n   "
  },
  {
    "path": "src/store/modules/ImportSharedWallet.js",
    "chars": 860,
    "preview": "import axios from 'axios';\nimport { ONT_PASS_NODE, ONT_PASS_URL } from '../../core/consts'\nimport dbService from '../../"
  },
  {
    "path": "src/store/modules/LedgerConnector.js",
    "chars": 3592,
    "preview": "import { getDeviceInfo, getPublicKey } from '../../core/ontLedger'\nimport en from '../../lang/en'\nimport zh from '../../"
  },
  {
    "path": "src/store/modules/LedgerWallet.js",
    "chars": 1442,
    "preview": "import { Crypto } from 'ontology-ts-sdk'\nimport { WALLET_TYPE} from '../../core/consts'\nimport dbService from '../../cor"
  },
  {
    "path": "src/store/modules/LoadingModal.js",
    "chars": 839,
    "preview": "// import $ from 'jquery'\nconst state = {\n  showLoading: false\n}\n\nconst mutations = {\n  SHOW_LOADING_MODALS(state) {\n   "
  },
  {
    "path": "src/store/modules/NodeAuthorization.js",
    "chars": 17708,
    "preview": "import { getNodeUrl} from '../../core/utils'\nimport {NODE_DETAIL, NODE_NAME_LIST, OFF_CHAIN_NODES, NODE_CURRENT_STAKES} "
  },
  {
    "path": "src/store/modules/NodeAuthorizationSesameseed.js",
    "chars": 1642,
    "preview": "import { utils } from 'ontology-ts-sdk'\nimport axios from 'axios';\n\nconst state = {\n    sesameseed: { // for node user\n "
  },
  {
    "path": "src/store/modules/NodeStake.js",
    "chars": 6469,
    "preview": "import axios from 'axios'\nimport en from '../../lang/en'\nimport zh from '../../lang/zh'\nimport { ONT_PASS_NODE, ONT_PASS"
  },
  {
    "path": "src/store/modules/Oep4s.js",
    "chars": 7823,
    "preview": "import {Oep4, RestClient, Crypto, utils} from 'ontology-ts-sdk'\nimport {TEST_NET, MAIN_NET} from '../../core/consts'\nimp"
  },
  {
    "path": "src/store/modules/PaxMgmt.js",
    "chars": 511,
    "preview": "const state = {\n    unprocess_list: [\n       \n    ],\n    processing_list: [\n         {\n           cosigners: []\n        "
  },
  {
    "path": "src/store/modules/Setting.js",
    "chars": 512,
    "preview": "import dbService, { dbFind } from '../../core/dbService';\n\nconst net = localStorage.getItem('net');\nconst state = {\n    "
  },
  {
    "path": "src/store/modules/Tokens.js",
    "chars": 3298,
    "preview": "import httpService, {\n  getRestClient,\n  getTokenListUrl,\n  getTokenBalanceUrl\n} from '../../core/utils'\n\n// should cont"
  },
  {
    "path": "src/store/modules/Vote.js",
    "chars": 24201,
    "preview": "import { NODE_CURRENT_STAKES,OFF_CHAIN_NODES,  VOTE_ROLE, DEFAULT_SCRYPT, ONT_PASS_NODE, ONT_PASS_NODE_PRD,\n    ONT_PASS"
  },
  {
    "path": "src/store/modules/Wallets.js",
    "chars": 1990,
    "preview": "import dbService, {dbFind} from '../../core/dbService';\n\nconst state = {\n    NormalWallet:[],\n    SharedWallet: [],\n    "
  },
  {
    "path": "src/store/modules/index.js",
    "chars": 377,
    "preview": "/**\n * The file enables `@/store/index.js` to import all vuex modules\n * in a one-shot manner. There should not be any r"
  },
  {
    "path": "vue.config.js",
    "chars": 1469,
    "preview": "module.exports = {\n  pluginOptions: {\n    electronBuilder: {\n      nodeIntegration: true,\n      externals: [\"node-hid\", "
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the ontio/OWallet GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 141 files (754.2 KB), approximately 195.1k tokens, and a symbol index with 259 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!