bilix-software / solana-pump-fun

Facilitates the execution and simulation of buy and sell transactions for pump.fun on the Solana blockchain.
https://viper.bot
MIT License
100 stars 46 forks source link

Private key question #5

Closed gameuser1982 closed 4 months ago

gameuser1982 commented 5 months ago

const privateKey = 'your_private_key'; // Replace with your actual private key

Am I supposed to place my keypair here? If I just place the private key, how will it know the associated public key?

gameuser1982 commented 5 months ago

So correct me if I am wrong. All I need to do is take my mainnet wallet keypair .json and convert the keypair array inside the json to bs58 and then insert the bs58 private-public keypair where it says 'your_private_key' right?

bilix-software commented 5 months ago

The private key and public key are linked, so yes you only need to input the private key and the code will resolve that to a Keypair with a public and a private key. So yes if you convert the privatekey part of the keypair to bs58 and input it in the field, that should work. Check this stackexchange post for more info https://solana.stackexchange.com/questions/3259/splitting-a-solana-keypair-into-public-and-private-keys

gameuser1982 commented 5 months ago

The private key and public key are linked, so yes you only need to input the private key and the code will resolve that to a Keypair with a public and a private key. So yes if you convert the privatekey part of the keypair to bs58 and input it in the field, that should work. Check this stackexchange post for more info https://solana.stackexchange.com/questions/3259/splitting-a-solana-keypair-into-public-and-private-keys

I appreciate the reply back @bilix-software as I imagine you are quite busy. I did as you suggested and converted the private key part to bs58:

const fs = require('fs');
const bs58 = require('bs58');

const keypairArray = JSON.parse(fs.readFileSync('mainnet-keypair.json'));

const privateKeyArray = keypairArray.slice(0, 32);

const privateKeyUint8Array = Uint8Array.from(privateKeyArray);

const privateKeyBs58 = bs58.encode(privateKeyUint8Array);

console.log("BS58 Encoded Private Key:", privateKeyBs58);

I got my BS58 Private Key part.

Then I added it in to example.ts and also added in the following coin's mint address to test in simulation mode:

https://pump.fun/7wdyCEgWBjGQyTSChp74oZdYCSRgDfUHVKeitQeeNtFX

const mintAddress = '7wdyCEgWBjGQyTSChp74oZdYCSRgDfUHVKeitQeeNtFX'; //Replace with actual token mint address

I compiled and then ran, and I am getting a "Failed to retrieve coin data...". What am I missing? Is 7wdyCEgWBjGQyTSChp74oZdYCSRgDfUHVKeitQeeNtFX not the mint address?

Here is the full log:

