PoK commandline application
Installation #
- Install Node
- Install npx globally:
npm install -g npx
- Install node packages. In project root folder run:
npm install
- Change configuration object(row 14-19 in code sample)
- Running:
npm start
Commandline application #
Code #
import axios from "axios";
const readline = require('readline');
import { WebSocket } from 'ws';
import { Wallet } from 'ethers';
const appConfig = {
NOTARDEC_URL: 'https://uat-api.notardec.com/v0.5',
NOTARDEC_WS_URL: 'wss://uat-api.notardec.com/v0.5/ws',
STEP: '0'
}
const config = {
API_KEY: 'enter your api key',
ARTIFACT_NAME: 'enter your artifact name',
ARTIFACT_AUTHOR: "enter your artifact author",
ARTIFACT_ID: "enter your artifact id",
LINK_ARTIFACT_ID: "enter your link artifact id",
PRIVATE_KEY: ''
}
let pokData = {
POK_RESULT: '',
CHALLENGE_ID: '',
ADDRESS: '',
CHALLENGE: ''
};
let assetData = {
}
let transactions = {
ASSET_TRANSACTION: '',
LINK_TRANSACTION: ''
}
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
async function settingUp(config){
if (!config.API_KEY){
console.error('You must enter the API key')
return 0;
}
if (!config.ARTIFACT_ID && !config.ARTIFACT_NAME){
console.error('You must enter the artifact id or artifact name')
return 0;
}
if (!config.ARTIFACT_AUTHOR){
console.error('You must enter the author address')
return 0;
}
if (!config.LINK_ARTIFACT_ID){
console.error('You must enter the link artifact address')
return 0;
}
if (!config.PRIVATE_KEY){
console.error('You must enter the private key')
return 0;
}
console.log('Your configuration:')
console.log(config)
}
async function createOrGetArtifact(config,transactions) {
try {
if (config.ARTIFACT_ID){
console.log('Getting the asset')
const artifact = await getAsset(config.API_KEY, config.ARTIFACT_ID);
assetData = artifact.value
console.log('Asset:', artifact.value)
return artifact.value;
} else {
console.log('Creating the asset')
const pendingArtifact = await createAsset(config.API_KEY, {
name: config.ARTIFACT_NAME,
author: config.ARTIFACT_AUTHOR
});
transactions.ASSET_TRANSACTION = pendingArtifact.value.transactionId;
console.log('Please, confirm the asset creation transaction');
console.log('Enter [x] to back to the menu');
const isConfirmed = await checkTransactionStatus(config.API_KEY, pendingArtifact.value.transactionId);
if (isConfirmed) {
const artifact = await getAsset(config.API_KEY, pendingArtifact.value.id);
assetData = artifact.value
config.ARTIFACT_ID = artifact.value.id;
return artifact;
}
}
} catch (error) {
console.error('FAILED TO CREATE OR GET ARTIFACT')
error.message ? console.error(error.message) : null;
console.error(`status: ${error.status}`);
}
}
async function linkArtifacts(config, transactions){
try {
const payload = {
targetAssetIds: [config.LINK_ARTIFACT_ID]
}
console.log('Linking assets')
const transaction = await linkAssets(config.API_KEY, config.ARTIFACT_ID, payload)
console.log('Please, confirm the link transaction')
transaction.LINK_TRANSACTION = transaction.value.id
const isConfirmed = await checkTransactionStatus(config.API_KEY, transaction.value.id)
if (isConfirmed) {
const asset = await getAsset(config.API_KEY, assetData.id, true)
assetData = asset.value;
return true
}
} catch (e) {
console.error('FAILED TO LINK ASSETS')
error.message ? console.error(error.message) : null;
console.error(`status: ${error.status}`);
}
}
async function createPokForArtifact(config){
try {
console.log('Creating PoK')
const pok = await createPok(config.API_KEY, { address: config.ARTIFACT_AUTHOR});
pokData.CHALLENGE_ID = pok.I;
pokData.ADDRESS = config.ARTIFACT_AUTHOR;
pokData.CHALLENGE = pok.C;
console.log(pok);
return pok;
} catch (e) {
console.error('Failed to create pok')
console.error(e.message)
}
}
async function getAsset(apiKey, assetId, details = true) {
let url = `${appConfig.NOTARDEC_URL}/assets/${assetId}`;
if (details) {
url = `${appConfig.NOTARDEC_URL}/assets/${assetId}?details=true`;
}
const result = await axios.get(url, {
headers: {
'X-API-KEY': apiKey,
},
});
return result.data;
}
async function createAsset(apiKey, payload) {
const result = await axios.post(`${appConfig.NOTARDEC_URL}/assets`, payload, {
headers: {
'X-API-KEY': apiKey,
},
});
return result.data;
}
async function getTransaction(apiKey, transactionId) {
const result = await axios.get(`${appConfig.NOTARDEC_URL}/transactions/${transactionId}/status`, {
headers: {
'X-API-KEY': apiKey,
},
});
return result.data;
}
async function linkAssets(apiKey, assetId, payload) {
const result = await axios.post(`${appConfig.NOTARDEC_URL}/assets/${assetId}/links`, payload, {
headers: {
'X-API-KEY': apiKey,
},
});
return result.data;
}
async function createPok(apiKey, payload) {
const result = await axios.post(`${appConfig.NOTARDEC_URL}/pok`, payload, {
headers: {
'X-API-KEY': apiKey,
},
});
return result.data;
}
async function respondPok(apiKey, payload) {
const result = await axios.post(`${appConfig.NOTARDEC_URL}/pok/respond`, payload, {
headers: {
'X-API-KEY': apiKey,
},
});
return result.data;
}
async function checkTransactionStatus(apiKey, transactionId) {
const transactionStatus = await getTransaction(apiKey, transactionId);
if (transactionStatus.value.state !== 'Confirmed') {
console.log(`Transaction state: ${transactionStatus.value.state}`)
await new Promise(resolve => setTimeout(resolve, 2000));
return checkTransactionStatus(apiKey, transactionId);
} else {
console.log(`Transaction state: ${transactionStatus.value.state}`)
return true;
}
}
export const initWebSocketClient = (pokData) => {
console.log('Connected to Notardec WS');
const websocketListen= new WebSocket(appConfig.NOTARDEC_WS_URL);
websocketListen.onclose = () => {
console.log('Disconnected from Notardec WS');
setTimeout(() => initWebSocketClient(), 200);
};
websocketListen.onerror = (error) => {
console.log('There is an error with websockets' + error.message);
websocketListen.close();
};
websocketListen.onmessage = (message) => {
const data = JSON.parse(String(message.data));
switch (data.type) {
case 'POK_SUCCESS':
const successPok = JSON.parse(data.message)
pokData.POK_RESULT = successPok.result;
pokData.CHALLENGE_ID = successPok.challengeId;
pokData.ADDRESS = successPok.address
console.log('Responded pok:', successPok)
break;
case 'POK_FAILED':
const failedPok = JSON.parse(data.message)
pokData.POK_RESULT = failedPok.result;
pokData.CHALLENGE_ID = failedPok.challengeId;
pokData.ADDRESS = failedPok.address
console.log('Responded pok:', failedPok)
break;
case 'PING':
websocketListen.send(JSON.stringify({ message: '', type: 'PONG' }));
}
};
};
async function displayMainMenu(config) {
let choice;
if(appConfig.STEP == '0'){
console.log("This application demonstrates the functionality of PoK");
console.log('Enter [1] to start the process')
console.log("Enter [x] Exit");
choice = await askForUserInput("Enter your choice: ");
} else {
console.log('Enter [1] Continue the process')
if (appConfig.STEP >= 1) {
console.log('Enter [2] Show the config')
}
if (appConfig.STEP >= 2) {
console.log('Enter [3] Show the asset')
}
if (appConfig.STEP >= 5) {
console.log('Enter [4] Show the pok')
}
console.log("Enter [x] Exit");
choice = await askForUserInput("Enter your choice: ");
}
switch (choice) {
case '1':
switch (appConfig.STEP){
case '0':
let isConfigCorrect = await settingUp(config)
if(isConfigCorrect == 0) {
console.error('Please, fix the config')
process.exit();
}
appConfig.STEP = '1'
break;
case '1':
const asset = await createOrGetArtifact(config, transactions);
if(!asset) {
process.exit();
}
appConfig.STEP = '2'
break;
case '2':
const link = await linkArtifacts(config, transactions);
if (!link){
process.exit();
}
appConfig.STEP = '3'
break;
case '3':
const pok = await createPokForArtifact(config);
if(!pok){
process.exit();
}
appConfig.STEP = '4'
break;
case '4':
console.log('Responding PoK')
const wallet = new Wallet(config.PRIVATE_KEY);
const signature = await wallet.signMessage(pokData.CHALLENGE);
const sign = await respondPok(config.API_KEY, {
address: config.ARTIFACT_AUTHOR,
signature: signature,
challengeId: pokData.CHALLENGE_ID
})
appConfig.STEP = '5'
break;
}
break;
case '2':
console.log('Config:')
console.log(config)
break;
case '3':
console.log('Asset:')
console.log(assetData)
break;
case '4':
console.log('Pok:')
console.log(pokData);
break;
case 'x':
process.exit(0); // Exit the application
break;
default:
console.log("Invalid choice. Please try again.");
break;
}
if ( appConfig.STEP == '5') {
await askForUserInput("The process of creating a PoK is completed. Press enter to back to the menu: ");
} else {
await askForUserInput("Press enter to continue: ");
}
displayMainMenu(config)
}
async function askForUserInput(question) {
return new Promise((resolve, reject) => {
rl.question(question, (answer) => {
resolve(answer);
});
});
}
async function start(){
initWebSocketClient(pokData);
displayMainMenu(config);
}
start()