Skip to content

Commit

Permalink
Merge pull request #4 from eq-lab/feature/use-typeorm
Browse files Browse the repository at this point in the history
use typeorm
  • Loading branch information
mn13 authored Mar 20, 2024
2 parents 6ec6ada + e16bb62 commit 74fda37
Show file tree
Hide file tree
Showing 15 changed files with 1,715 additions and 60 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.vscode
dist
node_modules
*.sqlite
*.sqlite
.env
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
"license": "MIT",
"main": "dist/index.js",
"dependencies": {
"@stellar/stellar-sdk": "^11.2.1",
"better-sqlite3": "^8.6.0",
"bigint-conversion": "^2.4.3",
"@stellar/stellar-sdk": "^11.2.1"
"dotenv": "^16.4.5",
"mssql": "^10.0.2",
"typeorm": "^0.3.20"
},
"scripts": {
"start": "node dist/index.js",
Expand Down
11 changes: 10 additions & 1 deletion src/configuration.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { config } from 'dotenv';

config();

export const POOL_PRECISION_FACTOR = 1_000_000_000;
export const CONTRACT_CREATION_LEDGER = process.env.CONTRACT_CREATION_LEDGER || 753012;
export const POOL_ID = process.env.POOL_ID || "CCR254VF53IMGX36QVN4ZJOKR6GK3KQJD6BJISX7LE7TXPKQEUV3MFUB";
Expand All @@ -6,4 +10,9 @@ export const HORIZON_URL = process.env.HORIZON_URL || "https://horizon-futurenet
export const NETWORK_PASSPHRASE = process.env.NETWORK_PASSPHRASE || "Test SDF Future Network ; October 2022";
export const LIQUIDATOR_ADDRESS = process.env.LIQUIDATOR_ADDRESS;
export const LIQUIDATOR_SECRET = process.env.LIQUIDATOR_SECRET;
export const POOL_ASSETS = process.env.POOL_ASSETS || "CB3VNKT7UEAHHETRHPC3XEAE3SRSVIASUG3P6KG5JFVY6Q5SVISJH2EJ,CC3OEW3BQUUMRWGPDKYESZAOXEOPBLDHKMZR2JYNHR23LIF2ULQVCAUG,CB2O6IY6EVBWFCFKAI2FNWTAYOB4RASUTYPC6VWKQ6IN44VASBQOMWKY";
export const POOL_ASSETS = process.env.POOL_ASSETS || "CB3VNKT7UEAHHETRHPC3XEAE3SRSVIASUG3P6KG5JFVY6Q5SVISJH2EJ,CC3OEW3BQUUMRWGPDKYESZAOXEOPBLDHKMZR2JYNHR23LIF2ULQVCAUG,CB2O6IY6EVBWFCFKAI2FNWTAYOB4RASUTYPC6VWKQ6IN44VASBQOMWKY";
export const DB_HOST = process.env.DB_HOST;
export const DB_USERNAME = process.env.DB_USERNAME;
export const DB_PASSWORD = process.env.DB_PASSWORD;
export const DB_NAME = process.env.DB_NAME;
export const CHAIN = process.env.CHAIN;
43 changes: 0 additions & 43 deletions src/db.ts

This file was deleted.

12 changes: 7 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { populateDbWithBorrowers } from "./sync";
import { getDebtCoeff, getAccountPosition, getReserves, getBalance, liquidate } from "./contracts";
import { getDebtCoeff, getAccountPosition, getReserves, getBalance, liquidate } from "./infrastructure/soroban/contracts";
import { POOL_PRECISION_FACTOR, SOROBAN_URL, LIQUIDATOR_ADDRESS } from "./configuration";
import { readBorrowers, deleteBorrower, deleteBorrowers } from "./db";
import { SorobanRpc } from "@stellar/stellar-sdk";
import { deleteBorrowers, readBorrowers } from "./infrastructure/db/domain";
import { AppDataSource } from "./infrastructure/db/data-source";

async function main() {
await AppDataSource.initialize()
const rpc = new SorobanRpc.Server(SOROBAN_URL);

while (true) {
await populateDbWithBorrowers(rpc);
const users = readBorrowers();
const users = await readBorrowers();
const reserves = await getReserves(rpc);

const positionsResults = await Promise.allSettled(users.map(user => getAccountPosition(rpc, user.borrower)));
Expand All @@ -28,7 +30,7 @@ async function main() {
}
}

deleteBorrowers(borrowersToDelete);
await deleteBorrowers(borrowersToDelete);

const liquidatorBalances = new Map<string, bigint>;
const borrowersDebt = new Map<string, Map<string, bigint>>;
Expand Down Expand Up @@ -91,7 +93,7 @@ async function main() {

for (const liquidationResult of liquidationResults) {
if (liquidationResult.status === "fulfilled" && liquidationResult.value[1] == undefined) {
deleteBorrower(liquidationResult.value[0]);
await deleteBorrowers([liquidationResult.value[0]]);
} else {
console.warn(`Liquidation error: ${liquidationResult}`);
}
Expand Down
23 changes: 23 additions & 0 deletions src/infrastructure/db/data-source.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import "reflect-metadata"
import { DataSource } from "typeorm"
import { SlenderKeeperState } from "./entity/SlenderKeeperState"
import { SlenderBorrower } from "./entity/SlenderBorrowers"
import { DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME } from '../../configuration';

export const AppDataSource = new DataSource({
type: "mssql",
host: DB_HOST,
username: DB_USERNAME,
password: DB_PASSWORD,
database: DB_NAME,
synchronize: false,
logging: false,
entities: [SlenderKeeperState, SlenderBorrower],
migrations: [],
subscribers: [],
options: {
encrypt: false
}
});

process.on('exit', () => AppDataSource.destroy());
54 changes: 54 additions & 0 deletions src/infrastructure/db/domain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { CHAIN, POOL_ID } from "../../configuration"
import { AppDataSource } from "./data-source"
import { SlenderBorrower } from "./entity/SlenderBorrowers"
import { SlenderKeeperState } from "./entity/SlenderKeeperState"

export const readLastSyncedLedger = async () => {
const slenderKeeperRepository = AppDataSource.getRepository(SlenderKeeperState);
let currentState = await slenderKeeperRepository.findOneBy({ chain: CHAIN, contractAddress: POOL_ID });
if (currentState === null || currentState === undefined) {
currentState = new SlenderKeeperState();
currentState.lastSynced = 0;
currentState.chain = CHAIN;
currentState.contractAddress = POOL_ID;
await slenderKeeperRepository.save(currentState);
}
return currentState.lastSynced;
}

export const updateLastSyncedLedger = async (lastSyncedLedger: number) => {
const slenderKeeperRepository = AppDataSource.getRepository(SlenderKeeperState);
const currentState = await slenderKeeperRepository.findOneBy({ chain: CHAIN, contractAddress: POOL_ID });
currentState.lastSynced = lastSyncedLedger;
await slenderKeeperRepository.save(currentState);
}

export const readBorrowers = async () => {
const slenderKeeperRepository = AppDataSource.getRepository(SlenderKeeperState);
const currentState = await slenderKeeperRepository.findOneBy({ chain: CHAIN, contractAddress: POOL_ID });
const slenderBorrowerRepository = AppDataSource.getRepository(SlenderBorrower);
const borrowers = await slenderBorrowerRepository.findBy({ keeperStateId: currentState.id });
return borrowers;
}

export const insertBorrowers = async (borrowers: string[]) => {
const slenderKeeperRepository = AppDataSource.getRepository(SlenderKeeperState);
const currentState = await slenderKeeperRepository.findOneBy({ chain: CHAIN, contractAddress: POOL_ID });
const slenderBorrowerRepository = AppDataSource.getRepository(SlenderBorrower);
for (const borrower of borrowers) {
const b = new SlenderBorrower();
b.borrower = borrower;
b.keeperStateId = currentState.id;
await slenderBorrowerRepository.save(b);
}
}

export const deleteBorrowers = async (borrowers: string[]) => {
const slenderKeeperRepository = AppDataSource.getRepository(SlenderKeeperState);
const currentState = await slenderKeeperRepository.findOneBy({ chain: CHAIN, contractAddress: POOL_ID });
const slenderBorrowerRepository = AppDataSource.getRepository(SlenderBorrower);
for (const borrower of borrowers) {
const b = await slenderBorrowerRepository.findOneBy({ keeperStateId: currentState.id, borrower });
slenderBorrowerRepository.remove(b);
}
}
9 changes: 9 additions & 0 deletions src/infrastructure/db/entity/SlenderBorrowers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Entity, PrimaryColumn } from "typeorm"

@Entity("SlenderBorrowers")
export class SlenderBorrower {
@PrimaryColumn()
keeperStateId: number
@PrimaryColumn()
borrower: string
}
16 changes: 16 additions & 0 deletions src/infrastructure/db/entity/SlenderKeeperState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Column, Entity, PrimaryColumn, PrimaryGeneratedColumn } from "typeorm"

@Entity("SlenderKeeperState")
export class SlenderKeeperState {
@PrimaryGeneratedColumn()
id: number

@Column()
lastSynced: number

@PrimaryColumn()
contractAddress: string

@PrimaryColumn()
chain: string
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Address, BASE_FEE, Contract, Keypair, SorobanRpc, TimeoutInfinite, Tran
import { promisify } from "util";

import { PoolAccountPosition, PoolReserveData, ReserveData } from "./types";
import { LIQUIDATOR_ADDRESS, LIQUIDATOR_SECRET, NETWORK_PASSPHRASE, POOL_ASSETS, POOL_ID } from "./configuration";
import { LIQUIDATOR_ADDRESS, LIQUIDATOR_SECRET, NETWORK_PASSPHRASE, POOL_ASSETS, POOL_ID } from "../../configuration";
import { convertScvToJs } from "./parseScvToJs";

export async function getReserves(rpc: SorobanRpc.Server): Promise<ReserveData[]> {
Expand Down
File renamed without changes.
File renamed without changes.
12 changes: 6 additions & 6 deletions src/sync.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { readLastSyncedLedger, updateLastSyncedLedger, insertBorrowers } from "./db";
import { CONTRACT_CREATION_LEDGER, HORIZON_URL, POOL_ID } from "./configuration";
import { Horizon, SorobanRpc, humanizeEvents, xdr } from "@stellar/stellar-sdk";
import { insertBorrowers, readLastSyncedLedger, updateLastSyncedLedger } from "./infrastructure/db/domain";

export const populateDbWithBorrowers = async (rpc: SorobanRpc.Server) => {
let lastLedger = (await rpc.getLatestLedger()).sequence;
const lastSyncedLedger = readLastSyncedLedger();
const lastSyncedLedger = await readLastSyncedLedger();

if (lastLedger > lastSyncedLedger) {
const horizon = new Horizon.Server(HORIZON_URL);
let currentLedger = lastSyncedLedger === 0 ? CONTRACT_CREATION_LEDGER : lastSyncedLedger + 1;
let currentLedger = lastSyncedLedger === 0 ? parseInt(CONTRACT_CREATION_LEDGER.toString()) : lastSyncedLedger + 1;

console.log(`Sync from: ${currentLedger} to ${lastLedger}`);
console.log(`Sync from: ${currentLedger} to: ${lastLedger}`);

while (lastLedger > currentLedger) {
const transactions = await horizon.transactions().forLedger(currentLedger).call();
Expand All @@ -25,10 +25,10 @@ export const populateDbWithBorrowers = async (rpc: SorobanRpc.Server) => {
.filter(e => e.contractId === POOL_ID && e.topics[0] === 'borrow');
const borrower = events.map(e => e.topics[1]);

insertBorrowers(borrower);
await insertBorrowers(borrower);
}

updateLastSyncedLedger(currentLedger);
await updateLastSyncedLedger(currentLedger);

currentLedger += 1;
lastLedger = (await rpc.getLatestLedger()).sequence;
Expand Down
2 changes: 2 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"outDir": "dist",
"forceConsistentCasingInFileNames": true,
"sourceMap": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"include": [
"src"
Expand Down
Loading

0 comments on commit 74fda37

Please sign in to comment.