Skip to content

Commit

Permalink
Merge pull request #4418 from connext/sdk-server-config
Browse files Browse the repository at this point in the history
Sdk server config
  • Loading branch information
just-a-node authored Jun 8, 2023
2 parents 6783f8b + 546667e commit 8b7ba3e
Show file tree
Hide file tree
Showing 16 changed files with 392 additions and 112 deletions.
7 changes: 6 additions & 1 deletion ops/testnet/prod/backend/config.tf
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,13 @@ locals {
providers = ["https://rpc.ankr.com/polygon_mumbai"]
}
}

# The following are defined in variables.tf and don't map to the
# definitions of environment and network in agent configs.
environment = var.stage
cache = {
network = var.environment

redis = {
enabled = true
expirationTime = 10
host = module.sdk_server_cache.redis_instance_address,
Expand Down
7 changes: 6 additions & 1 deletion ops/testnet/staging/backend/config.tf
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,13 @@ locals {
providers = ["https://rpc.ankr.com/polygon_mumbai"]
}
}

# The following are defined in variables.tf and don't map to the
# definitions of environment and network in agent configs.
environment = var.stage
cache = {
network = var.environment

redis = {
enabled = true
expirationTime = 10
host = module.sdk_server_cache.redis_instance_address,
Expand Down
12 changes: 12 additions & 0 deletions packages/examples/sdk-server/.nycrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "../../../.nycrc.json",
"exclude": [
"src/config.ts",
"src/context.ts",
"src/server.ts",
"src/index.ts",
"src/routes/**/*.ts",
"src/types/**/*.ts",
"test/**/*.ts"
]
}
2 changes: 1 addition & 1 deletion packages/examples/sdk-server/config.json.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"logLevel": "debug",
"environment": "production",
"network": "testnet",
"cache": {
"redis": {
"enabled": true,
"expirationTime": 10,
"host": "localhost",
Expand Down
8 changes: 6 additions & 2 deletions packages/examples/sdk-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,28 @@
"dev": "yarn build && yarn start",
"lint": "eslint ./src --ext .ts --env node",
"clean": "rimraf ./dist ./tsconfig.tsBuildInfo",
"purge": "yarn clean && rimraf ./node_modules"
"purge": "yarn clean && rimraf ./node_modules",
"test": "nyc ts-mocha --check-leaks --exit --timeout 120000 'test/**/*.spec.ts'"
},
"keywords": [],
"dependencies": {
"@connext/nxtp-txservice": "workspace:*",
"@connext/nxtp-utils": "workspace:*",
"@connext/sdk": "workspace:*",
"@fastify/redis": "^6.1.1",
"@fastify/redis": "6.1.1",
"@fastify/type-provider-typebox": "2.4.0",
"dotenv": "16.0.3",
"ethers": "5.7.2",
"fastify": "4.13.0",
"pino": "8.10.0"
},
"devDependencies": {
"@types/node": "18.13.0",
"@types/pino": "7.0.5",
"nyc": "15.1.0",
"pino-pretty": "9.2.0",
"rimraf": "3.0.2",
"ts-mocha": "10.0.0",
"typescript": "4.9.5"
}
}
122 changes: 122 additions & 0 deletions packages/examples/sdk-server/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import * as fs from "fs";

import { Type, Static } from "@sinclair/typebox";
import { config as dotenvConfig } from "dotenv";
import { ajv } from "@connext/nxtp-utils";

const CACHE_EXPIRATION_SECS = 300;

dotenvConfig();

export const TChainConfig = Type.Object({
providers: Type.Array(Type.String()),
});

export const TServerConfig = Type.Object({
http: Type.Object({
port: Type.Integer({ minimum: 1, maximum: 65535 }),
host: Type.String(),
}),
});

export const TRedisConfig = Type.Object({
enabled: Type.Optional(Type.Boolean()),
expirationTime: Type.Optional(Type.Integer()),
host: Type.Optional(Type.String()),
port: Type.Optional(Type.Integer({ minimum: 1, maximum: 65535 })),
});

export const SdkServerConfigSchema = Type.Object({
chains: Type.Record(Type.String(), TChainConfig),
environment: Type.Union([Type.Literal("staging"), Type.Literal("production")]),
network: Type.Union([Type.Literal("testnet"), Type.Literal("mainnet"), Type.Literal("local")]),
logLevel: Type.Union([
Type.Literal("fatal"),
Type.Literal("error"),
Type.Literal("warn"),
Type.Literal("info"),
Type.Literal("debug"),
Type.Literal("trace"),
Type.Literal("silent"),
]),
mnemonic: Type.Optional(Type.String()),
redis: TRedisConfig,
server: TServerConfig,
});
export type SdkServerConfig = Static<typeof SdkServerConfigSchema>;

export const getEnvConfig = (): SdkServerConfig => {
let configJson: Record<string, any> = {};
let configFile: any = {};

try {
configJson = JSON.parse(process.env.SDK_SERVER_CONFIG || "");
} catch (e: unknown) {
console.info("No SDK_SERVER_CONFIG exists, using config file and individual env vars");
}
try {
let json: string;

const path = process.env.SDK_SERVER_CONFIG_FILE ?? "config.json";
if (fs.existsSync(path)) {
json = fs.readFileSync(path, { encoding: "utf-8" });
configFile = JSON.parse(json);
}
} catch (e: unknown) {
console.error("Error reading config file!");
process.exit(1);
}

const _sdkServerConfig: SdkServerConfig = {
chains: process.env.SDK_SERVER_CHAIN_CONFIG
? JSON.parse(process.env.SDK_SERVER_CHAIN_CONFIG)
: configJson.chains
? configJson.chains
: configFile.chains,
environment: process.env.SDK_SERVER_ENVIRONMENT || configJson.environment || configFile.environment || "production",
network: process.env.SDK_SERVER_NETWORK || configJson.network || configFile.network || "mainnet",
logLevel: process.env.SDK_SERVER_LOG_LEVEL || configJson.logLevel || configFile.logLevel || "info",
mnemonic: process.env.SDK_SERVER_MNEMONIC || configJson.mnemonic || configFile.mnemonic,
redis: {
enabled: process.env.SDK_SERVER_REDIS_ENABLED || configJson.redis?.enabled || configFile.redis?.enabled || false,
expirationTime:
process.env.SDK_SERVER_REDIS_EXPIRATION_TIME ||
configJson.redis?.expirationTime ||
configFile.redis?.expirationTime ||
CACHE_EXPIRATION_SECS,
host: process.env.SDK_SERVER_REDIS_HOST || configJson.redis?.host || configFile.redis?.host || "localhost",
port: process.env.SDK_SERVER_REDIS_PORT || configJson.redis?.port || configFile.redis?.port || 6379,
},
server: {
http: {
port:
process.env.SDK_SERVER_HTTP_SERVER_PORT ||
configJson.server?.http?.port ||
configFile.server?.http?.port ||
8080,
host:
process.env.SDK_SERVER_HTTP_SERVER_HOST ||
configJson.server?.http?.host ||
configFile.server?.http?.host ||
"localhost",
},
},
};

const validate = ajv.compile(SdkServerConfigSchema);
const valid = validate(_sdkServerConfig);
if (!valid) {
throw new Error(validate.errors?.map((err: unknown) => JSON.stringify(err, null, 2)).join(","));
}

return _sdkServerConfig;
};

export let sdkServerConfig: SdkServerConfig | undefined;

export const getConfig = async (): Promise<SdkServerConfig> => {
if (!sdkServerConfig) {
sdkServerConfig = getEnvConfig();
}
return sdkServerConfig;
};
8 changes: 8 additions & 0 deletions packages/examples/sdk-server/src/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Logger } from "@connext/nxtp-utils";

import { SdkServerConfig } from "./config";

export type SdkServerContext = {
logger: Logger;
config: SdkServerConfig;
};
105 changes: 4 additions & 101 deletions packages/examples/sdk-server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,103 +1,6 @@
import * as fs from "fs";
import { SdkServerConfig } from "./config";
import { makeSdkServer } from "./server";

import fastify, { FastifyInstance } from "fastify";
import { fastifyRedis } from "@fastify/redis";
import { ethers, providers } from "ethers";
import { SdkConfig, create } from "@connext/sdk";
import { getBestProvider } from "@connext/nxtp-utils";
export { makeSdkServer, SdkServerConfig };

import { poolRoutes } from "./pool";
import { utilsRoutes } from "./utils";
import { routerRoutes } from "./router";
import { baseRoutes } from "./base";

export const sdkServer = async (): Promise<FastifyInstance> => {
const server = fastify();

// Initialize SDK
let configJson: Record<string, any> = {};

try {
configJson = JSON.parse(process.env.NXTP_CONFIG || "");
} catch (e: unknown) {
console.info("No NXTP_CONFIG exists, using config file and individual env vars");
}

if (Object.keys(configJson).length === 0) {
try {
const path = process.env.NXTP_CONFIG_FILE ?? "config.json";
if (fs.existsSync(path)) {
const json = fs.readFileSync(path, { encoding: "utf-8" });
configJson = JSON.parse(json);
console.info("Using config file");
}
} catch (e: unknown) {
console.error("Error reading config file!");
process.exit(1);
}
}

const signer = ethers.Wallet.createRandom();
const signerAddress = await signer.getAddress();

const configuredProviders: Record<string, providers.JsonRpcProvider> = {};
const chains = configJson.chains;
for (const key in chains) {
const chain = chains[key];
const url = await getBestProvider(chain.providers as string[]);
const provider = new ethers.providers.JsonRpcProvider(url);
configuredProviders[key] = provider;
}

const nxtpConfig: SdkConfig = {
chains: chains,
logLevel: configJson.logLevel || "info",
signerAddress: signerAddress,
network: configJson.network,
environment: configJson.environment,
cartographerUrl: configJson.cartographerUrl,
};

const { sdkBase, sdkPool, sdkUtils, sdkRouter } = await create(nxtpConfig);

// Register Redis plugin if enabled
if (configJson.cache?.enabled) {
server.register(fastifyRedis, {
host: configJson.cache?.host || "localhost",
port: configJson.cache?.port || 6379,
});
}

// Register routes
server.get("/ping", async (_, reply) => {
return reply.status(200).send("pong\n");
});

server.post<{
Params: { domainId: string };
Body: providers.TransactionRequest;
}>("/sendTransaction/:domainId", async (request, reply) => {
const feeData = await configuredProviders[request.params.domainId].getFeeData();
// request.body.gasLimit = ethers.BigNumber.from("20000");
request.body.gasPrice = feeData.gasPrice!;
const txRes = await signer.connect(configuredProviders[request.params.domainId]).sendTransaction(request.body);
const txRec = await txRes.wait();
reply.status(200).send(txRec);
});

server.register(baseRoutes, { sdkBaseInstance: sdkBase, cacheConfig: configJson.cache });
server.register(poolRoutes, sdkPool);
server.register(utilsRoutes, sdkUtils);
server.register(routerRoutes, sdkRouter);

server.listen({ port: 8080 }, (err, address) => {
if (err) {
console.error(err);
process.exit(1);
}
console.log(`Server listening at ${address}`);
});
return server;
};

sdkServer();
makeSdkServer();
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
SdkCalculateAmountReceivedParamsSchema,
} from "@connext/sdk";

