Skip to content
Merged
Show file tree
Hide file tree
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
14 changes: 9 additions & 5 deletions .claude/commands/code-quality.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,8 @@ followed by `mod contract;` and `#[cfg(test)] mod test;`.
- Crate name: `stellar-<scope>` (`stellar-access`, `stellar-tokens`).
Internal Rust module names are snake_case.
- All library packages are `#![no_std]`. `[dependencies]` must not pull in
`std`-only crates. The `[dev-dependencies]` block may
(`stellar-event-assertion`, `soroban-sdk` with `testutils`).
`std`-only crates. The `[dev-dependencies]` block may (`soroban-sdk` with
`testutils`).
- Workspace fields use the `field.workspace = true` shorthand
(`edition.workspace = true`, `version.workspace = true`,
`license.workspace = true`, `repository.workspace = true`,
Expand Down Expand Up @@ -493,9 +493,13 @@ followed by `mod contract;` and `#[cfg(test)] mod test;`.
test through it.
- Authorisation in tests uses `e.mock_all_auths()` — never hand-build auth
payloads unless explicitly testing the auth machinery.
- Event assertions use `EventAssertion::new(&e, address.clone())` from the
`stellar-event-assertion` dev-dependency. Hand-decoding
`e.events().all()` is a violation when an `assert_*` helper exists.
- Event assertions compare the emitted entry against the typed
`#[contractevent]` struct serialized with `.to_xdr(&e, &address)`, e.g.
`assert_eq!(events.events().first().unwrap(), &Transfer { .. }.to_xdr(&e, &address))`,
with the count checked via `e.events().all().events().len()`. Use
`.first()` for index 0 and `.get(i)` afterwards. Hand-decoding topics/data
field-by-field out of `e.events().all()` is a violation — build the event
struct and let `to_xdr` produce the wire form.
- Panic tests use
`#[should_panic(expected = "Error(Contract, #<code>)")]` — the numeric
code must match the `#[repr(u32)]` value of the expected enum variant.
Expand Down
1 change: 0 additions & 1 deletion Architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ stellar-contracts/
│ ├── access/ # Role-based access controls and ownable patterns
│ ├── contract-utils/ # Utilities (pausable, upgradeable, cryptography)
│ ├── macros/ # Procedural and derive macros
│ ├── test-utils/ # Testing utilities and helpers
│ └── tokens/ # Token implementations (fungible, non-fungible)
│ ├── src/
│ │ ├── fungible/ # Fungible token implementation
Expand Down
18 changes: 14 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ packages/
├── fee-abstraction/ # fee forwarder
├── governance/ # governor, timelock, votes
├── macros/ # only_owner / only_role / when_paused, etc.
├── test-utils/ # event-assertion helper crate
├── tokens/ # fungible + non_fungible + rwa + vault
└── zk-email/ # zk-email auth primitives
examples/ # one example crate per feature; cdylib only
Expand Down Expand Up @@ -176,9 +175,20 @@ Reversing the two is a common mistake.
- Library-internal calls go inside
`e.as_contract(&address, || { ... })`; example tests go through the
generated `ExampleContractClient`.
- Event assertions: `EventAssertion::new(&e, address.clone())` from
`stellar-event-assertion`. Hand-decoding `e.events().all()` is a
violation when an `assert_*` helper exists.
- Event assertions: compare the emitted entry against the typed
`#[contractevent]` struct serialized with `.to_xdr(&e, &address)`:
```rust
let events = e.events().all();
assert_eq!(events.events().len(), 1);
assert_eq!(
events.events().first().unwrap(),
&Transfer { from: from.clone(), to: to.clone(), amount }.to_xdr(&e, &address),
);
```
Use `.first()` for index 0 and `.get(i)` for later events (clippy's
`get_first` rejects `.get(0)`). Hand-decoding topics/data out of
`e.events().all()` field-by-field is a violation — build the event
struct and let `to_xdr` produce the wire form.
- Panic tests use the numeric form:
`#[should_panic(expected = "Error(Contract, #<code>)")]`.

Expand Down
12 changes: 0 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ members = [
"packages/fee-abstraction",
"packages/governance",
"packages/macros",
"packages/test-utils/*",
"packages/tokens",
"packages/zk-email",
]
Expand Down Expand Up @@ -73,7 +72,6 @@ serde-json-core = { version = "0.6.0", default-features = false }
stellar-access = { path = "packages/access", version = "0.7.1" }
stellar-accounts = { path = "packages/accounts", version = "0.7.1" }
stellar-contract-utils = { path = "packages/contract-utils", version = "0.7.1" }
stellar-event-assertion = { path = "packages/test-utils/event-assertion" }
stellar-fee-abstraction = { path = "packages/fee-abstraction", version = "0.7.1" }
stellar-governance = { path = "packages/governance", version = "0.7.1" }
stellar-tokens = { path = "packages/tokens", version = "0.7.1" }
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ Refer to the [OpenZeppelin for Stellar Contracts](https://docs.openzeppelin.com/
- [`fee-abstraction/`](packages/fee-abstraction): Utilities for covering transaction fees with fungible tokens instead of XLM
- [`governance/`](packages/governance): Governance utilities (governor, votes, timelock)
- [`macros/`](packages/macros): Proc macros for some of the modules (`#[only_owner]`, `#[when_not_paused]`, etc.)
- [`test-utils/`](packages/test-utils): Utilities for testing
- [`tokens/`](packages/tokens): Various token types (fungible, non-fungible, real-world assets, vaults)
- [`zk-email/`](packages/zk-email): On-chain DKIM registry for zkEmail verification
- `examples/`: Example contracts
Expand Down
1 change: 0 additions & 1 deletion packages/access/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,3 @@ soroban-sdk = { workspace = true }

[dev-dependencies]
soroban-sdk = { workspace = true, features = ["testutils"] }
stellar-event-assertion = { workspace = true }
18 changes: 6 additions & 12 deletions packages/access/src/access_control/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ extern crate std;

use soroban_sdk::{
contract, symbol_short,
testutils::{Address as _, Ledger},
testutils::{Address as _, Events, Ledger},
Address, Env, Symbol,
};
use stellar_event_assertion::EventAssertion;

use crate::access_control::{
accept_admin_transfer, add_to_role_enumeration, ensure_if_admin_or_admin_role, get_admin,
Expand Down Expand Up @@ -38,8 +37,7 @@ fn admin_functions_work() {
assert!(has_role(&e, &user, &USER_ROLE).is_some());

// Test events
let event_assert = EventAssertion::new(&e, address.clone());
event_assert.assert_event_count(1);
assert_eq!(e.events().all().events().len(), 1);
});

e.as_contract(&address, || {
Expand All @@ -48,8 +46,7 @@ fn admin_functions_work() {
assert!(has_role(&e, &user, &USER_ROLE).is_none());

// Test events
let event_assert = EventAssertion::new(&e, address.clone());
event_assert.assert_event_count(1);
assert_eq!(e.events().all().events().len(), 1);
});
}

Expand Down Expand Up @@ -223,8 +220,7 @@ fn admin_transfer_works_with_admin_auth() {
assert_eq!(get_admin(&e), Some(new_admin));

// Verify events
let event_assert = EventAssertion::new(&e, address.clone());
event_assert.assert_event_count(1);
assert_eq!(e.events().all().events().len(), 1);
});
}

