Skip to content

Commit 5faa2ff

Browse files
nvsriramjohnsaigle
andauthored
solana: Add anchor linting (#507)
* Add a bash script to manually run anchor linting commands as it does not occur automatically in anchor-cli 0.29.0 * Add Makefile target that points to the new script * Add CI step to run the new make command * Replace usages of `AccountInfo` with documented usages of `UncheckedAccount` --------- Co-authored-by: John Saigle <[email protected]>
1 parent fc0f34f commit 5faa2ff

File tree

11 files changed

+71
-23
lines changed

11 files changed

+71
-23
lines changed

.github/workflows/solana.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ jobs:
131131
- name: Check idl
132132
run: |
133133
git diff --exit-code ts/idl
134+
- name: Set default Rust toolchain
135+
run: rustup default stable
136+
shell: bash
137+
- name: Run anchor lint
138+
run: make anchor-lint
139+
shell: bash
134140
- name: Run tests
135141
run: anchor test --skip-build
136142
shell: bash

solana/Makefile

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.DEFAULT_GOAL = build
2-
.PHONY: build cargo-build anchor-build prod-build test cargo-test anchor-test idl sdk clean node_modules lint fix-lint
2+
.PHONY: build cargo-build anchor-build prod-build test cargo-test anchor-test idl sdk clean node_modules lint cargo-lint anchor-lint fix-lint
33

44
#find and convert version line:
55
# turn `const VERSION: &str = "major.minor.patch";` into `major_minor_patch`
@@ -68,11 +68,20 @@ anchor-test: idl sdk node_modules
6868
#######################
6969
## LINT
7070

71-
lint:
71+
lint: cargo-lint anchor-lint
72+
73+
74+
cargo-lint:
7275
cargo fmt --check --all --manifest-path Cargo.toml
7376
cargo check --workspace --tests --manifest-path Cargo.toml
7477
cargo clippy --workspace --tests --manifest-path Cargo.toml -- -Dclippy::cast_possible_truncation
7578

79+
# Run anchor's linter on all Rust files in the current directory via `anchor idl parse`
80+
# Results written to /dev/null because we're just calling parse for the linting capabilities and we don't care about
81+
# the JSON output.
82+
# anchor-cli v0.29.0 doesn't seem to do linting on the command-line during the build process so this is a workaround
83+
anchor-lint:
84+
bash scripts/anchor-lint.sh
7685

7786
fix-lint:
7887
cargo fmt --all --manifest-path Cargo.toml

solana/programs/example-native-token-transfers/src/instructions/admin.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@ pub struct TransferOwnership<'info> {
3333
pub owner: Signer<'info>,
3434

3535
/// CHECK: This account will be the signer in the [claim_ownership] instruction.
36-
new_owner: AccountInfo<'info>,
36+
new_owner: UncheckedAccount<'info>,
3737

3838
#[account(
3939
seeds = [b"upgrade_lock"],
4040
bump,
4141
)]
42-
upgrade_lock: AccountInfo<'info>,
42+
/// CHECK: The seeds constraint enforces that this is the correct address
43+
upgrade_lock: UncheckedAccount<'info>,
4344

4445
#[account(
4546
mut,
@@ -89,7 +90,8 @@ pub struct ClaimOwnership<'info> {
8990
seeds = [b"upgrade_lock"],
9091
bump,
9192
)]
92-
upgrade_lock: AccountInfo<'info>,
93+
/// CHECK: The seeds constraint enforces that this is the correct address
94+
upgrade_lock: UncheckedAccount<'info>,
9395

9496
pub new_owner: Signer<'info>,
9597

@@ -204,7 +206,9 @@ pub struct RegisterTransceiver<'info> {
204206
pub payer: Signer<'info>,
205207

206208
#[account(executable)]
207-
pub transceiver: AccountInfo<'info>,
209+
/// CHECK: transceiver is meant to be a transceiver program. Arguably a `Program` constraint could be
210+
/// used here that wraps the Transceiver account type.
211+
pub transceiver: UncheckedAccount<'info>,
208212

209213
#[account(
210214
init,

