Most of client side interaction with Solana Programs is done in Typescript for now. That makes sense, because most frontend frameworks are built on top of Javascript.
But what if you want to use Python to interact with your program ? Let's see how this can be done in this short tutorial.
The library we'll be using is called AnchorPy, and was made by Kevin Heavey.
Link to the AnchorPy documentation: https://kevinheavey.github.io/anchorpy/
Let's create some tests for an Anchor program in Python. Here's a link to the program's repo we will the interacting with.
Install AnchorPy
First of all, install anchorpy and solders:
pip3 install anchorpy
pip3 install solders
Now, let's create a test file at tests/test.py
.
First of all, let's import some dependencies:
import asyncio
from anchorpy import create_workspace, close_workspace, Context
from solders.system_program import ID as SYS_PROGRAM_ID
from solders.pubkey import Pubkey
from solders.keypair import Keypair
from solders.sysvar import RENT
Testing our Anchor program
Our code will compose of a base that looks like this:
async def main():
# Read the deployed program from the workspace.
workspace = create_workspace()
# The program from the workspace we want to use
program = workspace["seahorse"]
# Close all HTTP clients in the workspace.
await close_workspace(workspace)
asyncio.run(main())
Ok, now we can get to our test's logic. We have three instructions in our Anchor program. Let's get through them and document everything that is happening.
First, we define the two Program addresses for the Token program and the Associated Token Program. Then we generate a Keypair for the Token Mint we're going to create afterwards.
TOKEN_PROGRAM_ID = Pubkey.from_string("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
ASSOCITAED_TOKEN_PROGRAM_ID = Pubkey.from_string("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")
# Create a Mint keypair. This will be our token mint.
mint = Keypair()
Invoking instructions
Now, we call the create_token instruction from our program and print the transaction signature.
create_token = await program.rpc["create_token"](ctx=Context(accounts={
"mint": mint.pubkey(),
"signer": program.provider.wallet.payer.pubkey(),
"system_program": SYS_PROGRAM_ID,
"rent": RENT,
"token_program": TOKEN_PROGRAM_ID
}, signers=[program.provider.wallet.payer, mint]))
print("Create token signature: ", create_token)
You may see some similarities with the Typescript Anchor library here. "create_token" is the instruction to be executed and the "accounts" context are the accounts passed into our instruction. The signers here are the Anchor workspace keypair and the Mint Keypair, needed to sign the creation of a Mint account. Pretty straightforward right ?
Derive PDA's
We want to create an associated token account now, for that we will need it's Public Key. You can do that by using find_program_adress
.
associated_token_account_pubkey, nonce = Pubkey.find_program_address([bytes(program.provider.wallet.payer.pubkey()), bytes(TOKEN_PROGRAM_ID), bytes(mint.pubkey())], ASSOCITAED_TOKEN_PROGRAM_ID)
We can now use this Pubkey in the instruction's accounts. This would look like:
create_associated_token_account = await program.rpc["create_associated_token_account"](ctx=Context(accounts={
"mint": mint.pubkey(),
"token_account" : associated_token_account_pubkey,
"signer": program.provider.wallet.payer.pubkey(),
"system_program": SYS_PROGRAM_ID,
"rent": RENT,
"token_program": TOKEN_PROGRAM_ID,
"associated_token_program" : ASSOCITAED_TOKEN_PROGRAM_ID
}, signers=[program.provider.wallet.payer]))
print("Create associated token account signature: ", create_associated_token_account)
Pass arguments to instruction
Last, let's see how we can add additional arguments into our instruction by minting some tokens to our workspace Keypair. Here we are mining 1000 tokens to the Token Account created before.
mint_token = await program.rpc["mint_token"](1000, ctx=Context(accounts={
"mint": mint.pubkey(),
"recipient" : associated_token_account_pubkey,
"signer": program.provider.wallet.payer.pubkey(),
"system_program": SYS_PROGRAM_ID,
"rent": RENT,
"token_program": TOKEN_PROGRAM_ID,
}, signers=[program.provider.wallet.payer]))
print("Mint token signature: ", mint_token)
Now, we could run our tests in the command line, but let's do something more convenient. Let's go to the Anchor.toml
file and change the current test script to this:
[scripts]
test = "python3 tests/test.py"
You can now run anchor test --skip-local-validator
and run the tests we wrote.
Conclusion
Thanks for reading this guide.
If you have any more questions, please contact me on Twitter or join the SolanaU Discord Server.
Top comments (0)