Skip to content
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
60 changes: 60 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"mcpServers": {
"neon-server": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@neondatabase/mcp-server-neon",
"start",
"napi_ctcjmic0tobrl04904dwx7qgpyfn96nl5l9ss8b1le4qlgz3816x6y2wnfejtgek"
],
"env": {}
},
"browser-tools": {
"type": "stdio",
"command": "/opt/homebrew/bin/node",
"args": [
"/Users/speed/.npm/_npx/dcd6f0de5842aab6/node_modules/@agentdeskai/browser-tools-mcp/dist/mcp-server.js",
"run"
],
"env": {}
},
"github": {
"type": "stdio",
"command": "/Users/speed/github-mcp-server/github-mcp-server",
"args": [
"stdio"
],
"env": {}
},
"taskmaster-ai": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"--package=task-master-ai",
"task-master-ai"
],
"env": {}
},
"exa": {
"type": "stdio",
"command": "/opt/homebrew/bin/npx",
"args": [
"exa-mcp-server"
],
"env": {}
},
"web-eval-agent": {
"type": "stdio",
"command": "uvx",
"args": [
"--from",
"git+https://github.com/Operative-Sh/web-eval-agent.git",
"webEvalAgent"
],
"env": {}
}
}
}
8 changes: 8 additions & 0 deletions convex/_generated/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ import type * as dex_uniswapV3 from "../dex/uniswapV3.js";
import type * as fairLaunch from "../fairLaunch.js";
import type * as fees_feeManager from "../fees/feeManager.js";
import type * as fees_initializeFees from "../fees/initializeFees.js";
import type * as fixBondingCurves from "../fixBondingCurves.js";
import type * as http from "../http.js";
import type * as jobQueue from "../jobQueue.js";
import type * as memeCoins from "../memeCoins.js";
import type * as migrations_addTokenIdToBondingCurves from "../migrations/addTokenIdToBondingCurves.js";
import type * as monitoring_alerts from "../monitoring/alerts.js";
import type * as monitoring_auditLog from "../monitoring/auditLog.js";
import type * as monitoring_metrics from "../monitoring/metrics.js";
Expand All @@ -60,8 +62,10 @@ import type * as oracles_priceOracle from "../oracles/priceOracle.js";
import type * as reflections from "../reflections.js";
import type * as revenue_creatorRevenue from "../revenue/creatorRevenue.js";
import type * as router from "../router.js";
import type * as runMigration from "../runMigration.js";
import type * as security_multiSigActions from "../security/multiSigActions.js";
import type * as security_multiSigQueries from "../security/multiSigQueries.js";
import type * as simulatedTrading from "../simulatedTrading.js";
import type * as social_comments from "../social/comments.js";
import type * as social_discord from "../social/discord.js";
import type * as social_formatter from "../social/formatter.js";
Expand Down Expand Up @@ -116,9 +120,11 @@ declare const fullApi: ApiFromModules<{
fairLaunch: typeof fairLaunch;
"fees/feeManager": typeof fees_feeManager;
"fees/initializeFees": typeof fees_initializeFees;
fixBondingCurves: typeof fixBondingCurves;
http: typeof http;
jobQueue: typeof jobQueue;
memeCoins: typeof memeCoins;
"migrations/addTokenIdToBondingCurves": typeof migrations_addTokenIdToBondingCurves;
"monitoring/alerts": typeof monitoring_alerts;
"monitoring/auditLog": typeof monitoring_auditLog;
"monitoring/metrics": typeof monitoring_metrics;
Expand All @@ -130,8 +136,10 @@ declare const fullApi: ApiFromModules<{
reflections: typeof reflections;
"revenue/creatorRevenue": typeof revenue_creatorRevenue;
router: typeof router;
runMigration: typeof runMigration;
"security/multiSigActions": typeof security_multiSigActions;
"security/multiSigQueries": typeof security_multiSigQueries;
simulatedTrading: typeof simulatedTrading;
"social/comments": typeof social_comments;
"social/discord": typeof social_discord;
"social/formatter": typeof social_formatter;
Expand Down
118 changes: 117 additions & 1 deletion convex/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export const getTokenAnalytics = query({
// Get bonding curve for real blockchain data
const bondingCurve = await ctx.db
.query("bondingCurves")
.withIndex("byTokenId", (q) => q.eq("tokenId", args.tokenId))
.withIndex("by_coin", (q) => q.eq("coinId", args.tokenId))
.first();

let holderDistribution: any[] = [];
Expand Down Expand Up @@ -326,6 +326,122 @@ export const updateTokenAnalytics = internalMutation({
});

// Fetch real-time analytics data from blockchain
// Get trade history for a token
export const getTradeHistory = query({
args: {
tokenId: v.id("memeCoins"),
limit: v.optional(v.number()),
},
handler: async (ctx, args) => {
const limit = args.limit ?? 50;

// Get bonding curve transactions
const bondingCurve = await ctx.db
.query("bondingCurves")
.withIndex("by_coin", (q) => q.eq("coinId", args.tokenId))
.first();

if (!bondingCurve) {
return [];
}

const transactions = await ctx.db
.query("bondingCurveTransactions")
.withIndex("by_curve", (q) => q.eq("bondingCurveId", bondingCurve._id))
.order("desc")
.take(limit);

return transactions.map((tx) => ({
type: tx.type,
price: tx.price,
amount: tx.type === "buy" ? tx.tokensOut : tx.tokensIn,
value: tx.type === "buy" ? tx.amountIn : tx.amountOut,
timestamp: tx.timestamp,
user: tx.user,
}));
},
});

// Get holder distribution
export const getHolderDistribution = query({
args: {
tokenId: v.id("memeCoins"),
},
handler: async (ctx, args) => {
const bondingCurve = await ctx.db
.query("bondingCurves")
.withIndex("by_coin", (q) => q.eq("coinId", args.tokenId))
.first();

if (!bondingCurve) {
return [];
}

const holders = await ctx.db
.query("bondingCurveHolders")
.withIndex("by_curve", (q) => q.eq("bondingCurveId", bondingCurve._id))
.collect();

// Group holders by balance range
const ranges = [
{ label: "0-100", min: 0, max: 100 },
{ label: "100-1K", min: 100, max: 1000 },
{ label: "1K-10K", min: 1000, max: 10000 },
{ label: "10K-100K", min: 10000, max: 100000 },
{ label: "100K+", min: 100000, max: Infinity },
];

const distribution = ranges.map((range) => ({
range: range.label,
count: holders.filter((h) => h.balance >= range.min && h.balance < range.max).length,
}));

return distribution;
},
});

// Get social metrics
export const getSocialMetrics = query({
args: {
tokenId: v.id("memeCoins"),
},
handler: async (ctx, args) => {
const socialShares = await ctx.db
.query("socialShares")
.withIndex("by_coin", (q) => q.eq("coinId", args.tokenId))
.collect();

const comments = await ctx.db
.query("comments")
.withIndex("by_token", (q) => q.eq("tokenId", args.tokenId))
.collect();

const reactions = await ctx.db
.query("reactions")
.withIndex("by_token", (q) => q.eq("tokenId", args.tokenId))
.collect();

return {
totalShares: socialShares.length,
totalComments: comments.length,
totalReactions: reactions.length,
platforms: {
twitter: socialShares.filter((s) => s.platform === "twitter").length,
telegram: socialShares.filter((s) => s.platform === "telegram").length,
discord: socialShares.filter((s) => s.platform === "discord").length,
},
reactionCounts: {
rocket: reactions.filter((r) => r.type === "rocket").length,
fire: reactions.filter((r) => r.type === "fire").length,
diamond: reactions.filter((r) => r.type === "diamond").length,
moon: reactions.filter((r) => r.type === "moon").length,
trash: reactions.filter((r) => r.type === "trash").length,
bear: reactions.filter((r) => r.type === "bear").length,
},
};
},
});

export const fetchRealTimeAnalytics = internalAction({
args: {
coinId: v.id("memeCoins"),
Expand Down
24 changes: 17 additions & 7 deletions convex/blockchain/bondingCurveIntegration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { ethers } from "ethers";

// Bonding Curve Contract ABI (essential functions)
const BONDING_CURVE_ABI = [
// Constructor
"constructor(address _token, address _feeRecipient)",
// Functions
"function buy(uint256 minTokensOut) external payable returns (uint256 tokensReceived)",
"function sell(uint256 tokenAmount, uint256 minEthOut) external returns (uint256 ethReceived)",
"function calculateBuyReturn(uint256 ethAmount) external view returns (uint256 tokenAmount)",
Expand Down Expand Up @@ -246,7 +249,9 @@ export const deployBondingCurveContract = internalAction({
? process.env.ETHEREUM_RPC_URL
: process.env.BSC_RPC_URL;

const privateKey = process.env.DEPLOYER_PRIVATE_KEY;
const privateKey = args.blockchain === "ethereum"
? process.env.ETHEREUM_DEPLOYER_PRIVATE_KEY
: process.env.BSC_DEPLOYER_PRIVATE_KEY;

if (!rpcUrl || !privateKey) {
throw new Error(`Missing configuration for ${args.blockchain}`);
Expand All @@ -256,11 +261,15 @@ export const deployBondingCurveContract = internalAction({
const signer = new ethers.Wallet(privateKey, provider);

// Bonding Curve contract bytecode (compiled from BondingCurve.sol)
const BONDING_CURVE_BYTECODE = process.env.BONDING_CURVE_BYTECODE;
// Concatenate bytecode parts (split due to Convex env var size limit)
const bytecodePart1 = process.env.BONDING_CURVE_BYTECODE_PART1;
const bytecodePart2 = process.env.BONDING_CURVE_BYTECODE_PART2;

if (!BONDING_CURVE_BYTECODE) {
if (!bytecodePart1 || !bytecodePart2) {
throw new Error("Bonding curve bytecode not configured");
}

const BONDING_CURVE_BYTECODE = bytecodePart1 + bytecodePart2;

// Deploy bonding curve contract
const BondingCurveFactory = new ethers.ContractFactory(
Expand All @@ -269,13 +278,14 @@ export const deployBondingCurveContract = internalAction({
signer
);

const graduationTarget = args.graduationTarget || 100; // 100 ETH default
const feePercent = args.feePercent || 100; // 1% default
// Get fee recipient address (treasury or deployer)
const feeRecipient = process.env.MAINNET_TREASURY_ADDRESS ||
process.env.FEE_COLLECTOR_ADDRESS ||
signer.address; // Default to deployer if no treasury set

const bondingCurve = await BondingCurveFactory.deploy(
args.tokenAddress,
ethers.parseEther(graduationTarget.toString()),
feePercent
feeRecipient
);

await bondingCurve.waitForDeployment();
Expand Down
Loading
Loading