candid@DESKTOP-5D7VSM9:~/solana-pump-fun$ npx tsc
candid@DESKTOP-5D7VSM9:~/solana-pump-fun$ node example.js
Error fetching coin data: AxiosError: Request failed with status code 503
    at settle (/home/candid/solana-pump-fun/node_modules/axios/dist/node/axios.cjs:1966:12)
    at IncomingMessage.handleStreamEnd (/home/candid/solana-pump-fun/node_modules/axios/dist/node/axios.cjs:3065:11)
    at IncomingMessage.emit (node:events:530:35)
    at endReadableNT (node:internal/streams/readable:1696:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
    at Axios.request (/home/candid/solana-pump-fun/node_modules/axios/dist/node/axios.cjs:3876:41)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  code: 'ERR_BAD_RESPONSE',
  config: {
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    },
    adapter: [ 'xhr', 'http' ],
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    env: { FormData: [Function], Blob: [class Blob] },
    validateStatus: [Function: validateStatus],
    headers: Object [AxiosHeaders] {
      Accept: '*/*',
      'Content-Type': undefined,
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0',
      'Accept-Language': 'en-US,en;q=0.5',
      'Accept-Encoding': 'gzip, deflate, br',
      Referer: 'https://www.pump.fun/',
      Origin: 'https://www.pump.fun',
      Connection: 'keep-alive',
      'Sec-Fetch-Dest': 'empty',
      'Sec-Fetch-Mode': 'cors',
      'Sec-Fetch-Site': 'cross-site',
      'If-None-Match': 'W/"43a-tWaCcS4XujSi30IFlxDCJYxkMKg"'
    },
    method: 'get',
    url: 'https://client-api-2-74b1891ee9f9.herokuapp.com/coins/7wdyCEgWBjGQyTSChp74oZdYCSRgDfUHVKeitQeeNtFX',
    data: undefined
  },
  request: <ref *1> ClientRequest {
    _events: [Object: null prototype] {
      abort: [Function (anonymous)],
      aborted: [Function (anonymous)],
      connect: [Function (anonymous)],
      error: [Function (anonymous)],
      socket: [Function (anonymous)],
      timeout: [Function (anonymous)],
      finish: [Function: requestOnFinish]
    },
    _eventsCount: 7,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    destroyed: true,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: true,
    maxRequestsOnConnectionReached: false,
    _defaultKeepAlive: true,
    useChunkedEncodingByDefault: false,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    strictContentLength: false,
    _contentLength: 0,
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    _closed: true,
    socket: TLSSocket {
      _tlsOptions: [Object],
      _secureEstablished: true,
      _securePending: false,
      _newSessionPending: false,
      _controlReleased: true,
      secureConnecting: false,
      _SNICallback: null,
      servername: 'client-api-2-74b1891ee9f9.herokuapp.com',
      alpnProtocol: false,
      authorized: true,
      authorizationError: null,
      encrypted: true,
      _events: [Object: null prototype],
      _eventsCount: 9,
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'client-api-2-74b1891ee9f9.herokuapp.com',
      _closeAfterHandlingError: false,
      _readableState: [ReadableState],
      _writableState: [WritableState],
      allowHalfOpen: false,
      _maxListeners: undefined,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: undefined,
      _server: null,
      ssl: [TLSWrap],
      _requestCert: true,
      _rejectUnauthorized: true,
      timeout: 5000,
      parser: null,
      _httpMessage: null,
      autoSelectFamilyAttemptedAddresses: [Array],
      [Symbol(alpncallback)]: null,
      [Symbol(res)]: [TLSWrap],
      [Symbol(verified)]: true,
      [Symbol(pendingSession)]: null,
      [Symbol(async_id_symbol)]: -1,
      [Symbol(kHandle)]: [TLSWrap],
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: Timeout {
        _idleTimeout: 5000,
        _idlePrev: [TimersList],
        _idleNext: [TimersList],
        _idleStart: 2171,
        _onTimeout: [Function: bound ],
        _timerArgs: undefined,
        _repeat: null,
        _destroyed: false,
        [Symbol(refed)]: false,
        [Symbol(kHasPrimitive)]: false,
        [Symbol(asyncId)]: 25,
        [Symbol(triggerId)]: 23
      },
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(shapeMode)]: true,
      [Symbol(kCapture)]: false,
      [Symbol(kSetNoDelay)]: false,
      [Symbol(kSetKeepAlive)]: true,
      [Symbol(kSetKeepAliveInitialDelay)]: 1,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(connect-options)]: [Object]
    },
    _header: 'GET /coins/7wdyCEgWBjGQyTSChp74oZdYCSRgDfUHVKeitQeeNtFX HTTP/1.1\r\n' +
      'Accept: */*\r\n' +
      'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0\r\n' +
      'Accept-Language: en-US,en;q=0.5\r\n' +
      'Accept-Encoding: gzip, deflate, br\r\n' +
      'Referer: https://www.pump.fun/\r\n' +
      'Origin: https://www.pump.fun\r\n' +
      'Connection: keep-alive\r\n' +
      'Sec-Fetch-Dest: empty\r\n' +
      'Sec-Fetch-Mode: cors\r\n' +
      'Sec-Fetch-Site: cross-site\r\n' +
      'If-None-Match: W/"43a-tWaCcS4XujSi30IFlxDCJYxkMKg"\r\n' +
      'Host: client-api-2-74b1891ee9f9.herokuapp.com\r\n' +
      '\r\n',
    _keepAliveTimeout: 0,
    _onPendingData: [Function: nop],
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 443,
      protocol: 'https:',
      options: [Object: null prototype],
      requests: [Object: null prototype] {},
      sockets: [Object: null prototype] {},
      freeSockets: [Object: null prototype],
      keepAliveMsecs: 1000,
      keepAlive: true,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      scheduling: 'lifo',
      maxTotalSockets: Infinity,
      totalSocketCount: 1,
      maxCachedSessions: 100,
      _sessionCache: [Object],
      [Symbol(shapeMode)]: false,
      [Symbol(kCapture)]: false
    },
    socketPath: undefined,
    method: 'GET',
    maxHeaderSize: undefined,
    insecureHTTPParser: undefined,
    joinDuplicateHeaders: undefined,
    path: '/coins/7wdyCEgWBjGQyTSChp74oZdYCSRgDfUHVKeitQeeNtFX',
    _ended: true,
    res: IncomingMessage {
      _events: [Object],
      _readableState: [ReadableState],
      _maxListeners: undefined,
      socket: null,
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      rawHeaders: [Array],
      rawTrailers: [],
      joinDuplicateHeaders: undefined,
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 503,
      statusMessage: 'Service Unavailable',
      client: [TLSSocket],
      _consuming: false,
      _dumped: false,
      req: [Circular *1],
      _eventsCount: 4,
      responseUrl: 'https://client-api-2-74b1891ee9f9.herokuapp.com/coins/7wdyCEgWBjGQyTSChp74oZdYCSRgDfUHVKeitQeeNtFX',
      redirects: [],
      [Symbol(shapeMode)]: true,
      [Symbol(kCapture)]: false,
      [Symbol(kHeaders)]: [Object],
      [Symbol(kHeadersCount)]: 18,
      [Symbol(kTrailers)]: null,
      [Symbol(kTrailersCount)]: 0
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    reusedSocket: false,
    host: 'client-api-2-74b1891ee9f9.herokuapp.com',
    protocol: 'https:',
    _redirectable: Writable {
      _events: [Object],
      _writableState: [WritableState],
      _maxListeners: undefined,
      _options: [Object],
      _ended: true,
      _ending: true,
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 0,
      _requestBodyBuffers: [],
      _eventsCount: 3,
      _onNativeResponse: [Function (anonymous)],
      _currentRequest: [Circular *1],
      _currentUrl: 'https://client-api-2-74b1891ee9f9.herokuapp.com/coins/7wdyCEgWBjGQyTSChp74oZdYCSRgDfUHVKeitQeeNtFX',
      [Symbol(shapeMode)]: true,
      [Symbol(kCapture)]: false
    },
    [Symbol(shapeMode)]: false,
    [Symbol(kCapture)]: false,
    [Symbol(kBytesWritten)]: 0,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    [Symbol(kOutHeaders)]: [Object: null prototype] {
      accept: [Array],
      'user-agent': [Array],
      'accept-language': [Array],
      'accept-encoding': [Array],
      referer: [Array],
      origin: [Array],
      connection: [Array],
      'sec-fetch-dest': [Array],
      'sec-fetch-mode': [Array],
      'sec-fetch-site': [Array],
      'if-none-match': [Array],
      host: [Array]
    },
    [Symbol(errored)]: null,
    [Symbol(kHighWaterMark)]: 16384,
    [Symbol(kRejectNonStandardBodyWrites)]: false,
    [Symbol(kUniqueHeaders)]: null
  },
  response: {
    status: 503,
    statusText: 'Service Unavailable',
    headers: Object [AxiosHeaders] {
      connection: 'keep-alive',
      server: 'Cowboy',
      date: 'Sun, 09 Jun 2024 12:05:40 GMT',
      'content-length': '506',
      'report-to': '{"group":"heroku-nel","max_age":3600,"endpoints":[{"url":"https://nel.heroku.com/reports?ts=1717934741&sid=e11707d5-02a7-43ef-b45e-2cf4d2036f7d&s=Vcm4SmtdE3lMVfjaizfti%2FiRoSN%2F7LTjnmZ2i%2FGF1R0%3D"}]}',
      'reporting-endpoints': 'heroku-nel=https://nel.heroku.com/reports?ts=1717934741&sid=e11707d5-02a7-43ef-b45e-2cf4d2036f7d&s=Vcm4SmtdE3lMVfjaizfti%2FiRoSN%2F7LTjnmZ2i%2FGF1R0%3D',
      nel: '{"report_to":"heroku-nel","max_age":3600,"success_fraction":0.005,"failure_fraction":0.05,"response_headers":["Via"]}',
      'content-type': 'text/html; charset=utf-8',
      'cache-control': 'no-cache, no-store'
    },
    config: {
      transitional: [Object],
      adapter: [Array],
      transformRequest: [Array],
      transformResponse: [Array],
      timeout: 0,
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      maxBodyLength: -1,
      env: [Object],
      validateStatus: [Function: validateStatus],
      headers: [Object [AxiosHeaders]],
      method: 'get',
      url: 'https://client-api-2-74b1891ee9f9.herokuapp.com/coins/7wdyCEgWBjGQyTSChp74oZdYCSRgDfUHVKeitQeeNtFX',
      data: undefined
    },
    request: <ref *1> ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: true,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: true,
      maxRequestsOnConnectionReached: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: false,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      strictContentLength: false,
      _contentLength: 0,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      _closed: true,
      socket: [TLSSocket],
      _header: 'GET /coins/7wdyCEgWBjGQyTSChp74oZdYCSRgDfUHVKeitQeeNtFX HTTP/1.1\r\n' +
        'Accept: */*\r\n' +
        'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0\r\n' +
        'Accept-Language: en-US,en;q=0.5\r\n' +
        'Accept-Encoding: gzip, deflate, br\r\n' +
        'Referer: https://www.pump.fun/\r\n' +
        'Origin: https://www.pump.fun\r\n' +
        'Connection: keep-alive\r\n' +
        'Sec-Fetch-Dest: empty\r\n' +
        'Sec-Fetch-Mode: cors\r\n' +
        'Sec-Fetch-Site: cross-site\r\n' +
        'If-None-Match: W/"43a-tWaCcS4XujSi30IFlxDCJYxkMKg"\r\n' +
        'Host: client-api-2-74b1891ee9f9.herokuapp.com\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: nop],
      agent: [Agent],
      socketPath: undefined,
      method: 'GET',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      joinDuplicateHeaders: undefined,
      path: '/coins/7wdyCEgWBjGQyTSChp74oZdYCSRgDfUHVKeitQeeNtFX',
      _ended: true,
      res: [IncomingMessage],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: 'client-api-2-74b1891ee9f9.herokuapp.com',
      protocol: 'https:',
      _redirectable: [Writable],
      [Symbol(shapeMode)]: false,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype],
      [Symbol(errored)]: null,
      [Symbol(kHighWaterMark)]: 16384,
      [Symbol(kRejectNonStandardBodyWrites)]: false,
      [Symbol(kUniqueHeaders)]: null
    },
    data: '<!DOCTYPE html>\n' +
      '\t<html>\n' +
      '\t  <head>\n' +
      '\t\t<meta name="viewport" content="width=device-width, initial-scale=1">\n' +
      '\t\t<meta charset="utf-8">\n' +
      '\t\t<title>Application Error</title>\n' +
      '\t\t<style media="screen">\n' +
      '\t\t  html,body,iframe {\n' +
      '\t\t\tmargin: 0;\n' +
      '\t\t\tpadding: 0;\n' +
      '\t\t  }\n' +
      '\t\t  html,body {\n' +
      '\t\t\theight: 100%;\n' +
      '\t\t\toverflow: hidden;\n' +
      '\t\t  }\n' +
      '\t\t  iframe {\n' +
      '\t\t\twidth: 100%;\n' +
      '\t\t\theight: 100%;\n' +
      '\t\t\tborder: 0;\n' +
      '\t\t  }\n' +
      '\t\t</style>\n' +
      '\t  </head>\n' +
      '\t  <body>\n' +
      '\t\t<iframe src="//www.herokucdn.com/error-pages/application-error.html"></iframe>\n' +
      '\t  </body>\n' +
      '\t</html>'
  }
}
Failed to retrieve coin data...
bilix-software commented 5 months ago

