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

Feat/sell simulation #627

Merged
merged 2 commits into from
Nov 27, 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
71 changes: 54 additions & 17 deletions packages/plugin-solana/src/providers/simulationSellingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface SellDetails {
sell_recommender_id: string | null;
}

export class simulationSellingService {
export class SimulationSellingService {
private trustScoreDb: TrustScoreDatabase;
private walletProvider: WalletProvider;
private connection: Connection;
Expand Down Expand Up @@ -178,7 +178,7 @@ export class simulationSellingService {
await this.startListeners();
}

private async startListeners() {
public async startListeners() {
// scanning recommendations and selling
console.log("Scanning for token performances...");
const tokenPerformances =
Expand All @@ -198,30 +198,67 @@ export class simulationSellingService {

// start the process in the sonar backend
tokenPerformances.forEach(async (tokenPerformance) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const tokenProvider = new TokenProvider(
tokenPerformance.tokenAddress,
this.walletProvider,
this.runtime.cacheManager
);
const shouldTrade = await tokenProvider.shouldTradeToken();
if (shouldTrade) {
const balance = tokenPerformance.balance;
const sell_recommender_id = tokenPerformance.recommenderId;
const tokenAddress = tokenPerformance.tokenAddress;
const process = await this.startProcessInTheSonarBackend(
tokenAddress,
balance,
true,
sell_recommender_id,
tokenPerformance.initial_mc
);
if (process) {
this.runningProcesses.add(tokenAddress);
}
// const shouldTrade = await tokenProvider.shouldTradeToken();
// if (shouldTrade) {
const balance = tokenPerformance.balance;
const sell_recommender_id = tokenPerformance.recommenderId;
const tokenAddress = tokenPerformance.tokenAddress;
const process = await this.startProcessInTheSonarBackend(
tokenAddress,
balance,
true,
sell_recommender_id,
tokenPerformance.initial_mc
);
if (process) {
this.runningProcesses.add(tokenAddress);
}
// }
});
}

public processTokenPerformance(tokenAddress: string) {
try {
const runningProcesses = this.runningProcesses;
// check if token is already being processed
if (runningProcesses.has(tokenAddress)) {
console.log(`Token ${tokenAddress} is already being processed`);
return;
}
const tokenPerformance =
this.trustScoreDb.getTokenPerformance(tokenAddress);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const tokenProvider = new TokenProvider(
tokenPerformance.tokenAddress,
this.walletProvider,
this.runtime.cacheManager
);
const balance = tokenPerformance.balance;
const sell_recommender_id = tokenPerformance.recommenderId;
const process = this.startProcessInTheSonarBackend(
tokenAddress,
balance,
true,
sell_recommender_id,
tokenPerformance.initial_mc
);
if (process) {
this.runningProcesses.add(tokenAddress);
}
} catch (error) {
console.error(
`Error getting token performance for token ${tokenAddress}:`,
error
);
}
}

private async startProcessInTheSonarBackend(
tokenAddress: string,
balance: number,
Expand Down
90 changes: 90 additions & 0 deletions packages/plugin-solana/src/providers/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import {
TokenTradeData,
CalculatedBuyAmounts,
Prices,
TokenCodex,
} from "../types/token.ts";
import NodeCache from "node-cache";
import * as path from "path";
import { toBN } from "../bignumber.ts";
import { WalletProvider, Item } from "./wallet.ts";
import { Connection, PublicKey } from "@solana/web3.js";
import axios from "axios";

const PROVIDER_CONFIG = {
BIRDEYE_API: "https://public-api.birdeye.so",
Expand All @@ -36,6 +38,8 @@ const PROVIDER_CONFIG = {
export class TokenProvider {
private cache: NodeCache;
private cacheKey: string = "solana/tokens";
private NETWORK_ID = 1399811149;
private GRAPHQL_ENDPOINT = "https://graph.codex.io/graphql";

constructor(
// private connection: Connection,
Expand Down Expand Up @@ -155,6 +159,89 @@ export class TokenProvider {
}
}

async fetchTokenCodex(): Promise<TokenCodex> {
try {
const cacheKey = `token_${this.tokenAddress}`;
const cachedData = this.getCachedData<TokenCodex>(cacheKey);
if (cachedData) {
console.log(
`Returning cached token data for ${this.tokenAddress}.`
);
return cachedData;
}
const query = `
query Token($address: String!, $networkId: Int!) {
token(input: { address: $address, networkId: $networkId }) {
id
address
cmcId
decimals
name
symbol
totalSupply
isScam
info {
circulatingSupply
imageThumbUrl
}
explorerData {
blueCheckmark
description
tokenType
}
}
}
`;

const variables = {
address: this.tokenAddress,
networkId: this.NETWORK_ID, // Replace with your network ID
};

const response = await axios.post(
this.GRAPHQL_ENDPOINT,
{
query,
variables,
},
{
headers: {
"Content-Type": "application/json",
Authorization: settings.CODEX_API_KEY,
},
}
);

const token = response.data?.data?.token;

if (!token) {
throw new Error(`No data returned for token ${tokenAddress}`);
}

this.setCachedData(cacheKey, token);

return {
id: token.id,
address: token.address,
cmcId: token.cmcId,
decimals: token.decimals,
name: token.name,
symbol: token.symbol,
totalSupply: token.totalSupply,
circulatingSupply: token.info?.circulatingSupply,
imageThumbUrl: token.info?.imageThumbUrl,
blueCheckmark: token.explorerData?.blueCheckmark,
isScam: token.isScam ? true : false,
};
} catch (error) {
console.error(
"Error fetching token data from Codex:",
error.message
);
return {} as TokenCodex;
}
}

async fetchPrices(): Promise<Prices> {
try {
const cacheKey = "prices";
Expand Down Expand Up @@ -813,6 +900,8 @@ export class TokenProvider {
);
const security = await this.fetchTokenSecurity();

const tokenCodex = await this.fetchTokenCodex();

console.log(`Fetching trade data for token: ${this.tokenAddress}`);
const tradeData = await this.fetchTokenTradeData();

Expand Down Expand Up @@ -862,6 +951,7 @@ export class TokenProvider {
dexScreenerData: dexData,
isDexScreenerListed,
isDexScreenerPaid,
tokenCodex,
};

// console.log("Processed token data:", processedData);
Expand Down
16 changes: 12 additions & 4 deletions packages/plugin-solana/src/providers/trustScoreProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Connection, PublicKey } from "@solana/web3.js";
import { getAssociatedTokenAddress } from "@solana/spl-token";
import { TokenProvider } from "./token.ts";
import { WalletProvider } from "./wallet.ts";
import { SimulationSellingService } from "./simulationSellingService.ts";
import {
TrustScoreDatabase,
RecommenderMetrics,
Expand Down Expand Up @@ -53,6 +54,7 @@ interface TokenRecommendationSummary {
export class TrustScoreManager {
private tokenProvider: TokenProvider;
private trustScoreDb: TrustScoreDatabase;
private simulationSellingService: SimulationSellingService;
private connection: Connection;
private baseMint: PublicKey;
private DECAY_RATE = 0.95;
Expand All @@ -73,6 +75,10 @@ export class TrustScoreManager {
);
this.backend = runtime.getSetting("BACKEND_URL");
this.backendToken = runtime.getSetting("BACKEND_TOKEN");
this.simulationSellingService = new SimulationSellingService(
runtime,
this.tokenProvider
);
}

//getRecommenederBalance
Expand Down Expand Up @@ -147,9 +153,9 @@ export class TrustScoreManager {
liquidityChange24h: 0,
holderChange24h:
processedData.tradeData.unique_wallet_24h_change_percent,
rugPull: false, // TODO: Implement rug pull detection
isScam: false, // TODO: Implement scam detection
marketCapChange24h: 0, // TODO: Implement market cap change
rugPull: false,
isScam: processedData.tokenCodex.isScam,
marketCapChange24h: 0,
sustainedGrowth: sustainedGrowth,
rapidDump: isRapidDump,
suspiciousVolume: suspiciousVolume,
Expand Down Expand Up @@ -362,6 +368,7 @@ export class TrustScoreManager {
const buySol = data.buy_amount / parseFloat(solPrice);
const buy_value_usd = data.buy_amount * processedData.tradeData.price;
const token = await this.tokenProvider.fetchTokenTradeData();
const tokenCodex = await this.tokenProvider.fetchTokenCodex();
const tokenPrice = token.price;
tokensBalance = buy_value_usd / tokenPrice;

Expand Down Expand Up @@ -418,7 +425,7 @@ export class TrustScoreManager {
holderChange24h:
processedData.tradeData.unique_wallet_24h_change_percent,
rugPull: false,
isScam: false,
isScam: tokenCodex.isScam,
marketCapChange24h: 0,
sustainedGrowth: false,
rapidDump: false,
Expand Down Expand Up @@ -446,6 +453,7 @@ export class TrustScoreManager {
};
this.trustScoreDb.addTransaction(transaction);
}
this.simulationSellingService.processTokenPerformance(tokenAddress);
// api call to update trade performance
this.createTradeInBe(tokenAddress, recommenderId, username, data);
return creationData;
Expand Down
Loading
Loading