STEPS TO SETUP PLUGIN 2.0 NODE ON LINUX VPS
This is a list of commands I used to set up Plugin 2.0. Right now, inv4fee has created an amazing script that the Plugin team is adopting. This is the original procedure.
I'm also trying to document the job as much as possible. Looking at it now, there may be some changes, but most of it should still be useful.
I hope this helps you all understand how to set up Plugin 2.0.
1. Login as root to your new VPS
2. Update the system and add in base packages before proceeding by executing below command on the root terminal.
sudo apt update -y && sudo apt upgrade -y && sudo apt install -y git nano curl && sudo apt autoremove -y
3. Allow permissions on below ports.
sudo apt install ufw
Port 22
is a common SSH port, but please adjust it according to your specifications.
sudo ufw allow 6688/tcp
sudo ufw allow 6689/tcp
sudo ufw allow 22/tcp
# sudo ufw allow YOUR_PORT_NUMBER/tcp
sudo ufw enable
# If prompted, please enter `y` and press Enter key.
4. Create a new admin user account
sudo groupadd my_new_user
sudo useradd -p $(openssl passwd -6 my_new_password) my_new_user -m -s /bin/bash -g my_new_user -G sudo
In this guide, you will set up as follows:
- Username : Doraemon
- Password : Nobita10Shizuka
sudo groupadd Doraemon
sudo useradd -p $(openssl passwd -6 Nobita10Shizuka) Doraemon -m -s /bin/bash -g Doraemon -G sudo
5. Now open a new terminal session to your VPS and logon with your new admin user account and complete the rest of the steps.
sudo -i -u Doraemon
6. Install GO 1.20.6 version and set GOROOT, GOPATH and PATH
cd ~ && wget https://dl.google.com/go/go1.20.6.linux-amd64.tar.gz
sudo tar -xvf go1.20.6.linux-amd64.tar.gz
sudo mv go /usr/local
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
go version
7. Install NVM(node version manager) and Node 16.14.0
cd ~ && curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
source ~/.bashrc
nvm install 16.14.0
nvm use 16.14.0
node --version
8. Install [Postgres (> 11.x and <=15.x)]
cd ~ && sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget -qO- https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo tee /etc/apt/trusted.gpg.d/pgdg.asc &>/dev/null
sudo apt install postgresql postgresql-client -y
sudo systemctl status postgresql
psql --version
9. Create Data Base for plugin_mainnet_db in Postgres and set password
Note: Restriction for Database Password
- Must be at least 16 characters long
- Must not comprise: Leading or trailing whitespace / user's API email.
The Plugin node requires three passwords, but with the script used in Plugin 1.0, you can freely generate them. Please save the generated passwords in a memo.
cd ~ && wget -O gen_passwd.sh https://raw.githubusercontent.com/11ppm/plugin-deployment/main/gen_passwd.sh
chmod +x gen_passwd.sh
Method A
./gen_passwd.sh
./gen_passwd.sh -keys
./gen_passwd.sh -db
./gen_passwd.sh -api
-
./gen_passwd.sh -keys
=> 0iP5So8lGt3eJM:K=unsix2;58*.gT32 -
./gen_passwd.sh -db
=> cmGip2lu5imYLIlcOUeEUakZe1Qysf -
./gen_passwd.sh -api
=> fvSNoxI2c1Z1znx3lt
echo $(tr -cd A-Za-z < /dev/urandom | fold -w10 | head -n1)@plinode.local
-
echo $(tr -cd A-Za-z < /dev/urandom | fold -w10 | head -n1)@plinode.local
=> uGxLfwxBfC@plinode.local
Method B
Alternatively, after executing the command 9-1
, please copy and paste the following command into the terminal and execute it. This will randomly create the necessary password and other requirements for setting up the node.
#!/bin/bash
# Set Colour Vars
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Important Infomation
IP_ADDRESS=$(ip addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -n1)
NEW_KEYSTORE="$(./gen_passwd.sh -keys)"
NEW_DB_PWD="$(./gen_passwd.sh -db)"
_AUTOGEN_API_USER=$(tr -cd A-Za-z < /dev/urandom | fold -w10 | head -n1)
NEW_API_EMAIL="$_AUTOGEN_API_USER@plinode.local"
NEW_API_PWD="$(./gen_passwd.sh -api)"
# Print
echo \ &&
echo -e "${GREEN}#########################################################################${NC}" \ &&
echo \ &&
echo -e "${RED}## IMPORTANT INFORMATION - PLEASE RECORD TO YOUR PASSWORD SAFE${NC}" \ &&
echo \ &&
echo -e "${GREEN}#########################################################################${NC}" \ &&
echo \ &&
echo -e "${RED}## KEY STORE SECRET: $NEW_KEYSTORE${NC}" \ &&
echo \ &&
echo -e "${RED}## POSTGRES DB PASSWORD: $NEW_DB_PWD${NC}" \ &&
echo \ &&
echo -e "${RED}## API USERNAME: $NEW_API_EMAIL${NC}" \ &&
echo -e "${RED}## API PASSWORD: $NEW_API_PWD${NC}" \ &&
echo \ &&
echo -e "${GREEN}#########################################################################${NC}" \ &&
echo \ &&
echo -e "${GREEN}Your Plugin node GUI IP address is as follows:${NC}" \ &&
echo \ &&
echo -e " ${RED}http://$IP_ADDRESS:6688${NC}" \ &&
echo \ &&
echo -e "${GREEN}#########################################################################${NC}"
sudo systemctl start postgresql.service
this will login to Postgres
sudo -i -u postgres psql
CREATE DATABASE plugin_mainnet_db;
ALTER USER postgres WITH PASSWORD 'new_password';
It is recommended to use the password outputted by the command ./gen_passwd.sh -db
for 9-1
.
In this demo, I have created the following password:
-
./gen_passwd.sh -db
cmGip2lu5imYLIlcOUeEUakZe1Qysf
ALTER USER postgres WITH PASSWORD 'cmGip2lu5imYLIlcOUeEUakZe1Qysf';
Please keep a note of this password as it will be used for the command 13-3
.
Command to exit Postgres
\q
10. Ensure you have python3
python3 --version
11. Download Plugin 2.0 codebase
cd ~ && git clone https://github.com/GoPlugin/pluginV2.git && cd pluginV2
ls -la
# ll
12. Install pnpm
npm install -g pnpm
13. Setup Environment:
apicredentials.txt
-
Modify
apicredentials.txt
file with a valid email id and complex password13-1nano apicredentials.txt
To save the changes made to the file in
nano
, follow these steps:- Press the
"Ctrl"
and"X"
keys on your keyboard at the same time. - Press the
"Y"
key on your keyboard to confirm that you want to save the changes. - Press the
"Enter"
key on your keyboard to exit the editor.
These steps will save the changes you made to the file and exit the nano editor.
:: - Press the
config.toml
- Modify
config.toml
with appropriate RPC, WSS, and ChainID13-2nano config.toml
-
Mainnet
MainnetRPC : https://erpc.xinfin.network WSS : wss://ws.xinfin.network PluginContractAddress : 0xFf7412Ea7C8445C46a8254dFB557Ac1E48094391 Chain ID : 50
-
Apothem
ApothemRPC : https://erpc.apothem.network WSS : wss://ws.apothem.network/ws PluginContractAddress : 0x33f4212b027E22aF7e6BA21Fc572843C0D701CD1 Chain ID : 51
-
Preliminary RPC
wss://ws.xinfin.network
Compeleted : The following four RPCs can respond to requests with "Oracle request received" and complete within the limits of OCA's four seats.
https://xdcpayrpc.blocksscan.io/
https://rpc-xdc.icecreamswap.com/
https://erpc.xdcrpc.com/
https://earpc.xinfin.network/
ERROR : The following five RPCs display the same error as the image.
https://xdcfnode1.goplugin.co/
https://rpc.xinfin.network/
https://rpc.xdcrpc.com/
https://rpc1.xinfin.network/
http://my_fullnode_ip:8989/
secrets.toml
- Modify secrets.toml with appropriate Keystore and Database URL
13-3
nano secrets.toml
secrets.toml (Sample)[Password] Keystore = 'uXgNT04ZvGLBe%CoZFn8R%NJ!' [Database] URL = 'postgresql://postgres:NIMh8ePEg58881F88DCw2wnsN0zX82@127.0.0.1:5432/plugin_mainnet_db?sslmode=disable'
Note: This password uses the password used in the command 9-5
. Restriction for Database Password
- Must be at least 16 characters long
- Must not comprise: Leading or trailing whitespace / user's API email
14. Install and build all plugin dependencies
cd ~/pluginV2/ && sudo apt install build-essential
# y
make install
15. Setup the profile
Modify the .profile file in $Home directory of the admin account with below content and run the command “source ~/.profile”
nano ~/.profile
GOROOT=/usr/local/go
GOPATH=$HOME/go
PATH=$GOPATH/bin:$GOROOT/bin:$PATH
SECURE_COOKIES=false
source ~/.profile
16. Start the plugin node
plugin --admin-credentials-file apicredentials.txt -c config.toml -s secrets.toml node start
Please provide a valid email
and password
from apicredentials.txt
which will be used to login to http://localhost:6688
To run a node in the background, you can add &
at the end of the command. However, I recommend installing pm2
for this purpose. Please follow the steps below.
To stop the flowing logs, press Control + C
. This will pause the logs and at the same time, you won't be able to access the dashboard.
cd ~/pluginV2/ && npm install pm2 -g
The command npm install pm2 -g
installs the pm2 package globally. Global installation is done to make pm2 available throughout the system.
Therefore, you can use the pm2 command from any directory. Even if you run it in the home directory and then move to another directory, pm2 will still be available.
【日本語】
npm install pm2 -g
コマンドは、グローバルにpm2パッケージをインストールします。グローバルインストールは、システム全体でpm2を使用できるようにするために行われます。
したがって、どのディレクトリにいてもpm2コマンドを使用することができます。ホームディレクトリで実行した場合でも、他のディレクトリに移動しても、pm2は利用可能です。
cat > NodeStartPM2.sh
# Of course, you can also use `nano`.
Copy and paste the following script, and close it with Control + D
.
echo "<<<<<<<<<------------------STARTING PLUGIN NODE--------------------->>>>>>>>>"
plugin --admin-credentials-file apicredentials.txt -c config.toml -s secrets.toml node start
echo "<<<<<<<<<<<-------------------Plugin node is running .. use "pm2 status" to check the status-------->>>>>>>>>>>"
# Press enter on the next line and close the terminal by pressing Control + D
ls -la
# ll
Start Plugin Node
pm2 start NodeStartPM2.sh
pm2 startup
If the server is restarted as it is, the pm2 process will not start automatically. To start it automatically even if the server is restarted, please execute the following command:
pm2 startup
Then, you will see the following message:
[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
Copy and paste the command in the yellow box as instructed and press enter.
Finally, make sure that the following screen is displayed.
Then, it is recommended to execute the following command before actually restarting the server:
pm2 save
sudo reboot
After restarting the server, please log in again and execute the following command:
pm2 ls
Make sure that NodeStartPM2
is running.
Log in to the dashboard
provide a valid email and password from apicredentials.txt
which will be used to login to http://localhost:6688
.
cat apicredentials.txt
echo http://$(hostname -i):6688
Deposit XDC and PLI to Node Address.
- Click on the gear icon located in the top right corner of the dashboard.
- Click on 'Key Management'.
- Scroll down to the bottom of the screen and locate the 'Address' under 'EVM Chain Accounts'. This will be your 'Node Address'.
- Send 1XDC and 1PLI to this Node Address.
- Verify that the balances of XDC and PLI have increased.
Setup of Job and Deployment of Contract
17. Oracle Contract
Using Remix, create an Oracle contract.
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
import "@goplugin/test/src/v0.7/Operator.sol";
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.
- Mainnet PLI Contract :
Mainnet PLI Contract
0xFf7412Ea7C8445C46a8254dFB557Ac1E48094391
- Apothem PLI Contract :
Apothem PLI Contract
0x33f4212b027E22aF7e6BA21Fc572843C0D701CD1
0xFf7412Ea7C8445C46a8254dFB557Ac1E48094391
0x33f4212b027E22aF7e6BA21Fc572843C0D701CD1
18. Job setup
type = "directrequest"
schemaVersion = 1
name = "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" allowUnrestrictedNetworkAccess="true"]
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)"]
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.
JOB SETUP
- The value of the name key should be changed.
- The Oracle Address will be changed in two locations.
- The URL will be modified.
Regarding CMC, the APIKEY will be updated. - The path will be modified.
# Cryptocompare
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
"""
# Coingecko
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
"""
# Binance
# Bitrue
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
"""
# Kucoin
- https://api.kucoin.com/api/v1/market/orderbook/level1?symbol=XDC-USDT
- path="data,price"
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
"""
# CMC
- Please change YOUR_API_KEY to your own API.
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)"]
# Coinranking
- Website
- API Document
- Please change YOUR_API_KEY to your own API.
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"
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
"""
# Coinpaprika
- Website
- API Document
- 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"
fetch [type=http method=GET url="https://api.coinpaprika.com/v1/tickers/cgo-comtech-gold?quotes=USD" allowUnrestrictedNetworkAccess="true"]
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\\"]"]
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
"""
# Tradermade
- Website
- API Document
- Please change YOUR_API_KEY to your own API.
- path="quotes,0,mid"
fetch [type=http method=GET url="https://marketdata.tradermade.com/api/v1/live?api_key=YOUR_API_KEY¤cy=USDJPY" allowUnrestrictedNetworkAccess="true"]
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¤cy=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
"""
# Bitfinex
- Website
- API Document
- path="6"
fetch [type=http method=GET url="https://api-pub.bitfinex.com/v2/ticker/tXDCUSD" allowUnrestrictedNetworkAccess="true"]
parse [type="jsonparse" path="6" data="$(fetch)"]
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
# BitMart
- Website
- API Document
- path="data,last"
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)"]
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
"""
JOBIDを取得し、ハイフン-
を取り除きます。
19. CONSUMER CONTRACT
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
-
.
- Please remove the hyphen
- API(peer)
- Please make the URL the same as when creating the JOB.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@goplugin/test/src/v0.8/PluginClient.sol";
import "@goplugin/test/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: 0x33f4212b027E22aF7e6BA21Fc572843C0D701CD1
* B. Oracle: 0x6090149792dAAeE9D1D568c9f9a6F6B46AA29eFD (Plugin DevRel)
* C. jobId: ca98366cc7314957b8c012c72f05aeeb
*
*/
constructor() ConfirmedOwner(msg.sender) {
setPluginToken(0x33f4212b027E22aF7e6BA21Fc572843C0D701CD1);//Pli address as mentioned in ‘A’
setPluginOracle(0x06b321e3da4a5c67fBF074bb48C6408074bDD785);//Oracle address
jobId = "53034a3f099949f787937a96fa3e9a32";//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",
// "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD"
// );
req.add(
"get",
"https://min-api.cryptocompare.com/data/price?fsym=XDC&tsyms=USD"
);
// Set the path to find the desired data in the API response, where the response format is:
// {"RAW":
// {"ETH":
// {"USD":
// {
// "VOLUME24HOUR": xxx.xxx,
// }
// }
// }
// }
// request.add("path", "RAW.ETH.USD.VOLUME24HOUR"); // Plugin nodes prior to 1.0.0 support this format
//req.add("path", "RAW.ETH.USD.VOLUME24HOUR"); // Plugin nodes 1.0.0 and later support this format
//req.add("path", "USD"); // Plugin nodes 1.0.0 and later support this format
//req.add("path", "Result,data,result"); // Plugin nodes 1.0.0 and later support this format
// 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"
);
}
}
Git Command
The following command is commonly used when using Git for version control.
git fetch
git fetch
-
git fetch
: Retrieves the latest changes from the remote repository, but does not apply them to the local branch. The fetched changes can be used later for merging or checking out.
git log --oneline origin/main
git log --oneline origin/main
-
git log --oneline origin/main
: Displays the commit history of theorigin/main
branch in a one-line format. The--oneline
option shows the commit messages in a concise form.
In the given output of the
git log --oneline origin/main
command, there are two mentions of "HEAD".-
b7a5ee2 (HEAD -> main) contracts updated
: This line indicates that the current branch,main
, is pointing to the commit with the hashb7a5ee2
. The(HEAD -> main)
part shows the current branch reference. -
89b2f7c (origin/main, origin/HEAD) PLI value changes
: This line indicates that the remote branchorigin/main
and the symbolic referenceorigin/HEAD
are both pointing to the commit with the hash89b2f7c
. The(origin/main, origin/HEAD)
part shows the references associated with this commit.
The "HEAD" reference in Git represents the currently checked out commit or branch. It can be used to navigate and make changes within the repository.
-
git merge
git merge
-
git merge
: Merges a branch into the current branch. It incorporates the changes from the specified branch into the current branch, combining the commit histories.
git pull
git pull
-
git pull
: Fetches the latest changes from the remote repository and merges them into the current branch. It is a combination ofgit fetch
andgit merge
.
git chekout
git chekout 1a2b3c4d
-
git checkout 1a2b3c4d
: Switches to the specified commit or branch.1a2b3c4d
is the commit hash or branch name. This command allows you to go back to a specific commit state or move to a different branch. However, it does not create a new branch.
Reset
This command is very dangerous. It will completely delete. Once deleted, it cannot be undone.
cd ~ && sudo rm -rf go/ go1.20.6.linux-amd64.tar.gz /usr/local/go pluginV2/
Remix.ethereum & MetaMask
Compeleted : The following four RPCs can respond to requests with "Oracle request received" and complete within the limits of OCA's five seats.
ERROR : The following four RPCs display the same error as the image.
MetaMask
- blocksscan.io
- https://xdcpayrpc.blocksscan.io/
- 50
- XDC
- https://observer.xdc.org/
Remix.ethereum
Oracle.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
import "@goplugin/test/src/v0.7/Operator.sol";