Upgrading from Plugin Node V1 to V2 Using Soft Reset

# Introduction

This guide provides a method for upgrading from Plugin Node 1.0 to 2.0 using a soft reset. **The [official Plugin documentation](https://docs.goplugin.co/plugin-2.0-node-operators/plugin-2.0-node-operators) offers a soft reset option for V1 nodes**. After the soft reset, installing Plugin 2.0 will assign a new node address.

<details><summary>【日本語】</summary>

このガイドは、Plugin Node 1.0から2.0へ、ソフトリセットを使ってアップグレードを行う方法を提供しています。**[Plugin公式ドキュメント](https://docs.goplugin.co/plugin-2.0-node-operators/plugin-2.0-node-operators)では、V1ノードのソフトリセットオプションが提供されています**。ソフトリセット後、Plugin 2.0をインストールすると新しいノードアドレスが割り当てられます。
</details>

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/61617f8d-604b-edc4-1a1d-58b28bfd7ba8.png)


# 1. Processing on V1 nodes

On Plugin Node 1.0, we perform the following five steps:

Pluginノード1.0上で、以下の5つの手順を実行します：

:::note
1. Updating Linux systems
1. Output a JSON file of Node Address
1. Initializing Backup Folder and Permissions Setup
1. Store the necessary files in the backup directory
1. Soft Reset of V1 Node

<details><summary>【日本語】</summary>

1. Linuxシステム更新
1. ノードアドレスのJSONファイルを出力
1. バックアップフォルダと権限のセットアップの初期化
1. backupディレクトリに必要なファイルを格納
1. V1ノードのソフトリセット
</details>
:::

## 1-1. Plugin Node Preparation Commands

Commands for updating Linux systems, installing tools, configuring security, and cleaning for plugin node setup.

プラグインノード用のLinuxシステム更新、ツールインストール、セキュリティ設定、クリーニングのコマンド群

```sh:1-1
sudo apt update -y && sudo apt upgrade -y && sudo apt install -y git nano ufw curl tree htop && sudo apt autoremove -y && sudo apt autoclean -y && sudo timedatectl set-timezone UTC
```


## 1-2. Node Address Keystore File Output

The command outputs the node address keystore file to the home directory.

ノードアドレスのキーストアファイルをホームディレクトリに出力します。

```sh:1-2
cd ~/plugin-deployment/ && ./pli_node_scripts.sh keys
```
![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/2df8518d-5e75-6aa5-f6e0-931df9b63ab7.png)


## 1-3. Initializing Backup Folder and Permissions Setup

Lets now run the setup script to ensure that the backup folder & permissions are in place.

バックアップフォルダと権限が整っていることを確認するために、セットアップスクリプトを実行しましょう。

```sh:1-3-1
./_plinode_setup_bkup.sh
```

:::note
**Perform Full Backup Before Upgrading to Plugin Node 2.0**

Before upgrading to Plugin Node 2.0, it is recommended to perform a full backup in Plugin Node 1.0 (using commands 1-3-2). Additionally, create a directory named `originals/pluginV1` within the `/plinode_backups/` directory and copy the relevant files from Plugin Node 1.0 (using commands 1-3-3).


<details><summary>【日本語】</summary>

<!--(上に空行が必要)-->
Plugin Node 2.0にアップグレードする前に、1.0でフルバックアップを実行し（コマンド1-3-2）、さらに`/plinode_backups/`ディレクトリ内に`originals/pluginV1`ディレクトリを作成し、Plugin Node 1.0の関連するファイルをコピー（コマンド1-3-3）しておくことをお勧めします。
</details>

```sh:1-3-2
cd ~/plugin-deployment/ && ./_plinode_backup.sh -full
```
![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/da290d8d-a51f-e91e-af80-69281f746acd.png)

```sh:1-3-3
mkdir -p /plinode_backups/originals/pluginV1/ && cd ~/plugin-deployment/ && cp -u 2_nodeStartPM2.sh 3_initiatorStartPM2.sh .env.apicred .env.password /plinode_backups/originals/pluginV1/ && cd ~ && cp -u plinode_$(hostname -f).vars plinode_$(hostname -f)_keys*.json /plinode_backups/originals/pluginV1/ && tree -a /plinode_backups/ 
```
![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/1274ff49-30dc-91a6-8d80-1c2206990232.png)
:::


## 1-4. Important Files Copying

```sh:1-4
cp ~/plinode_$(hostname -f).vars /plinode_backups/plinode_V1.vars
cp $(ls -t ~/plinode_$(hostname -f)_keys_* | head -n 1) /plinode_backups/plinode_V1_keys.json
cp ~/plugin-deployment/.env.password /plinode_backups/.env.password
ll /plinode_backups/
```
:::note
The files to be copied are as follows.
1. Node configuration file
1. json file where Node Address information is defined
1. Keystore file required when importing Node Address
<details><summary>【日本語】</summary>

コピーするファイルは下記のとおりです。
1. Nodeの設定ファイル
1. Node Address情報が定義されているjsonファイル
1. Node Addressインポート時に必要となるkeystoreファイル
</details>
:::

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/1a1e3b82-5a97-f868-8394-3e68cbb6a177.png)




## 1-5. Soft Reset of V1 Node

Performing Soft Reset on Plugin Node 1.0.

Plugin Node 1.0のソフトリセットを実行します。

```sh:1-5-1
cd ~/plugin-deployment/ && ./reset_pli.sh 
```
Please enter `y` in response to the prompt.

:::note warn
```sh:1-5-2
cd && cat ~/.profile
```
![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/2603f591-8103-fccc-3756-a659e366dd6b.png)


**If these environment variables remain, you will experience problems when building V2 nodes. Clear it in the next step.**

**これらの環境変数が残っていると、V2 ノードを構築するときに問題が発生します。次のステップで消去します。**

:::

# 2. Build V2 Node
:::note
Upgrade to V2 Node.
1. Download the script `pluginV2Install`
1. Soft Reset 
1. clear environment variables
1. Preparing files for V2 nodes
1. Run setup script
<details><summary>【日本語】</summary>

V2 Nodeにアップグレードしていきます。
1. `pluginV2Install`スクリプトをダウンロード
1. ソフトリセット
1. 環境変数のクリア
1. V2 ノードのためのファイルの準備
1. セットアップスクリプトの実行
</details>
:::