solana/programs/example-native-token-transfers/src/instructions/initialize.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ pub struct Initialize<'info> {
5858
seeds = [crate::TOKEN_AUTHORITY_SEED],
5959
bump,
6060
)]
61+
/// CHECK: [`token_authority`] is checked against the custody account and the [`mint`]'s mint_authority
62+
/// In any case, this function is used to set the Config and initialize the program so we
63+
/// assume the caller of this function will have total control over the program.
64+
///
65+
/// TODO: Using `UncheckedAccount` here leads to "Access violation in stack frame ...".
66+
/// Could refactor code to use `Box<_>` to reduce stack size.
6167
pub token_authority: AccountInfo<'info>,
6268

6369
#[account(
@@ -73,7 +79,7 @@ pub struct Initialize<'info> {
7379
/// function if the token account has already been created.
7480
pub custody: InterfaceAccount<'info, token_interface::TokenAccount>,
7581

76-
/// CHECK: checked to be the appropriate token progrem when initialising the
82+
/// CHECK: checked to be the appropriate token program when initialising the
7783
/// associated token account for the given mint.
7884
pub token_program: Interface<'info, token_interface::TokenInterface>,
7985
pub associated_token_program: Program<'info, AssociatedToken>,

solana/programs/example-native-token-transfers/src/instructions/luts.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,17 @@ pub struct InitializeLUT<'info> {
4545
seeds = [b"lut_authority"],
4646
bump
4747
)]
48-
pub authority: AccountInfo<'info>,
48+
/// CHECK: The seeds constraint enforces that this is the correct account.
49+
pub authority: UncheckedAccount<'info>,
4950

5051
#[account(
5152
mut,
5253
seeds = [authority.key().as_ref(), &recent_slot.to_le_bytes()],
5354
seeds::program = solana_address_lookup_table_program::id(),
5455
bump
5556
)]
56-
pub lut_address: AccountInfo<'info>,
57+
/// CHECK: The seeds constraint enforces that this is the correct account.
58+
pub lut_address: UncheckedAccount<'info>,
5759

5860
#[account(
5961
init_if_needed,
@@ -81,23 +83,27 @@ pub struct Entries<'info> {
8183
#[account(
8284
constraint = custody.key() == config.custody,
8385
)]
84-
pub custody: AccountInfo<'info>,
86+
/// CHECK: The constraint enforces that this is the correct account.
87+
pub custody: UncheckedAccount<'info>,
8588

8689
#[account(
8790
constraint = token_program.key() == config.token_program,
8891
)]
89-
pub token_program: AccountInfo<'info>,
92+
/// CHECK: The constraint enforces that this is the correct account.
93+
pub token_program: UncheckedAccount<'info>,
9094

9195
#[account(
9296
constraint = mint.key() == config.mint,
9397
)]
94-
pub mint: AccountInfo<'info>,
98+
/// CHECK: The constraint enforces that this is the correct account.
99+
pub mint: UncheckedAccount<'info>,
95100

96101
#[account(
97102
seeds = [crate::TOKEN_AUTHORITY_SEED],
98103
bump,
99104
)]
100-
pub token_authority: AccountInfo<'info>,
105+
/// CHECK: The seeds constraint enforces that this is the correct account.
106+
pub token_authority: UncheckedAccount<'info>,
101107

102108
pub outbox_rate_limit: Account<'info, OutboxRateLimit>,
103109

solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ pub struct ReleaseInbound<'info> {
3131
seeds = [crate::TOKEN_AUTHORITY_SEED],
3232
bump,
3333
)]
34-
pub token_authority: AccountInfo<'info>,
34+
/// CHECK The seeds constraint ensures that this is the correct address
35+
pub token_authority: UncheckedAccount<'info>,
3536

