agent-treasury 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +143 -0
- package/dist/activate.d.ts +59 -0
- package/dist/activate.d.ts.map +1 -0
- package/dist/activate.js +167 -0
- package/dist/activate.js.map +1 -0
- package/dist/balance.d.ts +47 -0
- package/dist/balance.d.ts.map +1 -0
- package/dist/balance.js +91 -0
- package/dist/balance.js.map +1 -0
- package/dist/idle-detector.d.ts +45 -0
- package/dist/idle-detector.d.ts.map +1 -0
- package/dist/idle-detector.js +125 -0
- package/dist/idle-detector.js.map +1 -0
- package/dist/index.d.ts +76 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +121 -0
- package/dist/index.js.map +1 -0
- package/dist/yield-finder.d.ts +47 -0
- package/dist/yield-finder.d.ts.map +1 -0
- package/dist/yield-finder.js +153 -0
- package/dist/yield-finder.js.map +1 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Clicks Protocol
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# agent-treasury
|
|
2
|
+
|
|
3
|
+
Treasury management utilities for AI agents.
|
|
4
|
+
|
|
5
|
+
Your agent earns USDC. It sits idle. You earn 0%.
|
|
6
|
+
|
|
7
|
+
`agent-treasury` fixes that. Track balances across chains, compare DeFi yields in real time, get alerts when funds go idle, and activate earning with one call.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install agent-treasury ethers
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { AgentTreasury } from "agent-treasury";
|
|
19
|
+
|
|
20
|
+
const treasury = new AgentTreasury();
|
|
21
|
+
const report = await treasury.report("0xYourAgentWallet");
|
|
22
|
+
console.log(report.recommendation);
|
|
23
|
+
// → "500.00 USDC is idle. Best yield: 4.2% APY (~$21.00/year). Consider activating yield."
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Features
|
|
27
|
+
|
|
28
|
+
### Balance Tracker
|
|
29
|
+
|
|
30
|
+
Check USDC balances across Base, Ethereum, Arbitrum, and Optimism in a single call.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
const balances = await treasury.getBalances("0x...");
|
|
34
|
+
console.log(balances.totalFormatted); // "1250.00"
|
|
35
|
+
console.log(balances.balances); // per-chain breakdown
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Yield Finder
|
|
39
|
+
|
|
40
|
+
Compare live supply APY across Aave V3, Compound V3, and Morpho on Base.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
const yields = await treasury.compareYields();
|
|
44
|
+
console.log(yields.best);
|
|
45
|
+
// → { protocol: "aave-v3", supplyAPY: 4.2, asset: "USDC", chain: "base" }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Idle Balance Detection
|
|
49
|
+
|
|
50
|
+
Get alerted when USDC sits idle too long.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
// One-time check
|
|
54
|
+
const idle = await treasury.getIdleBalance("0x...");
|
|
55
|
+
|
|
56
|
+
// Continuous monitoring
|
|
57
|
+
treasury.watchIdle("0x...", (alert) => {
|
|
58
|
+
console.log(`${alert.totalIdleFormatted} USDC idle for ${alert.idleDurationHuman}`);
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Configure thresholds:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
const treasury = new AgentTreasury({
|
|
66
|
+
idleThresholdUsdc: 50, // Alert when > 50 USDC
|
|
67
|
+
idleTimeMs: 30 * 60 * 1000, // idle for > 30 minutes
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Activate Yield
|
|
72
|
+
|
|
73
|
+
Put idle USDC to work with one call.
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { ClicksActivator } from "agent-treasury";
|
|
77
|
+
|
|
78
|
+
const clicks = new ClicksActivator();
|
|
79
|
+
const result = await clicks.deposit(signer, "500.00");
|
|
80
|
+
// → Deposits 500 USDC into optimized yield strategy
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Full Report
|
|
84
|
+
|
|
85
|
+
Get a complete treasury overview: balances, yields, idle status, and recommendations.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
const report = await treasury.report("0x...");
|
|
89
|
+
// {
|
|
90
|
+
// balances: { totalFormatted: "500.00", ... },
|
|
91
|
+
// yields: { best: { protocol: "aave-v3", supplyAPY: 4.2 }, ... },
|
|
92
|
+
// idleStatus: { idleDurationHuman: "3d 2h", ... },
|
|
93
|
+
// recommendation: "500.00 USDC is idle. Best yield: 4.2% APY..."
|
|
94
|
+
// }
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Configuration
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
const treasury = new AgentTreasury({
|
|
101
|
+
// Custom RPC endpoints
|
|
102
|
+
rpcs: {
|
|
103
|
+
base: "https://your-base-rpc.com",
|
|
104
|
+
ethereum: "https://your-eth-rpc.com",
|
|
105
|
+
},
|
|
106
|
+
// Track specific chains only
|
|
107
|
+
chains: ["base", "ethereum"],
|
|
108
|
+
// Yield protocols to compare
|
|
109
|
+
protocols: ["aave-v3", "compound-v3"],
|
|
110
|
+
// Idle detection settings
|
|
111
|
+
idleThresholdUsdc: 100,
|
|
112
|
+
idleTimeMs: 60 * 60 * 1000,
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## API
|
|
117
|
+
|
|
118
|
+
| Method | Description |
|
|
119
|
+
|--------|-------------|
|
|
120
|
+
| `getBalances(address)` | Multi-chain USDC balances |
|
|
121
|
+
| `compareYields()` | Compare DeFi APYs on Base |
|
|
122
|
+
| `getBestYield()` | Get highest current APY |
|
|
123
|
+
| `getIdleBalance(address)` | Check if balance is idle |
|
|
124
|
+
| `watchIdle(address, callback)` | Monitor for idle balances |
|
|
125
|
+
| `unwatchIdle(address)` | Stop monitoring |
|
|
126
|
+
| `report(address)` | Full treasury report |
|
|
127
|
+
|
|
128
|
+
## How It Works
|
|
129
|
+
|
|
130
|
+
1. **Balance Tracker** reads USDC balances via public RPC on Base, Ethereum, Arbitrum, and Optimism
|
|
131
|
+
2. **Yield Finder** queries Aave V3 and Compound V3 smart contracts on Base for current supply rates
|
|
132
|
+
3. **Idle Detector** compares balance snapshots over time to detect stagnant funds
|
|
133
|
+
4. **Activate** (optional) connects to Clicks Protocol to deposit idle USDC into yield strategies
|
|
134
|
+
|
|
135
|
+
Balance tracking and yield comparison work entirely standalone. The Clicks integration is an optional feature for agents that want automated yield activation.
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
Powered by [Clicks Protocol](https://clicksprotocol.xyz)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ethers } from "ethers";
|
|
2
|
+
export interface ActivateConfig {
|
|
3
|
+
/** Custom Clicks Router address (for testnet/custom deployments) */
|
|
4
|
+
routerAddress?: string;
|
|
5
|
+
/** Max slippage in basis points (default: 50 = 0.5%) */
|
|
6
|
+
maxSlippageBps?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface ActivateResult {
|
|
9
|
+
success: boolean;
|
|
10
|
+
txHash?: string;
|
|
11
|
+
sharesReceived?: string;
|
|
12
|
+
amountDeposited?: string;
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface YieldPosition {
|
|
16
|
+
shares: bigint;
|
|
17
|
+
estimatedValue: string;
|
|
18
|
+
protocol: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Activate yield on idle USDC via Clicks Protocol.
|
|
22
|
+
*
|
|
23
|
+
* This is the optional "earn on idle" feature.
|
|
24
|
+
* All other agent-treasury features work without it.
|
|
25
|
+
*/
|
|
26
|
+
export declare class ClicksActivator {
|
|
27
|
+
private routerAddress;
|
|
28
|
+
private maxSlippageBps;
|
|
29
|
+
constructor(config?: ActivateConfig);
|
|
30
|
+
/**
|
|
31
|
+
* Check if Clicks Protocol is available (contracts deployed).
|
|
32
|
+
* Returns false if router address is the zero address (pre-launch).
|
|
33
|
+
*/
|
|
34
|
+
isAvailable(): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Deposit idle USDC into Clicks Protocol yield strategies.
|
|
37
|
+
*
|
|
38
|
+
* @param signer - Ethers signer with USDC balance
|
|
39
|
+
* @param amountUsdc - Amount in USDC (human readable, e.g. "500.00")
|
|
40
|
+
*/
|
|
41
|
+
deposit(signer: ethers.Signer, amountUsdc: string): Promise<ActivateResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Withdraw from Clicks Protocol back to USDC.
|
|
44
|
+
*
|
|
45
|
+
* @param signer - Ethers signer that deposited
|
|
46
|
+
* @param shares - Amount of shares to withdraw
|
|
47
|
+
*/
|
|
48
|
+
withdraw(signer: ethers.Signer, shares: string): Promise<ActivateResult>;
|
|
49
|
+
/**
|
|
50
|
+
* Get current Clicks Protocol position for an address.
|
|
51
|
+
*/
|
|
52
|
+
getPosition(provider: ethers.Provider, address: string): Promise<YieldPosition | null>;
|
|
53
|
+
/**
|
|
54
|
+
* Quick start: one-call yield activation.
|
|
55
|
+
* Checks balance, finds best yield, deposits via Clicks.
|
|
56
|
+
*/
|
|
57
|
+
static quickStartMessage(idleAmount: string): string;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=activate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activate.d.ts","sourceRoot":"","sources":["../src/activate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAmChC,MAAM,WAAW,cAAc;IAC7B,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,cAAc,CAAS;gBAEnB,MAAM,GAAE,cAAmB;IAKvC;;;OAGG;IACH,WAAW,IAAI,OAAO;IAMtB;;;;;OAKG;IACG,OAAO,CACX,MAAM,EAAE,MAAM,CAAC,MAAM,EACrB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,cAAc,CAAC;IA0D1B;;;;;OAKG;IACG,QAAQ,CACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,CAAC;IAkC1B;;OAEG;IACG,WAAW,CACf,QAAQ,EAAE,MAAM,CAAC,QAAQ,EACzB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAyBhC;;;OAGG;IACH,MAAM,CAAC,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;CAWrD"}
|
package/dist/activate.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClicksActivator = void 0;
|
|
4
|
+
const ethers_1 = require("ethers");
|
|
5
|
+
/**
|
|
6
|
+
* Clicks Protocol integration for activating yield on idle USDC.
|
|
7
|
+
*
|
|
8
|
+
* This module connects to the Clicks Protocol smart contracts on Base
|
|
9
|
+
* to deposit idle USDC into optimized yield strategies.
|
|
10
|
+
*
|
|
11
|
+
* Clicks Protocol: https://clicksprotocol.xyz
|
|
12
|
+
*/
|
|
13
|
+
// Clicks Protocol contract addresses on Base
|
|
14
|
+
const CLICKS_CONTRACTS = {
|
|
15
|
+
/** Clicks Router — entry point for deposits */
|
|
16
|
+
router: "0x0000000000000000000000000000000000000000", // Placeholder until mainnet deploy
|
|
17
|
+
/** USDC on Base */
|
|
18
|
+
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
19
|
+
};
|
|
20
|
+
// ERC-20 approve ABI
|
|
21
|
+
const ERC20_APPROVE_ABI = [
|
|
22
|
+
"function approve(address spender, uint256 amount) returns (bool)",
|
|
23
|
+
"function allowance(address owner, address spender) view returns (uint256)",
|
|
24
|
+
];
|
|
25
|
+
// Clicks Router ABI (deposit interface)
|
|
26
|
+
const CLICKS_ROUTER_ABI = [
|
|
27
|
+
"function deposit(uint256 amount) external returns (uint256 shares)",
|
|
28
|
+
"function withdraw(uint256 shares) external returns (uint256 amount)",
|
|
29
|
+
"function balanceOf(address account) view returns (uint256)",
|
|
30
|
+
"function previewDeposit(uint256 assets) view returns (uint256 shares)",
|
|
31
|
+
"function previewWithdraw(uint256 shares) view returns (uint256 assets)",
|
|
32
|
+
"function totalAssets() view returns (uint256)",
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Activate yield on idle USDC via Clicks Protocol.
|
|
36
|
+
*
|
|
37
|
+
* This is the optional "earn on idle" feature.
|
|
38
|
+
* All other agent-treasury features work without it.
|
|
39
|
+
*/
|
|
40
|
+
class ClicksActivator {
|
|
41
|
+
constructor(config = {}) {
|
|
42
|
+
this.routerAddress = config.routerAddress ?? CLICKS_CONTRACTS.router;
|
|
43
|
+
this.maxSlippageBps = config.maxSlippageBps ?? 50;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if Clicks Protocol is available (contracts deployed).
|
|
47
|
+
* Returns false if router address is the zero address (pre-launch).
|
|
48
|
+
*/
|
|
49
|
+
isAvailable() {
|
|
50
|
+
return (this.routerAddress !== "0x0000000000000000000000000000000000000000");
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Deposit idle USDC into Clicks Protocol yield strategies.
|
|
54
|
+
*
|
|
55
|
+
* @param signer - Ethers signer with USDC balance
|
|
56
|
+
* @param amountUsdc - Amount in USDC (human readable, e.g. "500.00")
|
|
57
|
+
*/
|
|
58
|
+
async deposit(signer, amountUsdc) {
|
|
59
|
+
if (!this.isAvailable()) {
|
|
60
|
+
return {
|
|
61
|
+
success: false,
|
|
62
|
+
error: "Clicks Protocol not yet deployed. Visit https://clicksprotocol.xyz for launch updates.",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const amount = ethers_1.ethers.parseUnits(amountUsdc, 6);
|
|
67
|
+
const signerAddress = await signer.getAddress();
|
|
68
|
+
// Check and set approval
|
|
69
|
+
const usdc = new ethers_1.ethers.Contract(CLICKS_CONTRACTS.usdc, ERC20_APPROVE_ABI, signer);
|
|
70
|
+
const currentAllowance = await usdc.allowance(signerAddress, this.routerAddress);
|
|
71
|
+
if (currentAllowance < amount) {
|
|
72
|
+
const approveTx = await usdc.approve(this.routerAddress, amount);
|
|
73
|
+
await approveTx.wait();
|
|
74
|
+
}
|
|
75
|
+
// Deposit into Clicks
|
|
76
|
+
const router = new ethers_1.ethers.Contract(this.routerAddress, CLICKS_ROUTER_ABI, signer);
|
|
77
|
+
// Preview expected shares
|
|
78
|
+
const expectedShares = await router.previewDeposit(amount);
|
|
79
|
+
const minShares = expectedShares - (expectedShares * BigInt(this.maxSlippageBps)) / 10000n;
|
|
80
|
+
const tx = await router.deposit(amount);
|
|
81
|
+
const receipt = await tx.wait();
|
|
82
|
+
return {
|
|
83
|
+
success: true,
|
|
84
|
+
txHash: receipt.hash,
|
|
85
|
+
sharesReceived: expectedShares.toString(),
|
|
86
|
+
amountDeposited: amountUsdc,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
error: err instanceof Error ? err.message : String(err),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Withdraw from Clicks Protocol back to USDC.
|
|
98
|
+
*
|
|
99
|
+
* @param signer - Ethers signer that deposited
|
|
100
|
+
* @param shares - Amount of shares to withdraw
|
|
101
|
+
*/
|
|
102
|
+
async withdraw(signer, shares) {
|
|
103
|
+
if (!this.isAvailable()) {
|
|
104
|
+
return {
|
|
105
|
+
success: false,
|
|
106
|
+
error: "Clicks Protocol not yet deployed.",
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const router = new ethers_1.ethers.Contract(this.routerAddress, CLICKS_ROUTER_ABI, signer);
|
|
111
|
+
const sharesAmount = BigInt(shares);
|
|
112
|
+
const expectedAmount = await router.previewWithdraw(sharesAmount);
|
|
113
|
+
const tx = await router.withdraw(sharesAmount);
|
|
114
|
+
const receipt = await tx.wait();
|
|
115
|
+
return {
|
|
116
|
+
success: true,
|
|
117
|
+
txHash: receipt.hash,
|
|
118
|
+
amountDeposited: ethers_1.ethers.formatUnits(expectedAmount, 6),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
return {
|
|
123
|
+
success: false,
|
|
124
|
+
error: err instanceof Error ? err.message : String(err),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get current Clicks Protocol position for an address.
|
|
130
|
+
*/
|
|
131
|
+
async getPosition(provider, address) {
|
|
132
|
+
if (!this.isAvailable())
|
|
133
|
+
return null;
|
|
134
|
+
try {
|
|
135
|
+
const router = new ethers_1.ethers.Contract(this.routerAddress, CLICKS_ROUTER_ABI, provider);
|
|
136
|
+
const shares = await router.balanceOf(address);
|
|
137
|
+
if (shares === 0n)
|
|
138
|
+
return null;
|
|
139
|
+
const estimatedAssets = await router.previewWithdraw(shares);
|
|
140
|
+
return {
|
|
141
|
+
shares,
|
|
142
|
+
estimatedValue: ethers_1.ethers.formatUnits(estimatedAssets, 6),
|
|
143
|
+
protocol: "clicks",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Quick start: one-call yield activation.
|
|
152
|
+
* Checks balance, finds best yield, deposits via Clicks.
|
|
153
|
+
*/
|
|
154
|
+
static quickStartMessage(idleAmount) {
|
|
155
|
+
return [
|
|
156
|
+
`💰 You have ${idleAmount} USDC sitting idle.`,
|
|
157
|
+
``,
|
|
158
|
+
`Activate yield with Clicks Protocol:`,
|
|
159
|
+
` const clicks = new ClicksActivator();`,
|
|
160
|
+
` await clicks.deposit(signer, "${idleAmount}");`,
|
|
161
|
+
``,
|
|
162
|
+
`Learn more: https://clicksprotocol.xyz`,
|
|
163
|
+
].join("\n");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.ClicksActivator = ClicksActivator;
|
|
167
|
+
//# sourceMappingURL=activate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activate.js","sourceRoot":"","sources":["../src/activate.ts"],"names":[],"mappings":";;;AAAA,mCAAgC;AAEhC;;;;;;;GAOG;AAEH,6CAA6C;AAC7C,MAAM,gBAAgB,GAAG;IACvB,+CAA+C;IAC/C,MAAM,EAAE,4CAA4C,EAAE,mCAAmC;IACzF,mBAAmB;IACnB,IAAI,EAAE,4CAA4C;CACnD,CAAC;AAEF,qBAAqB;AACrB,MAAM,iBAAiB,GAAG;IACxB,kEAAkE;IAClE,2EAA2E;CAC5E,CAAC;AAEF,wCAAwC;AACxC,MAAM,iBAAiB,GAAG;IACxB,oEAAoE;IACpE,qEAAqE;IACrE,4DAA4D;IAC5D,uEAAuE;IACvE,wEAAwE;IACxE,+CAA+C;CAChD,CAAC;AAuBF;;;;;GAKG;AACH,MAAa,eAAe;IAI1B,YAAY,SAAyB,EAAE;QACrC,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,IAAI,gBAAgB,CAAC,MAAM,CAAC;QACrE,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,EAAE,CAAC;IACpD,CAAC;IAED;;;OAGG;IACH,WAAW;QACT,OAAO,CACL,IAAI,CAAC,aAAa,KAAK,4CAA4C,CACpE,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAO,CACX,MAAqB,EACrB,UAAkB;QAElB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EACH,wFAAwF;aAC3F,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,eAAM,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YAChD,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;YAEhD,yBAAyB;YACzB,MAAM,IAAI,GAAG,IAAI,eAAM,CAAC,QAAQ,CAC9B,gBAAgB,CAAC,IAAI,EACrB,iBAAiB,EACjB,MAAM,CACP,CAAC;YACF,MAAM,gBAAgB,GAAW,MAAM,IAAI,CAAC,SAAS,CACnD,aAAa,EACb,IAAI,CAAC,aAAa,CACnB,CAAC;YAEF,IAAI,gBAAgB,GAAG,MAAM,EAAE,CAAC;gBAC9B,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;gBACjE,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;YACzB,CAAC;YAED,sBAAsB;YACtB,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,QAAQ,CAChC,IAAI,CAAC,aAAa,EAClB,iBAAiB,EACjB,MAAM,CACP,CAAC;YAEF,0BAA0B;YAC1B,MAAM,cAAc,GAAW,MAAM,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YACnE,MAAM,SAAS,GACb,cAAc,GAAG,CAAC,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,GAAG,MAAM,CAAC;YAE3E,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACxC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;YAEhC,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,MAAM,EAAE,OAAO,CAAC,IAAI;gBACpB,cAAc,EAAE,cAAc,CAAC,QAAQ,EAAE;gBACzC,eAAe,EAAE,UAAU;aAC5B,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,CACZ,MAAqB,EACrB,MAAc;QAEd,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,mCAAmC;aAC3C,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,QAAQ,CAChC,IAAI,CAAC,aAAa,EAClB,iBAAiB,EACjB,MAAM,CACP,CAAC;YAEF,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,cAAc,GAAW,MAAM,MAAM,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;YAE1E,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;YAC/C,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;YAEhC,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,MAAM,EAAE,OAAO,CAAC,IAAI;gBACpB,eAAe,EAAE,eAAM,CAAC,WAAW,CAAC,cAAc,EAAE,CAAC,CAAC;aACvD,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CACf,QAAyB,EACzB,OAAe;QAEf,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;YAAE,OAAO,IAAI,CAAC;QAErC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,QAAQ,CAChC,IAAI,CAAC,aAAa,EAClB,iBAAiB,EACjB,QAAQ,CACT,CAAC;YAEF,MAAM,MAAM,GAAW,MAAM,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YACvD,IAAI,MAAM,KAAK,EAAE;gBAAE,OAAO,IAAI,CAAC;YAE/B,MAAM,eAAe,GAAW,MAAM,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;YAErE,OAAO;gBACL,MAAM;gBACN,cAAc,EAAE,eAAM,CAAC,WAAW,CAAC,eAAe,EAAE,CAAC,CAAC;gBACtD,QAAQ,EAAE,QAAQ;aACnB,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,iBAAiB,CAAC,UAAkB;QACzC,OAAO;YACL,eAAe,UAAU,qBAAqB;YAC9C,EAAE;YACF,sCAAsC;YACtC,yCAAyC;YACzC,mCAAmC,UAAU,KAAK;YAClD,EAAE;YACF,wCAAwC;SACzC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;CACF;AA/KD,0CA+KC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** USDC contract addresses per chain */
|
|
2
|
+
export declare const USDC_ADDRESSES: Record<string, string>;
|
|
3
|
+
/** Default public RPC endpoints */
|
|
4
|
+
export declare const DEFAULT_RPCS: Record<string, string>;
|
|
5
|
+
export type ChainName = "base" | "ethereum" | "arbitrum" | "optimism";
|
|
6
|
+
export interface ChainBalance {
|
|
7
|
+
chain: ChainName;
|
|
8
|
+
balance: bigint;
|
|
9
|
+
formatted: string;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
}
|
|
12
|
+
export interface BalanceSnapshot {
|
|
13
|
+
address: string;
|
|
14
|
+
balances: ChainBalance[];
|
|
15
|
+
total: bigint;
|
|
16
|
+
totalFormatted: string;
|
|
17
|
+
timestamp: number;
|
|
18
|
+
}
|
|
19
|
+
export interface BalanceHistoryEntry {
|
|
20
|
+
snapshot: BalanceSnapshot;
|
|
21
|
+
recordedAt: number;
|
|
22
|
+
}
|
|
23
|
+
export interface BalanceTrackerConfig {
|
|
24
|
+
/** Override RPC URLs per chain */
|
|
25
|
+
rpcs?: Partial<Record<ChainName, string>>;
|
|
26
|
+
/** Which chains to track (default: all) */
|
|
27
|
+
chains?: ChainName[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Multi-chain USDC balance tracker.
|
|
31
|
+
* Works standalone, no Clicks Protocol dependency.
|
|
32
|
+
*/
|
|
33
|
+
export declare class BalanceTracker {
|
|
34
|
+
private providers;
|
|
35
|
+
private chains;
|
|
36
|
+
private history;
|
|
37
|
+
constructor(config?: BalanceTrackerConfig);
|
|
38
|
+
/** Get USDC balance on a single chain */
|
|
39
|
+
getBalance(address: string, chain: ChainName): Promise<ChainBalance>;
|
|
40
|
+
/** Get USDC balances across all configured chains */
|
|
41
|
+
getBalances(address: string): Promise<BalanceSnapshot>;
|
|
42
|
+
/** Get balance history for an address */
|
|
43
|
+
getHistory(address: string): BalanceHistoryEntry[];
|
|
44
|
+
/** Clear history for an address (or all) */
|
|
45
|
+
clearHistory(address?: string): void;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=balance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"balance.d.ts","sourceRoot":"","sources":["../src/balance.ts"],"names":[],"mappings":"AAEA,wCAAwC;AACxC,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKjD,CAAC;AAEF,mCAAmC;AACnC,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAK/C,CAAC;AAKF,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;AAEtE,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,eAAe,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,kCAAkC;IAClC,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1C,2CAA2C;IAC3C,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;CACtB;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,SAAS,CAAqD;IACtE,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,OAAO,CAAiD;gBAEpD,MAAM,GAAE,oBAAyB;IAS7C,yCAAyC;IACnC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC;IAgB1E,qDAAqD;IAC/C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IA+B5D,yCAAyC;IACzC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAIlD,4CAA4C;IAC5C,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;CAOrC"}
|
package/dist/balance.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BalanceTracker = exports.DEFAULT_RPCS = exports.USDC_ADDRESSES = void 0;
|
|
4
|
+
const ethers_1 = require("ethers");
|
|
5
|
+
/** USDC contract addresses per chain */
|
|
6
|
+
exports.USDC_ADDRESSES = {
|
|
7
|
+
base: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
8
|
+
ethereum: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
9
|
+
arbitrum: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
|
|
10
|
+
optimism: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
|
|
11
|
+
};
|
|
12
|
+
/** Default public RPC endpoints */
|
|
13
|
+
exports.DEFAULT_RPCS = {
|
|
14
|
+
base: "https://mainnet.base.org",
|
|
15
|
+
ethereum: "https://eth.llamarpc.com",
|
|
16
|
+
arbitrum: "https://arb1.arbitrum.io/rpc",
|
|
17
|
+
optimism: "https://mainnet.optimism.io",
|
|
18
|
+
};
|
|
19
|
+
/** ERC-20 balanceOf ABI fragment */
|
|
20
|
+
const ERC20_ABI = ["function balanceOf(address) view returns (uint256)"];
|
|
21
|
+
/**
|
|
22
|
+
* Multi-chain USDC balance tracker.
|
|
23
|
+
* Works standalone, no Clicks Protocol dependency.
|
|
24
|
+
*/
|
|
25
|
+
class BalanceTracker {
|
|
26
|
+
constructor(config = {}) {
|
|
27
|
+
this.providers = new Map();
|
|
28
|
+
this.history = new Map();
|
|
29
|
+
this.chains = config.chains ?? Object.keys(exports.USDC_ADDRESSES);
|
|
30
|
+
for (const chain of this.chains) {
|
|
31
|
+
const rpcUrl = config.rpcs?.[chain] ?? exports.DEFAULT_RPCS[chain];
|
|
32
|
+
this.providers.set(chain, new ethers_1.ethers.JsonRpcProvider(rpcUrl));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Get USDC balance on a single chain */
|
|
36
|
+
async getBalance(address, chain) {
|
|
37
|
+
const provider = this.providers.get(chain);
|
|
38
|
+
if (!provider)
|
|
39
|
+
throw new Error(`Chain "${chain}" not configured`);
|
|
40
|
+
const usdcAddress = exports.USDC_ADDRESSES[chain];
|
|
41
|
+
const contract = new ethers_1.ethers.Contract(usdcAddress, ERC20_ABI, provider);
|
|
42
|
+
const balance = await contract.balanceOf(address);
|
|
43
|
+
return {
|
|
44
|
+
chain,
|
|
45
|
+
balance,
|
|
46
|
+
formatted: ethers_1.ethers.formatUnits(balance, 6),
|
|
47
|
+
timestamp: Date.now(),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Get USDC balances across all configured chains */
|
|
51
|
+
async getBalances(address) {
|
|
52
|
+
const results = await Promise.allSettled(this.chains.map((chain) => this.getBalance(address, chain)));
|
|
53
|
+
const balances = [];
|
|
54
|
+
for (const result of results) {
|
|
55
|
+
if (result.status === "fulfilled") {
|
|
56
|
+
balances.push(result.value);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const total = balances.reduce((sum, b) => sum + b.balance, 0n);
|
|
60
|
+
const snapshot = {
|
|
61
|
+
address,
|
|
62
|
+
balances,
|
|
63
|
+
total,
|
|
64
|
+
totalFormatted: ethers_1.ethers.formatUnits(total, 6),
|
|
65
|
+
timestamp: Date.now(),
|
|
66
|
+
};
|
|
67
|
+
// Store in history
|
|
68
|
+
const existing = this.history.get(address) ?? [];
|
|
69
|
+
existing.push({ snapshot, recordedAt: Date.now() });
|
|
70
|
+
// Keep last 1000 entries per address
|
|
71
|
+
if (existing.length > 1000)
|
|
72
|
+
existing.shift();
|
|
73
|
+
this.history.set(address, existing);
|
|
74
|
+
return snapshot;
|
|
75
|
+
}
|
|
76
|
+
/** Get balance history for an address */
|
|
77
|
+
getHistory(address) {
|
|
78
|
+
return this.history.get(address) ?? [];
|
|
79
|
+
}
|
|
80
|
+
/** Clear history for an address (or all) */
|
|
81
|
+
clearHistory(address) {
|
|
82
|
+
if (address) {
|
|
83
|
+
this.history.delete(address);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
this.history.clear();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.BalanceTracker = BalanceTracker;
|
|
91
|
+
//# sourceMappingURL=balance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"balance.js","sourceRoot":"","sources":["../src/balance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { BalanceTracker, BalanceTrackerConfig, ChainName } from "./balance";
|
|
2
|
+
export interface IdleBalanceAlert {
|
|
3
|
+
address: string;
|
|
4
|
+
totalIdle: bigint;
|
|
5
|
+
totalIdleFormatted: string;
|
|
6
|
+
idleSince: number;
|
|
7
|
+
idleDurationMs: number;
|
|
8
|
+
idleDurationHuman: string;
|
|
9
|
+
chains: ChainName[];
|
|
10
|
+
}
|
|
11
|
+
export type IdleCallback = (alert: IdleBalanceAlert) => void | Promise<void>;
|
|
12
|
+
export interface IdleDetectorConfig extends BalanceTrackerConfig {
|
|
13
|
+
/** Minimum balance in USDC (raw 6-decimal) to consider "idle" (default: 100 USDC) */
|
|
14
|
+
thresholdUsdc?: number;
|
|
15
|
+
/** How long balance must be idle before alerting, in ms (default: 1 hour) */
|
|
16
|
+
idleTimeMs?: number;
|
|
17
|
+
/** Polling interval in ms (default: 5 minutes) */
|
|
18
|
+
pollIntervalMs?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Detects idle USDC balances and triggers alerts.
|
|
22
|
+
* Works standalone, no Clicks Protocol dependency.
|
|
23
|
+
*/
|
|
24
|
+
export declare class IdleDetector {
|
|
25
|
+
private tracker;
|
|
26
|
+
private thresholdRaw;
|
|
27
|
+
private idleTimeMs;
|
|
28
|
+
private pollIntervalMs;
|
|
29
|
+
private watched;
|
|
30
|
+
private timers;
|
|
31
|
+
constructor(config?: IdleDetectorConfig);
|
|
32
|
+
/** Start watching an address for idle balances */
|
|
33
|
+
watch(address: string, callback: IdleCallback): void;
|
|
34
|
+
/** Stop watching an address */
|
|
35
|
+
unwatch(address: string): void;
|
|
36
|
+
/** Stop watching all addresses */
|
|
37
|
+
unwatchAll(): void;
|
|
38
|
+
/** Check an address once (can be called manually) */
|
|
39
|
+
checkOnce(address: string): Promise<IdleBalanceAlert | null>;
|
|
40
|
+
/** Get the underlying balance tracker */
|
|
41
|
+
getTracker(): BalanceTracker;
|
|
42
|
+
private checkAddress;
|
|
43
|
+
private evaluateSnapshot;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=idle-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idle-detector.d.ts","sourceRoot":"","sources":["../src/idle-detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAmB,oBAAoB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE7F,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE7E,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAoBD;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,OAAO,CAA0C;IACzD,OAAO,CAAC,MAAM,CAA0D;gBAE5D,MAAM,GAAE,kBAAuB;IAS3C,kDAAkD;IAClD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI;IAoBpD,+BAA+B;IAC/B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAS9B,kCAAkC;IAClC,UAAU,IAAI,IAAI;IAMlB,qDAAqD;IAC/C,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAKlE,yCAAyC;IACzC,UAAU,IAAI,cAAc;YAId,YAAY;IAiC1B,OAAO,CAAC,gBAAgB;CAwBzB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IdleDetector = void 0;
|
|
4
|
+
const balance_1 = require("./balance");
|
|
5
|
+
function formatDuration(ms) {
|
|
6
|
+
const seconds = Math.floor(ms / 1000);
|
|
7
|
+
if (seconds < 60)
|
|
8
|
+
return `${seconds}s`;
|
|
9
|
+
const minutes = Math.floor(seconds / 60);
|
|
10
|
+
if (minutes < 60)
|
|
11
|
+
return `${minutes}m`;
|
|
12
|
+
const hours = Math.floor(minutes / 60);
|
|
13
|
+
if (hours < 24)
|
|
14
|
+
return `${hours}h ${minutes % 60}m`;
|
|
15
|
+
const days = Math.floor(hours / 24);
|
|
16
|
+
return `${days}d ${hours % 24}h`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Detects idle USDC balances and triggers alerts.
|
|
20
|
+
* Works standalone, no Clicks Protocol dependency.
|
|
21
|
+
*/
|
|
22
|
+
class IdleDetector {
|
|
23
|
+
constructor(config = {}) {
|
|
24
|
+
this.watched = new Map();
|
|
25
|
+
this.timers = new Map();
|
|
26
|
+
this.tracker = new balance_1.BalanceTracker(config);
|
|
27
|
+
// Convert USDC threshold to 6-decimal raw
|
|
28
|
+
const thresholdUsdc = config.thresholdUsdc ?? 100;
|
|
29
|
+
this.thresholdRaw = BigInt(Math.floor(thresholdUsdc * 1e6));
|
|
30
|
+
this.idleTimeMs = config.idleTimeMs ?? 60 * 60 * 1000; // 1 hour
|
|
31
|
+
this.pollIntervalMs = config.pollIntervalMs ?? 5 * 60 * 1000; // 5 min
|
|
32
|
+
}
|
|
33
|
+
/** Start watching an address for idle balances */
|
|
34
|
+
watch(address, callback) {
|
|
35
|
+
if (this.watched.has(address)) {
|
|
36
|
+
this.unwatch(address);
|
|
37
|
+
}
|
|
38
|
+
const tracked = {
|
|
39
|
+
address,
|
|
40
|
+
lastChangeAt: Date.now(),
|
|
41
|
+
lastBalance: 0n,
|
|
42
|
+
callback,
|
|
43
|
+
};
|
|
44
|
+
this.watched.set(address, tracked);
|
|
45
|
+
// Initial check + start polling
|
|
46
|
+
this.checkAddress(tracked);
|
|
47
|
+
const timer = setInterval(() => this.checkAddress(tracked), this.pollIntervalMs);
|
|
48
|
+
this.timers.set(address, timer);
|
|
49
|
+
}
|
|
50
|
+
/** Stop watching an address */
|
|
51
|
+
unwatch(address) {
|
|
52
|
+
this.watched.delete(address);
|
|
53
|
+
const timer = this.timers.get(address);
|
|
54
|
+
if (timer) {
|
|
55
|
+
clearInterval(timer);
|
|
56
|
+
this.timers.delete(address);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Stop watching all addresses */
|
|
60
|
+
unwatchAll() {
|
|
61
|
+
for (const address of this.watched.keys()) {
|
|
62
|
+
this.unwatch(address);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Check an address once (can be called manually) */
|
|
66
|
+
async checkOnce(address) {
|
|
67
|
+
const snapshot = await this.tracker.getBalances(address);
|
|
68
|
+
return this.evaluateSnapshot(address, snapshot);
|
|
69
|
+
}
|
|
70
|
+
/** Get the underlying balance tracker */
|
|
71
|
+
getTracker() {
|
|
72
|
+
return this.tracker;
|
|
73
|
+
}
|
|
74
|
+
async checkAddress(tracked) {
|
|
75
|
+
try {
|
|
76
|
+
const snapshot = await this.tracker.getBalances(tracked.address);
|
|
77
|
+
// Check if balance changed
|
|
78
|
+
if (snapshot.total !== tracked.lastBalance) {
|
|
79
|
+
tracked.lastBalance = snapshot.total;
|
|
80
|
+
tracked.lastChangeAt = Date.now();
|
|
81
|
+
return; // Balance changed, reset idle timer
|
|
82
|
+
}
|
|
83
|
+
// Balance unchanged, check if idle long enough
|
|
84
|
+
const idleDuration = Date.now() - tracked.lastChangeAt;
|
|
85
|
+
if (snapshot.total >= this.thresholdRaw && idleDuration >= this.idleTimeMs) {
|
|
86
|
+
const alert = {
|
|
87
|
+
address: tracked.address,
|
|
88
|
+
totalIdle: snapshot.total,
|
|
89
|
+
totalIdleFormatted: snapshot.totalFormatted,
|
|
90
|
+
idleSince: tracked.lastChangeAt,
|
|
91
|
+
idleDurationMs: idleDuration,
|
|
92
|
+
idleDurationHuman: formatDuration(idleDuration),
|
|
93
|
+
chains: snapshot.balances
|
|
94
|
+
.filter((b) => b.balance > 0n)
|
|
95
|
+
.map((b) => b.chain),
|
|
96
|
+
};
|
|
97
|
+
await tracked.callback(alert);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// Silently skip failed checks — network issues are transient
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
evaluateSnapshot(address, snapshot) {
|
|
105
|
+
const tracked = this.watched.get(address);
|
|
106
|
+
const lastChangeAt = tracked?.lastChangeAt ?? Date.now();
|
|
107
|
+
const idleDuration = Date.now() - lastChangeAt;
|
|
108
|
+
if (snapshot.total >= this.thresholdRaw) {
|
|
109
|
+
return {
|
|
110
|
+
address,
|
|
111
|
+
totalIdle: snapshot.total,
|
|
112
|
+
totalIdleFormatted: snapshot.totalFormatted,
|
|
113
|
+
idleSince: lastChangeAt,
|
|
114
|
+
idleDurationMs: idleDuration,
|
|
115
|
+
idleDurationHuman: formatDuration(idleDuration),
|
|
116
|
+
chains: snapshot.balances
|
|
117
|
+
.filter((b) => b.balance > 0n)
|
|
118
|
+
.map((b) => b.chain),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
exports.IdleDetector = IdleDetector;
|
|
125
|
+
//# sourceMappingURL=idle-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idle-detector.js","sourceRoot":"","sources":["../src/idle-detector.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export { BalanceTracker, USDC_ADDRESSES, DEFAULT_RPCS, type ChainName, type ChainBalance, type BalanceSnapshot, type BalanceHistoryEntry, type BalanceTrackerConfig, } from "./balance";
|
|
2
|
+
export { YieldFinder, type Protocol, type YieldRate, type YieldComparison, type YieldHistoryEntry, type YieldFinderConfig, } from "./yield-finder";
|
|
3
|
+
export { IdleDetector, type IdleBalanceAlert, type IdleCallback, type IdleDetectorConfig, } from "./idle-detector";
|
|
4
|
+
export { ClicksActivator, type ActivateConfig, type ActivateResult, type YieldPosition, } from "./activate";
|
|
5
|
+
import { BalanceTracker, type ChainName } from "./balance";
|
|
6
|
+
import { YieldFinder } from "./yield-finder";
|
|
7
|
+
import { IdleDetector, type IdleCallback } from "./idle-detector";
|
|
8
|
+
import { ClicksActivator } from "./activate";
|
|
9
|
+
import { ethers } from "ethers";
|
|
10
|
+
export interface AgentTreasuryConfig {
|
|
11
|
+
/** Base RPC URL override */
|
|
12
|
+
rpcUrl?: string;
|
|
13
|
+
/** Override RPC URLs per chain */
|
|
14
|
+
rpcs?: Partial<Record<ChainName, string>>;
|
|
15
|
+
/** Which chains to track (default: all) */
|
|
16
|
+
chains?: ChainName[];
|
|
17
|
+
/** Yield finder protocols */
|
|
18
|
+
protocols?: ("aave-v3" | "morpho" | "compound-v3")[];
|
|
19
|
+
/** Idle detection: minimum USDC to alert (default: 100) */
|
|
20
|
+
idleThresholdUsdc?: number;
|
|
21
|
+
/** Idle detection: time before alert in ms (default: 1 hour) */
|
|
22
|
+
idleTimeMs?: number;
|
|
23
|
+
/** Clicks Protocol router address override */
|
|
24
|
+
clicksRouterAddress?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* AgentTreasury — unified treasury management for AI agents.
|
|
28
|
+
*
|
|
29
|
+
* Track balances, compare yields, detect idle funds, and optionally
|
|
30
|
+
* activate yield via Clicks Protocol.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { AgentTreasury } from "agent-treasury";
|
|
35
|
+
*
|
|
36
|
+
* const treasury = new AgentTreasury();
|
|
37
|
+
* const balances = await treasury.getBalances("0x...");
|
|
38
|
+
* const yields = await treasury.compareYields();
|
|
39
|
+
* const idle = await treasury.getIdleBalance("0x...");
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare class AgentTreasury {
|
|
43
|
+
readonly balance: BalanceTracker;
|
|
44
|
+
readonly yields: YieldFinder;
|
|
45
|
+
readonly idle: IdleDetector;
|
|
46
|
+
readonly clicks: ClicksActivator;
|
|
47
|
+
constructor(config?: AgentTreasuryConfig);
|
|
48
|
+
/** Get USDC balances across all chains */
|
|
49
|
+
getBalances(address: string): Promise<import("./balance").BalanceSnapshot>;
|
|
50
|
+
/** Get idle balance info for an address */
|
|
51
|
+
getIdleBalance(address: string): Promise<import("./idle-detector").IdleBalanceAlert | null>;
|
|
52
|
+
/** Compare current DeFi yields on Base */
|
|
53
|
+
compareYields(): Promise<import("./yield-finder").YieldComparison>;
|
|
54
|
+
/** Get the best available yield */
|
|
55
|
+
getBestYield(): Promise<import("./yield-finder").YieldRate | null>;
|
|
56
|
+
/** Watch an address for idle balances */
|
|
57
|
+
watchIdle(address: string, callback: IdleCallback): void;
|
|
58
|
+
/** Stop watching an address */
|
|
59
|
+
unwatchIdle(address: string): void;
|
|
60
|
+
/** Stop all idle watchers */
|
|
61
|
+
stopAll(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Full treasury report: balances + yields + idle status + Clicks position.
|
|
64
|
+
*/
|
|
65
|
+
report(address: string, provider?: ethers.Provider): Promise<{
|
|
66
|
+
address: string;
|
|
67
|
+
balances: import("./balance").BalanceSnapshot;
|
|
68
|
+
yields: import("./yield-finder").YieldComparison;
|
|
69
|
+
idleStatus: import("./idle-detector").IdleBalanceAlert | null;
|
|
70
|
+
clicksPosition: import("./activate").YieldPosition | null;
|
|
71
|
+
recommendation: string;
|
|
72
|
+
generatedAt: number;
|
|
73
|
+
}>;
|
|
74
|
+
private getRecommendation;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,cAAc,EACd,YAAY,EACZ,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,GAC1B,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,WAAW,EACX,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,GACvB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,kBAAkB,GACxB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,aAAa,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAA6B,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AACtF,OAAO,EAAE,WAAW,EAA0B,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,YAAY,EAA2B,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC3F,OAAO,EAAE,eAAe,EAAuB,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,WAAW,mBAAmB;IAClC,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1C,2CAA2C;IAC3C,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,CAAC,SAAS,GAAG,QAAQ,GAAG,aAAa,CAAC,EAAE,CAAC;IACrD,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,aAAa;IACxB,SAAgB,OAAO,EAAE,cAAc,CAAC;IACxC,SAAgB,MAAM,EAAE,WAAW,CAAC;IACpC,SAAgB,IAAI,EAAE,YAAY,CAAC;IACnC,SAAgB,MAAM,EAAE,eAAe,CAAC;gBAE5B,MAAM,GAAE,mBAAwB;IA6B5C,0CAA0C;IACpC,WAAW,CAAC,OAAO,EAAE,MAAM;IAIjC,2CAA2C;IACrC,cAAc,CAAC,OAAO,EAAE,MAAM;IAIpC,0CAA0C;IACpC,aAAa;IAInB,mCAAmC;IAC7B,YAAY;IAIlB,yCAAyC;IACzC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY;IAIjD,+BAA+B;IAC/B,WAAW,CAAC,OAAO,EAAE,MAAM;IAI3B,6BAA6B;IAC7B,OAAO;IAIP;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ;;;;;;;;;IAsBxD,OAAO,CAAC,iBAAiB;CAa1B"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AgentTreasury = exports.ClicksActivator = exports.IdleDetector = exports.YieldFinder = exports.DEFAULT_RPCS = exports.USDC_ADDRESSES = exports.BalanceTracker = void 0;
|
|
4
|
+
var balance_1 = require("./balance");
|
|
5
|
+
Object.defineProperty(exports, "BalanceTracker", { enumerable: true, get: function () { return balance_1.BalanceTracker; } });
|
|
6
|
+
Object.defineProperty(exports, "USDC_ADDRESSES", { enumerable: true, get: function () { return balance_1.USDC_ADDRESSES; } });
|
|
7
|
+
Object.defineProperty(exports, "DEFAULT_RPCS", { enumerable: true, get: function () { return balance_1.DEFAULT_RPCS; } });
|
|
8
|
+
var yield_finder_1 = require("./yield-finder");
|
|
9
|
+
Object.defineProperty(exports, "YieldFinder", { enumerable: true, get: function () { return yield_finder_1.YieldFinder; } });
|
|
10
|
+
var idle_detector_1 = require("./idle-detector");
|
|
11
|
+
Object.defineProperty(exports, "IdleDetector", { enumerable: true, get: function () { return idle_detector_1.IdleDetector; } });
|
|
12
|
+
var activate_1 = require("./activate");
|
|
13
|
+
Object.defineProperty(exports, "ClicksActivator", { enumerable: true, get: function () { return activate_1.ClicksActivator; } });
|
|
14
|
+
const balance_2 = require("./balance");
|
|
15
|
+
const yield_finder_2 = require("./yield-finder");
|
|
16
|
+
const idle_detector_2 = require("./idle-detector");
|
|
17
|
+
const activate_2 = require("./activate");
|
|
18
|
+
/**
|
|
19
|
+
* AgentTreasury — unified treasury management for AI agents.
|
|
20
|
+
*
|
|
21
|
+
* Track balances, compare yields, detect idle funds, and optionally
|
|
22
|
+
* activate yield via Clicks Protocol.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { AgentTreasury } from "agent-treasury";
|
|
27
|
+
*
|
|
28
|
+
* const treasury = new AgentTreasury();
|
|
29
|
+
* const balances = await treasury.getBalances("0x...");
|
|
30
|
+
* const yields = await treasury.compareYields();
|
|
31
|
+
* const idle = await treasury.getIdleBalance("0x...");
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
class AgentTreasury {
|
|
35
|
+
constructor(config = {}) {
|
|
36
|
+
const balanceConfig = {
|
|
37
|
+
rpcs: config.rpcs,
|
|
38
|
+
chains: config.chains,
|
|
39
|
+
};
|
|
40
|
+
const yieldConfig = {
|
|
41
|
+
rpcUrl: config.rpcUrl ?? config.rpcs?.base,
|
|
42
|
+
protocols: config.protocols,
|
|
43
|
+
};
|
|
44
|
+
const idleConfig = {
|
|
45
|
+
...balanceConfig,
|
|
46
|
+
thresholdUsdc: config.idleThresholdUsdc,
|
|
47
|
+
idleTimeMs: config.idleTimeMs,
|
|
48
|
+
};
|
|
49
|
+
const activateConfig = {
|
|
50
|
+
routerAddress: config.clicksRouterAddress,
|
|
51
|
+
};
|
|
52
|
+
this.balance = new balance_2.BalanceTracker(balanceConfig);
|
|
53
|
+
this.yields = new yield_finder_2.YieldFinder(yieldConfig);
|
|
54
|
+
this.idle = new idle_detector_2.IdleDetector(idleConfig);
|
|
55
|
+
this.clicks = new activate_2.ClicksActivator(activateConfig);
|
|
56
|
+
}
|
|
57
|
+
// ── Convenience methods ──────────────────────────────────────────
|
|
58
|
+
/** Get USDC balances across all chains */
|
|
59
|
+
async getBalances(address) {
|
|
60
|
+
return this.balance.getBalances(address);
|
|
61
|
+
}
|
|
62
|
+
/** Get idle balance info for an address */
|
|
63
|
+
async getIdleBalance(address) {
|
|
64
|
+
return this.idle.checkOnce(address);
|
|
65
|
+
}
|
|
66
|
+
/** Compare current DeFi yields on Base */
|
|
67
|
+
async compareYields() {
|
|
68
|
+
return this.yields.compareYields();
|
|
69
|
+
}
|
|
70
|
+
/** Get the best available yield */
|
|
71
|
+
async getBestYield() {
|
|
72
|
+
return this.yields.getBestYield();
|
|
73
|
+
}
|
|
74
|
+
/** Watch an address for idle balances */
|
|
75
|
+
watchIdle(address, callback) {
|
|
76
|
+
this.idle.watch(address, callback);
|
|
77
|
+
}
|
|
78
|
+
/** Stop watching an address */
|
|
79
|
+
unwatchIdle(address) {
|
|
80
|
+
this.idle.unwatch(address);
|
|
81
|
+
}
|
|
82
|
+
/** Stop all idle watchers */
|
|
83
|
+
stopAll() {
|
|
84
|
+
this.idle.unwatchAll();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Full treasury report: balances + yields + idle status + Clicks position.
|
|
88
|
+
*/
|
|
89
|
+
async report(address, provider) {
|
|
90
|
+
const [balances, yields, idleStatus] = await Promise.all([
|
|
91
|
+
this.getBalances(address),
|
|
92
|
+
this.compareYields(),
|
|
93
|
+
this.getIdleBalance(address),
|
|
94
|
+
]);
|
|
95
|
+
const clicksPosition = provider
|
|
96
|
+
? await this.clicks.getPosition(provider, address)
|
|
97
|
+
: null;
|
|
98
|
+
return {
|
|
99
|
+
address,
|
|
100
|
+
balances,
|
|
101
|
+
yields,
|
|
102
|
+
idleStatus,
|
|
103
|
+
clicksPosition,
|
|
104
|
+
recommendation: this.getRecommendation(balances.totalFormatted, yields.best?.supplyAPY ?? 0, idleStatus !== null),
|
|
105
|
+
generatedAt: Date.now(),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
getRecommendation(totalUsdc, bestApy, isIdle) {
|
|
109
|
+
const amount = parseFloat(totalUsdc);
|
|
110
|
+
if (amount === 0)
|
|
111
|
+
return "No USDC balance detected.";
|
|
112
|
+
if (!isIdle)
|
|
113
|
+
return `Balance of ${totalUsdc} USDC is active.`;
|
|
114
|
+
if (bestApy === 0)
|
|
115
|
+
return `${totalUsdc} USDC is idle. Yield data unavailable.`;
|
|
116
|
+
const yearlyEarning = (amount * bestApy) / 100;
|
|
117
|
+
return `${totalUsdc} USDC is idle. Best yield: ${bestApy}% APY (~$${yearlyEarning.toFixed(2)}/year). Consider activating yield.`;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
exports.AgentTreasury = AgentTreasury;
|
|
121
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** Supported yield protocols on Base */
|
|
2
|
+
export type Protocol = "aave-v3" | "morpho" | "compound-v3";
|
|
3
|
+
export interface YieldRate {
|
|
4
|
+
protocol: Protocol;
|
|
5
|
+
asset: string;
|
|
6
|
+
chain: string;
|
|
7
|
+
supplyAPY: number;
|
|
8
|
+
timestamp: number;
|
|
9
|
+
}
|
|
10
|
+
export interface YieldComparison {
|
|
11
|
+
rates: YieldRate[];
|
|
12
|
+
best: YieldRate | null;
|
|
13
|
+
fetchedAt: number;
|
|
14
|
+
}
|
|
15
|
+
export interface YieldHistoryEntry {
|
|
16
|
+
comparison: YieldComparison;
|
|
17
|
+
recordedAt: number;
|
|
18
|
+
}
|
|
19
|
+
export interface YieldFinderConfig {
|
|
20
|
+
/** Base RPC URL override */
|
|
21
|
+
rpcUrl?: string;
|
|
22
|
+
/** Which protocols to check (default: all) */
|
|
23
|
+
protocols?: Protocol[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Compare DeFi yields for USDC on Base.
|
|
27
|
+
* Works standalone, no Clicks Protocol dependency.
|
|
28
|
+
*/
|
|
29
|
+
export declare class YieldFinder {
|
|
30
|
+
private provider;
|
|
31
|
+
private protocols;
|
|
32
|
+
private history;
|
|
33
|
+
constructor(config?: YieldFinderConfig);
|
|
34
|
+
/** Fetch Aave V3 USDC supply APY on Base */
|
|
35
|
+
private getAaveRate;
|
|
36
|
+
/** Fetch Compound V3 USDC supply APY on Base */
|
|
37
|
+
private getCompoundRate;
|
|
38
|
+
/** Fetch Morpho USDC supply APY on Base (simplified) */
|
|
39
|
+
private getMorphoRate;
|
|
40
|
+
/** Compare yields across configured protocols */
|
|
41
|
+
compareYields(): Promise<YieldComparison>;
|
|
42
|
+
/** Get the best current yield */
|
|
43
|
+
getBestYield(): Promise<YieldRate | null>;
|
|
44
|
+
/** Get historical yield comparisons */
|
|
45
|
+
getHistory(): YieldHistoryEntry[];
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=yield-finder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yield-finder.d.ts","sourceRoot":"","sources":["../src/yield-finder.ts"],"names":[],"mappings":"AAEA,wCAAwC;AACxC,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,aAAa,CAAC;AAE5D,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,eAAe,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAkCD,MAAM,WAAW,iBAAiB;IAChC,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;CACxB;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,OAAO,CAA2B;gBAE9B,MAAM,GAAE,iBAAsB;IAO1C,4CAA4C;YAC9B,WAAW;IA+BzB,gDAAgD;YAClC,eAAe;IA8B7B,wDAAwD;YAC1C,aAAa;IAa3B,iDAAiD;IAC3C,aAAa,IAAI,OAAO,CAAC,eAAe,CAAC;IAkC/C,iCAAiC;IAC3B,YAAY,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAK/C,uCAAuC;IACvC,UAAU,IAAI,iBAAiB,EAAE;CAGlC"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.YieldFinder = void 0;
|
|
4
|
+
const ethers_1 = require("ethers");
|
|
5
|
+
// On-chain contract addresses on Base for reading supply rates
|
|
6
|
+
const PROTOCOL_CONTRACTS = {
|
|
7
|
+
"aave-v3": {
|
|
8
|
+
// Aave V3 Pool on Base — getReserveData returns supply rate
|
|
9
|
+
address: "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5",
|
|
10
|
+
abi: [
|
|
11
|
+
"function getReserveData(address asset) view returns (uint256 configuration, uint128 liquidityIndex, uint128 currentLiquidityRate, uint128 variableBorrowIndex, uint128 currentVariableBorrowRate, uint128 currentStableBorrowRate, uint40 lastUpdateTimestamp, uint16 id, address aTokenAddress, address stableDebtTokenAddress, address variableDebtTokenAddress, address interestRateStrategyAddress, uint128 accruedToTreasury, uint128 unbacked, uint128 isolationModeTotalDebt)",
|
|
12
|
+
],
|
|
13
|
+
},
|
|
14
|
+
"morpho": {
|
|
15
|
+
// Morpho Blue on Base
|
|
16
|
+
address: "0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb",
|
|
17
|
+
abi: [
|
|
18
|
+
"function market(bytes32 id) view returns (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee)",
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
"compound-v3": {
|
|
22
|
+
// Compound V3 (Comet) USDC on Base
|
|
23
|
+
address: "0xb125E6687d4313864e53df431d5425969c15Eb2F",
|
|
24
|
+
abi: [
|
|
25
|
+
"function getSupplyRate(uint256 utilization) view returns (uint64)",
|
|
26
|
+
"function getUtilization() view returns (uint256)",
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
const USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
31
|
+
// Ray = 1e27 (Aave rate precision)
|
|
32
|
+
const RAY = 10n ** 27n;
|
|
33
|
+
const SECONDS_PER_YEAR = 31536000;
|
|
34
|
+
/**
|
|
35
|
+
* Compare DeFi yields for USDC on Base.
|
|
36
|
+
* Works standalone, no Clicks Protocol dependency.
|
|
37
|
+
*/
|
|
38
|
+
class YieldFinder {
|
|
39
|
+
constructor(config = {}) {
|
|
40
|
+
this.history = [];
|
|
41
|
+
this.provider = new ethers_1.ethers.JsonRpcProvider(config.rpcUrl ?? "https://mainnet.base.org");
|
|
42
|
+
this.protocols = config.protocols ?? ["aave-v3", "compound-v3"];
|
|
43
|
+
}
|
|
44
|
+
/** Fetch Aave V3 USDC supply APY on Base */
|
|
45
|
+
async getAaveRate() {
|
|
46
|
+
const { address, abi } = PROTOCOL_CONTRACTS["aave-v3"];
|
|
47
|
+
const contract = new ethers_1.ethers.Contract(address, abi, this.provider);
|
|
48
|
+
try {
|
|
49
|
+
const data = await contract.getReserveData(USDC_BASE);
|
|
50
|
+
// currentLiquidityRate is at index 2, in RAY (1e27)
|
|
51
|
+
const liquidityRate = BigInt(data[2]);
|
|
52
|
+
// APY = ((1 + rate/secondsPerYear)^secondsPerYear - 1) * 100
|
|
53
|
+
// Simplified: APY ≈ rate * 100 / RAY (for display purposes)
|
|
54
|
+
const apyPercent = Number((liquidityRate * 10000n) / RAY) / 100;
|
|
55
|
+
return {
|
|
56
|
+
protocol: "aave-v3",
|
|
57
|
+
asset: "USDC",
|
|
58
|
+
chain: "base",
|
|
59
|
+
supplyAPY: apyPercent,
|
|
60
|
+
timestamp: Date.now(),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return {
|
|
65
|
+
protocol: "aave-v3",
|
|
66
|
+
asset: "USDC",
|
|
67
|
+
chain: "base",
|
|
68
|
+
supplyAPY: 0,
|
|
69
|
+
timestamp: Date.now(),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Fetch Compound V3 USDC supply APY on Base */
|
|
74
|
+
async getCompoundRate() {
|
|
75
|
+
const { address, abi } = PROTOCOL_CONTRACTS["compound-v3"];
|
|
76
|
+
const contract = new ethers_1.ethers.Contract(address, abi, this.provider);
|
|
77
|
+
try {
|
|
78
|
+
const utilization = await contract.getUtilization();
|
|
79
|
+
const supplyRatePerSecond = await contract.getSupplyRate(utilization);
|
|
80
|
+
// Compound rate is per-second, scaled by 1e18
|
|
81
|
+
// APY = (1 + ratePerSecond)^secondsPerYear - 1
|
|
82
|
+
const ratePerSecond = Number(supplyRatePerSecond) / 1e18;
|
|
83
|
+
const apy = (Math.pow(1 + ratePerSecond, SECONDS_PER_YEAR) - 1) * 100;
|
|
84
|
+
return {
|
|
85
|
+
protocol: "compound-v3",
|
|
86
|
+
asset: "USDC",
|
|
87
|
+
chain: "base",
|
|
88
|
+
supplyAPY: Math.round(apy * 100) / 100,
|
|
89
|
+
timestamp: Date.now(),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return {
|
|
94
|
+
protocol: "compound-v3",
|
|
95
|
+
asset: "USDC",
|
|
96
|
+
chain: "base",
|
|
97
|
+
supplyAPY: 0,
|
|
98
|
+
timestamp: Date.now(),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Fetch Morpho USDC supply APY on Base (simplified) */
|
|
103
|
+
async getMorphoRate() {
|
|
104
|
+
// Morpho Blue uses market IDs; the USDC/WETH market is common
|
|
105
|
+
// For simplicity, we estimate from utilization
|
|
106
|
+
// In production, you'd query specific market IDs
|
|
107
|
+
return {
|
|
108
|
+
protocol: "morpho",
|
|
109
|
+
asset: "USDC",
|
|
110
|
+
chain: "base",
|
|
111
|
+
supplyAPY: 0, // Requires market ID — set to 0 if unavailable
|
|
112
|
+
timestamp: Date.now(),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/** Compare yields across configured protocols */
|
|
116
|
+
async compareYields() {
|
|
117
|
+
const fetchers = {
|
|
118
|
+
"aave-v3": () => this.getAaveRate(),
|
|
119
|
+
"morpho": () => this.getMorphoRate(),
|
|
120
|
+
"compound-v3": () => this.getCompoundRate(),
|
|
121
|
+
};
|
|
122
|
+
const results = await Promise.allSettled(this.protocols.map((p) => fetchers[p]()));
|
|
123
|
+
const rates = [];
|
|
124
|
+
for (const result of results) {
|
|
125
|
+
if (result.status === "fulfilled") {
|
|
126
|
+
rates.push(result.value);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Sort descending by APY
|
|
130
|
+
rates.sort((a, b) => b.supplyAPY - a.supplyAPY);
|
|
131
|
+
const comparison = {
|
|
132
|
+
rates,
|
|
133
|
+
best: rates.length > 0 ? rates[0] : null,
|
|
134
|
+
fetchedAt: Date.now(),
|
|
135
|
+
};
|
|
136
|
+
// Store history
|
|
137
|
+
this.history.push({ comparison, recordedAt: Date.now() });
|
|
138
|
+
if (this.history.length > 500)
|
|
139
|
+
this.history.shift();
|
|
140
|
+
return comparison;
|
|
141
|
+
}
|
|
142
|
+
/** Get the best current yield */
|
|
143
|
+
async getBestYield() {
|
|
144
|
+
const comparison = await this.compareYields();
|
|
145
|
+
return comparison.best;
|
|
146
|
+
}
|
|
147
|
+
/** Get historical yield comparisons */
|
|
148
|
+
getHistory() {
|
|
149
|
+
return [...this.history];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
exports.YieldFinder = YieldFinder;
|
|
153
|
+
//# sourceMappingURL=yield-finder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yield-finder.js","sourceRoot":"","sources":["../src/yield-finder.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-treasury",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Treasury management utilities for AI agents. Track balances, detect idle USDC, compare DeFi yields, and activate autonomous earning.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md",
|
|
10
|
+
"LICENSE"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"agent",
|
|
18
|
+
"treasury",
|
|
19
|
+
"ai-agent",
|
|
20
|
+
"usdc",
|
|
21
|
+
"yield",
|
|
22
|
+
"defi",
|
|
23
|
+
"base",
|
|
24
|
+
"idle",
|
|
25
|
+
"balance",
|
|
26
|
+
"autonomous",
|
|
27
|
+
"wallet",
|
|
28
|
+
"x402"
|
|
29
|
+
],
|
|
30
|
+
"homepage": "https://clicksprotocol.xyz",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/clicks-protocol/agent-treasury"
|
|
34
|
+
},
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"author": "Clicks Protocol <hello@clicksprotocol.xyz>",
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"ethers": "^6.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"ethers": "^6.13.0",
|
|
42
|
+
"typescript": "^5.4.0"
|
|
43
|
+
}
|
|
44
|
+
}
|