# 介绍

通过阅读本文档，可以使你快速上手使用 NightELF 进行 Dapp 开发。

[release version](/langs-zh) 等候发布......

[dev version NightELF](https://chrome.google.com/webstore/detail/aelf-explorer-extension-d/mlmlhipeonlflbcclinpbmcjdnpnmkpf)

## 如果你是普通用户

你可以直接略过以下内容，并仔细阅读 [User use document](/langs-zh/user)。

这会让你了解作为一名用户如何使用 NightELF 进行一些日常操作。

## 如果你是开发者

### 为什么要使用NightELF

通过 NightELF 可以帮助你快速实现AELF的转账、查询等操作。使你可以更加专注Dapp开发。

你可以通过查看 [Examples](broken://pages/-Lz523jfSee6U-WEIEc0) 了解如何快速实现转账功能

### 我们在开发 NightELF 时的一些想法

1. 我们要做一个支持AELF生态的浏览器扩展应用。
2. 这个扩展应用可以满足生态内的Dapp的交易签名。
3. 扩展应用本身可以当做一个钱包来使用（暂时未添加该功能）。

### 目前NightELF支持的功能

1. Dapp 的授权管理 （用户授权Dapp的合约使用权限管理）。
2. keypair 的创建、删除、备份、导入。
3. NightELF 的加密备份与导入。（通过导出NightELF备份文件，用户可以在任意一台装有Chrome浏览器的电脑上使用NightELF 而无需重新导入每一个keypair与授权信息）
4. NightELF 的定时锁定功能（防止用户离开后被恶意操作）
5. READONLY (不涉及到用户资产交易的方法无需用户确认信息 如 GetBalance)
6. 合约白名单 (如用户经常用到的Transfer 加入白名单后无需反复确认)

### Project Information

We use [ECDH](https://github.com/indutny/elliptic) to use public key to encryt data and private key to decrypt data.


# 用户文档

如果你是一名普通的用户，使用NightELF来做一些日常的操作的话，这里会举一些通俗易懂的例子来帮助你快速上手NightELF。


# 安装

你可以到 Chrome 应用商店搜索 `aelf-explorer-extension-dev` 或者 [点击此处下载](https://chrome.google.com/webstore/detail/aelf-explorer-extension-d/mlmlhipeonlflbcclinpbmcjdnpnmkpf)

你也可以通过[Github](https://github.com/hzz780/aelf-web-extension/tree/master/installFiles) 中的 public.crx 文件进行安装。


# 创建

## 创建

你可以把 NightELF 看做一个 keypair 与 授权的管理工具，你的所有 Keypair 与相应的授权情况都会在 NightELF 中显示，并且你可以通过。在初次使用 NightELF 的时候, 你需要做如下操作。

![Create](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-LubkfJd2l6Oq4EEAfqx%2Fstep-01.jpg?generation=1574772586829092\&alt=media)

首选你需要输入一个长度至少达到9位的密码，需要有一定的复杂程度, 可以包含大写字母、小写字母、符号、数字。 然后点击 `创建钱包` 按钮

## 协议

通过上一步，你可以看见NightELF的使用协议，请详细阅读我们的使用协议并决定您是否要使用NightELF，然后点击同意或者取消

![Agreen](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-LubkfJfLO9DBOQGtw-q%2Fstep-02.jpg?generation=1574772586750620\&alt=media)

## 使用界面

如果您看到了以下界面，证明你已经创建成功了。

![Home](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-LubkfJhSQFEkODE4z4c%2Fstep-03.jpg?generation=1574772586731447\&alt=media)


# 创建密钥对

## 创建密钥

\*如果你已经拥有了Keypair，请直接查看 [Keypair的备份与导入](/langs-zh/user/backup-import)

![Keypair](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-Lubkeop37aDT2p3-yRg%2Fstep-04.jpg?generation=1574772584740715\&alt=media)

点击图中所示的 `创建密钥` 按钮创建属于你的Keypair

![Create Keypair](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-LubkeorOWK9OPNLWnUa%2Fstep-05.jpg?generation=1574772586535196\&alt=media)

这里我们输入 `属于我的密钥`

你也可以输入任意一个你喜欢的Keypair的别名，来创建属于你自己的Keypair。

## 备份助记词

首先，你要备份你的助记词，助记词与你的 keypair 是一对一的关系，请仔细抄写助记词并妥善保管。

请勿使用截图，因为他人获取到你的助记词的同时他也将直接获取你的资产。

如果你不进行助记词的备份，那么你将无法创建这个Keypair。

![Backup](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-LubkeotGxTONoYkv73i%2Fstep-06.jpg?generation=1574772586654094\&alt=media)

按照顺序排列你所记录的助记词，用来确保你所记录的助记词为正确的。

![Backup](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-Lubkeovl7jh6A6Xw5Wt%2Fstep-07.jpg?generation=1574772584837670\&alt=media)

## 创建完成

创建完成后，在Keypair管理中，你就可以看到刚刚创建的 `属于我的密钥` 并可以看到与该Keypair相对应的地址 你可以点击 `复制地址` 复制你的 keypair 地址。

其他人可以通过该地址使用 AELF钱包 向你当前的账户进行Token转账。

![Success](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-LubkeoxUHFJ5Pjlzfh_%2Fstep-08.jpg?generation=1574772585898759\&alt=media)


# 备份/导入密钥对

## 备份 Keypair

如果你不慎遗失了你所记录的助记词怎么办？

这时候不要紧张，你只需要在 Keypair管理下找到 `备份`

![Backup keypair](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-LubkfTM0m2N1cqCqUYy%2Fstep-09.jpg?generation=1574772587847751\&alt=media)

这时你可以看到，你可以进行 `助记词` 的备份与 `私钥` 的备份。 无论是助记词还是私钥都可以帮助你导入你的Keypair。

点击你想要备份的类型，会弹出密码输入弹出昂，这里需要你输入你所设置的NightELF 密码。

1. 如果你选择了备份助记词，那么你的助记词会显示在当前界面中。

   ![Backup Mnemonic](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-LubkeotGxTONoYkv73i%2Fstep-06.jpg?generation=1574772586654094\&alt=media)

   你可以重新抄写你的助记词，并妥善保管。
2. 如果你选择了备份私钥，那么你将会看到私钥，并记录它。

   同样你的私钥也不能透露给其他人，如果他人得到了你的私钥他一样可以得到你的资产。

   ![Backup Private](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-LubkfTOpAi14ogB8ZaX%2Fstep-10.jpg?generation=1574772587359486\&alt=media)

## 导入 Keypair

如果你不慎卸载了 Chrome 浏览器，或者你的设备发生了损坏，不得已需要在其他设备上使用NightELF

你可以通过 导入Keypair 的方式导入你的Keypair。

![Import Keypair](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-Lubkeop37aDT2p3-yRg%2Fstep-04.jpg?generation=1574772584740715\&alt=media)

点击 `导入密钥` 按钮

![Import Keypair](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-LubkfTQHSgE32W0txFE%2Fstep-11.jpg?generation=1574772587458957\&alt=media)

我们提供了`助记词` 与 `私钥` 两种导入方式。无论你是用`助记词`还是用`私钥`都可以导入你的 Keypair，你可以通过点击助记词或者点击私钥来进行切换。（请勿将私钥填入助记词、或助记词填入私钥，这样做无法帮你找回keypair）

![Import Keypair](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-LubkfTS1UQ73B2X-IlZ%2Fstep-12.jpg?generation=1574772587494476\&alt=media)

输入`助记词`或者`私钥`后，输入Keypair别名，这里Keypair别名无需与之前相同，我们会帮你重新命名。

点击 `提交` 按钮后，你就可以看到已经导入的Keypair了。

![Import Keypair](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-LubkeoxUHFJ5Pjlzfh_%2Fstep-08.jpg?generation=1574772585898759\&alt=media)


# 备份插件

## 备份 NightELF

你可以备份你的NightELF数据，防止你的设备损坏或丢失。

你可以在NightELF主页点击 `管理` -> `备份NightELF` 然后输入你的 NightELF 密码。

![Backup NightELF](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-Lubkf806VW3MOX8wbnO%2Fstep-13.jpg?generation=1574772585836588\&alt=media)

点击 `备份NightELF`

浏览器会下载名为 `NightELF_backup_file_xxxxxx.txt` 文件， 请勿修改文件内的内容以防出现无法恢复数据的情况，并妥善存储该文件，同样建议你每隔一段时间就对 NightELF 进行一次备份。

文件经过加密处理，打开文件无法直接获取你的keypair信息，但是你依然要妥善保存。


# 删除密钥对/插件

## 删除 Keypair

如果你想在 NightELF 中移除某个 Keypair 你只需在 Keypair 管理页面点击相应的删除即可，这一操作无需你提供 NightELf 密码。

![Create Keypair](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-Lubken17346igre71S0%2Fstep-14.jpg?generation=1574772584490883\&alt=media)

点击`确认` 按钮即可删除你想要删除的Keypair，但是这一操作并不会删除你对该 Keypair 做的Dapp授权。

## 删除 NightELF

如果你想移除NightELF并清空数据，你可以通过 `管理` 中的 `删除NightELF` 进行删除，这一操作需要你输入你的NightELF密码，你也可以直接在Chrome中删除 NightELF 同样可以清空数据。


# 权限管理

当你授权某一Dapp权限时，你可以在NightELF中查看你授权的信息。

你可以通过 Home 中的 `应用管理` 查看你的所有授权信息。

![Permission Manager](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-Lubke_3C96l717rslSW%2Fstep-15.jpg?generation=1574772585066657\&alt=media)

你可以通过 `查看详情` 查看授权的详细合约信息，包含合约地址、合约名称、合约详细信息等....

![Permission Manager](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-Lubke_5PNnWtvvTF-Hg%2Fstep-16.jpg?generation=1574772585822205\&alt=media)

你可以选择删除某一个合约的权限，也可以选择删除全部权限。这一步不需要你提供 NightELF 密码，但是需要注意，删除某一合约可能导致您无法继续使用该合约的合约方法。

如果你删除MultiToken合约，那么你将无法进行转账与资产查询。


# 如何在DApp中使用

## 如何在Dapp中使用NightELF

当你进入一个符合AELF生态的 Dapp时，通常第一步会弹出提示框让你进行授权，你可以选择你任意的Keypair进行授权。

![Login](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-Lubkekh73mI6CPlY08J%2Fstep-17.jpg?generation=1574772598355945\&alt=media)

点击 `登录` 你可以看到看到当前 Dapp 所需要授权的详细信息。这可能包含 域名、合约地址、合约名称、合约介绍、Github地址等。

![Login](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-LubkekjvIBA8E9RkUrq%2Fstep-18.jpg?generation=1574772598379014\&alt=media)

如果你关掉这个窗口或者点击`取消` 则认为你不允许这次应用授权，那么你可能将无法使用该Dapp或者无法使用Dapp的大部分功能。

看到成功的提示后，你可以到NightELF的`应用管理`查找你授权的信息，如果你不知道如何找到授权信息可以查看[Permission Manager](/langs-zh/user/permission)


# 自动锁定

## 为什么要设置定时锁定

如果你已经做过授权，并且长时间离开你的个人设备并忘记锁定，那么对于你的资产是极其不安全的。任何人都可以通过NightELF进行操作。 NightELF 默认会设置15分钟的锁定时间，十五分钟之内你如果未做任何操作，NightELF会自动锁定，以此来保护你的资产安全。

## 如何设置定时锁定

如果你认为默认时间太长或者太短，你可以对定时锁定时间进行设置。我们提供了部分时间区间供选择，你也可以选择不需要自动锁定。

![Lock](https://2347166847-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-LubkdNCkmFe8t5enEta%2F-Lubkf05YpeEm5cvhARE%2Fstep-19.jpg?generation=1574772585317195\&alt=media)


# 开发者文档

## 1 Download

[release version, please waiting](/langs-zh/devdocs)

[dev version](https://chrome.google.com/webstore/detail/aelf-explorer-extension-d/mlmlhipeonlflbcclinpbmcjdnpnmkpf)

## 2 Preparation

### 2.1 Interaction Flow

* 1.Make sure the user get the Extension
* 2.Connect the blockchain
* 3.Initialize contract / Call the methods of the blockchain
* 4.Call the methods of contract&#x20;

### 2.2 Demo of Checking the Extension

```javascript
let nightElfInstance = null;
class NightElfCheck {
    constructor() {
        const readyMessage = 'NightElf is ready';
        let resovleTemp = null;
        this.check = new Promise((resolve, reject) => {
            if (window.NightElf) {
                resolve(readyMessage);
            }
            setTimeout(() => {
                reject({
                    error: 200001,
                    message: 'timeout / can not find NightElf / please install the extension'
                });
            }, 1000);
            resovleTemp = resolve;
        });
        document.addEventListener('NightElf', result => {
            console.log('test.js check the status of extension named nightElf: ', result);
            resovleTemp(readyMessage);
        });
    }
    static getInstance() {
        if (!nightElfInstance) {
            nightElfInstance = new NightElfCheck();
            return nightElfInstance;
        }
        return nightElfInstance;
    }
}
const nightElfCheck = NightElfCheck.getInstance();
nightElfCheck.check.then(message => {
    // connectChain -> Login -> initContract -> call contract methods
});
```

### 2.3 How Connect the blockchain

```javascript
const aelf = new window.NightElf.AElf({
    httpProvider: [
        'http://127.0.0.1:8101',
    ],
    appName: 'your own app name'
});
```

### 2.4 How to call the API

Callback or promise are both ok.

```javascript
// callback
aelf.chain.getChainStatus((error, result) => {
    console.log('>>>>>>>>>>>>> getChainStatus >>>>>>>>>>>>>');
    console.log(error, result);
});

// promise
aelf.chain.getChainStatus().then(result => {
    console.log('>>>>>>>>>>>>> getChainStatus >>>>>>>>>>>>>');
    console.log('promise then', result);
}).catch(error => {
    console.log('promise catch', error);
});
```

## 3 API Reference

Here you can find examples and in-depth information about NightELF's API.

You can see the demo code. [click here](https://github.com/AElfProject/aelf-web-extension/blob/master/devDemos/test.html)

If you want to check token transfer demo. [click here](https://github.com/AElfProject/aelf-web-extension/blob/master/demo/token/demo.html)

The methods act the same as the methods of the aelf-sdk.js

* [1. LOGIN](/langs-zh/devdocs#login)
* [2. GET\_CHAIN\_STATUS](/langs-zh/devdocs#get-chain-status)
* [3. CALL\_AELF\_CHAIN](/langs-zh/devdocs#call-aelf-chain)
* [4. INIT\_AELF\_CONTRACT](/langs-zh/devdocs#init-aelf-contract)
* [5. CALL\_AELF\_CONTRACT / CALL\_AELF\_CONTRACT\_READONLY](/langs-zh/devdocs#call-aelf-contract)
* [6. CHECK\_PERMISSION](/langs-zh/devdocs#check-permission)
* [7. SET\_CONTRACT\_PERMISSION](/langs-zh/devdocs#set-contract-permission)
* [8. REMOVE\_CONTRACT\_PERMISSION](/langs-zh/devdocs#remove-contract-permission)
* [9. REMOVE\_METHODS\_WHITELIST](/langs-zh/devdocs#remove-methods-whitelist)
* [10. GET\_SIGNATURE](/langs-zh/devdocs#get-signature)

### 3.1 LOGIN

LOGIN allows your application to request permission to interact with a user's NightELF and be provided with an account of the user's choosing.

```javascript
aelf.login({
    chainId: 'AELF',
    payload: {
        method: 'LOGIN',
        contracts: [{
            chainId: 'AELF',
            contractAddress: '4rkKQpsRFt1nU6weAHuJ6CfQDqo6dxruU3K3wNUFr6ZwZYc',
            contractName: 'token',
            description: 'token contract',
            github: ''
        }, {
            chainId: 'AELF TEST',
            contractAddress: '2Xg2HKh8vusnFMQsHCXW1q3vys5JxG5ZnjiGwNDLrrpb9Mb',
            contractName: 'TEST contractName',
            description: 'contract description',
            github: ''
        }]
    }
}, (error, result) => {
    console.log('login>>>>>>>>>>>>>>>>>>', result);
});

// result = {
//     "error": 0,
//     "errorMessage": "",
//     "message": "",
//     "detail": {
//         "name": "your name",
//         "address": "2RCLmZQ2291xDwSbDEJR6nLhFJcMkyfrVTq1i1YxWC4SdY49a6",
//         "publicKey": {
//             "x": "4958d5c48f003c771769f4a31413cd18053516615cbde502441af8452fb53441",
//             "y": "a80cc48a7f3b0f2552fd030cacbe9012ba055a3d553b70003f2e637d55fa0f23"
//         }
//     },
//     "sid": "350815427961739930163684",
//     "from": "contentNightElf"
// }

// the data in the extension
// keychain = {
//     keypairs: [{
//         name: 'your keypairs name',
//         address: 'your keypairs address',
//         mnemonic: 'your keypairs mnemonic',
//         privateKey: 'your keypairs privateKey'，
//         publicKey: {
//             x: 'f79c25eb......',
//             y: '7fa959ed......'
//         }
//     }],
//     permissions: [{
//         appName: 'hzzTest',
//         address: 'your keyparis address',
//         contracts: [{
//             chainId: 'AELF',
//             contractAddress: '4rkKQpsRFt1nU6weAHuJ6CfQDqo6dxruU3K3wNUFr6ZwZYc',
//             contractName: 'token',
//             description: 'token contract',
//             github: ''
//         }],
//         domain: 'Dapp domain'
//     }]
// }
```

### 3.2 GET\_CHAIN\_STATUS

```javascript
aelf.chain.getChainStatus((error, result) => {
    console.log('>>>>>>>>>>>>> connectChain >>>>>>>>>>>>>');
    console.log(error, result);
});
```

### 3.3 CALL\_AELF\_CHAIN

```javascript
// this txid is an example.
const txid = 'c45edfcca86f4f528cd8e30634fa4ac53801aae05365cfefc3bfe9b652fe5768';
aelf.chain.getTxResult(txid, (err, result) => {
    console.log('>>>>>>>>>>>>> getTxResult >>>>>>>>>>>>>');
    console.log(err, result);
});

// result = {
//     Status: "NotExisted"
//     TransactionId: "c45edfcca86f4f528cd8e30634fa4ac53801aae05365cfefc3bfe9b652fe5768"
//     ....
// }
```

### 3.4 INIT\_AELF\_CONTRACT

```javascript
// In aelf-sdk.js wallet is the realy wallet.
// But in extension sdk, we just need the address of the wallet.
const wallet = {
    address: '2JqnxvDiMNzbSgme2oxpqUFpUYfMjTpNBGCLP2CsWjpbHdu'
};
// It is different from the wallet created by Aelf.wallet.getWalletByPrivateKey();
// There is only one value named address;
aelf.chain.contractAt(
    '4rkKQpsRFt1nU6weAHuJ6CfQDqo6dxruU3K3wNUFr6ZwZYc',
    wallet,
    (error, result) => {
        console.log('>>>>>>>>>>>>> contractAt >>>>>>>>>>>>>');
        console.log(error, result);
        tokenContract = result;
    }
);

// result = {
//     Approve: ƒ (),
//     Burn: ƒ (),
//     ChargeTransactionFees: ƒ (),
//     ClaimTransactionFees: ƒ (),
//     ....
// }
```

### 3.5 CALL\_AELF\_CONTRACT / CALL\_AELF\_CONTRACT\_READONLY

```javascript
// tokenContract from the pre step.
tokenContract.GetBalance.call(
    {
        symbol: 'AELF',
        owner: '65dDNxzcd35jESiidFXN5JV8Z7pCwaFnepuYQToNefSgqk9'
    },
    (err, result) => {
        console.log('>>>>>>>>>>>>>>>>>>>', result);
    }
);

tokenContract.Approve(
    {
        symbol: 'AELF',
        spender: '4rkKQpsRFt1nU6weAHuJ6CfQDqo6dxruU3K3wNUFr6ZwZYc',
        amount: '100'
    },
    (err, result) => {
        console.log('>>>>>>>>>>>>>>>>>>>', result);
    }
);

// If you use tokenContract.GetBalance.call  this method is only applicable to queries that do not require extended authorization validation.(CALL_AELF_CONTRACT_READONLY)
// If you use tokenContract.Approve this requires extended authorization validation (CALL_AELF_CONTRACT)

// tokenContract.GetBalance.call(payload, (error, result) => {})
// result = {
//     symbol: "AELF",
//     owner: "65dDNxzcd35jESiidFXN5JV8Z7pCwaFnepuYQToNefSgqk9",
//     balance: 0
// }
```

### 3.6 CHECK\_PERMISSION

CHECK\_PERMISSION returns the contracts your can use with the address.

```javascript
aelf.checkPermission({
    type: 'address', // if you did not set type, it aways get by domain.
    address: '4WBgSL2fSem9ABD4LLZBpwP8eEymVSS1AyTBCqXjt5cfxXK'
}, (error, result) => {
    console.log('>>>>>>>>>>>>>', error, result);
});

// result = {
//     ...,
//     permissions:[
//         {
//             address: '...',
//             appName: 'hzzTest',
//             contracts: [{
//                 chainId: 'AELF',
//                 contractAddress: '4rkKQpsRFt1nU6weAHuJ6CfQDqo6dxruU3K3wNUFr6ZwZYc',
//                 contractName: 'token',
//                 description: 'token contract',
//                 github: ''
//             },
//             {
//                 chainId: 'AELF TEST',
//                 contractAddress: 'TEST contractAddress',
//                 contractName: 'TEST contractName',
//                 description: 'contract description',
//                 github: ''
//             }],
//             domian: 'Dapp domain'
//         }
//     ]
// }
```

### 3.7 SET\_CONTRACT\_PERMISSION

SET\_CONTRACT\_PERMISSION applies to the users to allow the Dapp use the contract.

```javascript
aelf.setContractPermission({
    chainId: 'AELF',
    payload: {
        address: '2JqnxvDiMNzbSgme2oxpqUFpUYfMjTpNBGCLP2CsWjpbHdu',
        contracts: [{
            chainId: 'AELF',
            contractAddress: 'TEST contractAddress',
            contractName: 'AAAA',
            description: 'contract description',
            github: ''
        }]
    }
}, (error, result) => {
    console.log('>>>>>>>>>>>>>', error, result);
});
```

### 3.8 REMOVE\_CONTRACT\_PERMISSION

```javascript
aelf.removeContractPermission({
    chainId: 'AELF',
    payload: {
        contractAddress: '2Xg2HKh8vusnFMQsHCXW1q3vys5JxG5ZnjiGwNDLrrpb9Mb'
    }
}, (error, result) => {
    console.log('>>>>>>>>>>>>>', error, result);
});
```

### 3.9 REMOVE\_METHODS\_WHITELIST

```javascript
aelf.removeMethodsWhitelist({
    chainId: 'AELF',
    payload: {
        contractAddress: '2Xg2HKh8vusnFMQsHCXW1q3vys5JxG5ZnjiGwNDLrrpb9Mb',
        whitelist: ['Approve']
    }
}, (error, result) => {
    console.log('removeWhitelist>>>>>>>>>>>>>>>>>', result);
});
```

### 3.10 GET\_SIGNATURE

```javascript
aelf.getSignature({
    address: 'address',
    hexToBeSign: 'hexToBeSign'
}).then(result => {
  // ...
}).cathc(error => {
  // ...
});
```

## 4.For Extension Developers

### 4.1. Download the code

```bash
git clone https://github.com/AElfProject/aelf-web-extension.git
```

### 4.2 Install dependent

```bash
    npm install
```

### 4.3 Run webpack

```bash
    npm run none
    npm run none:watch
    npm run dev
    npm run dev:watch
    npm run pro
    npm run pro:watch
```

### 4.4 Add to the browser

```bash
    open development mode, add the webpack output app/public.
```

### 4.5 How to publish to chrome

zip app/public to public.zip, and follow the notes.

### 4.6 Can not use crx

You can not install the extension from an offline crx if Chrome >= 73.

Please import the `.zip file` with developer mode.

## 5 Formatted Data Example

```javascript
    NightElf = {
        histories: [],
        keychain: {
            keypairs: [
                {
                    name: 'your keypairs name',
                    address: 'your keypairs address',
                    mnemonic: 'your keypairs mnemonic',
                    privateKey: 'your keupairs privateKey',
                    publicKey: {
                        x: 'you keupairs publicKey',
                        y: 'you keupairs publicKey'
                    }
                }
            ],
            permissions: [
                {
                    chainId: 'AELF',
                    contractAddress: 'contract address',
                    contractName: 'contract name',
                    description: 'contract description',
                    github: 'contract github',
                    whitelist: {
                        Approve: {
                            parameter1: 'a',
                            parameter2: 'b',
                            parameter3: 'c'
                        }
                    }
                }
            ]
        }
    }
```


# Getting Started

By reading this document, you can quickly get started with Dapp development using NightELF.

release version coming soon

[dev version NightELF](https://chrome.google.com/webstore/detail/aelf-explorer-extension-d/mlmlhipeonlflbcclinpbmcjdnpnmkpf)

## For Users

You can skip the following and read the User use document carefully. It will be able to help you to use NightELF.

## For Developers

### Why do you need to use NightELF?

You can quickly implement operations such as making and querying transactions on AELF through NightELF. You can learn how to quickly implement the transfer function by checking Examples

### Few Thoughts When We Developed NightELF

1. We want to make a browser extension that supports the aelf ecosystem.
2. This extension can satisfy Dapps’ transaction signature in the aelf ecosystem.
3. This extension itself can be used as a wallet (this feature is not being added for the time being).

### Features Which NightELF Currently Supports

1. Dapp authorization management (users can authorize Dapp's contract usage rights management).
2. Keypair creation, deletion, backup, and import.
3. Encrypted backup and import of NightELF (By exporting NightELF backup file, users can use NightELF on any computer with Chrome without re-importing their keypairs and authorization information)
4. NightELF's timing lock function (to prevent users from malicious operations after leaving)
5. READONLY (Transaction methods that do not involve user asset do not require users’ confirmation such as GetBalance)
6. Contract Whitelist (such as transaction which often used by users, users do not need to be repeatedly confirmed after being added to the whitelist)

### Project Information

We use ECDH to use public keys to encrypt data and a private key to decrypt data.


# User document

If you are a user who use NightEL, here are some easy-to-understand examples to help you get started with NightELF quickly.


# Install

You can search `aelf-explorer-extension-dev` in Chrome App Store or click [here](https://chrome.google.com/webstore/detail/aelf-explorer-extension-d/mlmlhipeonlflbcclinpbmcjdnpnmkpf) to download. You can also install it from the public.crx file on Github.

You can download publick.crx from [Github](https://github.com/AElfProject/aelf-web-extension/tree/master/installFiles) too.


# Create

## Create NightELF Account

You can think of NightELF as a keypair and authorization management tool. All your keypairs and corresponding authorizations will be displayed in NightELF and you can manage them. When you are using NightELF for the first time, you need to do the following.

![Create](https://745133343-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-Lwc01oHXLh47jhyXlB8%2F-Lwc02mkF-M7h3W3e7ok%2Fcreate.jpg?generation=1576924364850422\&alt=media)

First, you need to enter a password with a length of at least 9 digits, which must have a certain degree of complexity. It can contain uppercase letters, lowercase letters, symbols, numbers. Then click the `Create Wallet` button

## Protocol

Through the previous step, you can see the NightELF User Agreement, please read it carefully and decide whether you want to use NightELF, then click Agree or Refuse

![Agreen](https://745133343-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-Lwc01oHXLh47jhyXlB8%2F-Lwc02mm48tTT4gkQxwJ%2Fprotocol.jpg?generation=1576924364910145\&alt=media)

## Homepage

If you see the following page, which means you have successfully created your NightELF account.

![Home](https://745133343-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-Lwc01oHXLh47jhyXlB8%2F-Lwc02moawosN_ngraO7%2FHomepage.jpg?generation=1576924364690558\&alt=media)


# Create Keypair


# Backup Keypair / Import Keypair

## Backup keypair

What if you accidentally lose your mnemonic?

Don't worry, you just need to click `backup` in Key Pairs page.

![Backup keypair](https://745133343-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-Lwc0TmmpfSBbQvtJGdy%2F-Lwc0UcQrVRQ4HBgpdZW%2Fbackup-wallet.jpg?generation=1576924479492645\&alt=media)

Then, you can use `Mnemonic` and `Private key` to back up. Both mnemonics and private key can help you to import your Keypair.

Click on the type you want to back up. A password input will pop up. Here you need to enter your NightELF password before backup.

## Import Keypair

If you accidentally uninstalled Chrome or your device was damaged and you will have to use NightELF on other devices.

We provide two methods: `Mnemonic` and `Private Key`. Whether you use a mnemonic or a private key can import your Keypair, you can switch by clicking the mnemonic or clicking the private key. (Do not enter the private key into the mnemonic or the mnemonic into the private key, this will not help you to retrieve the keypair).

![Import Keypair](https://745133343-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-Lwc0TmmpfSBbQvtJGdy%2F-Lwc0UcS869w2dRtkhjN%2Fkeypair.jpg?generation=1576924479680944\&alt=media)

Click the `Import Keypair` button

![Import Keypair](https://745133343-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-Lwc0TmmpfSBbQvtJGdy%2F-Lwc0UcUvcCU89I9SG9i%2Fimport-keypair.jpg?generation=1576924479479609\&alt=media)


# Backup NightELF

You can back up your NightELF data to prevent your device from being damaged or lost.

You can go to homepage first, then click Extension `Management` > `Backup NightELF`, enter your password and click Backup NightELF.

![Backup NightELF](https://745133343-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-Lwc0TmmpfSBbQvtJGdy%2F-Lwc0UnSpNNKeof5zKsm%2Fbackup-night-elf.jpg?generation=1576924480080818\&alt=media)

Click `Backup NightELF`

The browser will download the file named `NightELF_backup_file_xxxxxx.txt`.

Do not modify the file to prevent the data cannot be recovered. Please properly store the file. It is also recommended that you backup your NightELF once in a while.

The file is encrypted. You cannot directly get your keypair information when you open the file, but you still need to keep it properly.


# Delete Keypair / Delete NightELF

## Delete Keypair

If you want to remove the Keypair in your NightELF, click the corresponding delete button on the Keypair management page. This operation does not require you to provide the NightELF password.

![Create Keypair](https://745133343-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-Lwc0TmmpfSBbQvtJGdy%2F-Lwc0U_K6ponSELdCEA3%2Fdelete-keypair.jpg?generation=1576924479056337\&alt=media)

Click the `OK` button to delete the keypair you want to delete, but this operation will not delete the Dapp authorization you made to the keypair.

## Delete NightELF

If you want to remove NightELF and clear the data, you can delete it by deleting NightELF on the Application Management page. This operation requires you to enter your NightELF password. You can also delete NightELF directly in Chrome.


# Permission Manager

When you authorize a Dapp permission, you can view your authorized information in NightELF.

You can view all your authorization information through the `Application Management` page.

![Permission Manager](https://745133343-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-Lwc0TmmpfSBbQvtJGdy%2F-Lwc0UjNUCyuGMKPjJB5%2Fapplication.jpg?generation=1576924480099522\&alt=media)

You can go to the `Details page` to check authorized detailed contract information such as contract addresses, contract names, contract details, etc.

You can choose to authorize permissions of a contract or you can choose to remove all permissions. This step does not require you to provide your NightELF password, but you need to be aware that deleting a contract may prevent you from continuing to use the contract method of the contract.

If you delete the MultiToken contract, then you will not be able to perform transfers and asset queries.


# How to use in Dapp

## How to use NightELF in DAPP

When you enter a Dapp that complies with the AELF ecosystem, usually the first step will be a pop up a prompt box for you to authorize, you can choose any Keypair to authorize.

![Login](https://745133343-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-Lwc0TmmpfSBbQvtJGdy%2F-Lwc0Uov9QExtv2CXETK%2Flogin.jpg?generation=1576924480540421\&alt=media)

Click the `Login` button, then, you can see the details of authorizations required by the current Dapp. This may include the domain name, contract address, contract name, contract description, Github address, etc.

![Login](https://745133343-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-Lwc0TmmpfSBbQvtJGdy%2F-Lwc0UoxGB7gMktuCmVy%2Fauthorization.jpg?generation=1576924480748115\&alt=media)

If you close this window or click `Cancel`, this action means you do not allow this application’s authorizations, then you may not be able to use the Dapp or most of the functions of the Dapp.

After you submit and authorize the application, you can go to NightELF's `Application Management page` to find your authorization information. If you don't know how to find the authorization information, you can check [Permission Manager](/user/permission).


# Timing Lock

## Why do we need to set Timing Lock

If you have finished authorization, left your personal device for a long period of time, and forget to lock it, it is very unsafe for your assets. Anyone can operate through NightELF. NightELF will set a lock time of 15 minutes by default. If you do not perform any operation within 15 minutes, NightELF will automatically lock to protect your assets.

## How to set the Timing Lock

If you think the default time is too long or too short, you can set different lock time. We provide some different time intervals for you to choose, you can also choose not to use the Timing Lock.

![Backup](https://745133343-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LubkNzPS6f2R2zSyCt_%2F-Lwc0l-Z3aMUDbYOOKN0%2F-Lwc0ll8e4McCv3eI8SB%2Ftime-lock.jpg?generation=1576924553051493\&alt=media)


# Dev document

## 1 Download

[release version, please waiting](/devdocs)

[dev version](https://chrome.google.com/webstore/detail/aelf-explorer-extension-d/mlmlhipeonlflbcclinpbmcjdnpnmkpf)

## 2 Preparation

### 2.1 Interaction Flow

* 1.Make sure the user get the Extension
* 2.Connect the blockchain
* 3.Initialize contract / Call the methods of the blockchain
* 4.Call the methods of contract&#x20;

### 2.2 Demo of Checking the Extension

```javascript
let nightElfInstance = null;
class NightElfCheck {
    constructor() {
        const readyMessage = 'NightElf is ready';
        let resovleTemp = null;
        this.check = new Promise((resolve, reject) => {
            if (window.NightElf) {
                resolve(readyMessage);
            }
            setTimeout(() => {
                reject({
                    error: 200001,
                    message: 'timeout / can not find NightElf / please install the extension'
                });
            }, 1000);
            resovleTemp = resolve;
        });
        document.addEventListener('NightElf', result => {
            console.log('test.js check the status of extension named nightElf: ', result);
            resovleTemp(readyMessage);
        });
    }
    static getInstance() {
        if (!nightElfInstance) {
            nightElfInstance = new NightElfCheck();
            return nightElfInstance;
        }
        return nightElfInstance;
    }
}
const nightElfCheck = NightElfCheck.getInstance();
nightElfCheck.check.then(message => {
    // connectChain -> Login -> initContract -> call contract methods
});
```

### 2.3 How Connect the blockchain

```javascript
const aelf = new window.NightElf.AElf({
    httpProvider: [
        'http://127.0.0.1:8101',
    ],
    appName: 'your own app name'
});
```

### 2.4 How to call the API

Callback or promise are both ok.

```javascript
// callback
aelf.chain.getChainStatus((error, result) => {
    console.log('>>>>>>>>>>>>> getChainStatus >>>>>>>>>>>>>');
    console.log(error, result);
});

// promise
aelf.chain.getChainStatus().then(result => {
    console.log('>>>>>>>>>>>>> getChainStatus >>>>>>>>>>>>>');
    console.log('promise then', result);
}).catch(error => {
    console.log('promise catch', error);
});
```

## 3 API Reference

Here you can find examples and in-depth information about NightELF's API.

You can see the demo code. [click here](https://github.com/AElfProject/aelf-web-extension/blob/master/devDemos/test.html)

If you want to check token transfer demo. [click here](https://github.com/AElfProject/aelf-web-extension/blob/master/demo/token/demo.html)

The methods act the same as the methods of the aelf-sdk.js

* [1. LOGIN](/devdocs#login)
* [2. GET\_CHAIN\_STATUS](/devdocs#get-chain-status)
* [3. CALL\_AELF\_CHAIN](/devdocs#call-aelf-chain)
* [4. INIT\_AELF\_CONTRACT](/devdocs#init-aelf-contract)
* [5. CALL\_AELF\_CONTRACT / CALL\_AELF\_CONTRACT\_READONLY](/devdocs#call-aelf-contract)
* [6. CHECK\_PERMISSION](/devdocs#check-permission)
* [7. SET\_CONTRACT\_PERMISSION](/devdocs#set-contract-permission)
* [8. REMOVE\_CONTRACT\_PERMISSION](/devdocs#remove-contract-permission)
* [9. REMOVE\_METHODS\_WHITELIST](/devdocs#remove-methods-whitelist)
* [10. GET\_SIGNATURE](/devdocs#get-signature)

### 3.1 LOGIN

LOGIN allows your application to request permission to interact with a user's NightELF and be provided with an account of the user's choosing.

```javascript
aelf.login({
    chainId: 'AELF',
    payload: {
        method: 'LOGIN',
        contracts: [{
            chainId: 'AELF',
            contractAddress: '4rkKQpsRFt1nU6weAHuJ6CfQDqo6dxruU3K3wNUFr6ZwZYc',
            contractName: 'token',
            description: 'token contract',
            github: ''
        }, {
            chainId: 'AELF TEST',
            contractAddress: '2Xg2HKh8vusnFMQsHCXW1q3vys5JxG5ZnjiGwNDLrrpb9Mb',
            contractName: 'TEST contractName',
            description: 'contract description',
            github: ''
        }]
    }
}, (error, result) => {
    console.log('login>>>>>>>>>>>>>>>>>>', result);
});

// result = {
//     "error": 0,
//     "errorMessage": "",
//     "message": "",
//     "detail": {
//         "name": "your name",
//         "address": "2RCLmZQ2291xDwSbDEJR6nLhFJcMkyfrVTq1i1YxWC4SdY49a6",
//         "publicKey": {
//             "x": "4958d5c48f003c771769f4a31413cd18053516615cbde502441af8452fb53441",
//             "y": "a80cc48a7f3b0f2552fd030cacbe9012ba055a3d553b70003f2e637d55fa0f23"
//         }
//     },
//     "sid": "350815427961739930163684",
//     "from": "contentNightElf"
// }

// the data in the extension
// keychain = {
//     keypairs: [{
//         name: 'your keypairs name',
//         address: 'your keypairs address',
//         mnemonic: 'your keypairs mnemonic',
//         privateKey: 'your keypairs privateKey'，
//         publicKey: {
//             x: 'f79c25eb......',
//             y: '7fa959ed......'
//         }
//     }],
//     permissions: [{
//         appName: 'hzzTest',
//         address: 'your keyparis address',
//         contracts: [{
//             chainId: 'AELF',
//             contractAddress: '4rkKQpsRFt1nU6weAHuJ6CfQDqo6dxruU3K3wNUFr6ZwZYc',
//             contractName: 'token',
//             description: 'token contract',
//             github: ''
//         }],
//         domain: 'Dapp domain'
//     }]
// }
```

### 3.2 GET\_CHAIN\_STATUS

```javascript
aelf.chain.getChainStatus((error, result) => {
    console.log('>>>>>>>>>>>>> connectChain >>>>>>>>>>>>>');
    console.log(error, result);
});
```

### 3.3 CALL\_AELF\_CHAIN

```javascript
// this txid is an example.
const txid = 'c45edfcca86f4f528cd8e30634fa4ac53801aae05365cfefc3bfe9b652fe5768';
aelf.chain.getTxResult(txid, (err, result) => {
    console.log('>>>>>>>>>>>>> getTxResult >>>>>>>>>>>>>');
    console.log(err, result);
});

// result = {
//     Status: "NotExisted"
//     TransactionId: "c45edfcca86f4f528cd8e30634fa4ac53801aae05365cfefc3bfe9b652fe5768"
//     ....
// }
```

### 3.4 INIT\_AELF\_CONTRACT

```javascript
// In aelf-sdk.js wallet is the realy wallet.
// But in extension sdk, we just need the address of the wallet.
const wallet = {
    address: '2JqnxvDiMNzbSgme2oxpqUFpUYfMjTpNBGCLP2CsWjpbHdu'
};
// It is different from the wallet created by Aelf.wallet.getWalletByPrivateKey();
// There is only one value named address;
aelf.chain.contractAt(
    '4rkKQpsRFt1nU6weAHuJ6CfQDqo6dxruU3K3wNUFr6ZwZYc',
    wallet,
    (error, result) => {
        console.log('>>>>>>>>>>>>> contractAt >>>>>>>>>>>>>');
        console.log(error, result);
        tokenContract = result;
    }
);

// result = {
//     Approve: ƒ (),
//     Burn: ƒ (),
//     ChargeTransactionFees: ƒ (),
//     ClaimTransactionFees: ƒ (),
//     ....
// }
```

### 3.5 CALL\_AELF\_CONTRACT / CALL\_AELF\_CONTRACT\_READONLY

```javascript
// tokenContract from the pre step.
tokenContract.GetBalance.call(
    {
        symbol: 'AELF',
        owner: '65dDNxzcd35jESiidFXN5JV8Z7pCwaFnepuYQToNefSgqk9'
    },
    (err, result) => {
        console.log('>>>>>>>>>>>>>>>>>>>', result);
    }
);

tokenContract.Approve(
    {
        symbol: 'AELF',
        spender: '4rkKQpsRFt1nU6weAHuJ6CfQDqo6dxruU3K3wNUFr6ZwZYc',
        amount: '100'
    },
    (err, result) => {
        console.log('>>>>>>>>>>>>>>>>>>>', result);
    }
);

// If you use tokenContract.GetBalance.call  this method is only applicable to queries that do not require extended authorization validation.(CALL_AELF_CONTRACT_READONLY)
// If you use tokenContract.Approve this requires extended authorization validation (CALL_AELF_CONTRACT)

// tokenContract.GetBalance.call(payload, (error, result) => {})
// result = {
//     symbol: "AELF",
//     owner: "65dDNxzcd35jESiidFXN5JV8Z7pCwaFnepuYQToNefSgqk9",
//     balance: 0
// }
```

### 3.6 CHECK\_PERMISSION

CHECK\_PERMISSION returns the contracts your can use with the address.

```javascript
aelf.checkPermission({
    type: 'address', // if you did not set type, it aways get by domain.
    address: '4WBgSL2fSem9ABD4LLZBpwP8eEymVSS1AyTBCqXjt5cfxXK'
}, (error, result) => {
    console.log('>>>>>>>>>>>>>', error, result);
});

// result = {
//     ...,
//     permissions:[
//         {
//             address: '...',
//             appName: 'hzzTest',
//             contracts: [{
//                 chainId: 'AELF',
//                 contractAddress: '4rkKQpsRFt1nU6weAHuJ6CfQDqo6dxruU3K3wNUFr6ZwZYc',
//                 contractName: 'token',
//                 description: 'token contract',
//                 github: ''
//             },
//             {
//                 chainId: 'AELF TEST',
//                 contractAddress: 'TEST contractAddress',
//                 contractName: 'TEST contractName',
//                 description: 'contract description',
//                 github: ''
//             }],
//             domian: 'Dapp domain'
//         }
//     ]
// }
```

### 3.7 SET\_CONTRACT\_PERMISSION

SET\_CONTRACT\_PERMISSION applies to the users to allow the Dapp use the contract.

```javascript
aelf.setContractPermission({
    chainId: 'AELF',
    payload: {
        address: '2JqnxvDiMNzbSgme2oxpqUFpUYfMjTpNBGCLP2CsWjpbHdu',
        contracts: [{
            chainId: 'AELF',
            contractAddress: 'TEST contractAddress',
            contractName: 'AAAA',
            description: 'contract description',
            github: ''
        }]
    }
}, (error, result) => {
    console.log('>>>>>>>>>>>>>', error, result);
});
```

### 3.8 REMOVE\_CONTRACT\_PERMISSION

```javascript
aelf.removeContractPermission({
    chainId: 'AELF',
    payload: {
        contractAddress: '2Xg2HKh8vusnFMQsHCXW1q3vys5JxG5ZnjiGwNDLrrpb9Mb'
    }
}, (error, result) => {
    console.log('>>>>>>>>>>>>>', error, result);
});
```

### 3.9 REMOVE\_METHODS\_WHITELIST

```javascript
aelf.removeMethodsWhitelist({
    chainId: 'AELF',
    payload: {
        contractAddress: '2Xg2HKh8vusnFMQsHCXW1q3vys5JxG5ZnjiGwNDLrrpb9Mb',
        whitelist: ['Approve']
    }
}, (error, result) => {
    console.log('removeWhitelist>>>>>>>>>>>>>>>>>', result);
});
```

### 3.10 GET\_SIGNATURE

```javascript
aelf.getSignature({
    address: 'address',
    hexToBeSign: 'hexToBeSign'
}).then(result => {
  // ...
}).cathc(error => {
  // ...
});
```

## 4.For Extension Developers

### 4.1. Download the code

```bash
git clone https://github.com/AElfProject/aelf-web-extension.git
```

### 4.2 Install dependent

```bash
    npm install
```

### 4.3 Run webpack

```bash
    npm run none
    npm run none:watch
    npm run dev
    npm run dev:watch
    npm run pro
    npm run pro:watch
```

### 4.4 Add to the browser

```bash
    open development mode, add the webpack output app/public.
```

### 4.5 How to publish to chrome

zip app/public to public.zip, and follow the notes.

### 4.6 Can not use crx

You can not install the extension from an offline crx if Chrome >= 73.

Please import the `.zip file` with developer mode.

## 5 Formatted Data Example

```javascript
    NightElf = {
        histories: [],
        keychain: {
            keypairs: [
                {
                    name: 'your keypairs name',
                    address: 'your keypairs address',
                    mnemonic: 'your keypairs mnemonic',
                    privateKey: 'your keupairs privateKey',
                    publicKey: {
                        x: 'you keupairs publicKey',
                        y: 'you keupairs publicKey'
                    }
                }
            ],
            permissions: [
                {
                    chainId: 'AELF',
                    contractAddress: 'contract address',
                    contractName: 'contract name',
                    description: 'contract description',
                    github: 'contract github',
                    whitelist: {
                        Approve: {
                            parameter1: 'a',
                            parameter2: 'b',
                            parameter3: 'c'
                        }
                    }
                }
            ]
        }
    }
```


