Use Anchor’s automatic JS/TS clients to send instructions to your program.
@coral-xyz/anchor
is a Typescript client that includes everything you’ll
need to interact with Anchor programsProvider
object combines a connection
to a cluster and a
specified wallet
to enable transaction signingProgram
object provides a custom API to interact with a
specific program. You create a Program
instance using a program’s IDL and
Provider
.MethodsBuilder
provides a simple interface through Program
for building instructions and transactions@coral-xyz/anchor
) provides a simplified format for
building instructions and transactions.
@coral-xyz/anchor
to simplify
your client-side program interaction.
Program
object. A Program
instance
represents a specific Nexis Native Chain program and provides a custom API for reading and
writing to the program.
To create an instance of Program
, you’ll need the following:
Connection
- the cluster connectionWallet
- default keypair used to pay for and sign transactionsProvider
- encapsulates the Connection
to a Nexis Native Chain cluster and a Wallet
ProgramId
- the program’s onchain addressProgram
instance. We’ll go over each of them individually to get a better idea
of how everything ties together.
initialize
and increment
).
Notice that in addition to specifying the instructions, it species the accounts
and inputs for each instruction. The initialize
instruction requires three
accounts:
counter
- the new account being initialized in the instructionuser
- the payer for the transaction and initializationsystemProgram
- the system program is invoked to initialize a new accountincrement
instruction requires two accounts:
counter
- an existing account to increment the count fielduser
- the payer from the transactionuser
is required
as a signer because the isSigner
flag is marked as true
. Additionally,
neither instructions require any additional instruction data since the args
section is blank for both.
Looking further down at the accounts
section, you can see that the program
contains one account type named Counter
with a single count
field of type
u64
.
Although the IDL does not provide the implementation details for each
instruction, we can get a basic idea of how the onchain program expects
instructions to be constructed and see the structure of the program accounts.
Regardless of how you get it, you need an IDL file to interact with a program
using the @coral-xyz/anchor
package. To use the IDL, you’ll need to include
the IDL file in your project and then import the file.
Program
object using the IDL, you first need to create
an Anchor Provider
object.
The Provider
object combines two things:
Connection
- the connection to a Nexis Native Chain cluster (i.e. localhost, devnet,
mainnet)Wallet
- a specified address used to pay for and sign transactionsProvider
is then able to send transactions to the Nexis Native Chain blockchain on
behalf of a Wallet
by including the wallet’s signature to outgoing
transactions. When using a frontend with a Nexis Native Chain wallet provider, all outgoing
transactions must still be approved by the user via their wallet browser
extension.
Setting up the Wallet
and Connection
would look something like this:
useConnection
hook from
@nexis-network/wallet-adapter-react
to get the Connection
to a Nexis Native Chain cluster.
Note that the Wallet
object provided by the useWallet
hook from
@nexis-network/wallet-adapter-react
is not compatible with the Wallet
object that
the Anchor Provider
expects. However, @nexis-network/wallet-adapter-react
also
provides a useAnchorWallet
hook.
For comparison, here is the AnchorWallet
from useAnchorWallet
:
WalletContextState
from useWallet
:
WalletContextState
provides much more functionality compared to the
AnchorWallet
, but the AnchorWallet
is required to set up the Provider
object.
To create the Provider
object you use AnchorProvider
from
@coral-xyz/anchor
.
The AnchorProvider
constructor takes three parameters:
connection
- the Connection
to the Nexis Native Chain clusterwallet
- the Wallet
objectopts
- optional parameter that specifies the confirmation options, using a
default setting if one is not providedProvider
object, you then set it as the default
provider using setProvider
.
Program
.
The constructor requires three parameters:
idl
- the IDL as type Idl
programId
- the onchain address of the program as a string
or PublicKey
Provider
- the provider discussed in the previous sectionProgram
object creates a custom API you can use to interact with a Nexis Native Chain
program. This API is the one stop shop for all things related to communicating
with onchain programs. Among other things, you can send transactions, fetch
deserialized accounts, decode instruction data, subscribe to account changes,
and listen to events. You can also
learn more about the Program
class.
To create the Program
object, first import Program
and Idl
from
@coral-xyz/anchor
. Idl
is a type you can use when working with Typescript.
Next, specify the programId
of the program. We have to explicitly state the
programId
since there can be multiple programs with the same IDL structure
(i.e. if the same program is deployed multiple times using different addresses).
When creating the Program
object, the default Provider
is used if one is not
explicitly specified.
All together, the final setup looks something like this:
MethodsBuilder
Program
object is set up, you can use the Anchor Methods Builder to
build instructions and transactions related to the program. The MethodsBuilder
uses the IDL to provide a simplified format for building transactions that
invoke program instructions.
Note that the camel case naming convention is used when interacting with a
program from the client, compared to the snake case naming convention used when
the writing the program in rust.
The basic MethodsBuilder
format looks like this:
methods
on program
- this is the builder API for creating
instruction calls related to the program’s IDL.instructionName(instructionDataInputs)
-
simply call the instruction using dot syntax and the instruction’s name,
passing in any instruction arguments as comma-separated valuesaccounts
- using dot syntax, call .accounts
, passing in an object
with each account the instruction expects based on the IDLsigners
- using dot syntax, call .signers
, passing in an
array of additional signers required by the instructionrpc
- this method creates and sends a signed transaction with the
specified instruction and returns a TransactionSignature
. When using
.rpc
, the Wallet
from the Provider
is automatically included as a
signer and does not have to be listed explicitly.Wallet
specified with the Provider
, the .signer([])
line can be
excluded.
You can also build the transaction directly by changing .rpc()
to
.transaction()
. This builds a Transaction
object using the instruction
specified.
.instruction()
and then manually add the instructions to a new transaction.
This builds a TransactionInstruction
object using the instruction specified.
MethodsBuilder
provides a simplified and more flexible
way to interact with onchain programs. You can build an instruction, a
transaction, or build and send a transaction using basically the same format
without having to manually serialize or deserialize the accounts or instruction
data.
Program
object also allows you to easily fetch and filter program
accounts. Simply call account
on program
and then specify the name of the
account type as reflected on the IDL. Anchor then deserializes and returns all
accounts as specified.
The example below shows how you can fetch all existing counter
accounts for
the Counter program.
memcmp
and then specifying an offset
and the bytes
to filter for.
The example below fetches all counter
accounts with a count
of 0. Note that
the offset
of 8 is for the 8 byte discriminator Anchor uses to identify
account types. The 9th byte is where the count
field begins. You can refer to
the IDL to see that the next byte stores the count
field of type u64
. Anchor
then filters for and returns all accounts with matching bytes in the same
position.
fetch
if you know the address of the account you’re looking for.
fetchMultiple
.
initialize
- initializes a new Counter
account and sets the count
to 0
increment
- increments the count
on an existing Counter
accountnpm install
and then run the app with npm run dev
.
This project is a simple Next.js application. It includes the
WalletContextProvider
we created in the
Wallets lesson,
the idl.json
file for the Counter program, and the Initialize
and
Increment
components we’ll be building throughout this lab. The programId
of
the program we’ll be invoking is also included in the starter code.
Initialize
Program
object in
Initialize.tsx
component.
Remember, we’ll need an instance of Program
to use the Anchor MethodsBuilder
to invoke the instructions on our program. For that, we’ll need an Anchor wallet
and a connection, which we can get from the useAnchorWallet
and
useConnection
hooks. Let’s also create a useState
to capture the program
instance.
Program
instance. Let’s do this
in a useEffect
.
First we need to either get the default provider if it already exists, or create
it if it doesn’t. We can do that by calling getProvider
inside a try/catch
block. If an error is thrown, that means there is no default provider and we
need to create one.
Once we have a provider, we can construct a Program
instance.
initialize
instruction. We’ll do this inside the onClick
function.
First, we’ll need to generate a new Keypair
for the new Counter
account
since we are initializing an account for the first time.
Then we can use the Anchor MethodsBuilder
to create and send a new
transaction. Remember, Anchor can infer some of the accounts required, like the
user
and systemAccount
accounts. However, it can’t infer the counter
account because we generate that dynamically, so you’ll need to add it with
.accounts
. You’ll also need to add that keypair as a sign with .signers
.
Lastly, you can use .rpc()
to submit the transaction to the user’s wallet.
Once the transaction goes through, call setUrl
with the explorer URL and then
call setCounter
, passing in the counter account.
Increment
Increment.tsx
component. Just as before, complete
the setup to create the Program
object. In addition to calling setProgram
,
the useEffect
should call refreshCount
.
Add the following code for the initial set up:
MethodsBuilder
to build a new instruction to invoke
the increment
instruction. Again, Anchor can infer the user
account from the
wallet so we only need to include the counter
account.
refreshCount
so you can click it to show the new
count after each increment
invocation.
Inside refreshCount
, let’s use program
to fetch the counter account, then
use setCount
to set the count to the number stored on the program:
npm run dev
.
Initialize Counter
buttonInitialize Counter
button, and then approve the transactioninitialize
transaction. The Increment Counter
button, Refresh Count
button, and the count should also all appear.Increment Counter
button, and then approve the transactionRefresh Count
. The count should increment on
the screen.solution-increment
branch before
continuing.
decrement
instructionprogramId
with the one from your new program