## 2-1. git clone `pluginV2Install`

```sh:2-1-1
cd && git clone https://github.com/GoPlugin/pluginV2Install.git
cd ~/pluginV2Install/
chmod +x *.sh
```

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/9a334f5c-2a44-ae1b-21fd-ccd790c964a6.png)

:::note alert
### ------ Important ------
**On December 25, 2023, at 17:10**

The mainnet RPC is set to `https://erpc.xinfin.network` by default, but I have noticed that it can be unstable at times. Therefore, personally, I believe it would be desirable to change it to `https://earpc.xinfin.network`. The following commands are used to change the `https://erpc.xinfin.network` string to `https://earpc.xinfin.network` in the `~/pluginV2Install/sample.vars` file. Finally, please verify if the change has been made correctly using the `grep` command.

<details><summary>【日本語】</summary>

<!--(上に空行が必要)-->
**2023年12月25日、17時10分**
メインネットのRPCはデフォルトで `https://erpc.xinfin.network` に設定されていますが、時に不安定であることが確認されています。そのため、個人的には `https://earpc.xinfin.network` に変更することが望ましいと考えています。次のコマンドは、`~/pluginV2Install/sample.vars` ファイル内の `https://erpc.xinfin.network` という文字列を `https://earpc.xinfin.network` に変更するためのものです。最後に、変更が正しく行われたかを確認するために `grep` コマンドを使用してください。
</details>

| Before          | After                   |
|-----------------|-------------------------|
| https://erpc.xinfin.network | https://earpc.xinfin.network |

```sh:2-1-2
sed -i -e "s|https://erpc.xinfin.network|https://earpc.xinfin.network|g" ~/pluginV2Install/sample.vars
grep "mainnet_httpUrl" ~/pluginV2Install/sample.vars
```

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/78d43e86-8302-2c61-d94c-9a7ca88c1bab.png)



:::

## 2-2. Soft Reset Again

Performing Soft Reset Again.

再びソフトリセットを実行します。

```sh:2-2-1
cd ~/pluginV2Install && ./reset_pli.sh
```
Please enter `y` in response to the prompt.

```sh:2-2-2
source ~/.profile
```

:::note warn

```sh:2-2-3
cat ~/.profile
```
![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/7172353f-34bf-04aa-ef95-6bded9195044.png)


Soft reset for V2 nodes and ensure environment variables are reduced. However, **`FEATURE_EXTERNAL_INITIATORS` is not removed.**

V2ノード用のソフトリセットを利用して環境変数が削除されていることを確認します。ただし、**`FEATURE_EXTERNAL_INITIATORS` は削除されません。**
:::

## 2-3. Delete environment variables

These commands remove the environment variable `FEATURE_EXTERNAL_INITIATORS` from the profile and unset it.

これらのコマンドは、環境変数 FEATURE_EXTERNAL_INITIATORS をプロファイルから削除し、その設定を無効化します。

```sh:2-3
sed -i '/FEATURE_EXTERNAL_INITIATORS/d' ~/.profile
cat ~/.profile
echo $FEATURE_EXTERNAL_INITIATORS
unset FEATURE_EXTERNAL_INITIATORS
echo $FEATURE_EXTERNAL_INITIATORS
```
:::note

**Confirm environment variables are cleared.**

**環境変数がクリアされていることを確認します。**

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/801427a3-8a2a-66d9-2846-8f02fa1c36ed.png)


:::

:::note warn
**Reference:**
Building a V2 Node with the environment variable still set results in the following message being displayed and the process not starting:

*"Config validation failed: invalid environment: environment variable `FEATURE_EXTERNAL_INITIATORS` must not be set: unsupported with config v2."*

<details><summary>【日本語】</summary>

**参考：**
環境変数が残った状態で V2 Node をビルドすると、以下のメッセージが表示され処理が開始されません。

*"Config validation failed: invalid environment: environment variable `FEATURE_EXTERNAL_INITIATORS` must not be set: unsupported with config v2."*

*設定の検証に失敗しました：無効な環境：環境変数 FEATURE_EXTERNAL_INITIATORS は設定されてはなりません：設定 v2 ではサポートされていません。*

</details>

![2023-10-21 16.05.34.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090248/4aad8edd-a366-5bbf-eb0e-dd9d8e0b5fb0.jpeg)
:::

## 2-4. Preparing V2 Node
### Update sample.vars
In order to inherit the settings of V1 Node, read the vars file of V1 Node and edit sample.vars.

V1 Nodeの設定を引き継ぐために、V1 Nodeのvarsファイルを読み込んでsample.varsを編集します。

:::note
The items to be carried over are as follows.
1. `API_EMAIL`     : Dashboard login user ID
1. `API_PASS`      : Dashboard login password
1. `PASS_KEYSTORE` : keystore
1. `DB_PWD_NEW`    : PostgreSQL DB password
<details><summary>【日本語】</summary>

引き継ぐ項目は下記のとおりです。
1. `API_EMAIL`     : ダッシュボードのログインユーザID
1. `API_PASS`      : ダッシュボードのログインパスワード
1. `PASS_KEYSTORE` : キーストア 
1. `DB_PWD_NEW`    : PostgreSQL DBのパスワード
</details>
:::

```sh:2-4-1
source /plinode_backups/plinode_V1.vars && \
sed -i "/API_EMAIL=/c\API_EMAIL=\"$API_EMAIL\"" ~/pluginV2Install/sample.vars && \
sed -i "/API_PASS=/c\API_PASS='$API_PASS'" ~/pluginV2Install/sample.vars && \
sed -i "/PASS_KEYSTORE=/c\PASS_KEYSTORE='$PASS_KEYSTORE'" ~/pluginV2Install/sample.vars && \
sed -i "/DB_PWD_NEW=/c\DB_PWD_NEW=\"$DB_PWD_NEW\"" ~/pluginV2Install/sample.vars
```

### Delete V1 Node files from Home Directory
Delete unnecessary files related to the V1 Node from the home directory.

ホームディレクトリからV1ノードの不要なファイルを削除します。
```sh:2-4-2
rm -rf ~/plinode_$(hostname -f)*
```

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/dde64cda-cebf-0f04-e7ee-42af3b1e54d4.png)