Ah it seems they have changed their api endpoint. Pull the last commit to see the new endpoint or change the url in api.ts to const url = https://frontend-api.pump.fun/coins/${mintStr};

gameuser1982 commented 5 months ago

Ah it seems they have changed their api endpoint. Pull the last commit to see the new endpoint or change the url in api.ts to const url = https://frontend-api.pump.fun/coins/${mintStr};

@bilix-software thanks again for this update. That did the fix the mint issue, but I am having problems with the private key now. I am getting this error:

candid@DESKTOP-5D7VSM9:~/solana-pump-fun$ npx tsc
candid@DESKTOP-5D7VSM9:~/solana-pump-fun$ node example.js
Error: bad secret key size
    at Keypair.fromSecretKey (/home/candid/solana-pump-fun/node_modules/@solana/web3.js/lib/index.cjs.js:8805:13)
    at /home/candid/solana-pump-fun/src/utils.js:21:34
    at Generator.next (<anonymous>)
    at /home/candid/solana-pump-fun/src/utils.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (/home/candid/solana-pump-fun/src/utils.js:4:12)
    at getKeyPairFromPrivateKey (/home/candid/solana-pump-fun/src/utils.js:20:12)
    at /home/candid/solana-pump-fun/src/swap.js:28:70
    at Generator.next (<anonymous>)
    at fulfilled (/home/candid/solana-pump-fun/src/swap.js:5:58)

