Skip to content

Commit bd0fa3d

Browse files
committed
feat(instruction): implement Ticket 1.4 — instruction interfaces
- Add 8 discriminator constants (INIT_MARKET through SETTLE_TRADE) - Add 5 args structs with wincode derives (InitializeMarketArgs, PlaceOrderArgs, CancelOrderArgs, MatchOrdersArgs, SettleTradeArgs) - Add 5 account context structs with TryFrom<AccountView> validation (signer, writable, program ID key checks, duplicate mutable guards) - Add 3 error variants: InvalidArgument, InvalidProgramId, InvalidAccountCount - Add CI workflow (fmt, clippy -D clippy::unwrap_used, test) - Add .rustfmt.toml and build.rs for clippy cfg support - Add #![deny(clippy::unwrap_used)] at crate level - Add pinocchio-associated-token-account dependency - Update justfile with fix recipe and unwrap lint in clippy - Format all code with cargo fmt Closes #11
1 parent 2fb7f72 commit bd0fa3d

13 files changed

Lines changed: 575 additions & 87 deletions

File tree

.github/workflows/ci.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
12+
jobs:
13+
fmt:
14+
name: Format
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
- uses: dtolnay/rust-toolchain@stable
19+
with:
20+
components: rustfmt
21+
- run: cargo fmt --check
22+
23+
clippy:
24+
name: Clippy
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@v4
28+
- uses: dtolnay/rust-toolchain@stable
29+
with:
30+
components: clippy
31+
- uses: actions/cache@v4
32+
with:
33+
path: |
34+
~/.cargo/registry
35+
~/.cargo/git
36+
target
37+
key: ${{ runner.os }}-clippy-${{ hashFiles('**/Cargo.lock') }}
38+
restore-keys: ${{ runner.os }}-clippy-
39+
- run: cargo clippy --all-targets -- -D warnings -D clippy::unwrap_used
40+
41+
test:
42+
name: Test
43+
runs-on: ubuntu-latest
44+
steps:
45+
- uses: actions/checkout@v4
46+
- uses: dtolnay/rust-toolchain@stable
47+
- uses: actions/cache@v4
48+
with:
49+
path: |
50+
~/.cargo/registry
51+
~/.cargo/git
52+
target
53+
key: ${{ runner.os }}-test-${{ hashFiles('**/Cargo.lock') }}
54+
restore-keys: ${{ runner.os }}-test-
55+
- run: cargo test

.rustfmt.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
edition = "2024"
2+
max_width = 100
3+
tab_spaces = 4

Cargo.lock

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ crate-type = ["cdylib", "lib"]
1010
pinocchio = "0.11.1"
1111
pinocchio-system = "0.4"
1212
pinocchio-token = "0.4"
13+
pinocchio-associated-token-account = "0.4"
1314
bytemuck = { version = "1.14", features = ["derive"] }
1415
wincode = { version = "0.4", features = ["derive"] }
1516

build.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn main() {
2+
// Pinocchio's entrypoint! macro emits cfg(target_os = "solana").
3+
// Register it so clippy/cargo doesn't complain about unknown cfgs.
4+
println!("cargo:rustc-check-cfg=cfg(target_os, values(\"solana\"))");
5+
}

