rckprtr/pumpdotfun-sdk

Unable to buy/sell - message: 'Curve is complete'

Closed this issue · 2 comments

@rckprtr, sorry to do this to you, but some things just don't make a lot of sense.

Let's say no modifications have been made to the createAndBuy function, and 1.5 SOL was used to initially buy tokens. The bonding curve would be completed since all the tokens have been bought.

Bonding Curve Account:

complete: true
discriminator: 6966180631402821399n
realSolReserves: 1469351843n  <---- 1.5 SOL (minus slippage fees or pumpfun fees?)
realTokenReserves: 0n    <---- No tokens available
tokenTotalSupply: 1000000000000000n
virtualSolReserves: 31469351843n
virtualTokenReserves: 1022900000000000n

I've noticed that after the tokens have been bought, the sell function won't work because this error appears:
message: 'Curve is complete'

Explanation:

From my understanding, the issue arises because the bonding curve mechanism is designed to indicate completion when all tokens are bought. In this scenario, spending 1.5 SOL results in buying up all available tokens, leaving no tokens for further transactions. This state is reflected in the complete: true status in the bonding curve account. I'm assuming the issue lies in the getBuyPrice & getSellPrice.

So, when the bonding curve is marked as complete, this will not allow anymore tokens for future transactions, causing the sell function to throw the "Curve is complete" error.

image
image

Additional Details:

Network: devnet
Quicknode API
Node.js

Code:

async function main() {
  const BUY_SOL_AMOUNT = BigInt(1.5 * LAMPORTS_PER_SOL);

  // Initialize mint key pair
  const mintKeypair = initializeMintKeypair();

  let bondingCurveAccount = await pumpFunSDK.getBondingCurveAccount(mintKeypair.publicKey);
  if (!bondingCurveAccount) {
    const result = await pumpFunSDK.createAndBuy(owner, mintKeypair, createTokenMetadata, BUY_SOL_AMOUNT);

    if (result.success) { 
      console.log('-----Success Token Created!-----');
      console.log(`https://pump.fun/${mintKeypair.publicKey.toBase58()}`);
      await getSPLBalance(mintKeypair, owner);
    }
  }
}

function initializeMintKeypair() {
  console.log('-----Initialize Mint Wallet-----');
  let mintKeypair;
  try {
    // Read from file
    const keypairInfo = getKeypairInfo();
    mintKeypair = Keypair.fromSecretKey(bs58.decode(keypairInfo.secretKey));
    console.log('Using existing keypair:', keypairInfo.publicKey);
  } catch (error) {
    console.log('No existing keypair found. Creating a new one.');
    saveMintKeypair(mint);
    mintKeypair = mint;
  }
  return mintKeypair;
}

Interesting, I minted a new token on devnet:

These are the params assigned to my Bonding Curve with 0 buys, you can do the same and pass in 0n as the buy amount. The realTokenReserves is much lower then it is on mainnet

Bonding curve after create and buy BondingCurveAccount {
  discriminator: 6966180631402821399n,
  virtualTokenReserves: 1073000000000000n,
  virtualSolReserves: 30000000000n,
  realTokenReserves: 50100000000000n,
  realSolReserves: 0n,
  tokenTotalSupply: 1000000000000000n,
  complete: false
}

So I decided to check Global Params to see if this was correct, these params get assigned to the bonding curve when its first created.

GlobalAccount {
  discriminator: 9183522199395952807n,
  initialized: true,
  authority: PublicKey [PublicKey(DCpJReAfonSrgohiQbTmKKbjbqVofspFRHz9yQikzooP)] {
    _bn: <BN: b5531d6246f2015e72621c71ebf9304871dd8bbcf6f6c714948be6ddbd1e6ff2>
  },
  feeRecipient: PublicKey [PublicKey(68yFSZxzLWJXkxxRGydZ63C6mHx1NLEDWmwN9Lb5yySg)] {
    _bn: <BN: 4c5519e9876412b852caf722a4281dcd6b846a0a1275d13aa2969224e85b65b1>
  },
  initialVirtualTokenReserves: 1073000000000000n,
  initialVirtualSolReserves: 30000000000n,
  initialRealTokenReserves: 50100000000000n,
  tokenTotalSupply: 1000000000000000n,
  feeBasisPoints: 100n
}

Looks like its accurate.

Then I decided to chart it out in Python
image

According to that the max SOL for this bonding curve is 1.466~ SOL. So buying 1.5 SOL would buy out the entire bonding curve on devnet and complete it.

The function you pointed out throws an exception when the bonding curve account is reporting the bonding curve is actually complete and Im only reading on-chain data to determine this.

It looks like pump.fun is either testing out a new curve or set the devnet to a really low realTokenReserves as an experiment.

The mainnet initial real token reserve I believe is 793100000000000 and on devnet its now 50100000000000

One more thing, this is the error message you get when trying to buy/sell on a completed bonding curve on chain:

Program log: AnchorError thrown in programs/pump/src/lib.rs:227. Error Code: BondingCurveComplete. Error Number: 6005. Error Message: The bonding curve has completed and liquidity migrated to raydium..',

@rckprtr thank you for your detailed response.
So, if it takes 1.5 SOL to buy out all the tokens on devnet, how much would it take to buy out all the tokens on mainnet given the differences in initial real token reserves? Also, do you think selling will be affected if all the tokens have been depleted?