Tutorial
Note
It is recommended to use the generated client instead of the dynamic client where possible, as it is easier to work with and comes with proper type hints.
This tutorial takes the JS snippets from the official Anchor tutorial and shows how to achieve the same thing using AnchorPy.
A Minimal Example
This section covers the basic-0
tutorial:
Generating a Client
Here is how we generate a client from an IDL and use it to interact with a smart contract.
from pathlib import Path
import asyncio
import json
from solders.pubkey import Pubkey
from anchorpy import Idl, Program
async def main():
# Read the generated IDL.
with Path("target/idl/basic_0.json").open() as f:
raw_idl = f.read()
idl = Idl.from_json(raw_idl)
# Address of the deployed program.
program_id = Pubkey.from_string("<YOUR-PROGRAM-ID>")
# Generate the program client from IDL.
async with Program(idl, program_id) as program:
# Execute the RPC.
await program.rpc["initialize"]()
# If we don't use the context manager, we need to
# close the underlying http client, otherwise we get warnings.
# await program.close()
asyncio.run(main())
// Read the generated IDL.
const idl = JSON.parse(require('fs').readFileSync('./target/idl/basic_0.json', 'utf8'));
// Address of the deployed program.
const programId = new anchor.web3.Pubkey('<YOUR-PROGRAM-ID>');
// Generate the program client from IDL.
const program = new anchor.Program(idl, programId);
// Execute the RPC.
await program.rpc.initialize();
Note the differences between Python and JS here:
- We call
program.rpc["initialize"]()
instead ofprogram.rpc.initialize()
- We call
program.close()
to close the HTTP connection.
Workspaces
Here is how workspaces look in AnchorPy:
import asyncio
from anchorpy import create_workspace, close_workspace
async def main():
# Read the deployed program from the workspace.
workspace = create_workspace()
program = workspace["basic_0"]
# Execute the RPC.
await program.rpc["initialize"]()
# Close all HTTP clients in the workspace, otherwise we get warnings.
await close_workspace(workspace)
asyncio.run(main())
// Read the deployed program from the workspace.
const program = anchor.workspace.Basic0;
// Execute the RPC.
await program.rpc.initialize();
Note the differences between Python and JS:
- Workspace instantiation is explicit: we have to call the
create_workspace
function.- Note however that AnchorPy provides the
workspace_fixture
factory for convenience. See the testing section for more.
- Note however that AnchorPy provides the
- We have a
close_workspace
function that callsclose_program
on all the programs in the workspace. - The workspace is called
basic_0
instead ofBasic0
. This is because AnchorPy uses snake case 🐍
Note
AnchorPy uses the same case convention as Rust, so names should look just like they do in lib.rs
.
If you're unsure of a name, check program.idl
: it shows how AnchorPy sees the IDL after parsing
it and converting some cases.
Arguments and Accounts
Creating and Initializing Accounts
Here is how we call an RPC function with arguments.
As in the main Anchor tutorial, we will use anchor/tutorial/examples/basic-1
:
import asyncio
from solders.keypair import Keypair
from solders.system_program import ID as SYS_PROGRAM_ID
from anchorpy import create_workspace, close_workspace, Context
async def main():
# Read the deployed program from the workspace.
workspace = create_workspace()
# The program to execute.
program = workspace["basic_1"]
# The Account to create.
my_account = Keypair()
# Execute the RPC.
accounts = {
"my_account": my_account.pubkey(),
"user": program.provider.wallet.public_key,
"system_program": SYS_PROGRAM_ID
}
await program.rpc["initialize"](1234, ctx=Context(accounts=accounts, signers=[my_account]))
# Close all HTTP clients in the workspace, otherwise we get warnings.
await close_workspace(workspace)
asyncio.run(main())
// The program to execute.
const program = anchor.workspace.Basic1;
// The Account to create.
const myAccount = anchor.web3.Keypair();
// Create the new account and initialize it with the program.
await program.rpc.initialize(new anchor.BN(1234), {
accounts: {
myAccount: myAccount.Pubkey,
user: provider.wallet.Pubkey,
systemProgram: SystemProgram.programId,
},
signers: [myAccount],
});
Note how AnchorPy uses an explicit Context
object in contrast to TS/JS.