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

core: Onchain Price Fetching & Registry observing #2

Merged
merged 8 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,16 @@
NODE_ENV=development

NODE_PORT=3001
NODE_HOST=localhost
NODE_HOST=localhost

COINGECKO_BASE_URL=https://api.coingecko.com/api/v3/
COINGECKO_API_KEY=
COINGECKO_API_KEY_QUERY_NAME=x_cg_demo_api_key

ALCHEMY_URL=
PRIVATE_KEY=

# Sepolia data
TICKER_USD_FEED_REGISTRY=0xF3D020838782213d3da52daa079A9c07F0A8e67e
TICKER_PRICE_STORAGE=0xa909e0bC9a35cC161dE9eA85cA76AB7A9b5b0121
CONTRACTS_DEPLOYMENT_BLOCK=4840144
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module.exports = {
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
root: true,
ignorePatterns: ["dist/**/*"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
"object-curly-spacing": ["warn", "always"],
Expand Down
56 changes: 56 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: PR Tests

on:
pull_request:
branches:
- main
workflow_dispatch:

jobs:
dependencies:
runs-on: ubuntu-latest

container:
image: node:18

strategy:
matrix:
node-version: [18.x]

steps:
- name: Checkout
uses: actions/checkout@v2

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}

- name: Cache node modules
uses: actions/cache@v1
with:
path: node_modules
key: node_modules-${{ hashFiles('**/yarn.lock') }}

- name: Install yarn
run: npm install -g yarn

- name: Install dependencies
run: yarn install

lint:
runs-on: ubuntu-latest
needs: dependencies

steps:
- name: Checkout
uses: actions/checkout@v2

- name: Load node modules
uses: actions/cache@v1
with:
path: node_modules
key: node_modules-${{ hashFiles('**/yarn.lock') }}

- name: Code passes lint check
run: yarn lint
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ node_modules
.vscode

# Ignore built ts files
dist/**/*
dist
14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,34 @@
"main": "index.js",
"license": "MIT",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "nodemon",
"lint": "eslint .",
"lint:fix": "yarn lint --fix"
"lint:fix": "yarn lint --fix",
"sc:extract": "typechain --target=ethers-v6 './src/contracts/abi/json/*.json' --out-dir './src/contracts'"
},
"devDependencies": {
"@typechain/ethers-v6": "^0.5.1",
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/node-cron": "^3.0.11",
"@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser": "^6.13.2",
"eslint": "^8.55.0",
"nodemon": "^3.0.2",
"ts-node": "^10.9.2",
"typechain": "^8.3.2",
"typescript": "^5.3.3"
},
"dependencies": {
"axios": "^1.6.2",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2"
"ethers": "^6.9.0",
"express": "^4.18.2",
"node-cron": "^3.0.3",
"redux": "^5.0.0"
}
}
4 changes: 3 additions & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import express, { Router, Request, Response } from "express";
import bodyParser from "body-parser";
import cors from "cors";
import api from "./api";
import { initApp } from "./jobs/app.jobs";

const { NODE_PORT, NODE_HOST } = CONFIG;
const app = express();
Expand All @@ -16,8 +17,9 @@ app.use(bodyParser.json());
const apiRouter = Router();
apiRouter.use("/api", api);

app.use(apiRouter);
initApp();

