web3-defi-protocols
SKILL.md
DeFi Protocol Integration
Connect SpoonOS agents to major DeFi protocols.
Supported Protocols
| Protocol | Type | Chains |
|---|---|---|
| Aave V3 | Lending | ETH, Polygon, Arbitrum, Optimism, Base |
| Compound V3 | Lending | ETH, Polygon, Arbitrum, Base |
| 1inch | DEX Aggregator | All major EVM |
| CoW Protocol | MEV-protected swaps | ETH, Gnosis |
| Uniswap V3 | DEX | All major EVM |
Aave V3 Integration
Contract Addresses
AAVE_V3_ADDRESSES = {
"ethereum": {
"pool": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"pool_data_provider": "0x7B4EB56E7CD4b454BA8ff71E4518426369a138a3",
"oracle": "0x54586bE62E3c3580375aE3723C145253060Ca0C2"
},
"polygon": {
"pool": "0x794a61358D6845594F94dc1DB02A252b5b4814aD",
"pool_data_provider": "0x69FA688f1Dc47d4B5d8029D5a35FB7a548310654",
"oracle": "0xb023e699F5a33916Ea823A16485e259257cA8Bd1"
},
"arbitrum": {
"pool": "0x794a61358D6845594F94dc1DB02A252b5b4814aD",
"pool_data_provider": "0x69FA688f1Dc47d4B5d8029D5a35FB7a548310654",
"oracle": "0xb56c2F0B653B2e0b10C9b928C8580Ac5Df02C7C7"
},
"base": {
"pool": "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5",
"pool_data_provider": "0x2d8A3C5677189723C4cB8873CfC9C8976FDF38Ac",
"oracle": "0x2Cc0Fc26eD4563A5ce5e8bdcfe1A2878676Ae156"
}
}
Aave Tool Implementation
# scripts/aave_lending.py
from spoon_ai.tools.base import BaseTool
from pydantic import Field
from web3 import Web3
import json
AAVE_POOL_ABI = [...] # See references/aave-abi.md
class AaveLendingTool(BaseTool):
name: str = "aave_lending"
description: str = "Supply, borrow, repay on Aave V3"
parameters: dict = Field(default={
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["supply", "borrow", "repay", "withdraw", "positions"],
"description": "Lending action to perform"
},
"asset": {"type": "string", "description": "Token symbol (USDC, WETH, etc.)"},
"amount": {"type": "string", "description": "Amount in token units"},
"chain": {"type": "string", "default": "ethereum"}
},
"required": ["action"]
})
async def execute(self, action: str, asset: str = None,
amount: str = None, chain: str = "ethereum") -> str:
if action == "positions":
return await self._get_positions(chain)
elif action == "supply":
return await self._supply(asset, amount, chain)
elif action == "borrow":
return await self._borrow(asset, amount, chain)
elif action == "repay":
return await self._repay(asset, amount, chain)
elif action == "withdraw":
return await self._withdraw(asset, amount, chain)
async def _get_positions(self, chain: str) -> str:
"""Get user's Aave positions."""
addresses = AAVE_V3_ADDRESSES[chain]
w3 = Web3(Web3.HTTPProvider(RPC_URLS[chain]))
pool_data = w3.eth.contract(
address=addresses["pool_data_provider"],
abi=POOL_DATA_PROVIDER_ABI
)
user_address = os.getenv("WALLET_ADDRESS")
reserves = pool_data.functions.getUserReservesData(
addresses["pool"],
user_address
).call()
positions = []
for reserve in reserves:
if reserve[1] > 0 or reserve[2] > 0: # supplied or borrowed
positions.append({
"asset": reserve[0],
"supplied": reserve[1] / 1e18,
"borrowed": reserve[2] / 1e18
})
return json.dumps({"positions": positions}, indent=2)
1inch Integration
API Configuration
ONEINCH_API = {
"base_url": "https://api.1inch.dev",
"swap_endpoint": "/swap/v6.0/{chain_id}/swap",
"quote_endpoint": "/swap/v6.0/{chain_id}/quote",
"tokens_endpoint": "/swap/v6.0/{chain_id}/tokens"
}
CHAIN_IDS = {
"ethereum": 1,
"polygon": 137,
"arbitrum": 42161,
"optimism": 10,
"base": 8453
}
1inch Swap Tool
# scripts/oneinch_swap.py
import aiohttp
import os
from spoon_ai.tools.base import BaseTool
from pydantic import Field
class OneInchSwapTool(BaseTool):
name: str = "oneinch_swap"
description: str = "Get swap quotes and execute via 1inch aggregator"
parameters: dict = Field(default={
"type": "object",
"properties": {
"action": {"type": "string", "enum": ["quote", "swap"]},
"from_token": {"type": "string", "description": "Source token address"},
"to_token": {"type": "string", "description": "Destination token address"},
"amount": {"type": "string", "description": "Amount in wei"},
"chain": {"type": "string", "default": "ethereum"},
"slippage": {"type": "number", "default": 1, "description": "Slippage %"}
},
"required": ["action", "from_token", "to_token", "amount"]
})
async def execute(self, action: str, from_token: str, to_token: str,
amount: str, chain: str = "ethereum", slippage: float = 1) -> str:
chain_id = CHAIN_IDS[chain]
api_key = os.getenv("ONEINCH_API_KEY")
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
if action == "quote":
url = f"{ONEINCH_API['base_url']}/swap/v6.0/{chain_id}/quote"
params = {
"src": from_token,
"dst": to_token,
"amount": amount
}
else:
url = f"{ONEINCH_API['base_url']}/swap/v6.0/{chain_id}/swap"
params = {
"src": from_token,
"dst": to_token,
"amount": amount,
"from": os.getenv("WALLET_ADDRESS"),
"slippage": slippage
}
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers, params=params) as resp:
if resp.status != 200:
error = await resp.text()
return f"Error: {error}"
data = await resp.json()
if action == "quote":
return self._format_quote(data)
else:
return self._format_swap(data)
def _format_quote(self, data: dict) -> str:
return f"""
1inch Quote:
- From: {data['srcToken']['symbol']}
- To: {data['dstToken']['symbol']}
- Input: {int(data['srcAmount']) / 10**data['srcToken']['decimals']:.6f}
- Output: {int(data['dstAmount']) / 10**data['dstToken']['decimals']:.6f}
- Gas: {data.get('gas', 'N/A')}
"""
CoW Protocol Integration
MEV-Protected Swaps
# scripts/cow_swap.py
import aiohttp
from spoon_ai.tools.base import BaseTool
from pydantic import Field
from eth_account import Account
from eth_account.messages import encode_typed_data
COW_API = {
"ethereum": "https://api.cow.fi/mainnet",
"gnosis": "https://api.cow.fi/xdai"
}
class CowSwapTool(BaseTool):
name: str = "cow_swap"
description: str = "MEV-protected swaps via CoW Protocol"
parameters: dict = Field(default={
"type": "object",
"properties": {
"action": {"type": "string", "enum": ["quote", "order"]},
"sell_token": {"type": "string"},
"buy_token": {"type": "string"},
"sell_amount": {"type": "string"},
"chain": {"type": "string", "default": "ethereum"}
},
"required": ["action", "sell_token", "buy_token", "sell_amount"]
})
async def execute(self, action: str, sell_token: str, buy_token: str,
sell_amount: str, chain: str = "ethereum") -> str:
base_url = COW_API[chain]
if action == "quote":
return await self._get_quote(base_url, sell_token, buy_token, sell_amount)
else:
return await self._create_order(base_url, sell_token, buy_token, sell_amount)
async def _get_quote(self, base_url: str, sell_token: str,
buy_token: str, sell_amount: str) -> str:
url = f"{base_url}/api/v1/quote"
payload = {
"sellToken": sell_token,
"buyToken": buy_token,
"sellAmountBeforeFee": sell_amount,
"kind": "sell",
"from": os.getenv("WALLET_ADDRESS"),
"receiver": os.getenv("WALLET_ADDRESS")
}
async with aiohttp.ClientSession() as session:
async with session.post(url, json=payload) as resp:
if resp.status != 200:
return f"Error: {await resp.text()}"
data = await resp.json()
return f"""
CoW Protocol Quote:
- Sell: {int(data['quote']['sellAmount']) / 1e18:.6f}
- Buy: {int(data['quote']['buyAmount']) / 1e18:.6f}
- Fee: {int(data['quote']['feeAmount']) / 1e18:.6f}
- Valid until: {data['quote']['validTo']}
- MEV Protected: Yes
"""
Yield Strategy Tools
APY Aggregator
# scripts/yield_finder.py
import aiohttp
from spoon_ai.tools.base import BaseTool
from pydantic import Field
DEFI_LLAMA_API = "https://yields.llama.fi"
class YieldFinderTool(BaseTool):
name: str = "yield_finder"
description: str = "Find best DeFi yields across protocols"
parameters: dict = Field(default={
"type": "object",
"properties": {
"token": {"type": "string", "description": "Token symbol"},
"chain": {"type": "string", "default": "all"},
"min_tvl": {"type": "number", "default": 1000000},
"top_n": {"type": "integer", "default": 5}
},
"required": ["token"]
})
async def execute(self, token: str, chain: str = "all",
min_tvl: float = 1000000, top_n: int = 5) -> str:
async with aiohttp.ClientSession() as session:
async with session.get(f"{DEFI_LLAMA_API}/pools") as resp:
if resp.status != 200:
return f"Error fetching yields"
pools = await resp.json()
# Filter by token and criteria
filtered = [
p for p in pools["data"]
if token.upper() in p.get("symbol", "").upper()
and p.get("tvlUsd", 0) >= min_tvl
and (chain == "all" or p.get("chain", "").lower() == chain.lower())
]
# Sort by APY
filtered.sort(key=lambda x: x.get("apy", 0), reverse=True)
result = f"Top {top_n} yields for {token}:\n\n"
for i, pool in enumerate(filtered[:top_n], 1):
result += f"""{i}. {pool['project']} ({pool['chain']})
- APY: {pool['apy']:.2f}%
- TVL: ${pool['tvlUsd']:,.0f}
- Pool: {pool['symbol']}
"""
return result
Token Addresses
Common Tokens
TOKENS = {
"ethereum": {
"USDC": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"USDT": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
"DAI": "0x6B175474E89094C44Da98b954EeacdeCB5BE3830",
"WETH": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"WBTC": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
"AAVE": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"
},
"polygon": {
"USDC": "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", # Native USDC
"USDT": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
"WETH": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619",
"WPOL": "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270"
},
"arbitrum": {
"USDC": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", # Native
"USDT": "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
"WETH": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
"ARB": "0x912CE59144191C1204E64559FE8253a0e49E6548"
},
"base": {
"USDC": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"WETH": "0x4200000000000000000000000000000000000006",
"cbETH": "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22"
}
}
Environment Variables
# API Keys
ONEINCH_API_KEY=...
# RPC URLs
ETHEREUM_RPC=https://eth.llamarpc.com
POLYGON_RPC=https://polygon-rpc.com
ARBITRUM_RPC=https://arb1.arbitrum.io/rpc
# Wallet
PRIVATE_KEY=0x...
WALLET_ADDRESS=0x...
References
references/aave-abi.md- Aave V3 contract ABIsreferences/defi-addresses.md- Protocol addresses by chainreferences/token-lists.md- Verified token addresses
Weekly Installs
1
Repository
xspoonai/spoon-…me-skillGitHub Stars
12
First Seen
6 days ago
Security Audits
Installed on
amp1
cline1
openclaw1
opencode1
cursor1
kimi-cli1