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
20 changes: 20 additions & 0 deletions contracts/accord/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ pub struct ProposalApprovalProgress {
pub total_weight: u32,
}

#[derive(Clone, Debug, Eq, PartialEq)]
#[contracttype]
pub struct OwnerWeight {
pub owner: Address,
pub weight: u32,
}

#[derive(Clone, Debug, Eq, PartialEq)]
#[contracttype]
pub struct ProposalCreatedEvent {
Expand Down Expand Up @@ -2022,6 +2029,19 @@ impl AccordContract {
Ok(read_owners_map(&env)?.keys())
}

/// Returns every current owner's address paired with their voting weight,
/// in a single call. The sum of the returned weights equals the current
/// total-weight counter. Read-only; no authorization required.
pub fn get_owner_weights(env: Env) -> Result<Vec<OwnerWeight>, ContractError> {
let owners = read_owners_map(&env)?;
let mut result = Vec::new(&env);
for owner in owners.keys().iter() {
let weight = owners.get(owner.clone()).unwrap_or(0);
result.push_back(OwnerWeight { owner, weight });
}
Ok(result)
}

/// Returns the spending limit for an (owner, token) pair, or `None` if no
/// limit is set (the owner is unrestricted for that token).
pub fn get_spending_limit(env: Env, owner: Address, token: Address) -> Option<i128> {
Expand Down
66 changes: 66 additions & 0 deletions contracts/accord/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5609,6 +5609,72 @@ fn get_owner_weight_returns_owner_not_found_for_non_owner() {
assert_eq!(client.get_owner_weight(&owner_b), 1);
}

// ─── get_owner_weights ────────────────────────────────────────────────────

/// Confirms get_owner_weights returns every owner with the correct weight
/// for a multisig with several owners holding different weights, and that
/// the sum of returned weights matches the total-weight counter.
#[test]
fn get_owner_weights_returns_all_owners_with_correct_weights() {
let (env, client, owner_a, owner_b, owner_c, token_client) =
setup_three_owner_weighted([5, 3, 2], 8);

let result = client.get_owner_weights();

assert_eq!(result.len(), 3);

let mut sum: u32 = 0;
for entry in result.iter() {
match entry.owner {
_ if entry.owner == owner_a => assert_eq!(entry.weight, 5),
_ if entry.owner == owner_b => assert_eq!(entry.weight, 3),
_ if entry.owner == owner_c => assert_eq!(entry.weight, 2),
_ => panic!("unexpected owner in result"),
}
sum = sum.checked_add(entry.weight).unwrap();
}

assert_eq!(sum, client.get_total_weight());
}

/// After adding and then removing an owner, get_owner_weights must reflect
/// the current set and the total-weight counter must still match.
#[test]
fn get_owner_weights_reflects_owner_changes() {
let (env, client, owner_a, owner_b, owner_c, non_owner, token_client) = setup(2);

// Initial: 3 owners each weight 1, total_weight = 3.
let result = client.get_owner_weights();
assert_eq!(result.len(), 3);
let mut sum: u32 = 0;
for entry in result.iter() {
assert_eq!(entry.weight, 1);
sum = sum.checked_add(entry.weight).unwrap();
}
assert_eq!(sum, 3);

// Add non_owner as a fourth owner (weight 1 by default).
let add_id = client.create_add_owner_proposal(
&owner_a,
&non_owner,
&str(&env, "Add fourth owner"),
&DEADLINE,
);
client.approve(&owner_a, &add_id);
client.approve(&owner_b, &add_id);
client.execute(&owner_c, &add_id);

let result = client.get_owner_weights();
assert_eq!(result.len(), 4);
let mut sum: u32 = 0;
for entry in result.iter() {
assert_eq!(entry.weight, 1);
sum = sum.checked_add(entry.weight).unwrap();
}
assert_eq!(sum, 4);
assert_eq!(sum, client.get_total_weight());
}

// ─── Issue #320: total-weight overflow rejection ─────────────────────────────

/// Tests that the overflow-checked arithmetic protecting the total-weight
Expand Down
17 changes: 17 additions & 0 deletions docs/CONTRACT_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,23 @@ Returns the current voting weight for `owner`. The weight reflects the owner's i

---

## `get_owner_weights`

```rust
fn get_owner_weights(env: Env) -> Result<Vec<OwnerWeight>, ContractError>
```

Returns every current owner's address paired with their voting weight, in a single call. The returned list is a `Vec<OwnerWeight>` where each entry contains an `owner` field (the address) and a `weight` field (the owner's individual voting weight). The sum of all returned weights equals the current total-weight counter. This avoids the need for N separate `get_owner_weight` calls when rendering a full governance overview. Read-only; no authorization required.

| Return field | Type | Description |
|---|---|---|
| `owner` | `Address` | A current owner's address |
| `weight` | `u32` | That owner's individual voting weight |

**Errors:** `NotInitialized`

---

## `has_approved`

```rust
Expand Down
Loading