Skip to content

Commit

Permalink
borrowing endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
mrq1911 committed Dec 11, 2024
1 parent c1f7863 commit 39cc515
Show file tree
Hide file tree
Showing 12 changed files with 1,685 additions and 17 deletions.
1,291 changes: 1,282 additions & 9 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
"discord.js": "^14.0.3",
"dotenv": "^16.0.1",
"ethers": "^5.7.2",
"express": "^4.21.2",
"markdown-to-ansi": "^1.0.0",
"memoizee": "^0.4.17"
"memoizee": "^0.4.17",
"p-queue": "^8.0.1"
},
"devDependencies": {
"jest": "^28.1.3"
Expand Down
3 changes: 3 additions & 0 deletions src/bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import borrowing from "./handlers/borrowing.js";
import {initDiscord} from "./discord.js";
import {rpc, sha, token, channel} from "./config.js";
import {currenciesHandler} from "./currencies.js";
import {endpoints} from "./endpoints.js";

async function main() {
console.log('🐍⌚');
Expand All @@ -24,6 +25,8 @@ async function main() {
console.log(`connected to ${rpc} (${chain} ${version})`);
await initDiscord(token, channel);

await endpoints.start();

const events = new Events();
events.addHandler(currenciesHandler);
events.addHandler(xyk);
Expand Down
4 changes: 4 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ export const channel = process.env.DISCORD_CHANNEL;
export const sha = process.env.COMMIT_SHA || 'dev';
export const usdCurrencyId = process.env.USD_TOKEN || '4';
export const whaleAmount = (Number(process.env.WHALE_AMOUNT) || 10) * 10 ** 12;
export const grafanaUrl = process.env.GRAFANA;
export const grafanaDatasource = process.env.GRAFANA_DATASOURCE || 10;
export const port = process.env.PORT || 3000;
export const liquidationAlert = Number(process.env.LIQ_ALERT);
3 changes: 2 additions & 1 deletion src/currencies.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function currenciesHandler(events) {
.on('otc', 'Placed', ({event: {data: {assetIn}}}) => assetIn && loadCurrency(assetIn))
}

async function loadCurrency(id) {
export async function loadCurrency(id) {
if (!currencies[id]) {
let currency = (await api().query.assetRegistry.assets(id)).toHuman();
if (api().query.assetRegistry.assetMetadataMap) {
Expand Down Expand Up @@ -106,4 +106,5 @@ export const formatUsdValue = value => {
const symbol = currencies[usdCurrencyId].symbol || currencies[usdCurrencyId].name || 'USD';
return ` *~ ${new Intl.NumberFormat('en-US', {maximumSignificantDigits: amount < 1 ? 1 : 4, maximumFractionDigits: 2}).format(amount).replace(/,/g, " ")} ${symbol}*`;
};
export const formatUsdNumber = amount => new Intl.NumberFormat('en-US', {style: 'currency', currency: 'USD'}).format(amount);
export const formatAsset = asset => `**${formatAmount(asset)}**${asset.currencyId.toString() === usdCurrencyId ? formatUsdValue(usdValue(asset)) : ''}`;
3 changes: 3 additions & 0 deletions src/discord.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {Client, GatewayIntentBits} from 'discord.js';
import markdownToAnsi from 'markdown-to-ansi'
import memoize from "memoizee";

let _client = null;
let _channel = null;
Expand Down Expand Up @@ -37,3 +38,5 @@ export function broadcast(message) {
}
}
}

export const broadcastOnce = memoize(broadcast);
64 changes: 64 additions & 0 deletions src/endpoints.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import express from 'express';
import { createServer } from 'http';
import {port} from "./config.js";

class EndpointRegistry {
constructor() {
this.app = express();
this.server = createServer(this.app);
this.registeredEndpoints = new Map();

this.app.use(express.json());

this.app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Internal Server Error' });
});
}

registerEndpoint(namespace, routes, middleware = []) {
if (this.registeredEndpoints.has(namespace)) {
throw new Error(`Endpoint namespace '${namespace}' is already registered`);
}

const router = express.Router();

middleware.forEach(mw => router.use(mw));

Object.entries(routes).forEach(([path, handlers]) => {
Object.entries(handlers).forEach(([method, handler]) => {
router[method.toLowerCase()](path, async (req, res, next) => {
try {
await handler(req, res, next);
} catch (error) {
next(error);
}
});
});
});

this.app.use(`/api/${namespace}`, router);
this.registeredEndpoints.set(namespace, { routes, middleware });
}

start() {
return new Promise((resolve) => {
this.server.listen(port, () => {
console.log(`listening on port ${port}`);
resolve();
});
});
}

stop() {
return new Promise((resolve) => {
this.server.close(resolve);
});
}

getRegisteredEndpoints() {
return Array.from(this.registeredEndpoints.keys());
}
}

export const endpoints = new EndpointRegistry();
20 changes: 15 additions & 5 deletions src/handlers/borrowing.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import {formatAccount, formatAsset} from "../currencies.js";
import {broadcast} from "../discord.js";
import poolAbi from "../resources/aave-pool.abi.js";
import oracleAbi from "../resources/dia-oracle.abi.js";
import ERC20Mapping from "../utils/erc20mapping.js";
import {toAccount} from "../utils/evm.js";
import Borrowers from "../utils/borrowers.js";

const borrowers = new Borrowers();

export default function borrowingHandler(events) {
borrowers.init();
events
.onLog('Supply', poolAbi, supply)
.onLog('Withdraw', poolAbi, withdraw)
.onLog('Borrow', poolAbi, borrow)
.onLog('Repay', poolAbi, repay)
.onLog('LiquidationCall', poolAbi, liquidationCall)
.onLog('Supply', poolAbi, borrowers.handler(supply))
.onLog('Withdraw', poolAbi, borrowers.handler(withdraw))
.onLog('Borrow', poolAbi, borrowers.handler(borrow))
.onLog('Repay', poolAbi, borrowers.handler(repay))
.onLog('LiquidationCall', poolAbi, borrowers.handler(liquidationCall))
.onLog('OracleUpdate', oracleAbi, oracleUpdate);
}

async function supply({log: {args: {reserve, amount, onBehalfOf}}}) {
Expand Down Expand Up @@ -47,3 +53,7 @@ async function liquidationCall({log: {args}}) {
const message = `${formatAccount(liquidator)} liquidated ${formatAsset(collateral)} of ${formatAccount(user)}`;
broadcast(message);
}

function oracleUpdate({blockNumber}) {
borrowers.updateAll(blockNumber);
}
142 changes: 142 additions & 0 deletions src/resources/dia-oracle.abi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
export default [
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "string",
"name": "key",
"type": "string"
},
{
"indexed": false,
"internalType": "uint128",
"name": "value",
"type": "uint128"
},
{
"indexed": false,
"internalType": "uint128",
"name": "timestamp",
"type": "uint128"
}
],
"name": "OracleUpdate",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "newUpdater",
"type": "address"
}
],
"name": "UpdaterAddressChange",
"type": "event"
},
{
"inputs": [
{
"internalType": "string",
"name": "key",
"type": "string"
}
],
"name": "getValue",
"outputs": [
{
"internalType": "uint128",
"name": "",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string[]",
"name": "keys",
"type": "string[]"
},
{
"internalType": "uint256[]",
"name": "compressedValues",
"type": "uint256[]"
}
],
"name": "setMultipleValues",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "key",
"type": "string"
},
{
"internalType": "uint128",
"name": "value",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "timestamp",
"type": "uint128"
}
],
"name": "setValue",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOracleUpdaterAddress",
"type": "address"
}
],
"name": "updateOracleUpdaterAddress",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"name": "values",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
];
Loading

0 comments on commit 39cc515

Please sign in to comment.