Reputation: 149
I'm trying to use solana-py to interact with a solana program where i don't have documentation about.
The program is the Solana Magic Eden NFT Marketplace . I already tried to get information about it from anchor but it has no data available.
My goal: I would like to list a NFT directly without the web-interface.
My test: As an example, i would like to list this NFT which i own: Robber#04977.
As i don't know anything about the program as their is no documentation available i looked into other transaction and found one which i tried to recreate but with my nft: Successful transaction.
I changed the Accounts, used my private key and created the transaction using solana-py: my failed transaction.
Please see edit below for current state.
Original code:
from solana.transaction import AccountMeta, Transaction, TransactionInstruction
from solana.rpc.types import TxOpts
from solana.account import Account
from solana.rpc.api import Client
from solana.publickey import PublicKey
from solana.keypair import Keypair
from getpass import getpass
import base58
# setup client
url = 'https://api.mainnet-beta.solana.com'
client = Client(url)
program = 'MEisE1HzehtrDpAAT8PnLHjpSSkRYakotTuJRPjTpo8'
# get account from private key
pwd = getpass('Chrome -> Phantom -> Settings -> Export private Key')
byte_array = base58.b58decode(pwd)
keypair = list(map(lambda b: int(str(b)), byte_array))[:]
initializer_account = Keypair(keypair[0:32])
# create transaction and sign it
txn = Transaction(recent_blockhash=client.get_recent_blockhash()['result']['value']['blockhash'], fee_payer=initializer_account.public_key)
txn.add(
TransactionInstruction(
keys=[
AccountMeta(pubkey=PublicKey(initializer_account.public_key), is_signer=True, is_writable=True),
AccountMeta(pubkey=PublicKey('GG24iCpytsz2nxei81FHyEyduQAxCAJHWkDLitwr9MxQ'), is_signer=False, is_writable=True),
AccountMeta(pubkey=PublicKey('3gS9AqTJ9adw23tZ87Hn1ccyYJ5KZ5tcoNQfYhCFu2e3'), is_signer=False, is_writable=True),
AccountMeta(pubkey=PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'), is_signer=False, is_writable=False),
AccountMeta(pubkey=PublicKey('11111111111111111111111111111111'), is_signer=False, is_writable=False),
],
program_id=PublicKey('MEisE1HzehtrDpAAT8PnLHjpSSkRYakotTuJRPjTpo8'),
data=bytes.fromhex('96d480ba740183710094357700000000ff') # sell für 2 Solana
)
)
txn.sign(initializer_account)
rpc_response = client.send_transaction(
txn,
initializer_account,
opts=TxOpts(skip_preflight=True, skip_confirmation=False)
)
The response contains the transaction id to my failed transaction.
{'jsonrpc': '2.0',
'result': 'NytmsBK59kckV3nGBsw6Vi9XAw8jkpkQGgHKCMYNFPYXLy57caNN7icNpMepofNsdncJ2BVziFJ82e8PKpH1EnV',
'id': 3}
The program log from solscan looks like this:
#1 Magic Eden NFT Marketplace instruction
> Program Magic Eden NFT Marketplace consumed 5829 of 200000 compute units
> Program returned error: Could not create program address with signer seeds: Provided seeds do not result in a valid address
Maybe it is some wrong data which i'm sending to the program. I just looked for historic transactions which were successful and used it for my transaction too.
edit: getting closer, but not yet done. I'm now also creating the instructions to create a account and to set authority. But these are done serial and not as an inner instruction.
from solana.transaction import AccountMeta, Transaction, TransactionInstruction
from solana.rpc.types import TxOpts
from solana.account import Account
from solana.rpc.api import Client
from solana.publickey import PublicKey
from solana.rpc.commitment import Recent, Root
from solana.keypair import Keypair
from solana.system_program import create_account, CreateAccountParams
from getpass import getpass
import base58
from spl.token.instructions import set_authority, SetAuthorityParams, AuthorityType
LAMPORTS_PER_SOL = 1000000000
url = 'https://api.mainnet-beta.solana.com'
client = Client(url)
pwd = getpass('Chrome -> Phantom -> Settings -> Export private Key')
# setup of accounts
program = 'MEisE1HzehtrDpAAT8PnLHjpSSkRYakotTuJRPjTpo8'
# get int based keypair of account
byte_array = base58.b58decode(pwd)
keypair = list(map(lambda b: int(str(b)), byte_array))[:]
initializer_account = Keypair(keypair[0:32])
token_account_robber = PublicKey('GG24iCpytsz2nxei81FHyEyduQAxCAJHWkDLitwr9MxQ')
# inner instruction: create account
from_account, new_account = initializer_account.public_key, Keypair().public_key
inner_instruction1 = create_account(
CreateAccountParams(
from_pubkey=from_account, new_account_pubkey=new_account,
lamports=int(0.00144768*LAMPORTS_PER_SOL), space=1, program_id=PublicKey('MEisE1HzehtrDpAAT8PnLHjpSSkRYakotTuJRPjTpo8'))
)
# make all accounts of this non signer and non writeable
inner_instruction1.keys[0].is_signer=False
inner_instruction1.keys[0].is_writable=False
inner_instruction1.keys[1].is_signer=False
inner_instruction1.keys[1].is_writable=False
# inner instruction: set authority
inner_instruction2 = set_authority(
SetAuthorityParams(
program_id=PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'),
account=token_account_robber,
authority=AuthorityType.ACCOUNT_OWNER,
current_authority=initializer_account.public_key,
new_authority=PublicKey('GUfCR9mK6azb9vcpsxgXyj7XRPAKJd4KMHTTVvtncGgp')
)
)
# combine all instructions
txn = Transaction(recent_blockhash=client.get_recent_blockhash()['result']['value']['blockhash'], fee_payer=initializer_account.public_key)
txn.add(
TransactionInstruction(
keys=[
AccountMeta(pubkey=PublicKey(initializer_account.public_key), is_signer=True, is_writable=True),
AccountMeta(pubkey=PublicKey('GG24iCpytsz2nxei81FHyEyduQAxCAJHWkDLitwr9MxQ'), is_signer=False, is_writable=True),
AccountMeta(pubkey=new_account, is_signer=False, is_writable=True),
AccountMeta(pubkey=PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'), is_signer=False, is_writable=False),
AccountMeta(pubkey=PublicKey('11111111111111111111111111111111'), is_signer=False, is_writable=False),
],
program_id=PublicKey('MEisE1HzehtrDpAAT8PnLHjpSSkRYakotTuJRPjTpo8'),
data=bytes.fromhex('96d480ba740183710094357700000000ff') # sell für 2 Solana
)
)
txn.add(inner_instruction1)
txn.add(inner_instruction2)
# sign and send
txn.sign(initializer_account)
rpc_response = client.send_transaction(
txn,
initializer_account,
opts=TxOpts(skip_preflight=True, skip_confirmation=False)
)
The 'rpc_reponse` contains the following:
{'jsonrpc': '2.0',
'result': 'HTjMcuUHDoE3BkhcpWnLA6xWScDFzS7zQxWzUtffjMUkrZxaRjwrVjr8ta2Hr2uKxSUDXMzkLGiWbodgZk5DoEX',
'id': 190}
The log from solscan:
#1 Magic Eden NFT Marketplace instruction
> Program Magic Eden NFT Marketplace consumed 8890 of 200000 compute units
> Program returned error: Could not create program address with signer seeds: Provided seeds do not result in a valid address
#2 System Program instruction
#3 Token Program instruction
Current problem: Added to the error in the log above the two new instructions (create account and set authority) are not inner instructions but just some instructions following the first instruction.
I have used anchor-py to get the idl of the program, but it is not available (anchorpy.error.IdlNotFoundError: IDL not found for program: MEisE1HzehtrDpAAT8PnLHjpSSkRYakotTuJRPjTpo8
).
Upvotes: 0
Views: 5561
Reputation: 701
thanks to this tweet I've found how to solve this issue:
anchorpy.error.IdlNotFoundError: IDL not found for program
After deploying your Anchor program, you have also to publish it's IDL using:
anchor idl init <programId> -f <target/idl/program.json>
Upvotes: 0
Reputation: 414
Disclaimer: I have never used the solana-py but looking at the accounts on the successful transaction I can see a difference. Account2 on the successful transaction is not an NFT token. ie. https://solscan.io/account/5KCdkEiCeQQ7XxZfFgQ2h4CaaMu72386LX7daxcSUyFo while on your failed transaction you are passing in https://solscan.io/token/3gS9AqTJ9adw23tZ87Hn1ccyYJ5KZ5tcoNQfYhCFu2e3 which is your actual NFT.
Upvotes: 1