How to check your program’s data accounts in both Anchor and Native Rust.
constraint
to checks whether the given expression
evaluates to true. Alternatively, you can use has_one
to check that a target
account field stored on the account matches the key of an account in the
Accounts
struct.update_admin
instruction that updates the
admin
field stored on an admin_config
account.
The instruction is missing a data validation check to verify the admin
account
signing the transaction matches the admin
stored on the admin_config
account. This means any account signing the transaction and passed into the
instruction as the admin
account can update the admin_config
account.
admin
key to the admin
key stored in the admin_config
account, throwing an
error if they don’t match.
update_admin
instruction would only
process if the admin
signer of the transaction matched the admin
stored on
the admin_config
account.
has_one
constraint. You can use the has_one
constraint to move the data validation check from the instruction logic to the
UpdateAdmin
struct.
In the example below, has_one = admin
specifies that the admin
account
signing the transaction must match the admin
field stored on the
admin_config
account. To use the has_one
constraint, the naming convention
of the data field on the account must be consistent with the naming on the
account validation struct.
constraint
to manually add an expression that must
evaluate to true in order for execution to continue. This is useful when for
some reason naming can’t be consistent or when you need a more complex
expression to fully validate the incoming data.
starter
branch of
this repository.
The starter code includes a program with two instructions and the boilerplate
setup for the test file.
The initialize_vault
instruction initializes a new Vault
account and a new
TokenAccount
. The Vault
account will store the address of a token account,
the authority of the vault, and a withdraw destination token account.
The authority of the new token account will be set as the vault
, a PDA of the
program. This allows the vault
account to sign for the transfer of tokens from
the token account.
The insecure_withdraw
instruction transfers all the tokens in the vault
account’s token account to a withdraw_destination
token account.
Notice that this instruction **does** have a signer check for
authority
and an owner check for vault
. However, nowhere in the account
validation or instruction logic is there code that checks that the authority
account passed into the instruction matches the authority
account on the
vault
.
insecure_withdraw
instructionauthority
tries to withdraw from the vault.
The test file includes the code to invoke the initialize_vault
instruction
using the provider wallet as the authority
and then mints 100 tokens to the
vault
token account.
Add a test to invoke the insecure_withdraw
instruction. Use
withdrawDestinationFake
as the withdrawDestination
account and walletFake
as the authority
. Then send the transaction using walletFake
.
Since there are no checks the verify the authority
account passed into the
instruction matches the values stored on the vault
account initialized in the
first test, the instruction will process successfully and the tokens will be
transferred to the withdrawDestinationFake
account.
anchor test
to see that both transactions will complete successfully.
secure_withdraw
instructionsecure_withdraw
.
This instruction will be identical to the insecure_withdraw
instruction,
except we’ll use the has_one
constraint in the account validation struct
(SecureWithdraw
) to check that the authority
account passed into the
instruction matches the authority
account on the vault
account. That way
only the correct authority account can withdraw the vault’s tokens.
secure_withdraw
instructionsecure_withdraw
instruction with two tests: one that uses
walletFake
as the authority and one that uses wallet
as the authority. We
expect the first invocation to return an error and the second to succeed.
anchor test
to see that the transaction using an incorrect authority
account will now return an Anchor Error while the transaction using correct
accounts completes successfully.
AnchorError caused by account: vault
).
solution
branch of
the repository.