Reading Entity State
Query entity balances, positions, and metadata onchain.Overview
Every entity (Org or Fund) maintains:- Balance: USDC holdings in the entity
- Manager: Address with permission to manage the entity
- Entity Type: Org (0) or Fund (1)
- Active Status: Whether the entity can receive/send funds
Basic Entity Information
Check Entity Balance
Copy
Ask AI
import { ethers } from 'ethers';
const ENTITY_ABI = [
'function balance() external view returns (uint256)',
'function manager() external view returns (address)',
'function entityType() external pure returns (uint8)',
'function baseToken() external view returns (address)'
];
async function getEntityInfo(entityAddress: string) {
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const entity = new ethers.Contract(entityAddress, ENTITY_ABI, provider);
const balance = await entity.balance();
const manager = await entity.manager();
const entityType = await entity.entityType();
const baseToken = await entity.baseToken();
console.log(`Balance: ${ethers.utils.formatUnits(balance, 6)} USDC`);
console.log(`Manager: ${manager}`);
console.log(`Entity Type: ${entityType === 0 ? 'Org' : 'Fund'}`);
console.log(`Base Token: ${baseToken}`);
return { balance, manager, entityType, baseToken };
}
Python/web3.py
Copy
Ask AI
from web3 import Web3
from typing import Dict
RPC_URL = 'https://eth-mainnet.g.alchemy.com/v2/YOUR-API-KEY'
w3 = Web3(Web3.HTTPProvider(RPC_URL))
ENTITY_ABI = [
{"inputs": [], "name": "balance", "outputs": [{"name": "", "type": "uint256"}], "stateMutability": "view", "type": "function"},
{"inputs": [], "name": "manager", "outputs": [{"name": "", "type": "address"}], "stateMutability": "view", "type": "function"},
{"inputs": [], "name": "entityType", "outputs": [{"name": "", "type": "uint8"}], "stateMutability": "pure", "type": "function"}
]
def get_entity_info(entity_address: str) -> Dict:
entity = w3.eth.contract(address=entity_address, abi=ENTITY_ABI)
balance = entity.functions.balance().call()
manager = entity.functions.manager().call()
entity_type = entity.functions.entityType().call()
print(f"Balance: {balance / 10**6:.2f} USDC")
print(f"Manager: {manager}")
print(f"Entity Type: {'Org' if entity_type == 0 else 'Fund'}")
return {
'balance': balance,
'manager': manager,
'entity_type': 'org' if entity_type == 0 else 'fund'
}
# Usage
entity_info = get_entity_info('0x...')
Verify Entity Status
Check if an entity is active and can transact:Copy
Ask AI
const REGISTRY_ABI = [
'function isActiveEntity(address entity) external view returns (bool)'
];
async function checkEntityStatus(entityAddress: string) {
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const registry = new ethers.Contract(REGISTRY_ADDRESS, REGISTRY_ABI, provider);
const isActive = await registry.isActiveEntity(entityAddress);
if (!isActive) {
console.log('⚠️ Entity is inactive - cannot receive donations or make transfers');
return false;
}
console.log('✓ Entity is active');
return true;
}
- Ethereum:
0x94106ca9c7e567109a1d39413052887d1f412183 - Base:
0x237b53bcfbd3a114b549dfec96a9856808f45c94 - Optimism:
0x5d216bb28852f98ceaa29180670397ab01774ea6
Check Entity Manager
Verify if an address is the manager of an entity:Copy
Ask AI
async function canManageEntity(
entityAddress: string,
walletAddress: string
): Promise<boolean> {
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const entity = new ethers.Contract(entityAddress, ENTITY_ABI, provider);
// Check if wallet is the manager
const manager = await entity.manager();
if (manager.toLowerCase() === walletAddress.toLowerCase()) {
console.log('✓ Address is the entity manager');
return true;
}
console.log('✗ Address is not the entity manager');
return false;
}
Get Org Tax ID
For Org entities, retrieve the tax identifier:Copy
Ask AI
const ORG_ABI = [
'function taxId() external view returns (bytes32)'
];
async function getOrgTaxId(orgAddress: string): Promise<string> {
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const org = new ethers.Contract(orgAddress, ORG_ABI, provider);
const taxIdBytes = await org.taxId();
const taxId = ethers.utils.parseBytes32String(taxIdBytes);
console.log(`Tax ID (EIN): ${taxId}`);
return taxId;
}
Compute Entity Address (Before Deployment)
Predict entity address before deployment:Copy
Ask AI
const FACTORY_ABI = [
'function computeOrgAddress(bytes32 orgId) external view returns (address)',
'function computeFundAddress(address manager, bytes32 salt) external view returns (address)'
];
async function predictOrgAddress(taxId: string) {
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const factory = new ethers.Contract(FACTORY_ADDRESS, FACTORY_ABI, provider);
const orgId = ethers.utils.formatBytes32String(taxId);
const predictedAddress = await factory.computeOrgAddress(orgId);
console.log(`Org will be deployed at: ${predictedAddress}`);
return predictedAddress;
}
async function predictFundAddress(manager: string, salt: string) {
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const factory = new ethers.Contract(FACTORY_ADDRESS, FACTORY_ABI, provider);
const saltBytes = ethers.utils.formatBytes32String(salt);
const predictedAddress = await factory.computeFundAddress(manager, saltBytes);
console.log(`Fund will be deployed at: ${predictedAddress}`);
return predictedAddress;
}
Check Fees
Query donation and transfer fees for an entity:Copy
Ask AI
const REGISTRY_ABI = [
'function getDonationFee(address entity) external view returns (uint32)',
'function getDonationFeeWithOverrides(address entity) external view returns (uint32)',
'function getTransferFee(address from, address to) external view returns (uint32)'
];
async function getEntityFees(entityAddress: string) {
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const registry = new ethers.Contract(REGISTRY_ADDRESS, REGISTRY_ABI, provider);
const donationFee = await registry.getDonationFee(entityAddress);
const donationFeeWithOverride = await registry.getDonationFeeWithOverrides(entityAddress);
console.log(`Donation Fee: ${donationFee / 100}%`);
console.log(`With Override: ${donationFeeWithOverride / 100}%`);
return {
donationFee: donationFee / 100,
donationFeeWithOverride: donationFeeWithOverride / 100
};
}
async function getTransferFee(fromEntity: string, toEntity: string) {
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const registry = new ethers.Contract(REGISTRY_ADDRESS, REGISTRY_ABI, provider);
const transferFee = await registry.getTransferFee(fromEntity, toEntity);
console.log(`Transfer Fee: ${transferFee / 100}%`);
return transferFee / 100;
}
Batch Query Multiple Entities
Efficiently query multiple entities:Copy
Ask AI
import { ethers } from 'ethers';
interface EntitySummary {
address: string;
balance: string;
manager: string;
entityType: 'org' | 'fund';
isActive: boolean;
}
async function batchGetEntities(
entityAddresses: string[]
): Promise<EntitySummary[]> {
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
// Create multicall contract (optional, for efficiency)
const results: EntitySummary[] = [];
for (const address of entityAddresses) {
const entity = new ethers.Contract(address, ENTITY_ABI, provider);
const registry = new ethers.Contract(REGISTRY_ADDRESS, REGISTRY_ABI, provider);
const [balance, manager, entityType, isActive] = await Promise.all([
entity.balance(),
entity.manager(),
entity.entityType(),
registry.isActiveEntity(address)
]);
results.push({
address,
balance: ethers.utils.formatUnits(balance, 6),
manager,
entityType: entityType === 0 ? 'org' : 'fund',
isActive
});
}
return results;
}
// Usage
const entities = await batchGetEntities([
'0x...', // Org 1
'0x...', // Fund 1
'0x...' // Org 2
]);
entities.forEach(e => {
console.log(`\n${e.entityType.toUpperCase()}: ${e.address}`);
console.log(` Balance: ${e.balance} USDC`);
console.log(` Manager: ${e.manager}`);
console.log(` Active: ${e.isActive ? '✓' : '✗'}`);
});
Common Query Patterns
Check if Entity Exists
Copy
Ask AI
async function entityExists(address: string): Promise<boolean> {
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const code = await provider.getCode(address);
// If code is '0x', no contract exists
if (code === '0x') {
console.log('No contract at this address');
return false;
}
// Verify it's an Endaoment entity
const registry = new ethers.Contract(REGISTRY_ADDRESS, REGISTRY_ABI, provider);
const isEntity = await registry.isActiveEntity(address);
if (!isEntity) {
console.log('Contract exists but is not an active Endaoment entity');
}
return isEntity;
}
Monitor Entity Balance Changes
Copy
Ask AI
async function watchEntityBalance(entityAddress: string) {
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const entity = new ethers.Contract(entityAddress, ENTITY_ABI, provider);
// Listen for donation events
entity.on('EntityDonationReceived', (from, to, tokenIn, amountIn, amountReceived, amountFee) => {
console.log('\n💰 Donation Received:');
console.log(` From: ${from}`);
console.log(` Amount: ${ethers.utils.formatUnits(amountReceived, 6)} USDC`);
console.log(` Fee: ${ethers.utils.formatUnits(amountFee, 6)} USDC`);
});
// Listen for transfer events
entity.on('EntityValueTransferred', (from, to, amountReceived, amountFee) => {
console.log('\n📤 Transfer Out:');
console.log(` To: ${to}`);
console.log(` Amount: ${ethers.utils.formatUnits(amountReceived, 6)} USDC`);
console.log(` Fee: ${ethers.utils.formatUnits(amountFee, 6)} USDC`);
});
console.log(`👀 Watching entity: ${entityAddress}`);
}