## 2-5. Run setup script

```sh:2-5-1
./pli_node_scripts.sh mainnet
```

:::note
**Important**
Confirm the script is complete and follow the instructions to run the command below.

**重要**
スクリプトが完了していることを確認して、指示に従って下記コマンドを実行してください。
:::

```sh:2-5-2
source ~/.profile
```
![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/616c0742-f13b-17f6-bd19-be37d99f024a.png)

The Node configuration file from V1 is being loaded.
V1のNode設定ファイルが読み込まれています。

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/3f14cd00-74dd-1b7c-0f4e-33c20b293e9a.png)

## 2-6. Depositing XDC and PLI into Node Address for Testing

Use XDCPay or MetaMask to deposit `1` XDC and `1` PLI into the NodeAddress for testing. Please ensure the amount is within the maximum limit of `10` XDC and `5` PLI.

1. Click on the gear icon located in the top right corner of the dashboard.
1. Click on 'Key Management'.
1. Scroll down to the bottom of the screen and locate the 'Address' under 'EVM Chain Accounts'. This will be your 'Node Address'.
1. Send 1XDC and 1PLI to this Node Address.
1. Verify that the balances of XDC and PLI have increased.

<details><summary>【日本語】</summary>

<!--(上に空行が必要)-->
XDCPayまたはMetaMaskを使って、テストに必要な `1` XDCと `1` PLIをNodeAddressに入金します。最大でも `10` XDC、`5` PLI以内にしてください。

1. ダッシュボードの右上にある歯車のアイコンをクリックします。
1. 「Key Management」をクリックします。
1. 画面の下部までスクロールし、「EVM Chain Accounts」の下にある「Address」を探します。これがあなたの「Node Address」になります。
1. このNode Addressに1XDCと1PLIを送ります。
1. XDCとPLIの残高が増加したことを確認します。
</details>

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/5c69f90f-e819-7165-81f8-9fdc6b85b043.png)



![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/7a3894fb-172c-cf1a-28e2-af5b7d8468de.png)


![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/a7c93efe-e578-4a97-47a1-752dceef568f.png)

The upgrade of the plugin node is now complete.

以上でプラグインノードのアップグレードは完了です。



# 3. Backup After Plugin V2 Upgrade

Once you have confirmed the successful import of the V1 node address into the dashboard, it is recommended to perform a backup.

V1ノードアドレスがダッシュボードに正常にインポートされたことを確認したら、バックアップを実行することをおすすめします。

### 3-1. Full Backup

Run the following commands to perform a FULL backup. As per the usage above this backups up both the conf files & the db.

以下のコマンドを実行して、完全なバックアップを実行してください。上記の使用法に従い、設定ファイルとデータベースの両方をバックアップします。

```sh:3-1
cd ~/pluginV2Install/ && ./_plinode_backup.sh -full
```
![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/3ce0ef64-4b64-98cc-0752-764cf0e3b0eb.png)


### 3-2. Create `originals/pluginV2` Directory and Copy Relevant Files

After a successful upgrade to Plugin Node 2.0, create a directory named `originals/pluginV2` within the `/plinode_backups/` directory and copy the relevant files from that moment into it.

Plugin Node 2.0のアップグレードが成功した場合、`/plinode_backups/`ディレクトリ内に`originals/pluginV2`ディレクトリを作成し、その時点で関連するファイルをコピーしてください。

```sh:3-2
mkdir -p /plinode_backups/originals/pluginV2 && cd ~/pluginV2/ && cp -u ~/pluginV2/apicredentials.txt config.toml secrets.toml /plinode_backups/originals/pluginV2/ && cd ~ &&cp -u ~/plinode_$(hostname -f).vars plinode_$(hostname -f)_keys*.json /plinode_backups/originals/pluginV2/ && tree -a /plinode_backups/
```
![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/8736169f-1053-59f6-45c8-291fcb1ce613.png)


### 3-3. Transferring the Backup Directory to Your Local PC

Use SFTP or a similar method to transfer the `/plinode_backups/` directory to your local PC. In the screenshot, I am using Turmius. Of course, it is also possible to execute commands.

<details><summary>【日本語】</summary>

<!--(上に空行が必要)-->
SFTPなどを使用して、`/plinode_backups/`ディレクトリをローカルPCに転送してください。スクリーンショットでは、Turmiusを使っています。もちろんコマンドで実行することも可能です。
</details>

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/80d52945-a601-7b6e-c8d0-871add63dc9b.png)

Local PC (MacBookAir)
![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/9c87f84d-9626-1083-c512-af1fd95147d2.png)




# 4. Setup of Job and Deployment of Contract

## 4-1. Oracle Contract
Using Remix, create an Oracle contract.

```javascript:17-1
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
import "@goplugin/contracts2_3/src/v0.7/Operator.sol";

/**
* A. Pli Mainnet Token: 0xFf7412Ea7C8445C46a8254dFB557Ac1E48094391
* A. Pli Apothem Token: 0x33f4212b027E22aF7e6BA21Fc572843C0D701CD1
*/
```

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/823cc8c8-2e1f-6a73-47cf-e44825070446.png)

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/58ce9e5e-5682-066f-0235-f13954fe4501.png)






Please enter the contract address of PLI (either on the mainnet or Apothem) and your Wallet Address (replace "xdc" at the beginning with "0x").

Your Wallet Address will be the owner of this contract.

:::note
```s:PLI Mainnet Contract Address
0xFf7412Ea7C8445C46a8254dFB557Ac1E48094391
```
```s:PLI Apothem Contract Address
0x33f4212b027E22aF7e6BA21Fc572843C0D701CD1
```
:::

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/2e62d430-8542-719c-7b01-6da76944fca1.png)

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/490580d7-53ae-939c-7b0d-43b536871b39.png)

:::note
```s:PLI Mainnet Contract Address
0xFf7412Ea7C8445C46a8254dFB557Ac1E48094391
```
```s:PLI Apothem Contract Address
0x33f4212b027E22aF7e6BA21Fc572843C0D701CD1
```
:::