3637
#[account(
3738
mut,
@@ -112,7 +113,7 @@ pub fn release_inbound_mint<'info>(
112113
token_interface::MintTo {
113114
mint: ctx.accounts.common.mint.to_account_info(),
114115
to: ctx.accounts.common.custody.to_account_info(),
115-
authority: ctx.accounts.common.token_authority.clone(),
116+
authority: ctx.accounts.common.token_authority.to_account_info(),
116117
},
117118
&[&[
118119
crate::TOKEN_AUTHORITY_SEED,
@@ -128,7 +129,7 @@ pub fn release_inbound_mint<'info>(
128129
ctx.accounts.common.custody.to_account_info(),
129130
ctx.accounts.common.mint.to_account_info(),
130131
ctx.accounts.common.recipient.to_account_info(),
131-
ctx.accounts.common.token_authority.clone(),
132+
ctx.accounts.common.token_authority.to_account_info(),
132133
ctx.remaining_accounts,
133134
inbox_item.amount,
134135
ctx.accounts.common.mint.decimals,
@@ -178,7 +179,7 @@ pub fn release_inbound_unlock<'info>(
178179
ctx.accounts.common.custody.to_account_info(),
179180
ctx.accounts.common.mint.to_account_info(),
180181
ctx.accounts.common.recipient.to_account_info(),
181-
ctx.accounts.common.token_authority.clone(),
182+
ctx.accounts.common.token_authority.to_account_info(),
182183
ctx.remaining_accounts,
183184
inbox_item.amount,
184185
ctx.accounts.common.mint.decimals,

solana/programs/example-native-token-transfers/src/instructions/transfer.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,16 @@ pub struct TransferBurn<'info> {
136136
],
137137
bump,
138138
)]
139+
/// CHECK: The seeds constraint enforces that this is the correct account.
139140
/// See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow.
140-
pub session_authority: AccountInfo<'info>,
141+
pub session_authority: UncheckedAccount<'info>,
141142

142143
#[account(
143144
seeds = [crate::TOKEN_AUTHORITY_SEED],
144145
bump,
145146
)]
146-
pub token_authority: AccountInfo<'info>,
147+
/// CHECK: The seeds constraint enforces that this is the correct account.
148+
pub token_authority: UncheckedAccount<'info>,
147149
}
148150

149151
pub fn transfer_burn<'info>(
@@ -281,8 +283,9 @@ pub struct TransferLock<'info> {
281283
],
282284
bump,
283285
)]
286+
/// CHECK: The seeds constraint enforces that this is the correct account
284287
/// See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow.
285-
pub session_authority: AccountInfo<'info>,
288+
pub session_authority: UncheckedAccount<'info>,
286289
}
287290

288291
pub fn transfer_lock<'info>(

solana/programs/example-native-token-transfers/src/transceivers/wormhole/instructions/broadcast_id.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub struct BroadcastId<'info> {
2424
seeds = [b"emitter"],
2525
bump
2626
)]
27+
/// CHECK: The seeds constraint ensures that this is the correct address
2728
pub emitter: UncheckedAccount<'info>,
2829

2930
pub wormhole: WormholeAccounts<'info>,

solana/programs/example-native-token-transfers/src/transceivers/wormhole/instructions/broadcast_peer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub struct BroadcastPeer<'info> {
2828
seeds = [b"emitter"],
2929
bump
3030
)]
31+
/// CHECK: The seeds constraint ensures that this is the correct address
3132
pub emitter: UncheckedAccount<'info>,
3233

3334
pub wormhole: WormholeAccounts<'info>,

solana/programs/wormhole-governance/src/instructions/governance.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ pub struct Governance<'info> {
4646
bump,
4747
)]
4848
/// CHECK: governance PDA. This PDA has to be the owner assigned to the
49-
/// governed program.
50-
pub governance: AccountInfo<'info>,
49+
/// governed program. This account is validated by Wormhole, not this program.
50+
pub governance: UncheckedAccount<'info>,
5151

5252
#[account(
5353
constraint = vaa.emitter_chain() == Into::<u16>::into(Chain::Solana) @ GovernanceError::InvalidGovernanceChain,
@@ -57,7 +57,8 @@ pub struct Governance<'info> {
5757
pub vaa: Account<'info, PostedVaa<GovernanceMessage>>,
5858

5959
#[account(executable)]
60-
pub program: AccountInfo<'info>,
60+
/// CHECK: This account is validated by Wormhole, not this program.
61+
pub program: UncheckedAccount<'info>,
6162

6263
#[account(
6364
init,

0 commit comments

Comments
 (0)