Skip to content

Commit 5a42252

Browse files
authored
Merge pull request #296 from Emeka000/good
entrypoints
2 parents f35593d + e1ba567 commit 5a42252

4 files changed

Lines changed: 132 additions & 0 deletions

File tree

EVENT_DICTIONARY.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,32 @@ Emitted when voting reaches majority **or** the vote window expires.
221221
- Claim description text.
222222
- Voter lists (derive from `vote_cast` stream).
223223
- PII of any kind.
224+
225+
---
226+
227+
## Read-only entrypoints
228+
229+
These entrypoints are callable via Soroban simulation without authentication.
230+
They perform **no storage reads or writes** and are safe to call repeatedly.
231+
232+
### `version` — deployed contract semver
233+
234+
Returns the semver string stamped at build time from `Cargo.toml` (e.g. `"0.1.0"`).
235+
No events emitted; no state mutation; no auth required.
236+
237+
| Property | Value |
238+
|----------|-------|
239+
| Auth required | None |
240+
| State mutation | None |
241+
| Return type | `String` — pure semver (`MAJOR.MINOR.PATCH`), no network or environment prefix |
242+
| Callable via simulation | Yes |
243+
244+
**Backend usage:** the deployment registry calls `version()` via simulation immediately
245+
after each deploy and records the result. If the returned value does not match the
246+
expected `CARGO_PKG_VERSION` baked into the release artifact, the registry logs an error
247+
and the deploy pipeline should halt and alert.
248+
249+
```
250+
GET /chain/contract-version?source_account=G…
251+
→ { "version": "0.1.0", "minResourceFee": "…" }
252+
```

contracts/niffyinsure/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ impl NiffyInsure {
9292
storage::get_admin(&env)
9393
}
9494

95+
/// Returns the semver version string stamped at build time from `Cargo.toml`.
96+
/// Read-only: no storage access, no auth required. Safe to call via simulation.
97+
pub fn version(env: Env) -> soroban_sdk::String {
98+
soroban_sdk::String::from_str(&env, env!("CARGO_PKG_VERSION"))
99+
}
100+
95101
/// Read-only: balance of the default payout token held by this contract (payout reserve).
96102
/// Matches funds available for `process_claim` for the configured default asset.
97103
pub fn get_treasury_balance(env: Env) -> i128 {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#![cfg(test)]
2+
3+
use niffyinsure::NiffyInsureClient;
4+
use soroban_sdk::{testutils::Address as _, Address, Env};
5+
6+
#[test]
7+
fn version_returns_nonempty_semver_string() {
8+
let env = Env::default();
9+
let contract_id = env.register(niffyinsure::NiffyInsure, ());
10+
let client = NiffyInsureClient::new(&env, &contract_id);
11+
12+
let v = client.version();
13+
let v_str = v.to_string();
14+
assert!(!v_str.is_empty(), "version() must not be empty");
15+
assert_eq!(
16+
v_str,
17+
env!("CARGO_PKG_VERSION"),
18+
"version() must match Cargo.toml"
19+
);
20+
}
21+
22+
#[test]
23+
fn version_requires_no_auth_and_no_init() {
24+
// Contract is not initialised — version() must succeed regardless.
25+
let env = Env::default();
26+
let contract_id = env.register(niffyinsure::NiffyInsure, ());
27+
let client = NiffyInsureClient::new(&env, &contract_id);
28+
let _ = client.version(); // must not panic
29+
}
30+
31+
#[test]
32+
fn version_is_idempotent() {
33+
let env = Env::default();
34+
env.mock_all_auths();
35+
let contract_id = env.register(niffyinsure::NiffyInsure, ());
36+
let client = NiffyInsureClient::new(&env, &contract_id);
37+
let admin = Address::generate(&env);
38+
let token = Address::generate(&env);
39+
client.initialize(&admin, &token);
40+
41+
let v1 = client.version();
42+
let v2 = client.version();
43+
assert_eq!(v1, v2);
44+
}

contracts/premium_calculator/src/lib.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ impl PremiumCalculator {
5656
storage::get_table(&env).map(|t| t.version).unwrap_or(0)
5757
}
5858

59+
/// Returns the semver version string stamped at build time from `Cargo.toml`.
60+
/// Read-only: no storage access, no auth required. Safe to call via simulation.
61+
pub fn version(env: Env) -> soroban_sdk::String {
62+
soroban_sdk::String::from_str(&env, env!("CARGO_PKG_VERSION"))
63+
}
64+
5965
/// Admin: replace the multiplier table. Version must be strictly greater.
6066
pub fn update_table(env: Env, new_table: MultiplierTable) -> Result<(), CalcError> {
6167
let admin = storage::get_admin(&env).ok_or(CalcError::NotInitialized)?;
@@ -164,3 +170,50 @@ fn mul_ratio(amount: i128, num: i128, den: i128) -> Result<i128, CalcError> {
164170
fn checked_sub(a: i128, b: i128) -> Result<i128, CalcError> {
165171
a.checked_sub(b).ok_or(CalcError::Overflow)
166172
}
173+
174+
// ── Tests ──────────────────────────────────────────────────────────────────────
175+
176+
#[cfg(test)]
177+
mod tests {
178+
use super::*;
179+
use soroban_sdk::{testutils::Address as _, Address, Env};
180+
181+
#[test]
182+
fn version_returns_nonempty_semver_string() {
183+
let env = Env::default();
184+
let contract_id = env.register(PremiumCalculator, ());
185+
let client = PremiumCalculatorClient::new(&env, &contract_id);
186+
187+
let v = client.version();
188+
let v_str = v.to_string();
189+
assert!(!v_str.is_empty(), "version() must not be empty");
190+
assert_eq!(
191+
v_str,
192+
env!("CARGO_PKG_VERSION"),
193+
"version() must match Cargo.toml"
194+
);
195+
}
196+
197+
#[test]
198+
fn version_requires_no_auth_and_no_init() {
199+
// Contract is not initialised — version() must succeed regardless.
200+
let env = Env::default();
201+
let contract_id = env.register(PremiumCalculator, ());
202+
let client = PremiumCalculatorClient::new(&env, &contract_id);
203+
let _ = client.version(); // must not panic
204+
}
205+
206+
#[test]
207+
fn version_is_idempotent() {
208+
let env = Env::default();
209+
env.mock_all_auths();
210+
let contract_id = env.register(PremiumCalculator, ());
211+
let client = PremiumCalculatorClient::new(&env, &contract_id);
212+
let admin = Address::generate(&env);
213+
client.initialize(&admin);
214+
215+
let v1 = client.version();
216+
let v2 = client.version();
217+
assert_eq!(v1, v2);
218+
}
219+
}

0 commit comments

Comments
 (0)