Skip to content
This repository was archived by the owner on Jan 24, 2025. It is now read-only.

Update signer-auth.md #473

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 25 additions & 8 deletions content/courses/program-security/signer-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ objectives:
- Implement signer checks using Anchor’s `Signer` type
- Implement signer checks using Anchor’s `#[account(signer)]` constraint
description:
"Ensure instructions are only ran by authorized accounts by implmementing
"Ensure instructions are only run by authorized accounts by implementing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to double check the grammar here but you're correct. 👍

Signer checks."
---

Expand Down Expand Up @@ -92,8 +92,8 @@ pub struct Vault {

#### Add signer authorization checks

All you need to do to validate that the `authority` account signed is to add a
signer check within the instruction. That simply means checking that
All you need to do to validate that the `authority` account is signed is to add a
signer check within the instructions. That simply means checking that
`authority.is_signer` is `true`, and returning a `MissingRequiredSignature`
error if `false`.

Expand Down Expand Up @@ -199,7 +199,7 @@ performed.
#### Use Anchor’s `#[account(signer)]` constraint

While in most cases, the `Signer` account type will suffice to ensure an account
has signed a transaction, the fact that no other ownership or type checks are
has signed a transaction, the fact that no other ownership or type of checks are
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. We want to say that there are no other checks regarding ownership or types.

If you like, you can re-word this sentence to make it clearer.

performed means that this account can’t really be used for anything else in the
instruction.

Expand All @@ -210,7 +210,7 @@ underlying data as well.

As an example of when this would be useful, imagine writing an instruction that
you expect to be invoked via CPI that expects one of the passed in accounts to
be both a **\*\***signer**\*\*** on the transaciton and a \***\*\*\*\*\*\***data
be both a **\*\***signer**\*\*** on the transaction and a \***\*\*\*\*\*\***data
source\***\*\*\*\*\*\***. Using the `Signer` account type here removes the
automatic deserialization and type checking you would get with the `Account`
type. This is both inconvenient, as you need to manually deserialize the account
Expand Down Expand Up @@ -299,6 +299,11 @@ While this is somewhat contrived in that any DeFi program with a vault would be
more sophisticated than this, it will show how the lack of a signer check can
result in tokens being withdrawn by the wrong party.

additional checks ensure:
a. The withdraw amount is not zero.
b. There are sufficient funds in the account.
c. The withdraw destination is not the same as the vault's token account.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're trying to focus on just signer checks in this chapter. I'm not totally sure adding other checks helps.

```rust
use anchor_lang::prelude::*;
use anchor_spl::token::{self, Mint, Token, TokenAccount};
Expand All @@ -316,8 +321,20 @@ pub mod signer_authorization {
}

pub fn insecure_withdraw(ctx: Context<InsecureWithdraw>) -> Result<()> {
let amount = ctx.accounts.token_account.amount;
// Check if the amount is greater than zero
if amount == 0 {
return Err(ProgramError::InvalidArgument.into());
}

// Check if there are enough tokens in the account
if ctx.accounts.token_account.amount < amount {
return Err(ProgramError::InsufficientFunds.into());
}

// Check if the withdraw destination is different from the vault's token account
if ctx.accounts.token_account.key() == ctx.accounts.withdraw_destination.key() {
return Err(ProgramError::InvalidArgument.into());
}
let seeds = &[b"vault".as_ref(), &[*ctx.bumps.get("vault").unwrap()]];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can ensure the code is properly formatted (4 spaces per CONTRIBUTING.md)? Looks like you're in one level too far left.

let signer = [&seeds[..]];

Expand Down Expand Up @@ -424,7 +441,7 @@ describe("signer-authorization", () => {
})
```

Run `anchor test` to see that both transactions will complete successfully.
Run `anchor test` to see that both transactions will be completed successfully.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is clearer than the old language.


```bash
signer-authorization
Expand Down Expand Up @@ -553,7 +570,7 @@ the remainder of the lessons on security vulnerabilities, the Challenge for each
lesson will be to audit your own code for the security vulnerability discussed
in the lesson.

Alternatively, you can find open source programs to audit. There are plenty of
Alternatively, you can find open-source programs to audit. There are plenty of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No dash needed, see https://opensource.org/

programs you can look at. A good start if you don't mind diving into native Rust
would be the
[SPL programs](https://github.com/solana-labs/solana-program-library).
Expand Down
Loading