import { approveIfNeededSchema, getCanonicalTokenIdSchema, calculateCanonicalKeySchema } from "./types/api";
import { approveIfNeededSchema, getCanonicalTokenIdSchema, calculateCanonicalKeySchema } from "../types/api";

interface BaseRoutesOptions {
sdkBaseInstance: SdkBase;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
getTokenSwapEventsSchema,
getHourlySwapVolumeSchema,
getDailySwapVolumeSchema,
} from "./types/api";
} from "../types/api";

export const poolRoutes = async (server: FastifyInstance, sdkPoolInstance: SdkPool): Promise<any> => {
const s = server.withTypeProvider<TypeBoxTypeProvider>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { SdkRouter } from "@connext/sdk";
import { FastifyInstance } from "fastify";
import { TypeBoxTypeProvider } from "@fastify/type-provider-typebox";

import { addLiquidityForRouterSchema, removeRouterLiquiditySchema, removeRouterLiquidityForSchema } from "./types/api";
import { addLiquidityForRouterSchema, removeRouterLiquiditySchema, removeRouterLiquidityForSchema } from "../types/api";

export const routerRoutes = async (server: FastifyInstance, sdkRouterInstance: SdkRouter): Promise<any> => {
const s = server.withTypeProvider<TypeBoxTypeProvider>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { SdkUtils } from "@connext/sdk";
import { FastifyInstance } from "fastify";
import { TypeBoxTypeProvider } from "@fastify/type-provider-typebox";

import { getTransfersSchema, getRoutersDataSchema, checkRouterLiquiditySchema } from "./types/api";
import { getTransfersSchema, getRoutersDataSchema, checkRouterLiquiditySchema } from "../types/api";

export const utilsRoutes = async (server: FastifyInstance, sdkUtilsInstance: SdkUtils): Promise<any> => {
const s = server.withTypeProvider<TypeBoxTypeProvider>();
Expand Down
Loading

0 comments on commit 8b7ba3e

Please sign in to comment.