Expand All @@ -246,8 +242,7 @@ fn admin_transfer_cancel_works() {
transfer_admin_role(&e, &new_admin, 1000);

// Verify events
let event_assert = EventAssertion::new(&e, address.clone());
event_assert.assert_event_count(1);
assert_eq!(e.events().all().events().len(), 1);
});

e.as_contract(&address, || {
Expand All @@ -258,8 +253,7 @@ fn admin_transfer_cancel_works() {
assert_eq!(get_admin(&e), Some(admin));

// Verify events
let event_assert = EventAssertion::new(&e, address.clone());
event_assert.assert_event_count(1);
assert_eq!(e.events().all().events().len(), 1);
});
}

Expand Down
12 changes: 4 additions & 8 deletions packages/access/src/ownable/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ extern crate std;

use soroban_sdk::{
contract,
testutils::{Address as _, Ledger},
testutils::{Address as _, Events, Ledger},
Address, Env,
};
use stellar_event_assertion::EventAssertion;

use crate::{
ownable::{
Expand Down Expand Up @@ -38,8 +37,7 @@ fn transfer_ownership_sets_pending() {
e.storage().temporary().get(&OwnableStorageKey::PendingOwner);
assert_eq!(pending.map(|p| p.address), Some(new_owner));

let assert = EventAssertion::new(&e, contract.clone());
assert.assert_event_count(1);
assert_eq!(e.events().all().events().len(), 1);
});
}

Expand All @@ -61,8 +59,7 @@ fn accept_ownership_completes_transfer() {
let stored_owner = get_owner(&e);
assert_eq!(stored_owner, Some(new_owner));

let assert = EventAssertion::new(&e, contract.clone());
assert.assert_event_count(1);
assert_eq!(e.events().all().events().len(), 1);
});
}

Expand All @@ -83,8 +80,7 @@ fn renounce_ownership_removes_owner() {

assert_eq!(get_owner(&e), None);

let assert = EventAssertion::new(&e, contract.clone());
assert.assert_event_count(1);
assert_eq!(e.events().all().events().len(), 1);
});
}

Expand Down
1 change: 0 additions & 1 deletion packages/accounts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ serde-json-core = { workspace = true }
[dev-dependencies]
soroban-sdk = { workspace = true, features = ["testutils"] }
soroban-test-helpers = { workspace = true }
stellar-event-assertion = { workspace = true }
ed25519-dalek = { workspace = true }
p256 = { workspace = true, features = ["ecdsa"] }
hex-literal = { workspace = true }
1 change: 0 additions & 1 deletion packages/contract-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ soroban-sdk = { workspace = true }
soroban-sdk = { workspace = true, features = ["testutils"] }
proptest = { workspace = true }
hex-literal = { workspace = true }
stellar-event-assertion = { workspace = true }
ark-grumpkin = { version = "0.6", default-features = false }
ark-ec = { version = "0.6", default-features = false }
ark-ff = { version = "0.6", default-features = false }
Expand Down
11 changes: 5 additions & 6 deletions packages/contract-utils/src/merkle_distributor/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ extern crate std;

use hex_literal::hex;
use soroban_sdk::{
contract, contracttype, testutils::Address as _, vec, Address, BytesN, Env, Vec,
contract, contracttype,
testutils::{Address as _, Events},
vec, Address, BytesN, Env, Vec,
};
use stellar_event_assertion::EventAssertion;

use crate::{
crypto::sha256::Sha256,
Expand Down Expand Up @@ -96,13 +97,11 @@ fn test_set_root_and_successful_claim_emits_events() {
Distributor::set_root(&e, root.clone());
assert_eq!(Distributor::get_root(&e), root);

let assert = EventAssertion::new(&e, address.clone());
assert.assert_event_count(1);
assert_eq!(e.events().all().events().len(), 1);

// Set claimed and verify event
Distributor::set_claimed(&e, 1);
let assert = EventAssertion::new(&e, address.clone());
assert.assert_event_count(2);
assert_eq!(e.events().all().events().len(), 2);
});
}

Expand Down
19 changes: 0 additions & 19 deletions packages/test-utils/event-assertion/Cargo.toml

This file was deleted.

Loading
Loading