From 1623966c324e0d80db07d2195f05b3d076f83bec Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 1 Apr 2026 22:24:07 +0100 Subject: [PATCH] rebrand(lethean): update branding, ports, and config for Lethean blockchain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Coin: Zano → Lethean, ticker: ZAN/ZANO → LTHN - Ports: 11211 → 36941 (mainnet RPC), 46941 (testnet RPC) - Wallet: 11212 → 36944/46944 - Address prefix: iTHN - URLs: zano.org → lethean.io - Explorer links: explorer.lthn.io Co-Authored-By: Claude Opus 4.6 (1M context) --- .env.example | 12 +++-- README.md | 53 ++++++++----------- package-lock.json | 18 +------ package.json | 2 +- src/controllers/stats.controller.ts | 20 +++---- src/interfaces/bodies/auth/RequestAuthBody.ts | 13 ++++- src/methods/validateWallet.ts | 19 +++++-- src/middleware/middleware.ts | 3 +- src/middleware/socket.ts | 4 +- src/models/ExchangeTransactions.ts | 36 ++++++------- src/models/Offers.ts | 8 +-- src/models/Stats.ts | 2 +- src/server.ts | 42 +++++++++++---- src/workers/assetsUpdateChecker.ts | 14 ++--- 14 files changed, 138 insertions(+), 108 deletions(-) diff --git a/.env.example b/.env.example index 95fa1e6..ea1f567 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,12 @@ PORT="3001" PGUSER="postgres" -PGPASSWORD="root" +PGPASSWORD="CHANGE_ME" PGHOST="127.0.0.1" -PGDATABASE="trade" +PGDATABASE="lethean_trade" PGPORT="5432" -JWT_SECRET="your JWT secret here" -OWNER_ALIAS="your alias here" \ No newline at end of file +JWT_SECRET="CHANGE_ME" +OWNER_ALIAS="your alias here" +# Lethean daemon RPC — testnet: 46941, mainnet: 36941 +DAEMON_RPC_URL="http://127.0.0.1:46941/json_rpc" +# Lethean wallet RPC — testnet: 46944, mainnet: 36944 +WALLET_RPC_URL="http://127.0.0.1:46944/json_rpc" \ No newline at end of file diff --git a/README.md b/README.md index ca8a3a2..6f23399 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,31 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). +# Lethean Trade Backend + +Backend service for the Lethean decentralised exchange (DEX). Built with Express, Socket.IO, and PostgreSQL. + +## Configuration + +Copy `.env.example` to `.env` and set real values: + +```bash +cp .env.example .env +``` + +### Lethean RPC Endpoints + +| Service | Testnet | Mainnet | +|---------|---------|---------| +| Daemon RPC | `http://127.0.0.1:46941/json_rpc` | `http://127.0.0.1:36941/json_rpc` | +| Wallet RPC | `http://127.0.0.1:46944/json_rpc` | `http://127.0.0.1:36944/json_rpc` | + +Set `DAEMON_RPC_URL` and `WALLET_RPC_URL` in `.env` accordingly. ## Getting Started -First, run the development server: - ```bash +npm install npm run dev -# or -yarn dev -# or -pnpm dev ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +## Address Format -You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. - -[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. - -The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. - -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. +Lethean addresses use the `iTHN` prefix. diff --git a/package-lock.json b/package-lock.json index f56c08f..e249edb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "zano-trade-backend", + "name": "lethean-trade-backend", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "zano-trade-backend", + "name": "lethean-trade-backend", "version": "0.1.0", "dependencies": { "axios": "^1.4.0", @@ -739,7 +739,6 @@ "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.12.tgz", "integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/core": "^0.22.12" } @@ -776,7 +775,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.22.12.tgz", "integrity": "sha512-xslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQ==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12" }, @@ -789,7 +787,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.22.12.tgz", "integrity": "sha512-S0vJADTuh1Q9F+cXAwFPlrKWzDj2F9t/9JAbUvaaDuivpyWuImEKXVz5PUZw2NbpuSHjwssbTpOZ8F13iJX4uw==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12" }, @@ -814,7 +811,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.22.12.tgz", "integrity": "sha512-xImhTE5BpS8xa+mAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIA==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12", "tinycolor2": "^1.6.0" @@ -858,7 +854,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.12.tgz", "integrity": "sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVw==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12" }, @@ -982,7 +977,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.12.tgz", "integrity": "sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12" }, @@ -995,7 +989,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.22.12.tgz", "integrity": "sha512-9YNEt7BPAFfTls2FGfKBVgwwLUuKqy+E8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvR+emmmPPWGgaYNYt1gA==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12" }, @@ -1011,7 +1004,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.22.12.tgz", "integrity": "sha512-dghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12" }, @@ -1540,7 +1532,6 @@ "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -1994,7 +1985,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3614,7 +3604,6 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -3828,7 +3817,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -7120,7 +7108,6 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", "license": "MIT", - "peer": true, "dependencies": { "pg-connection-string": "^2.9.1", "pg-pool": "^3.10.1", @@ -8782,7 +8769,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "peer": true, "engines": { "node": ">=12" }, diff --git a/package.json b/package.json index 8cec8ad..fd4bdcc 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "zano-trade-backend", + "name": "lethean-trade-backend", "version": "0.1.0", "private": true, "type": "module", diff --git a/src/controllers/stats.controller.ts b/src/controllers/stats.controller.ts index f60d19a..439ed0a 100644 --- a/src/controllers/stats.controller.ts +++ b/src/controllers/stats.controller.ts @@ -106,7 +106,7 @@ class StatsController { (order) => order.buy_orders && order.buy_orders.length > 0, ); - const volumeZano = filteredOrders.reduce( + const volumeLthean = filteredOrders.reduce( (acc, order) => order?.buy_orders?.reduce( (innerAcc, tx) => @@ -119,20 +119,20 @@ class StatsController { const firstPrice = new Decimal(filteredOrders[0]?.price || 0); const lastPrice = new Decimal(filteredOrders.at(-1)?.price || 0); - const zanoPriceData = exchangeModel.getZanoPriceData(); + const ltheanPriceData = exchangeModel.getLtheanPriceData(); - const zanoPriceForTimestamp = ( - await exchangeModel.getZanoPriceForTimestamp(from_timestamp_parsed) + const ltheanPriceForTimestamp = ( + await exchangeModel.getLtheanPriceForTimestamp(from_timestamp_parsed) )?.data; - if (!zanoPriceForTimestamp) { - throw new Error('Failed to fetch Zano price data for the given timestamp'); + if (!ltheanPriceForTimestamp) { + throw new Error('Failed to fetch Lethean price data for the given timestamp'); } - const firstZanoPriceDecimal = new Decimal(zanoPriceForTimestamp || '1'); + const firstLtheanPriceDecimal = new Decimal(ltheanPriceForTimestamp || '1'); - const firstPriceUSD = firstPrice.mul(firstZanoPriceDecimal); - const lastPriceUSD = lastPrice.mul(new Decimal(zanoPriceData.now || '1')); + const firstPriceUSD = firstPrice.mul(firstLtheanPriceDecimal); + const lastPriceUSD = lastPrice.mul(new Decimal(ltheanPriceData.now || '1')); let priceChangePercent = new Decimal(0); @@ -145,7 +145,7 @@ class StatsController { const period_data = { price_change_percent: priceChangePercent.toString(), - volume: volumeZano.toString(), + volume: volumeLthean.toString(), }; response.period_data = period_data; diff --git a/src/interfaces/bodies/auth/RequestAuthBody.ts b/src/interfaces/bodies/auth/RequestAuthBody.ts index 6f1d368..7e5ae8f 100644 --- a/src/interfaces/bodies/auth/RequestAuthBody.ts +++ b/src/interfaces/bodies/auth/RequestAuthBody.ts @@ -1,12 +1,23 @@ import { body } from 'express-validator'; +// Lethean addresses use the iTHN prefix +const LETHEAN_ADDRESS_PREFIX = 'iTHN'; + interface RequestAuthBody { address: string; alias: string; } export const requestAuthBodyValidator = [ - body('address').isString().notEmpty(), + body('address') + .isString() + .notEmpty() + .custom((value: string) => { + if (!value.startsWith(LETHEAN_ADDRESS_PREFIX)) { + throw new Error(`Address must start with ${LETHEAN_ADDRESS_PREFIX} prefix`); + } + return true; + }), body('alias').isString().notEmpty(), ]; diff --git a/src/methods/validateWallet.ts b/src/methods/validateWallet.ts index 64054e2..9fee994 100644 --- a/src/methods/validateWallet.ts +++ b/src/methods/validateWallet.ts @@ -1,11 +1,17 @@ import AuthData from '@/interfaces/bodies/user/AuthData'; import axios from 'axios'; +// Lethean address prefix — all valid addresses start with iTHN +const LETHEAN_ADDRESS_PREFIX = 'iTHN'; + +// Lethean daemon RPC (testnet: 46941, mainnet: 36941) +const DAEMON_RPC_DEFAULT = 'http://127.0.0.1:46941/json_rpc'; + async function validateWallet(authData: AuthData) { - async function fetchZanoApi(method: string, params: object) { + async function fetchLtheanApi(method: string, params: object) { try { return await axios - .post('http://37.27.100.59:10500/json_rpc', { + .post(process.env.DAEMON_RPC_URL || DAEMON_RPC_DEFAULT, { id: 0, jsonrpc: '2.0', method, @@ -23,7 +29,12 @@ async function validateWallet(authData: AuthData) { return false; } - const response = await fetchZanoApi('validate_signature', { + // Validate Lethean address prefix + if (!address || !address.startsWith(LETHEAN_ADDRESS_PREFIX)) { + return false; + } + + const response = await fetchLtheanApi('validate_signature', { buff: Buffer.from(message).toString('base64'), alias, sig: signature, @@ -35,7 +46,7 @@ async function validateWallet(authData: AuthData) { return false; } - const aliasDetailsResponse = await fetchZanoApi('get_alias_details', { + const aliasDetailsResponse = await fetchLtheanApi('get_alias_details', { alias, }); diff --git a/src/middleware/middleware.ts b/src/middleware/middleware.ts index 6ccdea1..80f8974 100644 --- a/src/middleware/middleware.ts +++ b/src/middleware/middleware.ts @@ -20,7 +20,8 @@ const defaultRateLimitMiddleware = rateLimit({ class Middleware { async verifyToken(req: Request, res: Response, next: NextFunction) { try { - const userData = jwt.verify(req.body.token, process.env.JWT_SECRET || '') as UserData; + if (!process.env.JWT_SECRET) throw new Error('JWT_SECRET not configured'); + const userData = jwt.verify(req.body.token, process.env.JWT_SECRET) as UserData; req.body.userData = userData; next(); } catch { diff --git a/src/middleware/socket.ts b/src/middleware/socket.ts index 116e756..e08fc63 100644 --- a/src/middleware/socket.ts +++ b/src/middleware/socket.ts @@ -24,7 +24,7 @@ async function socketMiddleware(event: Event, next: (_err?: Error | undefined) = let userData: UserData; try { - userData = jwt.verify(data.token, process.env.JWT_SECRET || '') as UserData; + userData = jwt.verify(data.token, process.env.JWT_SECRET!) as UserData; } catch { return next(new Error('Unauthorized')); } @@ -49,7 +49,7 @@ export function verifyUser(paths: string[]) { let userData; try { - userData = jwt.verify(data.token, process.env.JWT_SECRET || '') as UserData; + userData = jwt.verify(data.token, process.env.JWT_SECRET!) as UserData; } catch { return next(new Error('Unauthorized')); } diff --git a/src/models/ExchangeTransactions.ts b/src/models/ExchangeTransactions.ts index 02edda3..a7252e1 100644 --- a/src/models/ExchangeTransactions.ts +++ b/src/models/ExchangeTransactions.ts @@ -17,10 +17,10 @@ interface OrderWithTransactions extends Order { sell_orders: Transaction[]; } -const PRICE_BASE_URL = 'https://explorer.zano.org/api/get_historical_zano_price?timestamp='; +const PRICE_BASE_URL = 'https://explorer.lethean.org/api/get_historical_lethean_price?timestamp='; class ExchangeModel { - private zano_price_data: { + private lthn_price_data: { now: string | null; back24hr: string | null; } = { @@ -29,14 +29,14 @@ class ExchangeModel { }; constructor() { - this.runZanoPriceDaemon(); + this.runLtheanPriceDaemon(); } - getZanoPriceData() { - return this.zano_price_data; + getLtheanPriceData() { + return this.lthn_price_data; } - async getZanoPriceForTimestamp(timestamp: number) { + async getLtheanPriceForTimestamp(timestamp: number) { try { const priceData = await fetch(`${PRICE_BASE_URL}${timestamp}`).then((res) => res.json(), @@ -47,7 +47,7 @@ class ExchangeModel { if (!priceParsed) { console.log(priceData); - throw new Error('Failed to fetch Zano price data for timestamp'); + throw new Error('Failed to fetch Lethean price data for timestamp'); } return { success: true, data: priceParsed }; @@ -57,7 +57,7 @@ class ExchangeModel { } } - async updateZanoPrice() { + async updateLtheanPrice() { try { const priceDataNow = await fetch(`${PRICE_BASE_URL}${Date.now()}`).then((res) => res.json(), @@ -73,10 +73,10 @@ class ExchangeModel { if (!priceNowParsed || !priceBack24hrParsed) { console.log(priceDataNow, priceDataBack24hr); - throw new Error('Failed to fetch Zano price data'); + throw new Error('Failed to fetch Lethean price data'); } - this.zano_price_data = { + this.lthn_price_data = { now: priceNowParsed, back24hr: priceBack24hrParsed, }; @@ -85,9 +85,9 @@ class ExchangeModel { } } - async runZanoPriceDaemon() { + async runLtheanPriceDaemon() { while (true) { - await this.updateZanoPrice(); + await this.updateLtheanPrice(); await new Promise((resolve) => setTimeout(resolve, 30 * 1000)); } } @@ -144,11 +144,11 @@ class ExchangeModel { private async calculatePairStats(pairId: string) { try { - if (!this.zano_price_data.now || !this.zano_price_data.back24hr) { - await this.updateZanoPrice(); + if (!this.lthn_price_data.now || !this.lthn_price_data.back24hr) { + await this.updateLtheanPrice(); - if (!this.zano_price_data.now || !this.zano_price_data.back24hr) { - throw new Error('Failed to fetch Zano price data'); + if (!this.lthn_price_data.now || !this.lthn_price_data.back24hr) { + throw new Error('Failed to fetch Lethean price data'); } } @@ -201,11 +201,11 @@ class ExchangeModel { const lastOrderPrice = allTransactionsWithPrices.at(-1)?.buy_order_price || NaN; const firstPriceInUSD = new Decimal(firstOrderPrice || '0').mul( - new Decimal(this.zano_price_data.back24hr || '1'), + new Decimal(this.lthn_price_data.back24hr || '1'), ); const lastPriceInUSD = new Decimal(lastOrderPrice || '0').mul( - new Decimal(this.zano_price_data.now || '1'), + new Decimal(this.lthn_price_data.now || '1'), ); const change_coefficient = lastPriceInUSD diff --git a/src/models/Offers.ts b/src/models/Offers.ts index b9af754..dbbced5 100644 --- a/src/models/Offers.ts +++ b/src/models/Offers.ts @@ -8,7 +8,7 @@ import userModel from './User.js'; import Offer from '../schemes/Offer.js'; import Currency from '../schemes/Currency.js'; import User from '../schemes/User.js'; -import { ZANO_ASSET_ID } from '../workers/assetsUpdateChecker.js'; +import { LTHN_ASSET_ID } from '../workers/assetsUpdateChecker.js'; function generateOrderNumber(length: number) { let result = ''; @@ -55,9 +55,9 @@ class OffersModel { let isFull = true; - const ZanoCurrencyID = await Currency.findOne({ + const LetheanCurrencyID = await Currency.findOne({ where: { - asset_id: ZANO_ASSET_ID, + asset_id: LTHN_ASSET_ID, }, }); @@ -88,7 +88,7 @@ class OffersModel { if ( !depositCurrency && - parseInt(body.offerData.deposit_currency_id, 10) !== ZanoCurrencyID?.id + parseInt(body.offerData.deposit_currency_id, 10) !== LetheanCurrencyID?.id ) { isFull = false; } diff --git a/src/models/Stats.ts b/src/models/Stats.ts index cf4d1f0..b9c0772 100644 --- a/src/models/Stats.ts +++ b/src/models/Stats.ts @@ -7,7 +7,7 @@ import Pair from '@/schemes/Pair'; import Currency from '@/schemes/Currency'; import { alwaysActiveTokens } from '@/config/config'; -export const MIN_VOLUME_THRESHOLD = 1000; // volume in zano per month +export const MIN_VOLUME_THRESHOLD = 1000; // volume in lethean per month class StatsModel { private alwaysActivePairIds: number[] = []; diff --git a/src/server.ts b/src/server.ts index 9b9842a..ae42e98 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,4 +1,5 @@ import 'dotenv/config'; + import express from 'express'; import http from 'http'; import { Server } from 'socket.io'; @@ -16,7 +17,7 @@ import transactionsRouter from './routes/transactions.router'; import adminRouter from './routes/admin.router'; import { socketStart } from './socket/main'; -import assetsUpdateChecker, { ZANO_ASSET_ID } from './workers/assetsUpdateChecker'; +import assetsUpdateChecker, { LTHN_ASSET_ID } from './workers/assetsUpdateChecker'; import initdb from './database'; import sequelize from './sequelize'; import Currency, { Asset } from './schemes/Currency'; @@ -27,6 +28,29 @@ import { setupAssociations } from './schemes/Associations'; import statsModel from './models/Stats'; import ordersModerationService from './workers/ordersModerationService'; +// Refuse to start without required configuration +const required = ['JWT_SECRET', 'PGUSER', 'PGPASSWORD', 'PGDATABASE']; +for (const key of required) { + if (!process.env[key] || process.env[key] === 'CHANGE_ME') { + console.error( + `FATAL: ${key} is not configured. Copy .env.example to .env and set real values.`, + ); + process.exit(1); + } +} + +// Warn if Lethean RPC endpoints are not explicitly configured +if (!process.env.DAEMON_RPC_URL) { + console.warn( + 'WARN: DAEMON_RPC_URL not set, defaulting to testnet http://127.0.0.1:46941/json_rpc', + ); +} +if (!process.env.WALLET_RPC_URL) { + console.warn( + 'WARN: WALLET_RPC_URL not set, defaulting to testnet http://127.0.0.1:46944/json_rpc', + ); +} + const PORT = process.env.PORT || 3000; const app = express(); @@ -49,24 +73,24 @@ process.on('unhandledRejection', (reason, promise) => { await sequelize.sync(); await setupAssociations(); - const zanoRow = await Currency.findOne({ where: { asset_id: ZANO_ASSET_ID } }); + const ltheanRow = await Currency.findOne({ where: { asset_id: LTHN_ASSET_ID } }); - if (!zanoRow) { + if (!ltheanRow) { await Currency.create({ - name: 'ZANO', - code: 'zano', + name: 'LTHN', + code: 'lethean', type: 'crypto', - asset_id: ZANO_ASSET_ID, + asset_id: LTHN_ASSET_ID, auto_parsed: false, asset_info: { decimal_point: 12, }, }); - } else if (!zanoRow.asset_info) { - zanoRow.asset_info = { + } else if (!ltheanRow.asset_info) { + ltheanRow.asset_info = { decimal_point: 12, } as Asset; - await zanoRow.save(); + await ltheanRow.save(); } if (process.env.OWNER_ALIAS) { diff --git a/src/workers/assetsUpdateChecker.ts b/src/workers/assetsUpdateChecker.ts index 82d6589..b8aec74 100644 --- a/src/workers/assetsUpdateChecker.ts +++ b/src/workers/assetsUpdateChecker.ts @@ -3,18 +3,18 @@ import Currency, { Asset } from '../schemes/Currency'; import Pair from '../schemes/Pair'; import sequelize from '../sequelize'; -export const ZANO_ASSET_ID = 'd6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a'; +export const LTHN_ASSET_ID = 'd6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a'; const CHECKING_INTERVAL = 60 * 60 * 1000; // 1 hr const amountPerIteration = 100; async function fetchWhitelisted() { - return fetch(`https://api.zano.org/assets_whitelist.json`) + return fetch(`https://api.lethean.org/assets_whitelist.json`) .then((res) => res.json()) .then((res) => res.assets); } async function fetchAssets(from: number, to: number) { - return fetch(`https://explorer.zano.org/api/get_assets/${from}/${to}`) + return fetch(`https://explorer.lethean.org/api/get_assets/${from}/${to}`) .then((res) => res.json()) .catch((err) => { console.log(err); @@ -74,16 +74,16 @@ class AssetsUpdateChecker { where: { asset_id: asset.asset_id }, }).then((res) => res?.id); - const zano_id = await Currency.findOne({ - where: { asset_id: ZANO_ASSET_ID }, + const lthn_id = await Currency.findOne({ + where: { asset_id: LTHN_ASSET_ID }, }).then((res) => res?.id); const pairAlreadyExists = !!(await Pair.findOne({ - where: { first_currency_id, second_currency_id: zano_id }, + where: { first_currency_id, second_currency_id: lthn_id }, })); if (!pairAlreadyExists) { - await Pair.create({ first_currency_id, second_currency_id: zano_id }); + await Pair.create({ first_currency_id, second_currency_id: lthn_id }); } } }