## 4-2. Job setup
```toml:Sample Job Code - Cryptocompare -
type = "directrequest"
schemaVersion = 1
name = "Sample Request Cryptocompare_XDC_USD"
# It is recommended to give a memorable name to 'name'. 
# You can use it for searching later.
forwardingAllowed = false
maxTaskDuration = "0s"
contractAddress = "YOUR_ORACLE_ADDRESS"
# Please replace contractAddress with your oracle address.
minContractPaymentLinkJuels = "0"
observationSource = """
decode_log [type="ethabidecodelog" abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" data="$(jobRun.logData)" topics="$(jobRun.logTopics)"]
 
decode_cbor [type="cborparse" data="$(decode_log.data)"]
 
fetch [type="http" method=GET url="https://min-api.cryptocompare.com/data/price?fsym=XDC&tsyms=USD"]
parse [type="jsonparse" path="USD" data="$(fetch)"]
 
multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"]
 
encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"]
 
encode_tx [type="ethabiencode" abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)"
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" ]
 
submit_tx [type="ethtx" to="YOUR_ORACLE_ADDRESS" data="$(encode_tx)"] //paste the Oracle Address which you deployed in ‘to’ field
 
decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx
"""
# Please paste your Oracle Address in the 'to' field on the second line from the bottom.
```

:::note
JOB SETUP
1. The value of the name key should be changed.
2. The Oracle Address will be changed in two locations.
3. The URL will be modified.
Regarding CMC, the APIKEY will be updated.
4. The path will be modified.


#### # Cryptocompare
* https://min-api.cryptocompare.com/data/price?fsym=XDC&tsyms=USD
* path="USD"

<details><summary>Sample Job Code - Cryptocompare -</summary>

<!--(上に空行が必要)-->
```toml:Sample Job Code - Cryptocompare -
type = "directrequest"
schemaVersion = 1
name = "Sample Request Cryptocompare_XDC_USD"
forwardingAllowed = false
maxTaskDuration = "0s"
contractAddress = "YOUR_ORACLE_ADDRESS"
minContractPaymentLinkJuels = "0"
observationSource = """
decode_log [type="ethabidecodelog" abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" data="$(jobRun.logData)" topics="$(jobRun.logTopics)"]
 
decode_cbor [type="cborparse" data="$(decode_log.data)"]
 
fetch [type="http" method=GET url="https://min-api.cryptocompare.com/data/price?fsym=XDC&tsyms=USD"]
parse [type="jsonparse" path="USD" data="$(fetch)"]
 
multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"]
 
encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"]
 
encode_tx [type="ethabiencode" abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)"
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" ]
 
submit_tx [type="ethtx" to="YOUR_ORACLE_ADDRESS" data="$(encode_tx)"] //paste the Oracle Address which you deployed in ‘to’ field
 
decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx
"""
```
</details>

#### # Coingecko
* https://api.coingecko.com/api/v3/simple/price?ids=plugin&vs_currencies=usd
* path="plugin,usd"

<details><summary>Sample Job Code - Coingecko -</summary>

<!--(上に空行が必要)-->
```toml:Sample Job Code - Coingecko -
type = "directrequest"
schemaVersion = 1
name = "Sample Request CoinGecko_PLI_USD"
forwardingAllowed = false
maxTaskDuration = "0s"
contractAddress = "YOUR_ORACLE_ADDRESS"
minContractPaymentLinkJuels = "0"
observationSource = """
decode_log [type="ethabidecodelog" abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" data="$(jobRun.logData)" topics="$(jobRun.logTopics)"]
 
decode_cbor [type="cborparse" data="$(decode_log.data)"]
 
fetch [type="http" method=GET url="https://api.coingecko.com/api/v3/simple/price?include_last_updated_at=true&precision=10&ids=plugin&vs_currencies=usd"]
parse [type="jsonparse" path="plugin,usd" data="$(fetch)"]
 
multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"]
 
encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"]
 
encode_tx [type="ethabiencode" abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)"
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" ]
 
submit_tx [type="ethtx" to="YOUR_ORACLE_ADDRESS" data="$(encode_tx)"] //paste the Oracle Address which you deployed in ‘to’ field
 
decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx
"""
```
</details>

#### # Binance
* https://api1.binance.com/api/v3/ticker/price?symbol=XRPUSDT
* path="price"

<details><summary>Sample Job Code - Binance -</summary>

<!--(上に空行が必要)-->
```toml:Sample Job Code - Binance -
type = "directrequest"
schemaVersion = 1
name = "Sample Request Binance_XRP_USDT"
forwardingAllowed = false
maxTaskDuration = "0s"
contractAddress = "YOUR_ORACLE_ADDRESS"
minContractPaymentLinkJuels = "0"
observationSource = """
decode_log [type="ethabidecodelog" abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" data="$(jobRun.logData)" topics="$(jobRun.logTopics)"]
 
decode_cbor [type="cborparse" data="$(decode_log.data)"]
 
fetch [type="http" method=GET url="https://api1.binance.com/api/v3/ticker/price?symbol=XRPUSDT"]
parse [type="jsonparse" path="price" data="$(fetch)"]
 
multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"]
 
encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"]
 
encode_tx [type="ethabiencode" abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)"
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" ]
 
submit_tx [type="ethtx" to="YOUR_ORACLE_ADDRESS" data="$(encode_tx)"] //paste the Oracle Address which you deployed in ‘to’ field
 
decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx
"""
```
</details>

#### # Bitrue
* https://openapi.bitrue.com/api/v1/ticker/price?symbol=XDCUSDT
* path="price"

<details><summary>Sample Job Code - Bitrue -</summary>

<!--(上に空行が必要)-->
```toml:Sample Job Code - Bitrue -
type = "directrequest"
schemaVersion = 1
name = "Sample Request Bitrue_XDC_USDT"
forwardingAllowed = false
maxTaskDuration = "0s"
contractAddress = "YOUR_ORACLE_ADDRESS"
minContractPaymentLinkJuels = "0"
observationSource = """
decode_log [type="ethabidecodelog" abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" data="$(jobRun.logData)" topics="$(jobRun.logTopics)"]
 
decode_cbor [type="cborparse" data="$(decode_log.data)"]
 
fetch [type="http" method=GET url="https://openapi.bitrue.com/api/v1/ticker/price?symbol=XDCUSDT"]
parse [type="jsonparse" path="price" data="$(fetch)"]
 
multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"]
 
encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"]
 
encode_tx [type="ethabiencode" abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)"
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" ]
 
submit_tx [type="ethtx" to="YOUR_ORACLE_ADDRESS" data="$(encode_tx)"] //paste the Oracle Address which you deployed in ‘to’ field
 
decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx
"""
```
</details>