Here's what I attempted to do to fix the problem. Since it's complaining about the key size I did some additional error check in my BS58 conversion code:

const fs = require('fs');
const bs58 = require('bs58');

const keypairArray = JSON.parse(fs.readFileSync('mainnet-keypair.json', 'utf8'));

if (keypairArray.length !== 64) {
  throw new Error('Invalid keypair length. The keypair must be 64 bytes long.');
}

const keypairUint8Array = Uint8Array.from(keypairArray);

const privateKeyArray = keypairUint8Array.slice(0, 32);

const privateKeyBs58 = bs58.encode(privateKeyArray);

console.log("Base58 Encoded Private Key:", privateKeyBs58);

Despite the additional validation, it's still spitting out the same bs58 private key that is not being accepted by the solana-pump-fun due to "bad secret key size"

As a sanity check I went back to: https://solana.stackexchange.com/questions/3259/splitting-a-solana-keypair-into-public-and-private-keys

and loaded the keypair array listed in the stackexchange question ([4,182,130,247,119,117,227,207,112,73,170,126,222,197,244,99,215,107,255,202,33,43,36,17,104,111,157,246,196,192,174,95,240,23,238,206,118,215,154,238,229,96,11,37,156,123,51,223,5,231,17,117,86,136,103,14,75,95,175,132,148,54,1,46]) into a json file and loaded it with my BS58 conversion script. It split out the same base 58 private key KQ3cGFBdjJuRsB7U1K4to6cTGBPhgukqPgsi5pryr8v that's listed in solana.stackexchange.com solution so I know my conversion script is right.

