An automated collateral top-up system for Aave V3 positions using TriggerX SDK. This system monitors your Aave health factor and automatically supplies additional collateral when it falls below a specified threshold, protecting your position from liquidation.
This application:
- Monitors your Aave V3 position health factor in real-time
- Automatically triggers collateral top-up when health factor drops below threshold
- Uses Safe wallet for secure automated transactions
- Leverages TriggerX for decentralized automation
- Exposes a health monitoring API that TriggerX polls
- Node.js (v16 or higher)
- npm or yarn
- A wallet with:
- ETH for gas fees
- WETH for collateral top-up
- An active Aave V3 position with collateral and debt
- TriggerX API Key
- ngrok for exposing local API to the internet
git clone https://github.com/trigg3rX/aave-triggerX.git
cd aave-triggerX
npm installCreate a .env file in the root directory:
# Your wallet private key (must have ETH for gas)
PRIVATE_KEY=your_private_key_here
# TriggerX API Key (get from https://triggerx.network/)
TRIGGERX_API_KEY=your_triggerx_api_key_here
# Blockchain Configuration
SEPOLIA_RPC_URL=https://sepolia.optimism.io
CHAIN_ID=11155420
# Your wallet address (the one with Aave position)
USER_ADDRESS=0xYourWalletAddress
# Safe wallet address (will be created if not provided)
SAFE_WALLET_ADDRESS=0xYourSafeWalletAddress
# Aave V3 Contract Addresses (Optimism Sepolia)
AAVE_POOL_ADDRESS=0xb50201558B00496A145fE76f7424749556E326D8
AAVE_POOL_DATA_PROVIDER=0x9991e51345F8E60Ec76d5AF29D910B93dcC05620
# Public URL for health monitoring API (set after running ngrok)
PUBLIC_URL=https://your-ngrok-url.ngrok-free.devnpm startThis will start a local API server on port 3000.
In a new terminal:
ngrok http 3000Copy the ngrok URL (e.g., https://abc123.ngrok-free.dev) and update your .env file:
PUBLIC_URL=https://abc123.ngrok-free.devnpm run create-safeCopy the Safe wallet address to your .env file as SAFE_WALLET_ADDRESS.
Transfer WETH and ETH to your Safe wallet:
- WETH: For collateral top-up (e.g., 0.1 WETH)
- ETH: For gas fees (e.g., 0.01 ETH)
npm run approve-wethnpm run deploy-ngrokYour automation is now active!
aave-triggerX/
├── src/
│ ├── contracts/
│ │ └── abis.ts # Smart contract ABIs and addresses
│ ├── services/
│ │ ├── aave.service.ts # Aave interaction logic
│ │ ├── health-monitor.service.ts # Health monitoring API
│ │ └── triggerx.service.ts # TriggerX SDK integration
│ ├── utils/
│ │ └── config.ts # Configuration management
│ └── main.ts # Application entry point
├── scripts/
│ ├── create-safe-wallet.ts # Create Safe wallet
│ ├── prepare-safe-wallet.ts # Check Safe wallet status
│ ├── approve-weth-for-aave.ts # Approve WETH spending
│ └── deploy-ngrok-job.ts # Deploy job with ngrok URL
├── .env # Environment configuration
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
└── README.md # This file
- Health Monitoring API: Your local server exposes an endpoint that returns your current Aave health factor
- ngrok Tunnel: Exposes your local API to the internet so TriggerX can access it
- TriggerX Job: Polls your health factor API every ~90 seconds
- Condition Check: When health factor ≤ threshold, TriggerX triggers the job
- Safe Wallet Execution: The job executes via your Safe wallet, which:
- Approves WETH for Aave Pool
- Supplies collateral to Aave on your behalf
- Position Protected: Your health factor increases, protecting from liquidation
To use this system on different chains (e.g., Ethereum Mainnet, Arbitrum):
# Example: Ethereum Mainnet
SEPOLIA_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/your-api-key
CHAIN_ID=1
# Example: Arbitrum
SEPOLIA_RPC_URL=https://arb-mainnet.g.alchemy.com/v2/your-api-key
CHAIN_ID=42161Find Aave V3 addresses for your target chain from Aave Docs:
# Example: Ethereum Mainnet
AAVE_POOL_ADDRESS=0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2
AAVE_POOL_DATA_PROVIDER=0x7B4EB56E7CD4b454BA8ff71E4518426369a138a3Edit src/contracts/abis.ts:
// Update WETH address for your chain
export const WETH_ADDRESS = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'; // ETH Mainnet
// Common WETH addresses:
// Ethereum: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
// : 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619
// Arbitrum: 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
// Optimism: 0x4200000000000000000000000000000000000006To monitor a different wallet address:
# Change to the wallet you want to monitor
USER_ADDRESS=0xNewWalletAddressIf you want a new Safe wallet for this address:
npm run create-safeUpdate the new Safe address in .env:
SAFE_WALLET_ADDRESS=0xNewSafeWalletAddress- Fund the new Safe wallet with WETH and ETH
- Approve WETH:
npm run approve-weth - Deploy automation:
npm run deploy-ngrok
Edit src/utils/config.ts:
export const config = {
// ... other config
// Change threshold (1.2 = position triggers when HF drops below 1.2)
healthFactorThreshold: 1.5, // More conservative
// Change top-up amount (in wei)
topUpAmount: '50000000000000000', // 0.05 ETH instead of 0.01
// Change job duration (in seconds)
jobDuration: 3600, // 1 hour instead of 5 minutes
};If you have your own API for health monitoring:
Edit src/services/health-monitor.service.ts to add your custom logic, or replace it entirely with your API implementation.
If you already have a running health monitor API:
-
Ensure your API returns the health factor as a plain number (text/plain):
GET https://your-api.com/health-factor/{address} Response: 1.45 -
Update
scripts/deploy-ngrok-job.ts:
const jobInput = {
// ... other config
// Point to your external API
valueSourceUrl: `https://your-api.com/health-factor/${config.userAddress}`,
// ... rest of config
};- You don't need to run
npm startif using an external API - Deploy directly:
npm run deploy-ngrok
Your API must:
- Return health factor as a plain number (Content-Type: text/plain)
- Respond within 5-6 seconds (TriggerX timeout)
- Be publicly accessible (TriggerX needs to poll it)
- Return
0on errors
Example API response:
1.45
NOT JSON:
{"healthFactor": 1.45} // Won't workTo supply a different asset instead of WETH, edit scripts/deploy-ngrok-job.ts:
// Change WETH_ADDRESS to your desired token
const YOUR_TOKEN_ADDRESS = '0xYourTokenAddress';
// Update in safeTransactions
safeTransactions: [
{
// Approve your token instead of WETH
to: YOUR_TOKEN_ADDRESS,
data: new ethers.Interface([...]).encodeFunctionData('approve', [
config.aave.poolAddress,
ethers.MaxUint256
]),
// ...
},
{
// Supply your token
to: config.aave.poolAddress,
data: new ethers.Interface([...]).encodeFunctionData('supply', [
YOUR_TOKEN_ADDRESS, // Your token
config.topUpAmount,
config.userAddress,
0
]),
// ...
}
]You can add multiple transactions in safeTransactions array:
safeTransactions: [
// Transaction 1: Approve WETH
{ to: WETH_ADDRESS, data: approveData, operation: 0 },
// Transaction 2: Supply WETH
{ to: AAVE_POOL, data: supplyData, operation: 0 },
// Transaction 3: Enable collateral
{ to: AAVE_POOL, data: enableCollateralData, operation: 0 },
]npm start # Start health monitoring API
npm run deploy-ngrok # Deploy TriggerX job with ngrok URL
npm run create-safe # Create a new Safe wallet
npm run prepare-safe # Check Safe wallet balance and status
npm run approve-weth # Approve WETH for Aave Pool from Safe wallet
npm run build # Build TypeScript to JavaScript
npm run dev # Run in development mode with auto-reload
npm run clean # Remove build artifacts- Private Keys: Never commit
.envfile or share your private keys - Safe Wallet: Automation executes through Safe wallet, providing an additional security layer
- WETH Approval: Approves maximum WETH to avoid repeated approvals (save gas)
- API Exposure: ngrok exposes your health API publicly - ensure no sensitive data is exposed
- Fund Management: Only fund Safe wallet with amount needed for automation
-
Check health factor: Ensure it's actually below threshold
curl https://your-ngrok-url.ngrok-free.dev/health-factor/your-address
-
Verify Safe wallet:
npm run prepare-safe
- Ensure it has WETH for top-up
- Ensure it has ETH for gas
- Ensure WETH is approved for Aave Pool
-
Check ngrok: Ensure ngrok is running and URL is correct in
.env -
Job Status: Check if job is expired or completed (non-recurring jobs execute once)
If TriggerX times out calling your API:
- Check RPC provider speed (use Alchemy/Infura for faster responses)
- Ensure ngrok is running
- Verify firewall isn't blocking ngrok
- Insufficient ETH for gas in Safe wallet
- Insufficient WETH in Safe wallet
- WETH not approved for Aave Pool
- Health factor already above threshold
To make the job recurring (triggers multiple times):
Edit scripts/deploy-ngrok-job.ts:
const jobInput = {
// ...
recurring: true, // Change to true
timeFrame: 86400, // 24 hours
// ...
};To monitor multiple addresses:
- Create separate
.envfiles (.env.wallet1,.env.wallet2) - Run multiple instances:
# Terminal 1 NODE_ENV=wallet1 npm start # Terminal 2 (use different port) NODE_ENV=wallet2 PORT=3001 npm start
- Create separate ngrok tunnels for each
- Deploy separate jobs for each address
TriggerX supports various condition types:
conditionType: 'less_equal' // Health factor <= threshold
conditionType: 'greater_equal' // Health factor >= threshold
conditionType: 'equal' // Health factor == threshold
conditionType: 'between' // lowerLimit <= HF <= upperLimitThis software is provided "as is" without warranty of any kind. Use at your own risk. Always test thoroughly on testnets before using with real funds. The authors are not responsible for any loss of funds.
Built using TriggerX, Aave V3, and Safe Wallet