Skip to content
CanopySplit

CanopySplit

Turn Idle Capital into Urban Shade

Created on 9th November 2025

CanopySplit

CanopySplit

Turn Idle Capital into Urban Shade

The problem CanopySplit solves

1. Passive Climate Impact Without Losing Principal

  • Deposit WETH (or any ERC-20 asset) into yield-generating strategies
  • Keep 100% of your principal - withdraw anytime
  • All profits automatically fund climate projects - tree planting, MRV (monitoring/reporting/verification), maintenance
  • No manual donations, no performance fees, no middlemen

2. Transparent, Epoch-Based Allocation

  • Dynamic splits: Owner can adjust future epoch weights (e.g., 50% Planters, 30% MRV, 20% Maintenance)
  • On-chain receipts: Every distribution emits

    Distributed

    events with full breakdown
  • Live tracking: Frontend shows pending donations, lifetime donated, current epoch policy

3. Multi-Source Yield Aggregation

  • Aave v3 Integration: Deposits earn yield through aTokens (18-decimal WETH on Sepolia)
  • ERC-4626 Wrapper: Standard vault interface for composability
  • Uniswap v4 Hook (Local PoC): Swap fees can also donate to the same splitter

4. Role-Based Governance

  • Management/Keeper: Can trigger

    report()

    to realize profits → mint donation shares
  • Owner: Can adjust epoch weights and roll to new epochs
  • Users: Just deposit/withdraw; yield flows automatically

Challenges I ran into

Challenge 1: Sepolia Gas Cap Hell (16.7M limit)

The Bug:

Error: server returned an error response: error code -32000: transaction gas limit too high (cap: 16777216, tx: 25000000) # Then when we lowered it: Error: execution reverted: EvmError: OutOfGas (gas: 16711680) # Foundry said "Deployed to: 0x..." but: cast code 0xA487... --rpc-url $SEPOLIA_RPC_URL # Returns: 0x (NO CODE!)

What Was Happening:

  • Deploying

    YieldDonatingTokenizedStrategy

    implementation hit Sepolia's hard per-tx gas cap of 16,777,216
  • Contract creation bytecode was too large even with optimizer enabled
  • Foundry printed "Deployed to..." even when the tx reverted (misleading!)
  • We tried 15.7M gas → OOG. Tried 16.7M → rejected by node. Tried 16.6M → OOG again.

How We Fixed It:

foundry.toml - AGGRESSIVE size reduction [profile.default] optimizer = true optimizer_runs = 1 # Minimize runtime size via_ir = false # Reduce init complexity bytecode_hash = "none" # Remove metadata cbor_metadata = false # Remove CBOR

# Force clean rebuild forge clean && forge build -vvv # Deploy just under cap with legacy tx forge create YieldDonatingTokenizedStrategy \ --gas-limit 0xFD0000 \ # 16,646,144 (under cap) --gas-price 2gwei \ --legacy \ # Avoid EIP-1559 estimation quirks --broadcast -vvvv VERIFY it actually exists: cast code $IMPL --rpc-url $SEPOLIA_RPC_URL | wc -c # > 2 = success! cast call $IMPL "apiVersion()(string)" # "1.0.0" ✅

Result: Successfully deployed implementation at

0xE668230D8F3289F9e252cA67Cc7dbEDaE9dB90E5


Challenge 2: USDC Supply Cap Full on Sepolia

The Bug:

Tried to deploy ATokenVault for USDC: Error: call to non-contract address 0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e Then when we used correct PoolAddressesProvider: Deposits would fail with "supply cap reached" or liquidity issues

What Was Happening:

  • Aave v3 Sepolia USDC market had supply cap limits
  • Test USDC addresses on Sepolia were fragmented (multiple versions)
  • PoolAddressesProvider address from mainnet docs doesn't exist on Sepolia

How We Fixed It - THE WETH PIVOT:

Switched to WETH (18 decimals, no supply cap issues) export USDC_UNDERLYING=0xC558DBdd856501FCd9aaF1E62eae57A9F0629a3c # WETH! export AAVE_ADDRESSES_PROVIDER=0x012bAC54348C0E635dCAc9D5FB99f06F24136C9A # Correct Sepolia Deploy ATokenVault for WETH forge script script/DeployVault.s.sol:DeployVault \ --rpc-url $SEPOLIA_RPC_URL --broadcast -vv SUCCESS: ATokenVault (proxy): 0x6938238e57CBe1b4B51Eb3B51389cEf8d3a88521 ProxyAdmin: 0x119e5211b41f44362e6681e7EDF5fC07a46D7A4a Factory: 0x86b0e29414501643320B05AfF836D699681E450e

Challenge 3: Permit2 Allowance Spender Confusion (Uniswap v4)

The Bug:

Swap reverted with custom error: Error: custom error 0xe450d38c # InsufficientAllowance-style error Trace showed: Currency0::transferFrom(deployer, PoolManager, 1e18) └─ ← [Revert] custom error 0xe450d38c

What Was Happening:

  • We granted Permit2 allowance to PoolManager as spender
  • But the Router is the one that calls

    permit2.transferFrom()

    during settle
  • Permit2 checks:

    allowance[user][token][spender]

    where spender = Router, not PoolManager!

How We Fixed It:

// script/03_Swap.s.sol - BEFORE (wrong): permit2.approve(address(token0), address(poolManager), type(uint160).max, type(uint48).max); // AFTER (correct): // 1. Grant ERC20 approval to Permit2 token0.approve(address(permit2), type(uint256).max); // 2. Grant Permit2 allowance with Router as spender permit2.approve(address(token0), address(swapRouter), type(uint160).max, type(uint48).max); // 3. Also keep direct ERC20 approval to Router (fallback) token0.approve(address(swapRouter), type(uint256).max);

Result: Swap executed successfully, hook emitted

DonationExecuted

, recipients received donations!

Tracks Applied (6)

Best use of a Yield Donating Strategy

Complete Octant v2 YDS Implementation with Multi-Adapter Architecture ✅ Three Strategy Adapters: YieldDonatingStrateg...Read More

Most creative use of Octant v2 for public goods

Innovations: ✅ Epoch-Based Splits: Unlike single-recipient YDS, we route to 3 recipients with dynamic weights per epoch...Read More

Best tutorial for Octant v2 (written/video)

Blog Post about Octant V2 integration Wrote a blog post showing how Octant V2 makes the life easy for defi enthusiasts ...Read More

Best public goods projects

Transparent Climate Impact with Zero Fees ✅ Three Climate Recipients: Planters (50%), MRV (30%), Maintenance (20%) ✅ Tr...Read More

Best use of Aave v3 (Aave Vaults)

ERC-4626 Yield Vault with Aave v3 Integration ✅ ATokenVault Deployment on Sepolia: Vault (proxy): 0x6938238e57CBe1b4B...Read More

Best Use of Uniswap v4 Hooks

What We Built: TriSplitDonationHook - Micro-Donations on Every Swap ✅ Local Anvil Deployment: Hook at 0xf5e5DeaE9F2122...Read More

Technologies used

Cheer Project

Cheering for a project means supporting a project you like with as little as 0.0025 ETH. Right now, you can Cheer using ETH on Arbitrum, Optimism and Base.

Discussion

Builders also viewed

See more projects on Devfolio