Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sdk server config #4418

Merged
merged 12 commits into from
Jun 8, 2023
3 changes: 2 additions & 1 deletion ops/testnet/prod/backend/config.tf
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ locals {
}
}
environment = var.stage
cache = {
network = var.environment
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kinda weird that stage == environment and environment == network

doesn't really seem consistent with the other env var usage?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this comes from /ops/testnet/prod/backend/variables.tf:
image

Just how these are defined in ops right now.

redis = {
enabled = true
expirationTime = 10
host = module.sdk_server_cache.redis_instance_address,
Expand Down
3 changes: 2 additions & 1 deletion ops/testnet/staging/backend/config.tf
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ locals {
}
}
environment = var.stage
cache = {
network = var.environment
just-a-node marked this conversation as resolved.
Show resolved Hide resolved
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