191 lines
4.9 KiB
JavaScript
Raw Normal View History

2025-02-17 15:21:20 +07:00
// src/tools/launch_pumpfun_token.ts
import { Keypair, VersionedTransaction } from "@solana/web3.js"
async function uploadMetadata(
tokenName,
tokenTicker,
description,
imageUrl,
options
) {
// Create metadata object
const formData = new URLSearchParams()
formData.append("name", tokenName)
formData.append("symbol", tokenTicker)
formData.append("description", description)
formData.append("showName", "true")
if (options?.twitter) {
formData.append("twitter", options.twitter)
}
if (options?.telegram) {
formData.append("telegram", options.telegram)
}
if (options?.website) {
formData.append("website", options.website)
}
const imageResponse = await fetch(imageUrl)
const imageBlob = await imageResponse.blob()
const files = {
file: new File([imageBlob], "token_image.png", { type: "image/png" })
}
// Create form data with both metadata and file
const finalFormData = new FormData()
// Add all metadata fields
for (const [key, value] of formData.entries()) {
finalFormData.append(key, value)
}
// Add file if exists
if (files?.file) {
finalFormData.append("file", files.file)
}
const metadataResponse = await fetch("https://pump.fun/api/ipfs", {
method: "POST",
body: finalFormData
})
if (!metadataResponse.ok) {
throw new Error(`Metadata upload failed: ${metadataResponse.statusText}`)
}
return await metadataResponse.json()
}
async function createTokenTransaction(
agent,
mintKeypair,
metadataResponse,
options
) {
const payload = {
publicKey: agent.wallet_address.toBase58(),
action: "create",
tokenMetadata: {
name: metadataResponse.metadata.name,
symbol: metadataResponse.metadata.symbol,
uri: metadataResponse.metadataUri
},
mint: mintKeypair.publicKey.toBase58(),
denominatedInSol: "true", // API expects string "true"
amount: options?.initialLiquiditySOL || 0.0001,
slippage: options?.slippageBps || 5,
priorityFee: options?.priorityFee || 0.00005,
pool: "pump"
}
const response = await fetch("https://pumpportal.fun/api/trade-local", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
})
if (!response.ok) {
const errorText = await response.text()
throw new Error(
`Transaction creation failed: ${response.status} - ${errorText}`
)
}
return response
}
async function signAndSendTransaction(kit, tx, mintKeypair) {
try {
// Get the latest blockhash
const {
blockhash,
lastValidBlockHeight
} = await kit.connection.getLatestBlockhash()
// Update transaction with latest blockhash
tx.message.recentBlockhash = blockhash
// Sign the transaction
const signedTx = await kit.wallet.signTransaction(tx)
signedTx.sign([mintKeypair])
// Send and confirm transaction with options
const signature = await kit.connection.sendTransaction(signedTx, {
skipPreflight: false,
preflightCommitment: "confirmed",
maxRetries: 5
})
// Wait for confirmation
const confirmation = await kit.connection.confirmTransaction({
signature,
blockhash,
lastValidBlockHeight
})
if (confirmation.value.err) {
throw new Error(`Transaction failed: ${confirmation.value.err}`)
}
return signature
} catch (error) {
console.error("Transaction send error:", error)
if (error instanceof Error && "logs" in error) {
console.error("Transaction logs:", error.logs)
}
throw error
}
}
/**
* Launch a token on Pump.fun
* @param agent - SolanaAgentKit instance
* @param tokenName - Name of the token
* @param tokenTicker - Ticker of the token
* @param description - Description of the token
* @param imageUrl - URL of the token image
* @param options - Optional token options (twitter, telegram, website, initialLiquiditySOL, slippageBps, priorityFee)
* @returns - Signature of the transaction, mint address and metadata URI, if successful, else error
*/
export async function launchPumpFunToken(
agent,
tokenName,
tokenTicker,
description,
imageUrl,
options
) {
try {
const mintKeypair = Keypair.generate()
const metadataResponse = await uploadMetadata(
tokenName,
tokenTicker,
description,
imageUrl,
options
)
const response = await createTokenTransaction(
agent,
mintKeypair,
metadataResponse,
options
)
const transactionData = await response.arrayBuffer()
const tx = VersionedTransaction.deserialize(new Uint8Array(transactionData))
const signature = await signAndSendTransaction(agent, tx, mintKeypair)
return {
signature,
mint: mintKeypair.publicKey.toBase58(),
metadataUri: metadataResponse.metadataUri
}
} catch (error) {
console.error("Error in launchpumpfuntoken:", error)
if (error instanceof Error && "logs" in error) {
console.error("Transaction logs:", error.logs)
}
throw error
}
}