Skip to content

Commit

Permalink
Merge pull request #627 from ai16z/feat/sell-simulation
Browse files Browse the repository at this point in the history
Feat/sell simulation
  • Loading branch information
lalalune authored Nov 27, 2024
2 parents cf39911 + 8fa43ab commit 4a0e313
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 21 deletions.
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

0 comments on commit 4a0e313

Please sign in to comment.