I also know that mainnet-keypair.json contains a valid keypair array, with real mainnet Solana inside it. I can send and receive SOL with this keypair using the Solana CLI.

Yet when I do a BS58 private key extraction, the solana-pump-fun typescript rejects it. Any idea why?

bilix-software commented 5 months ago

Hi again, sorry for your continued issues. Try encoding the entire secretkey, a valid encoded secret key should be 88 characters long. Like so: const privateKey = bs58.encode(keypair.secretKey);

gameuser1982 commented 5 months ago

Hi again, sorry for your continued issues. Try encoding the entire secretkey, a valid encoded secret key should be 88 characters long. Like so: const privateKey = bs58.encode(keypair.secretKey);

@bilix-software Don't apologize, it's not fair to you since you put forth a lot of effort to make this great framework. It's just Murphy's Law rearing its ugly head.

Here's the rewritten BS58 conversion script. Now it encodes the entire private key pair to BS58:

const fs = require('fs');
const bs58 = require('bs58');
const { Keypair } = require('@solana/web3.js');

const keypairArray = JSON.parse(fs.readFileSync('/home/candid/.config/solana/mainnet-keypair.json', 'utf8'));

if (keypairArray.length !== 64) {
  throw new Error('Invalid keypair length. The keypair must be 64 bytes long.');
}

const keypairUint8Array = Uint8Array.from(keypairArray);

const keypair = Keypair.fromSecretKey(keypairUint8Array);

const privateKey = bs58.encode(keypair.secretKey);

const characterCount = privateKey.length;

console.log("Base58 Encoded Keypair:", privateKey);
console.log("Character Count of Base58 Encoded Keypair:", characterCount);

With my keypair that has real SOL inside it, the character count of the BS58 keypair is 87 characters, not 88 😅

Likewise, the keypair array from the stackexchange question is also 87 characters once encoded to BS58, though the extracted private key is exactly the same as the listed solution in stackexchange which I noted earlier. As the character length is 1 character off, am I doing something wrong?

bilix-software commented 5 months ago
const fs = require('fs');
const bs58 = require('bs58');
const { Keypair } = require('@solana/web3.js');

// Define the path to the keypair file
const keypairFilePath = './example-keypair.json';

