feat: implement auto-pump mechanism to prevent pool drainage
This commit is contained in:
parent
d9f2836fb9
commit
b8de80d8a9
8 changed files with 1727 additions and 29 deletions
|
|
@ -130,6 +130,8 @@ export async function GET({ params, url }) {
|
|||
isListed: coin.isListed,
|
||||
createdAt: coin.createdAt,
|
||||
creatorId: coin.creatorId,
|
||||
pumpFeeRate: coin.pumpFeeRate,
|
||||
burnRate: coin.burnRate,
|
||||
creatorName: user.name,
|
||||
creatorUsername: user.username,
|
||||
creatorBio: user.bio,
|
||||
|
|
@ -184,7 +186,9 @@ export async function GET({ params, url }) {
|
|||
poolCoinAmount: Number(coinData.poolCoinAmount),
|
||||
poolBaseCurrencyAmount: Number(coinData.poolBaseCurrencyAmount),
|
||||
circulatingSupply: Number(coinData.circulatingSupply),
|
||||
initialSupply: Number(coinData.initialSupply)
|
||||
initialSupply: Number(coinData.initialSupply),
|
||||
pumpFeeRate: Number(coinData.pumpFeeRate),
|
||||
burnRate: Number(coinData.burnRate)
|
||||
},
|
||||
candlestickData,
|
||||
volumeData,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,34 @@ async function calculate24hMetrics(coinId: number, currentPrice: number) {
|
|||
return { change24h: Number(change24h.toFixed(4)), volume24h: Number(volume24h.toFixed(4)) };
|
||||
}
|
||||
|
||||
function calculateAutoPumpEffects(
|
||||
coinData: any,
|
||||
transactionValue: number,
|
||||
tokensTraded: number
|
||||
) {
|
||||
const pumpFeeRate = Number(coinData.pumpFeeRate);
|
||||
const burnRate = Number(coinData.burnRate);
|
||||
|
||||
const pumpFee = transactionValue * pumpFeeRate;
|
||||
const tokensBurned = tokensTraded * burnRate;
|
||||
|
||||
// Ensure we don't burn more tokens than available in pool
|
||||
const maxBurnableTokens = Number(coinData.poolCoinAmount) * 0.99; // Keep 1% minimum
|
||||
const actualTokensBurned = Math.min(tokensBurned, maxBurnableTokens);
|
||||
|
||||
const newPoolBase = Number(coinData.poolBaseCurrencyAmount) + pumpFee;
|
||||
const newPoolCoin = Number(coinData.poolCoinAmount) - actualTokensBurned;
|
||||
const newCirculatingSupply = Number(coinData.circulatingSupply) - actualTokensBurned;
|
||||
|
||||
return {
|
||||
pumpFee,
|
||||
tokensBurned: actualTokensBurned,
|
||||
newPoolBase,
|
||||
newPoolCoin,
|
||||
newCirculatingSupply
|
||||
};
|
||||
}
|
||||
|
||||
export async function POST({ params, request }) {
|
||||
const session = await auth.api.getSession({
|
||||
headers: request.headers
|
||||
|
|
@ -127,6 +155,13 @@ export async function POST({ params, request }) {
|
|||
throw error(400, 'Trade amount too small - would result in zero tokens');
|
||||
}
|
||||
|
||||
// Apply auto-pump effects
|
||||
const autoPumpEffects = calculateAutoPumpEffects(coinData, amount, coinsBought);
|
||||
|
||||
const finalPoolBase = autoPumpEffects.newPoolBase;
|
||||
const finalPoolCoin = autoPumpEffects.newPoolCoin;
|
||||
const finalPrice = finalPoolBase / finalPoolCoin;
|
||||
|
||||
await tx.update(user)
|
||||
.set({
|
||||
baseCurrencyBalance: (userBalance - totalCost).toString(),
|
||||
|
|
@ -168,22 +203,25 @@ export async function POST({ params, request }) {
|
|||
type: 'BUY',
|
||||
quantity: coinsBought.toString(),
|
||||
pricePerCoin: (totalCost / coinsBought).toString(),
|
||||
totalBaseCurrencyAmount: totalCost.toString()
|
||||
totalBaseCurrencyAmount: totalCost.toString(),
|
||||
pumpFeeApplied: autoPumpEffects.pumpFee.toString(),
|
||||
tokensBurned: autoPumpEffects.tokensBurned.toString()
|
||||
});
|
||||
|
||||
await tx.insert(priceHistory).values({
|
||||
coinId: coinData.id,
|
||||
price: newPrice.toString()
|
||||
price: finalPrice.toString()
|
||||
});
|
||||
|
||||
const metrics = await calculate24hMetrics(coinData.id, newPrice);
|
||||
const metrics = await calculate24hMetrics(coinData.id, finalPrice);
|
||||
|
||||
await tx.update(coin)
|
||||
.set({
|
||||
currentPrice: newPrice.toString(),
|
||||
marketCap: (Number(coinData.circulatingSupply) * newPrice).toString(),
|
||||
poolCoinAmount: newPoolCoin.toString(),
|
||||
poolBaseCurrencyAmount: newPoolBaseCurrency.toString(),
|
||||
currentPrice: finalPrice.toString(),
|
||||
marketCap: (autoPumpEffects.newCirculatingSupply * finalPrice).toString(),
|
||||
poolCoinAmount: finalPoolCoin.toString(),
|
||||
poolBaseCurrencyAmount: finalPoolBase.toString(),
|
||||
circulatingSupply: autoPumpEffects.newCirculatingSupply.toString(),
|
||||
change24h: metrics.change24h.toString(),
|
||||
volume24h: metrics.volume24h.toString(),
|
||||
updatedAt: new Date()
|
||||
|
|
@ -191,12 +229,12 @@ export async function POST({ params, request }) {
|
|||
.where(eq(coin.id, coinData.id));
|
||||
|
||||
const priceUpdateData = {
|
||||
currentPrice: newPrice,
|
||||
marketCap: Number(coinData.circulatingSupply) * newPrice,
|
||||
currentPrice: finalPrice,
|
||||
marketCap: autoPumpEffects.newCirculatingSupply * finalPrice,
|
||||
change24h: metrics.change24h,
|
||||
volume24h: metrics.volume24h,
|
||||
poolCoinAmount: newPoolCoin,
|
||||
poolBaseCurrencyAmount: newPoolBaseCurrency
|
||||
poolCoinAmount: finalPoolCoin,
|
||||
poolBaseCurrencyAmount: finalPoolBase
|
||||
};
|
||||
|
||||
const tradeData = {
|
||||
|
|
@ -232,9 +270,13 @@ export async function POST({ params, request }) {
|
|||
type: 'BUY',
|
||||
coinsBought,
|
||||
totalCost,
|
||||
newPrice,
|
||||
priceImpact,
|
||||
newBalance: userBalance - totalCost
|
||||
newPrice: finalPrice,
|
||||
priceImpact: ((finalPrice - currentPrice) / currentPrice) * 100,
|
||||
newBalance: userBalance - totalCost,
|
||||
autoPumpEffects: {
|
||||
feeApplied: autoPumpEffects.pumpFee,
|
||||
tokensBurned: autoPumpEffects.tokensBurned,
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
|
|
@ -275,6 +317,13 @@ export async function POST({ params, request }) {
|
|||
throw error(400, 'Trade amount results in zero base currency received');
|
||||
}
|
||||
|
||||
// Apply auto-pump effects
|
||||
const autoPumpEffects = calculateAutoPumpEffects(coinData, totalCost, amount);
|
||||
|
||||
const finalPoolBase = autoPumpEffects.newPoolBase;
|
||||
const finalPoolCoin = autoPumpEffects.newPoolCoin;
|
||||
const finalPrice = finalPoolBase / finalPoolCoin;
|
||||
|
||||
await tx.update(user)
|
||||
.set({
|
||||
baseCurrencyBalance: (userBalance + totalCost).toString(),
|
||||
|
|
@ -307,22 +356,25 @@ export async function POST({ params, request }) {
|
|||
type: 'SELL',
|
||||
quantity: amount.toString(),
|
||||
pricePerCoin: (totalCost / amount).toString(),
|
||||
totalBaseCurrencyAmount: totalCost.toString()
|
||||
totalBaseCurrencyAmount: totalCost.toString(),
|
||||
pumpFeeApplied: autoPumpEffects.pumpFee.toString(),
|
||||
tokensBurned: autoPumpEffects.tokensBurned.toString()
|
||||
});
|
||||
|
||||
await tx.insert(priceHistory).values({
|
||||
coinId: coinData.id,
|
||||
price: newPrice.toString()
|
||||
price: finalPrice.toString()
|
||||
});
|
||||
|
||||
const metrics = await calculate24hMetrics(coinData.id, newPrice);
|
||||
const metrics = await calculate24hMetrics(coinData.id, finalPrice);
|
||||
|
||||
await tx.update(coin)
|
||||
.set({
|
||||
currentPrice: newPrice.toString(),
|
||||
marketCap: (Number(coinData.circulatingSupply) * newPrice).toString(),
|
||||
poolCoinAmount: newPoolCoin.toString(),
|
||||
poolBaseCurrencyAmount: newPoolBaseCurrency.toString(),
|
||||
currentPrice: finalPrice.toString(),
|
||||
marketCap: (autoPumpEffects.newCirculatingSupply * finalPrice).toString(),
|
||||
poolCoinAmount: finalPoolCoin.toString(),
|
||||
poolBaseCurrencyAmount: finalPoolBase.toString(),
|
||||
circulatingSupply: autoPumpEffects.newCirculatingSupply.toString(),
|
||||
change24h: metrics.change24h.toString(),
|
||||
volume24h: metrics.volume24h.toString(),
|
||||
updatedAt: new Date()
|
||||
|
|
@ -330,12 +382,12 @@ export async function POST({ params, request }) {
|
|||
.where(eq(coin.id, coinData.id));
|
||||
|
||||
const priceUpdateData = {
|
||||
currentPrice: newPrice,
|
||||
marketCap: Number(coinData.circulatingSupply) * newPrice,
|
||||
currentPrice: finalPrice,
|
||||
marketCap: autoPumpEffects.newCirculatingSupply * finalPrice,
|
||||
change24h: metrics.change24h,
|
||||
volume24h: metrics.volume24h,
|
||||
poolCoinAmount: newPoolCoin,
|
||||
poolBaseCurrencyAmount: newPoolBaseCurrency
|
||||
poolCoinAmount: finalPoolCoin,
|
||||
poolBaseCurrencyAmount: finalPoolBase
|
||||
};
|
||||
|
||||
const tradeData = {
|
||||
|
|
@ -371,9 +423,13 @@ export async function POST({ params, request }) {
|
|||
type: 'SELL',
|
||||
coinsSold: amount,
|
||||
totalReceived: totalCost,
|
||||
newPrice,
|
||||
priceImpact,
|
||||
newBalance: userBalance + totalCost
|
||||
newPrice: finalPrice,
|
||||
priceImpact: ((finalPrice - currentPrice) / currentPrice) * 100,
|
||||
newBalance: userBalance + totalCost,
|
||||
autoPumpEffects: {
|
||||
feeApplied: autoPumpEffects.pumpFee,
|
||||
tokensBurned: autoPumpEffects.tokensBurned
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Reference in a new issue