docs/epics/epic-1-foundation.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,12 @@ Create `src/state.rs` with all on-chain account structs using bytemuck `#[repr(C
140140

141141
### Ticket 1.4: Instruction Interfaces (instruction.rs)
142142

143-
**Status:** Not Started
143+
**Status:** ✅ Done
144144
**Priority:** P0
145145
**Estimated Effort:** Medium
146146

147147
**Description:**
148-
Create `src/instruction.rs` with instruction discriminator constants (0-7) and wincode-serializable argument structs for all 8 instructions. Also define account context structs using `TryFrom<&[AccountInfo]>`.
148+
Create `src/instruction.rs` with instruction discriminator constants (0-7) and wincode-serializable argument structs for all 8 instructions. Also define account context structs using `TryFrom<&[AccountView]>`.
149149

150150
**Files to create/modify:**
151151
- `src/instruction.rs` — Discriminators, args structs, account context structs
@@ -155,13 +155,14 @@ Create `src/instruction.rs` with instruction discriminator constants (0-7) and w
155155
- Discriminator constants: `pub const INIT_MARKET: u8 = 0;` through `pub const SETTLE_TRADE: u8 = 7;`
156156
- Args structs: `InitializeMarketArgs`, `PlaceOrderArgs`, `CancelOrderArgs`, `MatchOrdersArgs`, `SettleTradeArgs`
157157
- Account contexts: `InitializeMarketAccounts`, `PlaceOrderAccounts`, `CancelOrderAccounts`, `MatchOrdersAccounts`, `SettleTradeAccounts`
158-
- Each account context implements `TryFrom<&[AccountInfo]>` with validation (signer, writable, key checks)
158+
- Each account context implements `TryFrom<&[AccountView]>` with validation (signer, writable, key checks)
159+
- Custom error variants: `InvalidArgument`, `InvalidProgramId`, `InvalidAccountCount`
159160

160161
**Acceptance Criteria:**
161-
- [ ] All 8 discriminator constants defined
162-
- [ ] Wincode derives compile for all args structs
163-
- [ ] Account context structs validate signer, writable, and key checks per TDD §5.3
164-
- [ ] `TryFrom` returns `ProgramError` on invalid accounts
162+
- [x] All 8 discriminator constants defined
163+
- [x] Wincode derives compile for all args structs
164+
- [x] Account context structs validate signer, writable, and key checks per TDD §5.3
165+
- [x] `TryFrom` returns `FluxDexError` on invalid accounts
165166

166167
**Testing:**
167168
- Unit test each account context rejects missing signer

justfile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,14 @@ alias fc := fmt-check
3333

3434
# Clippy lints
3535
clippy:
36-
cargo clippy -- --deny warnings
36+
cargo clippy --all-targets -- -D warnings -D clippy::unwrap_used
3737
alias c := clippy
3838

39+
# Auto-fix formatting
40+
fix:
41+
cargo fmt --all
42+
alias fx := fix
43+
3944
# Format + clippy
4045
lint: fmt clippy
4146
alias l := lint
@@ -49,7 +54,7 @@ test:
4954
cargo test-sbf
5055

5156
# Run all tests
52-
test-all: test test-sbf
57+
test-all: test
5358
alias ta := test-all
5459

5560
# Clean build artifacts

src/error.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ pub enum FluxDexError {
4040
PmmInvalidK = 23,
4141
PmmEquilibriumZero = 24,
4242
OracleConfidenceTooWide = 25,
43+
InvalidArgument = 26,
44+
InvalidProgramId = 27,
45+
InvalidAccountCount = 28,
4346
}
4447

4548
impl From<FluxDexError> for ProgramError {
@@ -60,7 +63,7 @@ mod tests {
6063
/// This array is the single source of truth for the tests below. Removing
6164
/// a variant from the enum breaks compilation here; the length assertion
6265
/// guards against accidental additions or omissions.
63-
const ALL: [FluxDexError; 26] = [
66+
const ALL: [FluxDexError; 29] = [
6467
FluxDexError::InvalidInstructionData,
6568
FluxDexError::InvalidAccountOwner,
6669
FluxDexError::InvalidDiscriminator,
@@ -87,13 +90,16 @@ mod tests {
8790
FluxDexError::PmmInvalidK,
8891
FluxDexError::PmmEquilibriumZero,
8992
FluxDexError::OracleConfidenceTooWide,
93+
FluxDexError::InvalidArgument,
94+
FluxDexError::InvalidProgramId,
95+
FluxDexError::InvalidAccountCount,
9096
];
9197

9298
/// TDD §8 defines exactly 26 variants. Adding or removing one without
9399
/// updating the spec/registry must fail the build.
94100
#[test]
95-
fn has_exactly_twenty_six_variants() {
96-
assert_eq!(ALL.len(), 26);
101+
fn has_exactly_twenty_nine_variants() {
102+
assert_eq!(ALL.len(), 29);
97103
}
98104

99105
/// Every variant must convert into a `ProgramError::Custom`.
@@ -118,7 +124,10 @@ mod tests {
118124
ProgramError::Custom(code) => code,
119125
other => panic!("{variant:?} produced {other:?}, expected Custom"),
120126
};
121-
assert!(codes.insert(code), "duplicate custom code {code} for {variant:?}");
127+
assert!(
128+
codes.insert(code),
129+
"duplicate custom code {code} for {variant:?}"
130+
);
122131
}
123132
assert_eq!(codes.len(), ALL.len());
124133
}
@@ -136,7 +145,7 @@ mod tests {
136145
})
137146
.collect();
138147
codes.sort_unstable();
139-
let expected: Vec<u32> = (0..26).collect();
148+
let expected: Vec<u32> = (0..29).collect();
140149
assert_eq!(codes, expected);
141150
}
142151
}

0 commit comments

Comments
 (0)