try {
    // Try to read the keypair from the file
    const keypairArray = JSON.parse(fs.readFileSync(keypairFilePath, 'utf8'));

    if (keypairArray.length !== 64) {
      throw new Error('Invalid keypair length. The keypair must be 64 bytes long.');
    }

    const keypairUint8Array = Uint8Array.from(keypairArray);
    const keypair = Keypair.fromSecretKey(keypairUint8Array);
    const privateKey = bs58.encode(keypair.secretKey);
    const characterCount = privateKey.length;

    console.log("Base58 Encoded Keypair:", privateKey);
    console.log("Character Count of Base58 Encoded Keypair:", characterCount);
} catch (error) {
    // If the file doesn't exist or an error occurs, generate a new keypair
    console.log('File not found or is invalid, generating new keypair...');
    const newKeypair = Keypair.generate();
    const newKeypairArray = Array.from(newKeypair.secretKey);

    // Save the new keypair to JSON
    fs.writeFileSync(keypairFilePath, JSON.stringify(newKeypairArray, null, 2), 'utf8');

    const newPrivateKey = bs58.encode(newKeypair.secretKey);
    const newCharacterCount = newPrivateKey.length;

    console.log("New Base58 Encoded Keypair:", newPrivateKey);
    console.log("Character Count of Base58 Encoded Keypair:", newCharacterCount);
}

I've used your code to create the following script that tries to read from a file and if it does not exists generate a new keypair and save that to json. I've not instantiated a file but you can see that the keypair generated from the solana web3 library generates a 88 character long keypair if encoded with bs58 in my output below. This keypair you should then also be able to import in phantom or another wallet of choice.

image

gameuser1982 commented 5 months ago

@bilix-software

I just ran your modified script and it is still generating an 87 character keypair.

candid@DESKTOP-5D7VSM9:~/bs58$ node convertKey3.js
File not found or is invalid, generating new keypair...
New Base58 Encoded Keypair: ikiBrFizVzd2PE5Tu1xcNhrJ8siWu1CDtKThWa58k7YeKkCJVPUz2r4s7u5xSTCgr369BYyNuPFby6xEz4QsiWU
Character Count of Base58 Encoded Keypair: 87