#### # Kucoin
* https://api.kucoin.com/api/v1/market/orderbook/level1?symbol=XDC-USDT
* path="data,price"

<details><summary>Sample Job Code - Kucoin -</summary>

<!--(上に空行が必要)-->
```toml:Sample Job Code - Kucoin -
type = "directrequest"
schemaVersion = 1
name = "Sample Request Kucoin_XDC_USDT"
forwardingAllowed = false
maxTaskDuration = "0s"
contractAddress = "YOUR_ORACLE_ADDRESS"
minContractPaymentLinkJuels = "0"
observationSource = """
decode_log [type="ethabidecodelog" abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" data="$(jobRun.logData)" topics="$(jobRun.logTopics)"]
 
decode_cbor [type="cborparse" data="$(decode_log.data)"]
 
fetch [type="http" method=GET url="https://api.kucoin.com/api/v1/market/orderbook/level1?symbol=XDC-USDT"]
parse [type="jsonparse" path="data,price" data="$(fetch)"]
 
multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"]
 
encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"]
 
encode_tx [type="ethabiencode" abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)"
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" ]
 
submit_tx [type="ethtx" to="YOUR_ORACLE_ADDRESS" data="$(encode_tx)"] //paste the Oracle Address which you deployed in ‘to’ field
 
decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx
"""
```
</details>

#### # CMC ／ CoinMarcketCap
* Please change YOUR_API_KEY to your own API.

```TOML
fetch [type=http method=GET url="https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest?symbol=XDC&convert=USDT" allowUnrestrictedNetworkAccess="true" headers="[\\"X-CMC_PRO_API_KEY\\", \\"YOUR_API_KEY\\"]"]
```
* parse [type="jsonparse" path="data,XDC,0,quote,USDT,price" data="$(fetch)"]

<details><summary>Sample Job Code - CMC -</summary>

<!--(上に空行が必要)-->
```toml:Sample Job Code - CMC -
type = "directrequest"
schemaVersion = 1
name = "CMC_XDC-USD"
forwardingAllowed = false
maxTaskDuration = "0s"
contractAddress = "YOUR_ORACLE_ADDRESS"
minContractPaymentLinkJuels = "0"
observationSource = """
 
decode_log [type="ethabidecodelog" abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" data="$(jobRun.logData)" topics="$(jobRun.logTopics)"] 

decode_cbor [type="cborparse" data="$(decode_log.data)"] 

fetch [type=http method=GET url="https://pro-api.coinmarketcap.com/v2/cryptocurrency/quotes/latest?symbol=XDC&convert=USDT" allowUnrestrictedNetworkAccess="true" headers="[\\"X-CMC_PRO_API_KEY\\", \\"YOUR_API_KEY\\"]"]

parse [type="jsonparse" path="data,XDC,0,quote,USDT,price" data="$(fetch)"]

multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"] 

encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"] 

encode_tx [type="ethabiencode" abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)" 
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" ] 

submit_tx [type="ethtx" to="YOUR_ORACLE_ADDRESS" data="$(encode_tx)"]

decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx 
"""
```
</details>