app.use(apiRouter);
// 404
app.use("*", (request: Request, response: Response) => {
return response.status(404).json({ message: "Not Found" });
Expand Down
18 changes: 17 additions & 1 deletion src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,15 @@ const corsOptions: CorsOptions = {
const {
NODE_PORT,
NODE_HOST,
NODE_ENV
NODE_ENV,
COINGECKO_BASE_URL,
COINGECKO_API_KEY,
COINGECKO_API_KEY_QUERY_NAME,
ALCHEMY_URL,
PRIVATE_KEY,
TICKER_USD_FEED_REGISTRY,
TICKER_PRICE_STORAGE,
CONTRACTS_DEPLOYMENT_BLOCK
} = process.env;

const ENV: ApplicationEnv = NODE_ENV as ApplicationEnv || ApplicationEnv.DEVELOPMENT;
Expand All @@ -28,4 +36,12 @@ export const CONFIG = {
NODE_HOST,
CORS_OPTIONS: corsOptions,
NODE_ENV: ENV,
COINGECKO_BASE_URL,
COINGECKO_API_KEY,
COINGECKO_API_KEY_QUERY_NAME,
ALCHEMY_URL,
PRIVATE_KEY,
TICKER_USD_FEED_REGISTRY,
TICKER_PRICE_STORAGE,
CONTRACTS_DEPLOYMENT_BLOCK: Number(CONTRACTS_DEPLOYMENT_BLOCK)
};
14 changes: 14 additions & 0 deletions src/constants/coingecko.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export enum CoinGeckoFiatCurrencies {
USD = "usd"
}

const chainlinkTickerToCoingeckoMap: {[symbol: string]: string} = {
"BTC": "bitcoin",
"ETH": "ethereum",
"LINK": "chainlink",
"SNX": "havven"
}

export function getCoingeckoIdByChainlinkTicker(ticker: string) {
return chainlinkTickerToCoingeckoMap[ticker];
}
186 changes: 186 additions & 0 deletions src/contracts/abi/ChainlinkAggregatorV3Abi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BigNumberish,
BytesLike,
FunctionFragment,
Result,
Interface,
ContractRunner,
ContractMethod,
Listener,
} from "ethers";
import type {
TypedContractEvent,
TypedDeferredTopicFilter,
TypedEventLog,
TypedListener,
TypedContractMethod,
} from "../common";

export interface ChainlinkAggregatorV3AbiInterface extends Interface {
getFunction(
nameOrSignature:
| "decimals"
| "description"
| "getRoundData"
| "latestRoundData"
| "version"
): FunctionFragment;

encodeFunctionData(functionFragment: "decimals", values?: undefined): string;
encodeFunctionData(
functionFragment: "description",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "getRoundData",
values: [BigNumberish]
): string;
encodeFunctionData(
functionFragment: "latestRoundData",
values?: undefined
): string;
encodeFunctionData(functionFragment: "version", values?: undefined): string;

decodeFunctionResult(functionFragment: "decimals", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "description",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "getRoundData",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "latestRoundData",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "version", data: BytesLike): Result;
}

export interface ChainlinkAggregatorV3Abi extends BaseContract {
connect(runner?: ContractRunner | null): ChainlinkAggregatorV3Abi;
waitForDeployment(): Promise<this>;

interface: ChainlinkAggregatorV3AbiInterface;

queryFilter<TCEvent extends TypedContractEvent>(
event: TCEvent,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;
queryFilter<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TypedEventLog<TCEvent>>>;

on<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
on<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;

once<TCEvent extends TypedContractEvent>(
event: TCEvent,
listener: TypedListener<TCEvent>
): Promise<this>;
once<TCEvent extends TypedContractEvent>(
filter: TypedDeferredTopicFilter<TCEvent>,
listener: TypedListener<TCEvent>
): Promise<this>;

listeners<TCEvent extends TypedContractEvent>(
event: TCEvent
): Promise<Array<TypedListener<TCEvent>>>;
listeners(eventName?: string): Promise<Array<Listener>>;
removeAllListeners<TCEvent extends TypedContractEvent>(
event?: TCEvent
): Promise<this>;

decimals: TypedContractMethod<[], [bigint], "view">;

description: TypedContractMethod<[], [string], "view">;

getRoundData: TypedContractMethod<
[_roundId: BigNumberish],
[
[bigint, bigint, bigint, bigint, bigint] & {
roundId: bigint;
answer: bigint;
startedAt: bigint;
updatedAt: bigint;
answeredInRound: bigint;
}
],
"view"
>;

latestRoundData: TypedContractMethod<
[],
[
[bigint, bigint, bigint, bigint, bigint] & {
roundId: bigint;
answer: bigint;
startedAt: bigint;
updatedAt: bigint;
answeredInRound: bigint;
}
],
"view"
>;

version: TypedContractMethod<[], [bigint], "view">;

getFunction<T extends ContractMethod = ContractMethod>(
key: string | FunctionFragment
): T;

getFunction(
nameOrSignature: "decimals"
): TypedContractMethod<[], [bigint], "view">;
getFunction(
nameOrSignature: "description"
): TypedContractMethod<[], [string], "view">;
getFunction(
nameOrSignature: "getRoundData"
): TypedContractMethod<
[_roundId: BigNumberish],
[
[bigint, bigint, bigint, bigint, bigint] & {
roundId: bigint;
answer: bigint;
startedAt: bigint;
updatedAt: bigint;
answeredInRound: bigint;
}
],
"view"
>;
getFunction(
nameOrSignature: "latestRoundData"
): TypedContractMethod<
[],
[
[bigint, bigint, bigint, bigint, bigint] & {
roundId: bigint;
answer: bigint;
startedAt: bigint;
updatedAt: bigint;
answeredInRound: bigint;
}
],
"view"
>;
getFunction(
nameOrSignature: "version"
): TypedContractMethod<[], [bigint], "view">;

filters: {};
}
Loading
Loading