> ## Documentation Index
> Fetch the complete documentation index at: https://docs.endaoment.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Donations

# Making Donations

Send USDC or other tokens to entities onchain.

## Overview

* **Direct USDC**: Approve and donate
* **Token Swap**: Any ERC20 → USDC via swap wrapper
* **Native ETH**: Wrapped to WETH → USDC
* Donation fees apply, `EntityDonationReceived` event emitted
* Permissionless - anyone can donate

## Direct USDC Donations

Single call: invoke `donate(amount)` on the entity contract.

### TypeScript

```typescript theme={null}
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
const usdc = new ethers.Contract(USDC_ADDRESS, USDC_ABI, signer);
const entity = new ethers.Contract(ENTITY_ADDRESS, ENTITY_ABI, signer);

const amount = ethers.utils.parseUnits('100', 6);

// Approve entity to spend USDC (required)
await usdc.approve(ENTITY_ADDRESS, amount);
await entity.donate(amount);
```

### Python

```python theme={null}
w3 = Web3(Web3.HTTPProvider(RPC_URL))
account = Account.from_key(PRIVATE_KEY)
usdc = w3.eth.contract(address=USDC_ADDRESS, abi=USDC_ABI)
entity = w3.eth.contract(address=ENTITY_ADDRESS, abi=ENTITY_ABI)

amount = 100 * (10 ** 6)  # 100 USDC

# Approve entity to spend USDC (required)
approve_tx = usdc.functions.approve(ENTITY_ADDRESS, amount).build_transaction({
    'from': account.address,
    'nonce': w3.eth.get_transaction_count(account.address)
})
signed = account.sign_transaction(approve_tx)
w3.eth.send_raw_transaction(signed.rawTransaction)

# Donate
tx = entity.functions.donate(amount).build_transaction({
    'from': account.address,
    'nonce': w3.eth.get_transaction_count(account.address)
})
signed_tx = account.sign_transaction(tx)
w3.eth.send_raw_transaction(signed_tx.rawTransaction)
```

## Token Swap + Donation

Swap any ERC20 to USDC and donate:

```typescript theme={null}
const WETH_ADDRESS = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
const USDC_ADDRESS = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
const ENTITY_ADDRESS = '0x...';  // Your entity
const SWAP_WRAPPER_ADDRESS = '0x60303F43028AD7198bc4bDF96ccBf734A87444df';

const weth = new ethers.Contract(WETH_ADDRESS, WETH_ABI, signer);
const entity = new ethers.Contract(ENTITY_ADDRESS, ENTITY_ABI, signer);
const amount = ethers.utils.parseEther('1');

// Hardcoded for example - in practice, this should be fetched from
// smart order router / Endaoment's backend
const path = ethers.utils.solidityPack(
  ['address', 'uint24', 'address'],
  [WETH_ADDRESS, 3000, USDC_ADDRESS]
);
const minOutput = ethers.utils.parseUnits('1800', 6);  // Min USDC with slippage
const deadline = Math.floor(Date.now() / 1000) + 600;  // 10 min
const swapData = ethers.utils.defaultAbiCoder.encode(
  ['bytes', 'uint256', 'uint256'],
  [path, minOutput, deadline]
);

await weth.approve(ENTITY_ADDRESS, amount);
await entity.swapAndDonate(SWAP_WRAPPER_ADDRESS, WETH_ADDRESS, amount, swapData);
```

### ETH Donation

```typescript theme={null}
const ETH_PLACEHOLDER = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
const amount = ethers.utils.parseEther('0.5');

// Encode swap path (WETH -> USDC)
const path = ethers.utils.solidityPack(
  ['address', 'uint24', 'address'],
  [WETH_ADDRESS, 3000, USDC_ADDRESS]
);
const minOutput = ethers.utils.parseUnits('900', 6);
const deadline = Math.floor(Date.now() / 1000) + 600;
const swapData = ethers.utils.defaultAbiCoder.encode(
  ['bytes', 'uint256', 'uint256'],
  [path, minOutput, deadline]
);

await entity.swapAndDonate(
  SWAP_WRAPPER_ADDRESS,
  ETH_PLACEHOLDER,
  amount,
  swapData,
  { value: amount }
);
```

## Reconcile Balance

Process USDC sent directly to entity:

```typescript theme={null}
await entity.reconcileBalance();
```

## Donation Fees

| Entity Type | Inbound Fee   | Note                                                        |
| ----------- | ------------- | ----------------------------------------------------------- |
| Org         | 1.5% (150 bp) | 100 USDC → 1.5 USDC fee, 98.5 USDC net                      |
| Fund        | 0.05-0.50%    | Tiered: 0.50% on first $250k, declining to 0.05% over $100M |

Funds also have 1.0% outbound fee on grants. Check exact fee: `registry.getDonationFee(entityAddress)`

<Note>
  Fee timing and compounding: inbound donation fees apply when the donation is processed (e.g., `donate()` or `swapAndDonate()`), reducing the entity’s USDC balance by the fee immediately. Outbound fees apply when funds are transferred via grants. If you donate and then later transfer, each step applies its respective fee (they do not “compound” at one step, but both fees apply across the two actions). Always verify exact fees via the Registry before large transactions.
</Note>

## Common Errors

| Error                           | Fix                                                                                                      |
| ------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `EntityInactive`                | Entity not active. Check: `registry.isActiveEntity(entityAddress)`                                       |
| `ERC20: insufficient allowance` | Increase approval: `usdc.approve(entity, amount)`                                                        |
| `InvalidAction`                 | Swap wrapper not approved. Check: `registry.isSwapperSupported(wrapperAddress)` before using the wrapper |

## Advanced Patterns

### Calculate Fees

```typescript theme={null}
const registry = new ethers.Contract(REGISTRY_ADDRESS, REGISTRY_ABI, provider);
const feeInBp = await registry.getDonationFee(entityAddress);
const feeAmount = amount.mul(feeInBp).div(10000);
const netAmount = amount.sub(feeAmount);
```

### Batch Donations

```typescript theme={null}
for (const {address, amount} of recipients) {
  const entity = new ethers.Contract(address, ENTITY_ABI, signer);
  await entity.donate(ethers.utils.parseUnits(amount, 6));
}
```

### Contract Integration

```solidity theme={null}
contract DonationHelper {
    function donateToEntity(address entity, uint256 amount) external {
        IERC20(usdc).transferFrom(msg.sender, address(this), amount);
        IERC20(usdc).approve(entity, amount);
        IEntity(entity).donate(amount);
    }
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Entity State" href="/developers/contracts/entity-state" icon="chart-simple">
    Query entity balances and info
  </Card>

  <Card title="Entity Deployment" href="/developers/contracts/entity-deployment" icon="rocket">
    Deploy Orgs and Funds
  </Card>

  <Card title="Entity Best Practices" href="/developers/contracts/entity-best-practices" icon="star">
    Implement production safeguards
  </Card>

  <Card title="Entity Events" href="/developers/contracts/entity-events" icon="bell">
    Monitor donation activity
  </Card>
</CardGroup>
