2

CODE

keypair = Keypair.generate()
key = keypair.secret_key

This secret key isn't compatible in phantom wallet. I figured that the phantom private key can be converted to Keypair compatible secret key by converting the first 32 bytes of the private key to base58.

base58.b58decode(phantom_key[:32])

My question is how do I do the opposite i.e. convert Keypair secret key to Phantom compatible private key?

3 Answers 3

2

I solved this today and the issue for me was with how I was generating the PrivateKey. The private key is a combination of the private+public key in bytes and this is then base 58 decoded here is my solution below.

from solana.rpc.api import Client, Keypair
import base58
from dotenv import dotenv_values

config = dotenv_values(".env")
client = Client(config["RPC_URL"])  #You can directly use the RPC_URL here without using dotenv

# Check if the client is connected to the cluster
if client:
    print("Connected to Solana cluster.")
else:
    print("Unable to connect to Solana cluster.")
new_account = Keypair()
#print(new_account.pubkey(), new_account.secret())`
wallet_address = new_account.pubkey()

private_key_bytes = new_account.secret()
public_key_bytes = bytes(new_account.pubkey())
encoded_keypair= private_key_bytes+public_key_bytes
private_key= base58.b58encode(encoded_keypair).decode()
print("Wallet Address: ",wallet_address)
print("Private Key: ",private_key)
2

Since Keypair.generate() doesn't even exist anymore, and the class itself has been moved into solders.py, here's an up-to-date(solana.py v0.32, solders v0.20) solution:

I tried all of this and a lot more, and noticed that Keypair.secret() doesn't look right. Because I assumed Keypair.secret() is the key. But it's only 32 bytes, and the key is 64 bytes.

As seen in the auto-tests here, solders.keypair.Keypair can actually be type-cast to bytes: bytes(Keypair()) https://github.com/kevinheavey/solders/blob/16656d9e508c5ed9bd237fd94a1c7bfa45eef9be/tests/test_keypair.py#L26

Doing so gives you the full 64 bytes of the private key.

# typecast whole Keypair object, not just Keypair.secret(). Very obvious, I know.
rawPK = bytes(solders.keypair.Keypair()) 
pk = base58.b58encode(rawPK).decode()

To then restore a keypair from this private key:

keypair = solders.keypair.Keypair.from_base58_string(pk)

Here's a complete example of how to export and import back a keypair:

import base58
import solders

keypair = solders.keypair.Keypair() # generates new keypair
generatedAddr = keypair.pubkey()

rawPK = bytes(keypair) 
pk = base58.b58encode(rawPK).decode()

restoredKeypair = solders.keypair.Keypair.from_base58_string(pk)
restoredAddr = restoredKeypair.pubkey()
restoredCorrectly = (restoredAddr == generatedAddr)
print(restoredCorrectly)

@Henry Tirla also already faced the same issue and got the right idea in his answer, but of course this is Solana SO, so I have 0 rep here and can't do anything. Awesome idea to add so much separation to blockchain sub-Stacks.

1

Keypair.generate() generates a 64 byte key. To get the private key which is compatible with Phantom, use base58.base58encode().

 import base58
 keypair = Keypair.generate()
 phantom_key = base58.b58encode(keypair.secret_key)

If we b58encode only the last 32 bytes, we get the public key.

pub_key = base58.b58encode(keypair.secret_key[32:]) # same as keypair.public_key

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.