#### # Coinranking
- **[Website](https://coinranking.com/)**
- **[API Document](https://developers.coinranking.com/api/documentation)**
- Please change YOUR_API_KEY to your own API.

```toml
fetch [type=http method=GET url="https://api.coinranking.com/v2/coin/77jGXSqWJ1ofG?referenceCurrencyUuid=yhjMzLPhuIDl" allowUnrestrictedNetworkAccess="true" headers="[\\"x-access-token\\", \\"YOUR_API_KEY\\"]"]
```

- path="data,coin,price"
 
<details><summary>Sample Job Code - coinranking -</summary>

<!--(上に空行が必要)-->
```toml:Sample Job Code - Coinranking - 
type = "directrequest"
schemaVersion = 1
name = "Coinranking_XDC-USD"
forwardingAllowed = false
maxTaskDuration = "0s"
contractAddress = "YOUR_ORACLE_ADDRESS"
minContractPaymentLinkJuels = "0"
observationSource = """
 
decode_log [type="ethabidecodelog" abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" data="$(jobRun.logData)" topics="$(jobRun.logTopics)"] 

decode_cbor [type="cborparse" data="$(decode_log.data)"] 

fetch [type=http method=GET url="https://api.coinranking.com/v2/coin/77jGXSqWJ1ofG?referenceCurrencyUuid=yhjMzLPhuIDl" allowUnrestrictedNetworkAccess="true" headers="[\\"x-access-token\\", \\"YOUR_API_KEY\\"]"]

parse [type="jsonparse" path="data,coin,price" data="$(fetch)"] 

multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"] 

encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"] 

encode_tx [type="ethabiencode" abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)" 
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" ] 

submit_tx [type="ethtx" to="YOUR_ORACLE_ADDRESS" data="$(encode_tx)"]

decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx 
"""
```
</details>


#### # Coinpaprika
- **[Website](https://coinpaprika.com/)**
- **[API Document](https://api.coinpaprika.com/)**
- The free version does not require an API key, but please note that **the paid version requires an API key and the base URL may also change**.
- Please change YOUR_API_KEY to your own API.
    | Plan   | Base URL                           |
    |--------|------------------------------------|
    | Free   | https://api.coinpaprika.com/v1/     |
    | Starter| https://api-pro.coinpaprika.com/v1/ |
- path="quotes,USD,price"

```toml :Coinpaprika - Free
fetch [type=http method=GET url="https://api.coinpaprika.com/v1/tickers/cgo-comtech-gold?quotes=USD" allowUnrestrictedNetworkAccess="true"]
```
```toml :Coinpaprika - Paid
fetch [type=http method=GET url="https://api-pro.coinpaprika.com/v1/tickers/cgo-comtech-gold?quotes=USD" allowUnrestrictedNetworkAccess="true" headers="[\\"Authorization\\", \\"YOUR_API_KEY\\"]"]
```
 
<details><summary>Sample Job Code - Coinpaprika -</summary>

<!--(上に空行が必要)-->
```toml:Sample Job Code - Coinpaprika -
type = "directrequest"
schemaVersion = 1
name = "Coinpaprika_CGO-USD"
forwardingAllowed = false
maxTaskDuration = "0s"
contractAddress = "YOUR_ORACLE_ADDRESS"
minContractPaymentLinkJuels = "0"
observationSource = """
 
decode_log [type="ethabidecodelog" abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" data="$(jobRun.logData)" topics="$(jobRun.logTopics)"] 

decode_cbor [type="cborparse" data="$(decode_log.data)"] 

fetch [type=http method=GET url="https://api.coinpaprika.com/v1/tickers/cgo-comtech-gold?quotes=USD" allowUnrestrictedNetworkAccess="true" headers="[\\"Authorization\\", \\"YOUR_API_KEY\\"]"]
parse [type="jsonparse" path="quotes,USD,price" data="$(fetch)"] 

multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"] 

encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"] 

encode_tx [type="ethabiencode" abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)" 
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" ] 

submit_tx [type="ethtx" to="YOUR_ORACLE_ADDRESS" data="$(encode_tx)"]

decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx 
"""
```
</details>

#### # Tradermade
- **[Website](https://marketdata.tradermade.com/)**
- **[API Document](https://marketdata.tradermade.com/docs/restful-api)**
- Please change YOUR_API_KEY to your own API.
- path="quotes,0,mid"

```toml :Tradermade
fetch [type=http method=GET url="https://marketdata.tradermade.com/api/v1/live?api_key=YOUR_API_KEY&currency=USDJPY" allowUnrestrictedNetworkAccess="true"]
```
 
<details><summary>Sample Job Code - Tradermade -</summary>

<!--(上に空行が必要)-->
```toml:Sample Job Code - Tradermade -
type = "directrequest"
schemaVersion = 1
name = "Tradermade_USD-JPY"
forwardingAllowed = false
maxTaskDuration = "0s"
contractAddress = "YOUR_ORACLE_ADDRESS"
minContractPaymentLinkJuels = "0"
observationSource = """
 
decode_log [type="ethabidecodelog" abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" data="$(jobRun.logData)" topics="$(jobRun.logTopics)"] 

decode_cbor [type="cborparse" data="$(decode_log.data)"] 

fetch [type=http method=GET url="https://marketdata.tradermade.com/api/v1/live?api_key=YOUR_API_KEY&currency=USDJPY" allowUnrestrictedNetworkAccess="true"]
parse [type="jsonparse" path="quotes,0,mid" data="$(fetch)"] 

multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"] 

encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"] 

encode_tx [type="ethabiencode" abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)" 
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" ] 

submit_tx [type="ethtx" to="YOUR_ORACLE_ADDRESS" data="$(encode_tx)"]

decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx 
"""
```
</details>

#### # Bitfinex
- **[Website](https://www.bitfinex.com/)**
- **[API Document](https://docs.bitfinex.com/docs)**
- path="6"

```toml :Bitfinex
fetch [type=http method=GET url="https://api-pub.bitfinex.com/v2/ticker/tXDCUSD" allowUnrestrictedNetworkAccess="true"]
parse [type="jsonparse" path="6" data="$(fetch)"] 
```

<details><summary>Sample Job Code - Bitfinex -</summary>

<!--(上に空行が必要)-->
```toml:Sample Job Code - Bitfinex -
type = "directrequest"
schemaVersion = 1
name = "Bitfirex_XDC-USD"
forwardingAllowed = false
maxTaskDuration = "0s"
contractAddress = "YOUR_ORACLE_ADDRESS"
minContractPaymentLinkJuels = "0"
observationSource = """
 
decode_log [type="ethabidecodelog" abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" data="$(jobRun.logData)" topics="$(jobRun.logTopics)"] 

decode_cbor [type="cborparse" data="$(decode_log.data)"] 

fetch [type=http method=GET url="https://api-pub.bitfinex.com/v2/ticker/tXDCUSD" allowUnrestrictedNetworkAccess="true"]
parse [type="jsonparse" path="6" data="$(fetch)"] 

multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"] 

encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"] 

encode_tx [type="ethabiencode" abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)" 
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" ] 

submit_tx [type="ethtx" to="YOUR_ORACLE_ADDRESS" data="$(encode_tx)"]

decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx 
```
</details>


#### # BitMart

- **[Website](https://www.bitmart.com/)**
- **[API Document](https://developer-pro.bitmart.com/en/spot/#get-ticker-of-a-trading-pair-v3)**
- path="data,last"

```toml :Bitfinex
fetch [type="http" method=GET url="https://api-cloud.bitmart.com/spot/quotation/v3/ticker?symbol=PLI_USDT"]
parse [type="jsonparse" path="data,last" data="$(fetch)"]
```

<details><summary>Sample Job Code - BitMart -</summary>

<!--(上に空行が必要)-->
```toml:Sample Job Code - BitMart -
type = "directrequest"
schemaVersion = 1
name = "Sample Request BitMart_PLI_USDT"
forwardingAllowed = false
maxTaskDuration = "0s"
contractAddress = "YOUR_ORACLE_ADDRESS"
minContractPaymentLinkJuels = "0"
observationSource = """
decode_log [type="ethabidecodelog" abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)" data="$(jobRun.logData)" topics="$(jobRun.logTopics)"]
 
decode_cbor [type="cborparse" data="$(decode_log.data)"]
 
fetch [type="http" method=GET url="https://api-cloud.bitmart.com/spot/quotation/v3/ticker?symbol=PLI_USDT"]
parse [type="jsonparse" path="data,last" data="$(fetch)"]
 
multiply [type="multiply" input="$(parse)" times="$(decode_cbor.times)"]
 
encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256 value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(multiply) }"]
 
encode_tx [type="ethabiencode" abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)"
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}" ]
 
submit_tx [type="ethtx" to="YOUR_ORACLE_ADDRESS" data="$(encode_tx)"] //paste the Oracle Address which you deployed in ‘to’ field
 
decode_log -> decode_cbor -> fetch -> parse -> multiply -> encode_data -> encode_tx -> submit_tx
"""
```
</details>

:::





Bitrue
![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/7aebb042-51fe-d4ef-5dcd-0c9c251b548c.png)

Cryptocomapre
![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/7b373ee8-cb39-8ad0-ff0c-3752071f3b31.png)

:::note
**Get the JOBID and remove the hyphen `-`.**

**JOBIDを取得し、ハイフン`-`を取り除きます。**

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/ee614ed0-ff1e-9766-98cf-b9ac2f96f4ac.png)

:::



## 4-3. CONSUMER CONTRACT

I will create a smart contract using Remix.

Remixを使って、スマートコントラクトを作成します。

https://remix.xinfin.network/


:::note
Please feel free to make any necessary modifications to the following:

* Mainnet or Apothem
    * Mainnet - 0xFf7412Ea7C8445C46a8254dFB557Ac1E48094391
    * Apothem - 0x33f4212b027E22aF7e6BA21Fc572843C0D701CD1
* Oracle Address
    * Please change the leading 'xdc' to '0x'.
* JOBID
    * Please remove the hyphen `-`.
* API(peer)
    * Please make the URL the same as when creating the JOB.

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/185abcc2-4220-9b2c-919e-3a71df5a1417.png)

```javascript:Consumer Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;


import "@goplugin/contracts2_3/src/v0.8/PluginClient.sol";
import "@goplugin/contracts2_3/src/v0.8/ConfirmedOwner.sol";

/**
* THIS IS AN EXAMPLE CONTRACT WHICH USES HARDCODED VALUES FOR CLARITY.
* THIS EXAMPLE USES UN-AUDITED CODE.
* DO NOT USE THIS CODE IN PRODUCTION.
*/


contract APIConsumer is PluginClient, ConfirmedOwner {
using Plugin for Plugin.Request;


uint256 public volume;
bytes32 private jobId;
uint256 private fee;


event RequestVolume(bytes32 indexed requestId, uint256 volume);


/**
* @notice Initialize the pli token and target oracle
*
* Details:
* A. Pli Token for Mainnt: 0xff7412ea7c8445c46a8254dfb557ac1e48094391
* B. Oracle: [Copy paste the Oracle Contract Address, which you deployed as first step in this page] (Plugin DevRel)
* C. jobId: <job ID>
*
*/
constructor() ConfirmedOwner(msg.sender) {
setPluginToken(0xFf7412Ea7C8445C46a8254dFB557Ac1E48094391);//Pli address as mentioned in ‘A’
setPluginOracle(<Copy paste the Oracle Contract Address>);//Oracle address
jobId = "<job ID>";//Job ID as stored in ‘C’ JOB SUBMISSION
fee = (0.001 * 1000000000000000000) / 10;
}


/**
* Create a Plugin request to retrieve API response, find the target
* data, then multiply by 1000000000000000000 (to remove decimal places from data).
*/
function requestVolumeData() public returns (bytes32 requestId) {
Plugin.Request memory req = buildPluginRequest(
jobId,
address(this),
this.fulfill.selector
);


// Set the URL to perform the GET request on
// req.add(
// "get",
// "<sample_api_link>/data/pricemultifull?fsyms=ETH&tsyms=USD"
// );
req.add(
"get",
"<sample_api_link>/data/price?fsym=XDC&tsyms=USDT"
);


// Multiply the result by 1000000000000000000 to remove decimals
int256 timesAmount = 10 ** 18;
req.addInt("times", timesAmount);


// Sends the request
return sendPluginRequest(req, fee);
}


/**
* Receive the response in the form of uint256
*/
function fulfill(
bytes32 _requestId,
uint256 _volume
) public recordPluginFulfillment(_requestId) {
emit RequestVolume(_requestId, _volume);
volume = _volume;
}


/**
* Allow withdraw of Link tokens from the contract
*/
function withdrawPli() public onlyOwner {
PliTokenInterface pli = PliTokenInterface(PluginTokenAddress());
require(
pli.transfer(msg.sender, pli.balanceOf(address(this))),
"Unable to transfer"
);
}
}
```

:::

:::note warn

Please pay attention to the version of the Remix compiler. **It should be `0.8.7`**. In versions newer than `0.8.20`, errors will occur.

Remixのコンパイラのバージョンに注意してください。**`0.8.7`で良いでしょう**。`0.8.20`より新しいバージョンでは、エラーが出ます。

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/1ba69c93-ecff-84ef-34bb-673287527a9d.png)
:::

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/f250bed0-c5de-21df-fd2b-eebb0dc6f93a.png)

↓

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/39bd03ef-11f1-7bdd-151e-db9b70da1804.png)

↓

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/cd1d214f-4ff3-acfa-3dc0-643ea6f8813b.png)

↓

:::note
As of December 29, 2023, the gas fee on the XDC mainnet is **`0.25` gwei**. If the XDC network's mainnet officially transitions to XDCPoS2.0, the gas fee is expected to increase to **`12.5` gwei**.

2023年12月29日現在、XDCメインネットのガス代は **`0.25`gwei** です。 XDCネットワークのメインネットが正式にXDCPoS2.0に移行した場合、ガス代は **`12.5`gwei** になる予定です。

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/73504383-397f-97fc-39cc-6cc0c0f1ffda.png)
:::

↓

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/e11dffa7-7e4d-bd6e-58ec-2df7f54ced9b.png)

↓

Please wait for about 2 to 3 minutes. You can see that it's complete on the dashboard.

2〜3分、待ちます。するとダッシュボードで`Completed`と表示されていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/80784bf3-5ebe-71a6-33cf-4b8b18c432ee.png)

You can also check it on the Remix. Please click on `Volume`.

Remixでも確認することができます。`Volume`をクリックしてください。

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/b60db510-0349-ebbb-0eb9-90c5a69e015c.png)

