#!/usr/bin/env node
/*
* liji
*/
'use strict'
const http = require('http')
const url = require('url')
const request = require('request')
// Example: various application transactions
// NOTE: Though we passed arguments directly to functions in
// this example to show that it is possible, we'd recommend using the
// makeApplicationCreateTxnFromObject, makeApplicationOptInTxnFromObject, etc.
// counterparts in your code for readability.
//const algosdk = require('..');
const algosdk = require('algosdk');
const utils = require('./utils');
/**
* Configurabales
*/
const ALGO_NETWORK = 'livenet'
const BIND_IP = '0.0.0.0'
const SERVER_PORT = 10283
/**
* Error codes.
*/
const ERR_BADSIG = 40100 // the submitted signature didn't pass verification.
const ERR_OVERSPENDING = 40200 // user's balance is insufficient for the transaction.
const ERR_APIDATA = 50300 // API returned unparseable message.
const ERR_APINETWORK = 50400 // API site communication error.
const API_BASE = '/algo-api'
const API_PATH_MAKETX = API_BASE + '/makesendtx'
const API_PATH_SENDTX = API_BASE + '/sendtx'
const API_PATH_CREATEASSETMAKETX = API_BASE + '/createassetmaketx'
const API_PATH_DELETEASSETMAKETX = API_BASE + '/deleteassetmaketx'
const API_PATH_SENDASSETMAKETX = API_BASE + '/sendassetmaketx'
process.title = 'algocoin'
const server = http.createServer(onClientRequest).listen(SERVER_PORT, BIND_IP)
server.setTimeout(60000) // 60s timeout
console.log(new Date().toISOString(), process.title, 'listening on', BIND_IP + ':' + SERVER_PORT)
/**
* Handler for bad requests.
*/
function badRequest(rsp) {
rsp.statusCode = 400 // "Bad Request"
// rsp.end('400 Bad Request')
rsp.write(JSON.stringify({
status: false,
msg: 'Bad request',
}, null, 4))
console.log(new Date().toISOString(), '[ERROR] Bad request.')
rsp.end()
}
function errorReport(rsp, code, msg) {
rsp.write(JSON.stringify({
status: false,
code: code,
msg: msg
}, null, 4))
console.log(new Date().toISOString(), '[ERROR] code:', code)
rsp.end()
}
async function makeTransactiontx(rsp, queryParams, client) {
console.log(queryParams);
try {
// define application parameters
const from = queryParams.from;
const toAddress = queryParams.to;
const payAmount = Number(queryParams.value);
const payFee = Number(queryParams.fee);
const payNote = queryParams.memo;
const enc = new TextEncoder();
const note = enc.encode(payNote);
//Check balance
let accountInfo = await client.accountInformation(from).do();
if (accountInfo.amount < payFee + payAmount) {
errorReport(rsp, 40200, "infusient balance");
}
//console.log(accountInfo.amount);
// Construct the transaction
let params = await client.getTransactionParams().do();
// comment out the next two lines to use suggested fee
params.fee = payFee;
//console.log(algosdk.ALGORAND_MIN_TX_FEE);
params.flatFee = true;
let txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
from: from,
to: toAddress,
amount: payAmount,
note: note,
suggestedParams: params
});
rsp.write(JSON.stringify({
status: true,
bytes_est: 256,
hash: Buffer.from(txn.bytesToSign()).toString("hex"),
tx_unsigned: Buffer.from(txn.toByte()).toString("hex")
}, null, 2))
//console.log(new Date().toISOString(), "txid = ", hash)
rsp.end()
}
catch (e) {
console.log("makeTransactionINFO", e);
badRequest(rsp);
}
}
async function makeCreateassettx(rsp, queryParams, client) {
console.log(queryParams);
try {
const senderAddress = queryParams.from;
// Construct the transaction
let params = await client.getTransactionParams().do();
const feePerByte = 10;
const firstValidRound = params.firstRound;
const lastValidRound = params.lastRound;
const genesisHash = params.genesisHash;
//const closeAssetsToAddr = "XIU7HGGAJ3QOTATPDSIIHPFVKMICXKHMOR2FJKHTVLII4FAOA3CYZQDLG4";
const receiverAddr = queryParams.from;
const amount = 0; // amount of assets to transfer
const assetIndex = Number(queryParams.assetIndex); // identifying index of the asset
// set suggested parameters
// in most cases, we suggest fetching recommended transaction parameters
// using the `algosdk.Algodv2.getTransactionParams()` method
const suggestedParams = {
fee: feePerByte,
firstRound: firstValidRound,
lastRound: lastValidRound,
genesisHash,
};
// create the asset transfer transaction
const transactionOptions = {
from: senderAddress,
to: senderAddress,
amount,
assetIndex,
suggestedParams,
};
const txn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject(
transactionOptions
);
rsp.write(JSON.stringify({
status: true,
bytes_est: 256,
hash: Buffer.from(txn.bytesToSign()).toString("hex"),
tx_unsigned: Buffer.from(txn.toByte()).toString("hex")
}, null, 2))
//console.log(new Date().toISOString(), "txid = ", hash)
rsp.end()
}
catch (e) {
console.log("makeCreateassettxINFO", e);
badRequest(rsp);
}
}
async function makeDeleteassetmaketx(rsp, queryParams, client) {
console.log(queryParams);
//assetOptionAddress
try {
const senderAddress = queryParams.from;
// Construct the transaction
let params = await client.getTransactionParams().do();
const feePerByte = 10;
const firstValidRound = params.firstRound;
const lastValidRound = params.lastRound;
const genesisHash = params.genesisHash;
const closeAssetsToAddr = queryParams.assetOptionAddress;
const amount = 0; // amount of assets to transfer
const assetIndex = Number(queryParams.assetIndex); // identifying index of the asset
// set suggested parameters
// in most cases, we suggest fetching recommended transaction parameters
// using the `algosdk.Algodv2.getTransactionParams()` method
const suggestedParams = {
fee: feePerByte,
firstRound: firstValidRound,
lastRound: lastValidRound,
genesisHash,
};
// create the asset transfer transaction
const transactionOptions = {
from: senderAddress,
to: closeAssetsToAddr,
closeRemainderTo: closeAssetsToAddr,
amount,
assetIndex,
suggestedParams,
};
const txn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject(
transactionOptions
);
rsp.write(JSON.stringify({
status: true,
bytes_est: 256,
hash: Buffer.from(txn.bytesToSign()).toString("hex"),
tx_unsigned: Buffer.from(txn.toByte()).toString("hex")
}, null, 2))
//console.log(new Date().toISOString(), "txid = ", hash)
rsp.end()
}
catch (e) {
console.log("deleteassetmaketxINFO", e);
badRequest(rsp);
}
}
async function makeSendassetmaketx(rsp, queryParams, client) {
console.log(queryParams);
try {
const senderAddress = queryParams.from;
const recieveAddress = queryParams.to;
const payNote = queryParams.memo;
const enc = new TextEncoder();
const note = enc.encode(payNote);
// Construct the transaction
let params = await client.getTransactionParams().do();
const feePerByte = Number(queryParams.fee);
const firstValidRound = params.firstRound;
const lastValidRound = params.lastRound;
const genesisHash = params.genesisHash;
//const closeAssetsToAddr = "XIU7HGGAJ3QOTATPDSIIHPFVKMICXKHMOR2FJKHTVLII4FAOA3CYZQDLG4";
const receiverAddr = queryParams.from;
const amount = Number(queryParams.value); // amount of assets to transfer
const assetIndex = Number(queryParams.assetIndex); // identifying index of the asset
// set suggested parameters
// in most cases, we suggest fetching recommended transaction parameters
// using the `algosdk.Algodv2.getTransactionParams()` method
const suggestedParams = {
fee: feePerByte,
flatFee:true,
firstRound: firstValidRound,
lastRound: lastValidRound,
genesisHash,
};
// create the asset transfer transaction
const transactionOptions = {
from: senderAddress,
to: recieveAddress,
amount,
note:note,
assetIndex,
suggestedParams,
};
const txn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject(
transactionOptions
);
rsp.write(JSON.stringify({
status: true,
bytes_est: 256,
hash: Buffer.from(txn.bytesToSign()).toString("hex"),
tx_unsigned: Buffer.from(txn.toByte()).toString("hex")
}, null, 2))
//console.log(new Date().toISOString(), "txid = ", hash)
rsp.end()
}
catch (e) {
console.log("makeCreateassettxINFO", e);
badRequest(rsp);
}
}
async function signTransaction(rsp, queryParams, client) {
console.log(queryParams);
try {
let txn = algosdk.decodeUnsignedTransaction(Buffer.from(queryParams.tx_unsigned, "hex"));
console.log(Buffer.from(txn.toByte()).toString("hex"));
//let signedTxnS = txn.signTxn(skSenderBuffer);
//const signedTxnsdecode=algosdk.decodeSignedTransaction(signedTxnS);
let signedTxn = txn.attachSignature(queryParams.from, Buffer.from(queryParams.sig, "hex"))
console.log(algosdk.decodeSignedTransaction(signedTxn));
let txId = txn.txID().toString();
console.log(txId);
await client.sendRawTransaction(signedTxn).do();
rsp.write(JSON.stringify({
status: true,
txid: txId,
tx: queryParams.tx_unsigned
}, null, 2));
rsp.end();
}
catch (e) {
console.log("sendTransactionINFO", e);
badRequest(rsp);
}
}
function onClientRequest(clientReq, serverRsp) {
serverRsp.setHeader('Content-Type', 'text/plain')
console.log(new Date().toISOString(), '[REQUEST]', clientReq.socket.remoteAddress, clientReq.url)
var clientUrl = url.parse(clientReq.url, true)
const token = {
'X-API-Key': 'fXSl5YOGZV3SQBJvIDEys4L4BMtefd317eLkznhY'
}
// initialize an algod client
const client = new algosdk.Algodv2(
token,
"https://mainnet-algorand.api.purestake.io/ps2",
''
);
if (clientUrl.pathname == API_PATH_MAKETX) {
makeTransactiontx(serverRsp, clientUrl.query, client);
} else if (clientUrl.pathname == API_PATH_DELETEASSETMAKETX) {
makeDeleteassetmaketx(serverRsp, clientUrl.query, client);
} else if (clientUrl.pathname == API_PATH_CREATEASSETMAKETX) {
makeCreateassettx(serverRsp, clientUrl.query, client);
} else if (clientUrl.pathname == API_PATH_SENDASSETMAKETX) {
makeSendassetmaketx(serverRsp, clientUrl.query, client);
} else if (clientUrl.pathname == API_PATH_SENDTX) {
signTransaction(serverRsp, clientUrl.query, client);
} else {
badRequest(serverRsp)
}
}