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: YieldDonatingStrate...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