So we've now established that there is either a problem with my operating system (I'm using Ubuntu 22.04.4 LTS as my subsystem under WSL2 with Windows 10 as the host OS) or the version of Solana (solana-cli 1.18.13 (src:12fe7d39; feat:4215500110, client:SolanaLabs) I am using.

I'm going to update both and try again and then continue writing this post.

After upgrading both I am now generating an 88 character keypair. It looks like I was lucky enough to use a version of Solana CLI that was generating a malformed keypair.

I then modified your BS58 conversion script:

const fs = require('fs');
const bs58 = require('bs58');
const { Keypair } = require('@solana/web3.js');

const keypairFilePath = '/home/candid/.config/solana/mainnet-keypair.json';

try {
    // Try to read the keypair from the file
    const keypairArray = JSON.parse(fs.readFileSync(keypairFilePath, 'utf8'));

    if (keypairArray.length !== 64) {
        throw new Error('Invalid keypair length. The keypair must be 64 bytes long.');
    }

    const privateKeyBytes = keypairArray.slice(0, 32); // Slice to get the private key
    const publicKeyBytes = keypairArray.slice(32); // Slice to get the public key
    const keypairBytes = keypairArray;

    const privateKey = bs58.encode(privateKeyBytes);
    const publicKey = bs58.encode(publicKeyBytes);
    const keypair = bs58.encode(keypairBytes);

    console.log("Base58 Encoded Keypair:", keypair);
    console.log("Character Count of Base58 Encoded Keypair:", keypair.length);

    console.log("Base58 Encoded Private Key:", privateKey);
    console.log("Base58 Encoded Public Key:", publicKey);

    const characterCountPrivateKey = privateKey.length;
    const characterCountPublicKey = publicKey.length;

    console.log("Character Count of Base58 Encoded Private Key:", characterCountPrivateKey);
    console.log("Character Count of Base58 Encoded Public Key:", characterCountPublicKey);
} catch (error) {
    // If the file doesn't exist or an error occurs, generate a new keypair
    console.log('File not found or is invalid, generating new keypair...');
    const newKeypair = Keypair.generate();
    const newKeypairArray = Array.from(newKeypair.secretKey);

    fs.writeFileSync(keypairFilePath, JSON.stringify(newKeypairArray, null, 2), 'utf8');

    const newPrivateKeyBytes = newKeypairArray.slice(0, 32); // Slice to get the private key
    const newPublicKeyBytes = newKeypairArray.slice(32); // Slice to get the public key

    const newPrivateKey = bs58.encode(newPrivateKeyBytes);
    const newPublicKey = bs58.encode(newPublicKeyBytes);

    console.log("Base58 Encoded Keypair:", bs58.encode(newKeypairArray));
    console.log("Character Count of Base58 Encoded Keypair:", bs58.encode(newKeypairArray).length);

    console.log("New Base58 Encoded Private Key:", newPrivateKey);
    console.log("Character Count of New Base58 Encoded Private Key:", newPrivateKey.length);

    console.log("New Base58 Encoded Public Key:", newPublicKey);
    console.log("Character Count of New Base58 Encoded Public Key:", newPublicKey.length);
}

Now it gives me the complete keypair in BS58, and gives me the character count. Then it splits it from array the private key part, and public key part. It gives me the character count.

I am going to intentionally expose the private key and give you the output:

Base58 Encoded Keypair: 3UbaSGJaLyNXdDkgZeAWSMfdL157NynbV5ivnRaPutT7doztycg39KLa1LfYiDMJr5ftcEenWZ4mRgzX92s8rDjt
Character Count of Base58 Encoded Keypair: 88
Base58 Encoded Private Key: 9LPVHLkF6zY9AMvzDY4Mswv4AXkasvy4qVSncahJVwC4
Base58 Encoded Public Key: Dryct86kv5UMjVsiERXwAVgCbvmq7xdeBVyDDXN8oky4
Character Count of Base58 Encoded Private Key: 44
Character Count of Base58 Encoded Public Key: 44

I am also attaching the .json file

mainnet-keypair.json

Now I can see that the public key in BS58 from the script matches what I see when I type solana address

Everything should work right? Well unfortunately when I take that private key part and plug it into example.ts on the pump fun framework and recompile, it still complains of an invalid length of the private key.

Another curveball I discovered is when I removed the .json file and had the script generate a new keypair, and it generated an invalid character length key. I just generated this one:

candid@DESKTOP-5D7VSM9:~/bs58$ node convertKey5.js
File not found or is invalid, generating new keypair...
Base58 Encoded Keypair: AzEewnqMiwj5JQvCtUXtBhDbJLzhzj9MyBmgycUPjzNiwT8upK2gxxCxpykhZ7umfxKBGvQTuGoVrM8L6LacANj
Character Count of Base58 Encoded Keypair: 87
New Base58 Encoded Private Key: act46NeQDin1e5s9JzaGvZWidanzLcRz3ZpEwHRANnu
Character Count of New Base58 Encoded Private Key: 43
New Base58 Encoded Public Key: HRKULLhx6si3Ko2ukU6cXW2pt1YsCgfShQZ1jWrbEmAP
Character Count of New Base58 Encoded Public Key: 44

This seems to be a fluke though, as I generated a few more and they seem to be giving me a valid length:

candid@DESKTOP-5D7VSM9:~/bs58$ node convertKey5.js
File not found or is invalid, generating new keypair...
Base58 Encoded Keypair: 3imk6MXFPtWUky4uMHyAG7NNXnPk9D6J4q4qTy7hRoTT8kfY2YHwVgfDrvpK4AvjBz7TVm37aSWm96djBgWvorao
Character Count of Base58 Encoded Keypair: 88
New Base58 Encoded Private Key: AA79WfquvXqAKWanWgG7HEk63wkpSuXqePaUuR9ePFY4
Character Count of New Base58 Encoded Private Key: 44
New Base58 Encoded Public Key: ASFux5evD38qJtxHdDVYJGEyJnLAEBUVECm9CjwfDWHy
Character Count of New Base58 Encoded Public Key: 44

I never thought keypair generation, slicing, and private key extraction would be such a giant hairball of a problem.

bilix-software commented 5 months ago

Hmm interesting journey you have been on 😅, is it finally working for you now?

gameuser1982 commented 5 months ago

@bilix-software

Unfortunately no, it's still not working. Even this one with 88 characters isn't working:

Base58 Encoded Keypair: 3UbaSGJaLyNXdDkgZeAWSMfdL157NynbV5ivnRaPutT7doztycg39KLa1LfYiDMJr5ftcEenWZ4mRgzX92s8rDjt
Character Count of Base58 Encoded Keypair: 88
Base58 Encoded Private Key: 9LPVHLkF6zY9AMvzDY4Mswv4AXkasvy4qVSncahJVwC4
Base58 Encoded Public Key: Dryct86kv5UMjVsiERXwAVgCbvmq7xdeBVyDDXN8oky4
Character Count of Base58 Encoded Private Key: 44
Character Count of Base58 Encoded Public Key: 44

When I insert the BS58 private key part 9LPVHLkF6zY9AMvzDY4Mswv4AXkasvy4qVSncahJVwC4 it still tells me the private key length is wrong.

mainnet-keypair.json

Is this private key working on your setup?

gameuser1982 commented 5 months ago

@bilix-software

Since I thought maybe my Ubuntu WSL2 sub system is the culprit, I setup node and other dependencies on my Windows 10 host OS (Windows 10 Pro 22H2 build 19045.4291)

I generated a new keypair:

PS C:\bs58> node convertKey5.js
File not found or is invalid, generating new keypair...
Base58 Encoded Keypair: 3h9EE9sM9EFa6qWeTNWkbW5RKApfiJwjaab3VkFDoEsixf2Edt7SgLQjKvgkFnpdkaZN15KhFrNvuSPKcTo9c6ok
Character Count of Base58 Encoded Keypair: 88
New Base58 Encoded Private Key: A4cyucniiaGYhZ59feNbppvCsxY7Fjnh8vEWP2hhxCnX
Character Count of New Base58 Encoded Private Key: 44
New Base58 Encoded Public Key: GW9Fx7FH5prSc72FAm9BksK17hzfR1wLoa2VMYVqNR1U
Character Count of New Base58 Encoded Public Key: 44

And below is the same keypair as above in its byte array format:

mainnet-keypair2.json

Then I inserted A4cyucniiaGYhZ59feNbppvCsxY7Fjnh8vEWP2hhxCnX into example.ts plus the mint address and am running in simulation mode like every other time except this time it's in Windows not Ubuntu:

PS C:\solana-pump-fun> npx tsc
PS C:\solana-pump-fun> node example.js
Error: bad secret key size
    at Keypair.fromSecretKey (C:\solana-pump-fun\node_modules\@solana\web3.js\lib\index.cjs.js:8805:13)
    at C:\solana-pump-fun\src\utils.js:21:34
    at Generator.next (<anonymous>)
    at C:\solana-pump-fun\src\utils.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (C:\solana-pump-fun\src\utils.js:4:12)
    at getKeyPairFromPrivateKey (C:\solana-pump-fun\src\utils.js:20:12)
    at C:\solana-pump-fun\src\swap.js:28:70
    at Generator.next (<anonymous>)
    at fulfilled (C:\solana-pump-fun\src\swap.js:5:58)
PS C:\solana-pump-fun> 

I have completely exhausted all my ideas on how to resolve this problem. What could be going wrong?

bilix-software commented 5 months ago

So you want to input the encoded keypair of 88 chars into the private key. This is the same size as you get when you export from for example Phantom. If I input 3h9EE9sM9EFa6qWeTNWkbW5RKApfiJwjaab3VkFDoEsixf2Edt7SgLQjKvgkFnpdkaZN15KhFrNvuSPKcTo9c6ok it sims for me (obviously unsuccessful).

I'll add some comments to the file for future reference so people know how to generate it better.

gameuser1982 commented 4 months ago

@bilix-software

Indeed the private keypair works. So did I misunderstand when I thought it only would need the private key part of the pair and that it would resolve the public key part on its own?

I am testing in simulation with the following coin:

https://pump.fun/9YAYKEGwE1XmAGYm2HNMipvesPmqGBwuowUW2sqdpump

I placed the following for the mint address:

9YAYKEGwE1XmAGYm2HNMipvesPmqGBwuowUW2sqdpump

and inserted the keypair 3h9EE9sM9EFa6qWeTNWkbW5RKApfiJwjaab3VkFDoEsixf2Edt7SgLQjKvgkFnpdkaZN15KhFrNvuSPKcTo9c6ok

I recompiled and ran:

candid@DESKTOP-5D7VSM9:~/solana-pump-fun$ npx tsc
candid@DESKTOP-5D7VSM9:~/solana-pump-fun$ node example.js
{
  context: { apiVersion: '1.18.15', slot: 271715936 },
  value: {
    accounts: null,
    err: 'AccountNotFound',
    innerInstructions: null,
    logs: [],
    returnData: null,
    unitsConsumed: 0
  }
}

Is this expected behavior? I am not sure how to interpret the "AccountNotFound" error. Is it because there is no SOL associated with the keypair, or does it interpret the MintAddress as not valid?

bilix-software commented 4 months ago

Yeah, that is normal if you try simulating for an account that doesn't have any balance. That's not because of the mint publickey.

gameuser1982 commented 4 months ago

@bilix-software

I confirm that simulation works after I add SOL to my generated wallet. Thank you again for your patience and for developing this framework.