Skip to content
main.ts 3.85 KiB
Newer Older
Maciej Hirsz's avatar
Maciej Hirsz committed
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
Maciej Hirsz's avatar
Maciej Hirsz committed
// This file is part of Substrate API Sidecar.
Maciej Hirsz's avatar
Maciej Hirsz committed
//
Maciej Hirsz's avatar
Maciej Hirsz committed
// Substrate API Sidecar is free software: you can redistribute it and/or modify
Maciej Hirsz's avatar
Maciej Hirsz committed
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

Maciej Hirsz's avatar
Maciej Hirsz committed
import * as express from 'express';
import * as bodyParser from 'body-parser';
Maciej Hirsz's avatar
Maciej Hirsz committed
import { Request, Response } from 'express';
import { ApiPromise } from '@polkadot/api';
import { BlockHash } from '@polkadot/types/interfaces/chain';
Maciej Hirsz's avatar
Maciej Hirsz committed
import { HttpProvider, WsProvider } from '@polkadot/rpc-provider';
Maciej Hirsz's avatar
Maciej Hirsz committed
import ApiHandler from './ApiHandler';
Maciej Hirsz's avatar
Maciej Hirsz committed

Maciej Hirsz's avatar
Maciej Hirsz committed
const HOST = process.env.BIND_HOST || '127.0.0.1';
Maciej Hirsz's avatar
Maciej Hirsz committed
const PORT = Number(process.env.BIND_PORT) || 8080;
Maciej Hirsz's avatar
Maciej Hirsz committed
const WS_URL = process.env.NODE_WS_URL || 'ws://127.0.0.1:9944';
Maciej Hirsz's avatar
Maciej Hirsz committed

Maciej Hirsz's avatar
Maciej Hirsz committed
type Params = { [key: string]: string };

Maciej Hirsz's avatar
Maciej Hirsz committed
interface Error {
	error: string;
}

function parseNumber(n: string): [Error | null, number] {
	const num = Number(n);

	if (!Number.isInteger(num)) {
		return [{ error: 'Invalid block number' }, 0];
	}

	return [null, num];
}

Maciej Hirsz's avatar
Maciej Hirsz committed
async function main() {
Maciej Hirsz's avatar
Maciej Hirsz committed
	const api = await ApiPromise.create({ provider: new WsProvider(WS_URL) });
Maciej Hirsz's avatar
Maciej Hirsz committed
	const handler = new ApiHandler(api);
Maciej Hirsz's avatar
Maciej Hirsz committed
	const app = express();

	app.use(bodyParser.json());

Maciej Hirsz's avatar
Maciej Hirsz committed
	function get(path: string, cb: (params: Params) => Promise<any>) {
		app.get(path, async (req, res) => {
			try {
				res.send(await cb(req.params));
			} catch(err) {
				console.error('Internal Error:', err);
Maciej Hirsz's avatar
Maciej Hirsz committed

Maciej Hirsz's avatar
Maciej Hirsz committed
				res.status(500).send({ error: 'Interal Error' });
			}
Maciej Hirsz's avatar
Maciej Hirsz committed
		});
	}


	function post(path: string, cb: (params: Params, body: any) => Promise<any>) {
		app.post(path, async (req, res) => {
			try {
				res.send(await cb(req.params, req.body));
			} catch(err) {
				console.error('Internal Error:', err);

				res.status(500).send({ error: 'Interal Error' });
			}
		});
	}

Maciej Hirsz's avatar
Maciej Hirsz committed
	get('/', async (req) => 'Sidecar is running, go to /block to get latest finalized block');
Maciej Hirsz's avatar
Maciej Hirsz committed

Maciej Hirsz's avatar
Maciej Hirsz committed
	get('/block/:number', async (params) => {
Maciej Hirsz's avatar
Maciej Hirsz committed
		const [error, number] = parseNumber(params.number);

		if (error) {
			return error;
		}

Maciej Hirsz's avatar
Maciej Hirsz committed
		const hash = await api.rpc.chain.getBlockHash(number);

Maciej Hirsz's avatar
Maciej Hirsz committed
		return await handler.fetchBlock(hash);
Maciej Hirsz's avatar
Maciej Hirsz committed
	});
Maciej Hirsz's avatar
Maciej Hirsz committed

	get('/block/', async () => {
Maciej Hirsz's avatar
Maciej Hirsz committed
		const hash = await api.rpc.chain.getFinalizedHead();

Maciej Hirsz's avatar
Maciej Hirsz committed
		return await handler.fetchBlock(hash);
Maciej Hirsz's avatar
Maciej Hirsz committed
	});
Maciej Hirsz's avatar
Maciej Hirsz committed

	get('/balance/:address', async (params) => {
		const { address } = params;
Maciej Hirsz's avatar
Maciej Hirsz committed
		const hash = await api.rpc.chain.getFinalizedHead();

Maciej Hirsz's avatar
Maciej Hirsz committed
		return await handler.fetchBalance(hash, address);
Maciej Hirsz's avatar
Maciej Hirsz committed
	});
Maciej Hirsz's avatar
Maciej Hirsz committed

	get('/balance/:address/:number', async (params) => {
		const { address } = params;
Maciej Hirsz's avatar
Maciej Hirsz committed
		const [error, number] = parseNumber(params.number);

		if (error) {
			return error;
		}

Maciej Hirsz's avatar
Maciej Hirsz committed
		const hash = await api.rpc.chain.getBlockHash(number);

Maciej Hirsz's avatar
Maciej Hirsz committed
		return await handler.fetchBalance(hash, address);
Maciej Hirsz's avatar
Maciej Hirsz committed
	});
Maciej Hirsz's avatar
Maciej Hirsz committed

Maciej Hirsz's avatar
Maciej Hirsz committed
	get('/metadata/', async () => {
		const hash = await api.rpc.chain.getFinalizedHead();

		return await handler.fetchMetadata(hash);
	});

	get('/metadata/:number', async (params) => {
		const [error, number] = parseNumber(params.number);

		if (error) {
			return error;
		}

		const hash = await api.rpc.chain.getBlockHash(number);

		return await handler.fetchMetadata(hash);
	});

	post('/tx/', async (_, body) => {
		if (body && typeof body.tx !== 'string') {
			return {
				error: "Missing field `tx` on request body.",
			};
		}

		return await handler.submitTx(body.tx);
	});

Maciej Hirsz's avatar
Maciej Hirsz committed
	app.listen(PORT, HOST, () => console.log(`Running on http://${HOST}:${PORT}/`))
Maciej Hirsz's avatar
Maciej Hirsz committed
}

main();