Summary
OpenZeppelin Stellar Contracts v0.6.0 introduces a new get_existing_roles function that returns all roles that currently have at least one member. This provides a direct on-chain method to enumerate roles without relying on indexer-based event reconstruction.
Current Implementation (Workaround)
The current StellarAccessControlService.getCurrentRoles() implementation uses a two-step workaround:
- Role Discovery via Indexer: If
knownRoleIds aren't provided during contract registration, the adapter queries the indexer for historical ROLE_GRANTED and ROLE_REVOKED events to discover roles
- Member Enumeration: Once role IDs are known, it uses
get_role_member_count and get_role_member to enumerate members
This approach has limitations:
- Requires indexer availability for role discovery
- Depends on historical event data being indexed
- Adds latency due to indexer queries
- May miss roles if indexer data is incomplete
New API from v0.6.0
From storage.rs:
/// Returns a vector containing all existing roles.
/// Defaults to empty vector if no roles exist.
///
/// # Arguments
///
/// * `e` - Access to Soroban environment.
///
/// # Notes
///
/// This function returns all roles that currently have at least one member.
pub fn get_existing_roles(e: &Env) -> Vec<Symbol> {
let key = AccessControlStorageKey::ExistingRoles;
if let Some(existing_roles) = e.storage().persistent().get(&key) {
e.storage().persistent().extend_ttl(&key, ROLE_TTL_THRESHOLD, ROLE_EXTEND_AMOUNT);
existing_roles
} else {
Vec::new(e)
}
}
Return type: Vec<Symbol> - A vector of role symbols (identifiers)
Proposed Implementation
1. Add on-chain reader function
Add getExistingRoles() function in packages/adapter-stellar/src/access-control/onchain-reader.ts:
export async function getExistingRoles(
contractAddress: string,
networkConfig: StellarNetworkConfig
): Promise<string[]>
2. Update feature detection
Add get_existing_roles to feature detection in packages/adapter-stellar/src/access-control/feature-detection.ts:
const hasExistingRolesFunction = !!functions.find(
(f) => f.name === 'get_existing_roles'
);
3. Update service to prefer new method
Modify StellarAccessControlService.getCurrentRoles() to:
- Check if contract supports
get_existing_roles (via feature detection)
- If supported, call
get_existing_roles to get role IDs directly
- If not supported, fall back to current indexer-based discovery
- Continue using
get_role_member_count and get_role_member for member enumeration
4. Fallback Strategy
The current indexer-based role discovery should remain as a fallback for:
- Contracts deployed before v0.6.0 that don't have
get_existing_roles
- Edge cases where on-chain call fails
Acceptance Criteria
References
Summary
OpenZeppelin Stellar Contracts v0.6.0 introduces a new
get_existing_rolesfunction that returns all roles that currently have at least one member. This provides a direct on-chain method to enumerate roles without relying on indexer-based event reconstruction.Current Implementation (Workaround)
The current
StellarAccessControlService.getCurrentRoles()implementation uses a two-step workaround:knownRoleIdsaren't provided during contract registration, the adapter queries the indexer for historicalROLE_GRANTEDandROLE_REVOKEDevents to discover rolesget_role_member_countandget_role_memberto enumerate membersThis approach has limitations:
New API from v0.6.0
From
storage.rs:Return type:
Vec<Symbol>- A vector of role symbols (identifiers)Proposed Implementation
1. Add on-chain reader function
Add
getExistingRoles()function inpackages/adapter-stellar/src/access-control/onchain-reader.ts:2. Update feature detection
Add
get_existing_rolesto feature detection inpackages/adapter-stellar/src/access-control/feature-detection.ts:3. Update service to prefer new method
Modify
StellarAccessControlService.getCurrentRoles()to:get_existing_roles(via feature detection)get_existing_rolesto get role IDs directlyget_role_member_countandget_role_memberfor member enumeration4. Fallback Strategy
The current indexer-based role discovery should remain as a fallback for:
get_existing_rolesAcceptance Criteria
getExistingRoleson-chain reader functionget_existing_rolesgetCurrentRolesto preferget_existing_roleswhen availableReferences