Skip to content

Commit

Permalink
Merge pull request #45 from QuantWealth/feat/orders-operations
Browse files Browse the repository at this point in the history
feat: added order operations
  • Loading branch information
0xNilesh authored Jun 1, 2024
2 parents f6ce06d + c7af47c commit 61f7c0e
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 15 deletions.
9 changes: 6 additions & 3 deletions packages/adapters/orderbook-db/src/schema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import mongoose from "mongoose";

/// Order Schema
/// TODO: amounts, dapps, signatures, stratrgyType need to be in a object[]
interface IOrder {
id: string;
signer: string;
Expand All @@ -11,11 +12,12 @@ interface IOrder {
cancelled?: number;
};
dapps: string[];
distribution: boolean;
distribution?: boolean;
amounts: string[];
signatures: string[];
signatures?: string[];
status: "P" | "E" | "C"; // Pending, Executed, Canceled
hashes?: string[]; // Optional array of transaction hashes
strategyType: "FLEXI" | "FIXED";
}

const OrderSchema = new mongoose.Schema<IOrder>({
Expand All @@ -32,7 +34,8 @@ const OrderSchema = new mongoose.Schema<IOrder>({
amounts: [{ type: String, required: true }],
signatures: [{ type: String, required: true }],
status: { type: String, enum: ["P", "E", "C"], required: true },
hashes: [{ type: String }]
hashes: [{ type: String }],
strategyType: { type: String, enum: ["FLEXY", "FIXED"], required: true },
});

// Pre-save middleware to set the order ID.
Expand Down
4 changes: 3 additions & 1 deletion packages/agents/nova/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"ethers": "^6.12.1",
"fs": "^0.0.1-security",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1"
"rxjs": "^7.8.1",
"uuid": "^9.0.1"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
Expand All @@ -45,6 +46,7 @@
"@types/jest": "^29.5.2",
"@types/node": "^20.3.1",
"@types/supertest": "^6.0.0",
"@types/uuid": "^9",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.42.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common';
import { Inject, Injectable } from '@nestjs/common';
import { DefiApyQueryDto } from './dto/approve.dto';
import { DefiApyResponse } from './dto/execute.dto';
import {
Expand All @@ -18,9 +18,13 @@ import { MetaTransactionData } from '@safe-global/safe-core-sdk-types';
import { getOrders, IOrder } from '@qw/orderbook-db';
import { ethers } from 'ethers';
import { getConfig } from '../../../config';
import { OrderModel } from '@qw/orderbook-db/dist/schema';
import { v4 as uuidv4 } from 'uuid';

@Injectable()
export class OrderbookService {
@Inject('ORDER_MODEL')
private orderModel: typeof OrderModel,
private wallet;
public config;
public signer;
Expand Down Expand Up @@ -61,9 +65,27 @@ export class OrderbookService {
});
}

// creates the pending order in orderbook and sends the approval transaction to gelato
async sendApproveTransaction(
userScwAddress: string,
userSignedTransaction: MetaTransactionData,
amount: string,
strategyType: "FLEXI" | "FIXED"
) {
const amounts = [amount]; // Currently, there is only one child contract, so the entire amount will be allocated to it.
const qwAaveV3Address = '0x0000000000000000000000000000000000000123';
const dapps = [qwAaveV3Address];
try {
await this._createOrder(userScwAddress, amounts, dapps, userSignedTransaction, strategyType);
await this._sendApproveTransaction(userScwAddress, userSignedTransaction);
} catch (err) {
console.error('Error sending approving tx:', err);
}
}

private async _sendApproveTransaction(
userScwAddress: string,
userSignedTransaction: MetaTransactionData,
) {
const rpc = this.config.chains[0].providers[0];
const gelatoApiKey = this.config.gelatoApiKey;
Expand Down Expand Up @@ -92,6 +114,31 @@ export class OrderbookService {
});
}

// internal fn
private async _createOrder(
userScwAddress: string,
amounts: string[],
dapps: string[],
userSignedTransaction: MetaTransactionData,
strategyType: "FLEXI" | "FIXED" // TODO: make it enum
) {
const currentTimestamp = Date.now();

this.orderModel.create({
id: uuidv4(),
signer: userScwAddress,
wallet: userScwAddress,
dapps,
amounts,
signatures: [userSignedTransaction],
status: "P",
strategyType,
timestamps: {
placed: currentTimestamp // Set the current timestamp as the placed time
}
})
}

/**
* Handles the batch execution of orders, both the receiveFunds and execute steps.
* Retrieves pending orders, processes them, and executes them using Gelato relay.
Expand Down Expand Up @@ -212,6 +259,17 @@ export class OrderbookService {
// update the status of the orderbook.
// TODO: update order status from pending to executed, optionally record hashes of transactions in order.hashes?
// Order schema should really record the gelato relay ID in this case...
await Promise.all(
pendingOrders.map((order) =>
OrderModel.updateOne(
{ id: order.id },
{
status: "E",
"timestamps.executed": Date.now(),
}
).exec()
)
);
}
}
}
61 changes: 51 additions & 10 deletions packages/agents/nova/src/core/resources/saving/saving.service.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,71 @@
import { Injectable } from '@nestjs/common';
import { Inject, Injectable } from '@nestjs/common';
import { SavingType, TSaving } from 'src/common/types';
import { CreateTransactionDto } from './dto/create-transaction.dto';
import { ethers } from 'ethers';
import { SavingApyQueryDto } from './dto/saving-apy-query.dto';
import { OrderModel } from '@qw/orderbook-db/dist/schema';

const getRandomApy = (min: number, max: number): number => {
return parseFloat((Math.random() * (max - min) + min).toFixed(2));
};

const fetchFromOrderbook = (scw: string): number => {
return 100;
};

@Injectable()
export class SavingService {
constructor(
@Inject('ORDER_MODEL')
private orderModel: typeof OrderModel,
) {}

// Function to fetch from the order book and calculate the sum of amounts
async fetchInvestedAmountsFromOrderbook(
scw: string,
): Promise<{ flexiAmount: number; fixedAmount: number }> {
try {
// Find all orders associated with the given SCW address
const orders = await this.orderModel.find({ wallet: scw });

// Initialize the amounts object
const amounts = {
flexiAmount: 0,
fixedAmount: 0,
};

// Calculate the sums of flexi and fixed amounts
orders.forEach((order) => {
if (order.status === 'E') {
// Only consider orders with status "E"
const orderAmount = order.amounts.reduce(
(sum, amount) => sum + parseFloat(amount),
0,
);
if (order.strategyType === 'FLEXI') {
amounts.flexiAmount += orderAmount;
} else if (order.strategyType === 'FIXED') {
amounts.fixedAmount += orderAmount;
}
}
});

return amounts;
} catch (error) {
console.error('Error fetching orders:', error);
throw error;
}
}

/**
* This service is called by /savings/all endpoint
* It retrieves all of the different type of Savings
* @returns savings array
*/
getAllSavings(query: SavingApyQueryDto): Array<TSaving> {
const amountInvested: number = fetchFromOrderbook(query.scwAddress); // fetch from orderbook
async getAllSavings(query: SavingApyQueryDto): Promise<Array<TSaving>> {
const amountInvested = await this.fetchInvestedAmountsFromOrderbook(
query.scwAddress,
); // fetch from orderbook
const SAVINGS: Array<TSaving> = [
{
investedAmount: amountInvested,
apy: getRandomApy(16, 20),
investedAmount: amountInvested.flexiAmount,
apy: getRandomApy(18, 20),
currentAmount: 0,
type: SavingType.FLEXI,
strategy: 1,
Expand All @@ -33,7 +74,7 @@ export class SavingService {
identifier: '0x1',
},
{
investedAmount: amountInvested,
investedAmount: amountInvested.fixedAmount,
apy: 22,
currentAmount: 0,
type: SavingType.FIX,
Expand Down

0 comments on commit 61f7c0e

Please sign in to comment.