You can see that the value of the completed job's "multiply" task is the same.

CompleteしたJobのmultiply`タスクの値と同じであることがわかります。

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/9db6e3eb-7a81-6d4c-6c81-277d9123aef6.png)

:::note
I recommend that you perform another backup once the job is complete. Please refer back to "**[3. Backup After Plugin V2 Upgrade](https://qiita.com/11ppm/private/971439917fb080d887a2#3-backup-after-plugin-v2-upgrade)**" for this. In this case, it is sufficient to back up the database only.

Jobがコンプリートしたら、再びバックアップをすることをおすすめします。"**[3. Backup After Plugin V2 Upgrade](https://qiita.com/11ppm/private/971439917fb080d887a2#3-backup-after-plugin-v2-upgrade)**" に戻って、そちらを参照してください。この場合は、databaseのバックアップだけでも構いません。
:::


# 5. Backup Again

I recommend that you perform another backup once the job is complete. Please refer back to "**[3. Backup After Plugin V2 Upgrade](https://qiita.com/11ppm/private/971439917fb080d887a2#3-backup-after-plugin-v2-upgrade)**" for this. **In this case, it is sufficient to back up the database only.** Use SFTP or a similar method to transfer the `/plinode_backups/` directory to your local PC.

<details><summary>【日本語】</summary>

<!--(上に空行が必要)-->
Jobがコンプリートしたら、再びバックアップをすることをおすすめします。"**[3. Backup After Plugin V2 Upgrade](https://qiita.com/11ppm/private/971439917fb080d887a2#3-backup-after-plugin-v2-upgrade)**" に戻って、そちらを参照してください。**この場合は、databaseのバックアップだけでも構いません。** SFTPなどを使用して、`/plinode_backups/`ディレクトリをローカルPCに転送してください。
</details>

```sh:5
cd ~/pluginV2Install/ && ./_plinode_backup.sh -db && tree -a /plinode_backups/ 
```
![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/a3f304cc-d060-8bde-802d-40712cef1c1b.png)


![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/80d52945-a601-7b6e-c8d0-871add63dc9b.png)


And that's the end of the guide.

以上です。


# Troubleshooting

:::note
If you encounter the following symptoms when logging into the dashboard, it is possible that the RPC your node is connected to is unstable. In such cases, consider executing the following command to change the RPC:

- `ETH` and `PLI` values are not displayed.
- When opening the `Node` tab, the `State` is displayed as `Unreachable`.

<details><summary>【日本語】</summary>

<!--(上に空行が必要)-->
ダッシュボードにログインした際に、以下の症状が現れる場合、おそらくノードが接続しているRPCが不安定である可能性があります。この場合、RPCを変更するために以下のコマンドを実行してみてください。

- `ETH`と`PLI`の値が表示されない
- `Node`タブを開くと`State`に`Unreachable`と表示されている
</details>
:::


![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/2713311b-36c5-5dc1-976a-be040295fa33.png)

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/8829edfd-ec2e-6d67-5b74-2df4604751cb.png)

![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/2957f61e-aa6a-42f0-594e-9fc557060be4.png)

### RPC Change Command

- `erpc.xinfin.network → earpc.xinfin.network` RPC Change Command

    This command replaces a specified URL (https://erpc.xinfin.network) with another URL (https://earpc.xinfin.network) in multiple files and then checks whether the replacement was successful. The target files include `~/pluginV2Install/sample.vars`, `~/plinode_$(hostname -f).vars`, and `~/pluginV2/config.toml`.
    
    <details><summary>【日本語】</summary>
    
    <!--(上に空行が必要)-->
    このコマンドは、指定したURL（`https://erpc.xinfin.network`）を別のURL（`https://earpc.xinfin.network`）に置換し、その後、置換が成功したかどうかを確認するコマンドです。対象ファイルは、`~/pluginV2Install/sample.vars`、`~/plinode_$(hostname -f).vars`、および `~/pluginV2/config.toml` です。
    </details>
    
    ```sh:T-1
    sed -i -e "s|https://erpc.xinfin.network|https://earpc.xinfin.network|g" ~/pluginV2Install/sample.vars ~/plinode_$(hostname -f).vars ~/pluginV2/config.toml && grep "mainnet_httpUrl" ~/pluginV2Install/sample.vars ~/plinode_$(hostname -f).vars && grep "httpUrl" ~/pluginV2/config.toml
    ```

    :::note warn
    If you want to revert to the default `erpc.xinfin.network`, execute the following command:
    
    デフォルトの`erpc.xinfin.network`に戻したい場合、以下のコマンドを実行してください。
    
    - `earpc.xinfin.network → erpc.xinfin.network` RPC Change Command
    
    ```sh:T-2
    sed -i -e "s|https://earpc.xinfin.network|https://erpc.xinfin.network|g" ~/pluginV2Install/sample.vars ~/plinode_$(hostname -f).vars ~/pluginV2/config.toml
    grep "mainnet_httpUrl" ~/pluginV2Install/sample.vars ~/plinode_$(hostname -f).vars && grep "httpUrl" ~/pluginV2/config.toml
    ```
