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

use typeorm #4

Merged
merged 2 commits into from
Mar 20, 2024
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
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
Loading