:::

### RPC & Websocket Confirm Command

- Verify the RPC & Websocket in the `~/pluginV2Install/sample.vars`, `~/plinode_$(hostname -f).vars`, and `~/pluginV2/config.toml` files.
    
    ```sh:T-3
    echo -e '\n【~/plinode_YOUR_HOSTENAME.vars】' && cat ~/plinode_$(hostname -f).vars | grep -E 'mainnet_wsUrl|mainnet_httpUrl' ;echo -e '\n【~/pluginV2Install/sample.vars】' && cat ~/pluginV2Install/sample.vars | grep -E 'mainnet_wsUrl|mainnet_httpUrl' ;echo -e '\n【~/pluginV2/config.toml】' && cat ~/pluginV2/config.toml | grep -E 'httpUrl|wsUrl' ;echo
    ```
    ![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/4ab88f30-5c9a-4e8d-3dae-aaf3a87bd58c.png)

### Pm2 Restart Command

- To apply the changes, restart the process.
変更を反映させるために、プロセスを再起動させます。

    
    ```sh:T-4
    pm2 restart all
    ```
    
    Finally, log in to the dashboard.
    
    最後にダッシュボードへログインします。
    
    ```sh:T-5
    echo https://$(ip a | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1'):6689 && cat ~/pluginV2/apicredentials.txt 
    ```
    
    ![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/e03ceaa4-30a2-7923-426e-3d7999317961.png)
    
    ![Screenshot by Dropbox Capture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518907/7fd7e089-c9fe-d312-997f-8f33f4027c56.png)


*Author: [11ppm](https://twitter.com/11ppm11)*