@elizaos/plugin-wallet 2.0.0-beta.1
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 +64 -0
- package/auto-enable.ts +76 -0
- package/dist/LpManagementService-BWrQ5-cO.mjs +353 -0
- package/dist/MockLpService-D_Apn4Fd.mjs +99 -0
- package/dist/aerodrome-CfnESC32.mjs +890 -0
- package/dist/chunk-hT5z_Zn9.mjs +35 -0
- package/dist/index.d.mts +34727 -0
- package/dist/index.mjs +21590 -0
- package/dist/lib/server-wallet-trade.d.mts +34 -0
- package/dist/lib/server-wallet-trade.mjs +306 -0
- package/dist/meteora-BPX39hZo.mjs +22640 -0
- package/dist/orca-Bybp1HXO.mjs +249 -0
- package/dist/pancakeswp-CkEXlXti.mjs +604 -0
- package/dist/plugin-ZO_MTyd0.mjs +529 -0
- package/dist/raydium-rfaM9yEf.mjs +539 -0
- package/dist/sdk/index.d.mts +32492 -0
- package/dist/sdk/index.mjs +6415 -0
- package/dist/types-D5252NZk.mjs +487 -0
- package/dist/uniswap-CReXgXVN.mjs +573 -0
- package/dist/wallet-action.d.mts +6 -0
- package/dist/wallet-action.mjs +820 -0
- package/package.json +152 -0
- package/src/actions/failure-codes.ts +79 -0
- package/src/actions/index.ts +1 -0
- package/src/analytics/birdeye/actions/wallet-search-address.ts +9 -0
- package/src/analytics/birdeye/birdeye-task.ts +175 -0
- package/src/analytics/birdeye/birdeye.ts +813 -0
- package/src/analytics/birdeye/constants.ts +74 -0
- package/src/analytics/birdeye/providers/agent-portfolio-provider.ts +18 -0
- package/src/analytics/birdeye/providers/market.ts +227 -0
- package/src/analytics/birdeye/providers/portfolio-factory.test.ts +138 -0
- package/src/analytics/birdeye/providers/portfolio-factory.ts +252 -0
- package/src/analytics/birdeye/providers/trending.ts +365 -0
- package/src/analytics/birdeye/providers/wallet.ts +14 -0
- package/src/analytics/birdeye/search-category.test.ts +207 -0
- package/src/analytics/birdeye/search-category.ts +506 -0
- package/src/analytics/birdeye/service.ts +992 -0
- package/src/analytics/birdeye/tasks/birdeye.ts +232 -0
- package/src/analytics/birdeye/types/api/common.ts +305 -0
- package/src/analytics/birdeye/types/api/defi.ts +220 -0
- package/src/analytics/birdeye/types/api/pair.ts +200 -0
- package/src/analytics/birdeye/types/api/search.ts +86 -0
- package/src/analytics/birdeye/types/api/token.ts +635 -0
- package/src/analytics/birdeye/types/api/trader.ts +76 -0
- package/src/analytics/birdeye/types/api/wallet.ts +181 -0
- package/src/analytics/birdeye/types/shared.ts +106 -0
- package/src/analytics/birdeye/utils.ts +700 -0
- package/src/analytics/dexscreener/errors.ts +28 -0
- package/src/analytics/dexscreener/index.ts +3 -0
- package/src/analytics/dexscreener/search-category.test.ts +49 -0
- package/src/analytics/dexscreener/search-category.ts +42 -0
- package/src/analytics/dexscreener/service.ts +595 -0
- package/src/analytics/dexscreener/types.ts +128 -0
- package/src/analytics/lpinfo/index.d.ts +7 -0
- package/src/analytics/lpinfo/index.ts +52 -0
- package/src/analytics/lpinfo/kamino/README.md +102 -0
- package/src/analytics/lpinfo/kamino/index.ts +24 -0
- package/src/analytics/lpinfo/kamino/providers/kaminoLiquidityProvider.ts +422 -0
- package/src/analytics/lpinfo/kamino/providers/kaminoPoolProvider.ts +365 -0
- package/src/analytics/lpinfo/kamino/providers/kaminoProvider.ts +496 -0
- package/src/analytics/lpinfo/kamino/services/kaminoLiquidityService.ts +1123 -0
- package/src/analytics/lpinfo/kamino/services/kaminoService.ts +758 -0
- package/src/analytics/lpinfo/steer/README.md +169 -0
- package/src/analytics/lpinfo/steer/index.ts +23 -0
- package/src/analytics/lpinfo/steer/providers/steerLiquidityProvider.ts +544 -0
- package/src/analytics/lpinfo/steer/services/steerLiquidityService.ts +1690 -0
- package/src/analytics/lpinfo/steer/steer-display-types.ts +99 -0
- package/src/analytics/news/index.ts +52 -0
- package/src/analytics/news/interfaces/types.ts +222 -0
- package/src/analytics/news/providers/defiNewsProvider.ts +734 -0
- package/src/analytics/news/services/newsDataService.ts +332 -0
- package/src/analytics/news/utils/formatters.ts +151 -0
- package/src/analytics/token-info/action.ts +240 -0
- package/src/analytics/token-info/index.ts +3 -0
- package/src/analytics/token-info/params.ts +215 -0
- package/src/analytics/token-info/providers.ts +681 -0
- package/src/analytics/token-info/service.ts +168 -0
- package/src/analytics/token-info/types.ts +74 -0
- package/src/audit/audit-log.ts +45 -0
- package/src/browser-shim/build-shim.ts +123 -0
- package/src/browser-shim/index.ts +5 -0
- package/src/browser-shim/shim.template.js +563 -0
- package/src/chains/evm/.github/workflows/npm-deploy.yml +112 -0
- package/src/chains/evm/LICENSE +21 -0
- package/src/chains/evm/README.md +106 -0
- package/src/chains/evm/actions/helpers.ts +147 -0
- package/src/chains/evm/actions/swap.ts +839 -0
- package/src/chains/evm/actions/transfer.ts +254 -0
- package/src/chains/evm/biome.json +61 -0
- package/src/chains/evm/bridge-router.ts +660 -0
- package/src/chains/evm/build.ts +89 -0
- package/src/chains/evm/chain-handler.ts +416 -0
- package/src/chains/evm/constants.ts +23 -0
- package/src/chains/evm/contracts/artifacts/OZGovernor.json +1707 -0
- package/src/chains/evm/contracts/artifacts/TimelockController.json +1007 -0
- package/src/chains/evm/contracts/artifacts/VoteToken.json +895 -0
- package/src/chains/evm/dex/aerodrome/index.ts +34 -0
- package/src/chains/evm/dex/aerodrome/services/AerodromeLpService.ts +558 -0
- package/src/chains/evm/dex/aerodrome/types.ts +318 -0
- package/src/chains/evm/dex/pancakeswp/index.ts +35 -0
- package/src/chains/evm/dex/pancakeswp/services/PancakeSwapV3LpService.ts +743 -0
- package/src/chains/evm/dex/pancakeswp/types.ts +65 -0
- package/src/chains/evm/dex/uniswap/index.ts +35 -0
- package/src/chains/evm/dex/uniswap/services/UniswapV3LpService.ts +759 -0
- package/src/chains/evm/dex/uniswap/types.ts +390 -0
- package/src/chains/evm/generated/specs/spec-helpers.ts +73 -0
- package/src/chains/evm/generated/specs/specs.ts +151 -0
- package/src/chains/evm/gov-router.ts +250 -0
- package/src/chains/evm/index.browser.ts +16 -0
- package/src/chains/evm/index.ts +31 -0
- package/src/chains/evm/prompts.ts +193 -0
- package/src/chains/evm/providers/get-balance.ts +123 -0
- package/src/chains/evm/providers/wallet.ts +715 -0
- package/src/chains/evm/routes/sign.ts +333 -0
- package/src/chains/evm/rpc-providers.ts +410 -0
- package/src/chains/evm/service.ts +140 -0
- package/src/chains/evm/templates/index.ts +10 -0
- package/src/chains/evm/types/index.ts +432 -0
- package/src/chains/evm/vitest.config.ts +18 -0
- package/src/chains/registry.ts +668 -0
- package/src/chains/solana/README.md +367 -0
- package/src/chains/wallet-action.ts +533 -0
- package/src/chains/wallet-router.test.ts +296 -0
- package/src/contracts.ts +65 -0
- package/src/core-augmentation.ts +10 -0
- package/src/index.ts +71 -0
- package/src/lib/server-wallet-trade.ts +192 -0
- package/src/lib/wallet-export-guard.ts +330 -0
- package/src/lp/actions/liquidity.ts +827 -0
- package/src/lp/e2e/real-token-tests.ts +428 -0
- package/src/lp/e2e/scenarios.ts +470 -0
- package/src/lp/e2e/test-utils.ts +145 -0
- package/src/lp/lp-manager-entry.ts +303 -0
- package/src/lp/services/ConcentratedLiquidityService.ts +120 -0
- package/src/lp/services/DexInteractionService.ts +226 -0
- package/src/lp/services/LpManagementService.test.ts +148 -0
- package/src/lp/services/LpManagementService.ts +632 -0
- package/src/lp/services/UserLpProfileService.ts +163 -0
- package/src/lp/services/VaultService.ts +153 -0
- package/src/lp/services/YieldOptimizationService.ts +344 -0
- package/src/lp/services/__tests__/MockLpService.ts +146 -0
- package/src/lp/tasks/LpAutoRebalanceTask.ts +117 -0
- package/src/lp/tasks/__tests__/LpAutoRebalanceTask.test.ts +370 -0
- package/src/lp/types.ts +582 -0
- package/src/lp/utils/solanaClient.ts +143 -0
- package/src/plugin.ts +125 -0
- package/src/policy/policy.ts +19 -0
- package/src/providers/canonical-provider.ts +27 -0
- package/src/providers/unified-wallet-provider.ts +79 -0
- package/src/register-routes.ts +11 -0
- package/src/routes/plugin.ts +47 -0
- package/src/routes/wallet-market-overview-route.ts +869 -0
- package/src/sdk/abi.ts +258 -0
- package/src/sdk/bridge/abis.ts +126 -0
- package/src/sdk/bridge/client.ts +518 -0
- package/src/sdk/bridge/index.ts +56 -0
- package/src/sdk/bridge/solana.ts +604 -0
- package/src/sdk/bridge/types.ts +202 -0
- package/src/sdk/convenience.ts +347 -0
- package/src/sdk/escrow/MutualStakeEscrow.ts +480 -0
- package/src/sdk/escrow/types.ts +64 -0
- package/src/sdk/escrow/verifiers.ts +73 -0
- package/src/sdk/identity/erc8004.ts +692 -0
- package/src/sdk/identity/reputation.ts +449 -0
- package/src/sdk/identity/uaid.ts +497 -0
- package/src/sdk/identity/validation.ts +372 -0
- package/src/sdk/index.ts +763 -0
- package/src/sdk/policy/SpendingPolicy.ts +260 -0
- package/src/sdk/policy/UptoBillingPolicy.ts +320 -0
- package/src/sdk/router/PaymentRouter.ts +215 -0
- package/src/sdk/router/index.ts +8 -0
- package/src/sdk/swap/SwapModule.ts +310 -0
- package/src/sdk/swap/abi.ts +117 -0
- package/src/sdk/swap/index.ts +34 -0
- package/src/sdk/swap/types.ts +135 -0
- package/src/sdk/tokens/decimals.ts +140 -0
- package/src/sdk/tokens/registry.ts +911 -0
- package/src/sdk/tokens/solana.ts +419 -0
- package/src/sdk/tokens/transfers.ts +327 -0
- package/src/sdk/types.ts +158 -0
- package/src/sdk/wallet-core.ts +115 -0
- package/src/sdk/x402/budget.ts +168 -0
- package/src/sdk/x402/chains/abstract/index.ts +280 -0
- package/src/sdk/x402/client.ts +320 -0
- package/src/sdk/x402/index.ts +46 -0
- package/src/sdk/x402/middleware.ts +92 -0
- package/src/sdk/x402/multi-asset.ts +144 -0
- package/src/sdk/x402/types.ts +156 -0
- package/src/services/wallet-backend-service.ts +328 -0
- package/src/types/wallet-router.ts +227 -0
- package/src/utils/intent-trajectory.ts +106 -0
- package/src/wallet/backend.ts +62 -0
- package/src/wallet/errors.ts +49 -0
- package/src/wallet/index.ts +27 -0
- package/src/wallet/local-eoa-backend.ts +201 -0
- package/src/wallet/pending.ts +60 -0
- package/src/wallet/select-backend.ts +47 -0
- package/src/wallet/steward-backend.ts +161 -0
- package/src/wallet-action.ts +1 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module tokens/transfers
|
|
3
|
+
* Multi-token transfer utilities for AgentWallet v6.
|
|
4
|
+
*
|
|
5
|
+
* Provides send/balance functions for any ERC-20 token or native gas token,
|
|
6
|
+
* with flexible amount input (raw bigint or human-readable string).
|
|
7
|
+
*
|
|
8
|
+
* All transfer functions go through viem's wallet client — they do NOT
|
|
9
|
+
* route through the AgentAccountV2 contract (use agentTransferToken for that).
|
|
10
|
+
* These are direct EOA/smart-wallet operations for wallets that hold the key.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
type Address,
|
|
15
|
+
type Chain,
|
|
16
|
+
encodeFunctionData,
|
|
17
|
+
type Hash,
|
|
18
|
+
type PublicClient,
|
|
19
|
+
parseAbi,
|
|
20
|
+
type WalletClient,
|
|
21
|
+
zeroAddress,
|
|
22
|
+
} from "viem";
|
|
23
|
+
import { formatBalance, parseAmount, toHuman } from "./decimals.js";
|
|
24
|
+
import { getGlobalRegistry } from "./registry.js";
|
|
25
|
+
|
|
26
|
+
// ─── ERC20 ABI (minimal) ─────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
const ERC20_ABI = parseAbi([
|
|
29
|
+
"function transfer(address to, uint256 amount) returns (bool)",
|
|
30
|
+
"function balanceOf(address account) view returns (uint256)",
|
|
31
|
+
"function decimals() view returns (uint8)",
|
|
32
|
+
"function symbol() view returns (string)",
|
|
33
|
+
"function name() view returns (string)",
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
export interface TransferOptions {
|
|
39
|
+
/** Gas price override */
|
|
40
|
+
gasPrice?: bigint;
|
|
41
|
+
/** Max fee per gas (EIP-1559) */
|
|
42
|
+
maxFeePerGas?: bigint;
|
|
43
|
+
/** Max priority fee per gas (EIP-1559) */
|
|
44
|
+
maxPriorityFeePerGas?: bigint;
|
|
45
|
+
/** Gas limit override */
|
|
46
|
+
gas?: bigint;
|
|
47
|
+
/** Chain ID for multi-chain operations */
|
|
48
|
+
chainId?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface TokenBalanceResult {
|
|
52
|
+
address: Address;
|
|
53
|
+
symbol: string;
|
|
54
|
+
name: string;
|
|
55
|
+
decimals: number;
|
|
56
|
+
rawBalance: bigint;
|
|
57
|
+
humanBalance: string;
|
|
58
|
+
formatted: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface NativeBalanceResult {
|
|
62
|
+
symbol: string;
|
|
63
|
+
decimals: number;
|
|
64
|
+
rawBalance: bigint;
|
|
65
|
+
humanBalance: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ─── Transfer context ─────────────────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
export interface TransferContext {
|
|
71
|
+
publicClient: PublicClient;
|
|
72
|
+
walletClient: WalletClient;
|
|
73
|
+
/** Caller's address (used as from address) */
|
|
74
|
+
account: Address;
|
|
75
|
+
/** Chain ID for registry lookups */
|
|
76
|
+
chainId?: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ─── Core transfer functions ──────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Send any ERC-20 token.
|
|
83
|
+
*
|
|
84
|
+
* @param ctx - Public + wallet clients and account
|
|
85
|
+
* @param to - Recipient address
|
|
86
|
+
* @param amount - Amount as raw bigint OR human-readable string (requires tokenAddress decimals lookup)
|
|
87
|
+
* @param tokenAddress - ERC-20 contract address
|
|
88
|
+
* @param options - Optional gas overrides
|
|
89
|
+
*/
|
|
90
|
+
export async function sendToken(
|
|
91
|
+
ctx: TransferContext,
|
|
92
|
+
to: Address,
|
|
93
|
+
amount: string | bigint,
|
|
94
|
+
tokenAddress: Address,
|
|
95
|
+
options: TransferOptions = {},
|
|
96
|
+
): Promise<Hash> {
|
|
97
|
+
let rawAmount: bigint;
|
|
98
|
+
|
|
99
|
+
if (typeof amount === "string") {
|
|
100
|
+
// Need decimals to parse string amount
|
|
101
|
+
let decimals: number;
|
|
102
|
+
|
|
103
|
+
// Try registry first
|
|
104
|
+
if (ctx.chainId != null) {
|
|
105
|
+
const entry = getGlobalRegistry().getTokenByAddress(
|
|
106
|
+
tokenAddress,
|
|
107
|
+
ctx.chainId,
|
|
108
|
+
);
|
|
109
|
+
decimals =
|
|
110
|
+
entry?.decimals ??
|
|
111
|
+
(await fetchTokenDecimals(ctx.publicClient, tokenAddress));
|
|
112
|
+
} else {
|
|
113
|
+
decimals = await fetchTokenDecimals(ctx.publicClient, tokenAddress);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
rawAmount = parseAmount(amount, decimals);
|
|
117
|
+
} else {
|
|
118
|
+
rawAmount = amount;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const data = encodeFunctionData({
|
|
122
|
+
abi: ERC20_ABI,
|
|
123
|
+
functionName: "transfer",
|
|
124
|
+
args: [to, rawAmount],
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return ctx.walletClient.sendTransaction({
|
|
128
|
+
account: ctx.account,
|
|
129
|
+
chain: requirePublicClientChain(ctx),
|
|
130
|
+
to: tokenAddress,
|
|
131
|
+
data,
|
|
132
|
+
...buildGasOptions(options),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Send native gas token (ETH, MATIC, AVAX, etc.).
|
|
138
|
+
*
|
|
139
|
+
* @param ctx - Transfer context
|
|
140
|
+
* @param to - Recipient address
|
|
141
|
+
* @param amount - Raw bigint OR human-readable string (18 decimals for ETH/MATIC/AVAX)
|
|
142
|
+
* @param options - Optional gas overrides
|
|
143
|
+
*/
|
|
144
|
+
export async function sendNative(
|
|
145
|
+
ctx: TransferContext,
|
|
146
|
+
to: Address,
|
|
147
|
+
amount: string | bigint,
|
|
148
|
+
options: TransferOptions = {},
|
|
149
|
+
): Promise<Hash> {
|
|
150
|
+
const rawAmount = parseAmount(amount, 18);
|
|
151
|
+
|
|
152
|
+
return ctx.walletClient.sendTransaction({
|
|
153
|
+
account: ctx.account,
|
|
154
|
+
chain: requirePublicClientChain(ctx),
|
|
155
|
+
to,
|
|
156
|
+
value: rawAmount,
|
|
157
|
+
...buildGasOptions(options),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Get the ERC-20 balance of the current account (or a specified address).
|
|
163
|
+
*
|
|
164
|
+
* @param ctx - Transfer context
|
|
165
|
+
* @param tokenAddress - ERC-20 contract address
|
|
166
|
+
* @param holder - Address to check (defaults to ctx.account)
|
|
167
|
+
*/
|
|
168
|
+
export async function getTokenBalance(
|
|
169
|
+
ctx: TransferContext,
|
|
170
|
+
tokenAddress: Address,
|
|
171
|
+
holder?: Address,
|
|
172
|
+
): Promise<TokenBalanceResult> {
|
|
173
|
+
const target = holder ?? ctx.account;
|
|
174
|
+
|
|
175
|
+
// Batch read: balanceOf + decimals + symbol + name
|
|
176
|
+
const [rawBalance, decimals, symbol, name] = await Promise.all([
|
|
177
|
+
ctx.publicClient.readContract({
|
|
178
|
+
address: tokenAddress,
|
|
179
|
+
abi: ERC20_ABI,
|
|
180
|
+
functionName: "balanceOf",
|
|
181
|
+
args: [target],
|
|
182
|
+
}) as Promise<bigint>,
|
|
183
|
+
ctx.publicClient.readContract({
|
|
184
|
+
address: tokenAddress,
|
|
185
|
+
abi: ERC20_ABI,
|
|
186
|
+
functionName: "decimals",
|
|
187
|
+
}) as Promise<number>,
|
|
188
|
+
ctx.publicClient.readContract({
|
|
189
|
+
address: tokenAddress,
|
|
190
|
+
abi: ERC20_ABI,
|
|
191
|
+
functionName: "symbol",
|
|
192
|
+
}) as Promise<string>,
|
|
193
|
+
ctx.publicClient.readContract({
|
|
194
|
+
address: tokenAddress,
|
|
195
|
+
abi: ERC20_ABI,
|
|
196
|
+
functionName: "name",
|
|
197
|
+
}) as Promise<string>,
|
|
198
|
+
]);
|
|
199
|
+
|
|
200
|
+
const humanBalance = toHuman(rawBalance, decimals);
|
|
201
|
+
const formatted = formatBalance(rawBalance, { symbol, decimals });
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
address: tokenAddress,
|
|
205
|
+
symbol,
|
|
206
|
+
name,
|
|
207
|
+
decimals,
|
|
208
|
+
rawBalance,
|
|
209
|
+
humanBalance,
|
|
210
|
+
formatted,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Get the native gas token balance of the current account (or a specified address).
|
|
216
|
+
*
|
|
217
|
+
* @param ctx - Transfer context
|
|
218
|
+
* @param holder - Address to check (defaults to ctx.account)
|
|
219
|
+
*/
|
|
220
|
+
export async function getNativeBalance(
|
|
221
|
+
ctx: TransferContext,
|
|
222
|
+
holder?: Address,
|
|
223
|
+
): Promise<NativeBalanceResult> {
|
|
224
|
+
const target = holder ?? ctx.account;
|
|
225
|
+
const rawBalance = await ctx.publicClient.getBalance({ address: target });
|
|
226
|
+
|
|
227
|
+
// Determine native token symbol from registry if chainId is known
|
|
228
|
+
let symbol = "ETH";
|
|
229
|
+
if (ctx.chainId != null) {
|
|
230
|
+
const native = getGlobalRegistry().getTokenByAddress(
|
|
231
|
+
zeroAddress,
|
|
232
|
+
ctx.chainId,
|
|
233
|
+
);
|
|
234
|
+
symbol = native?.symbol ?? "ETH";
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const humanBalance = toHuman(rawBalance, 18);
|
|
238
|
+
|
|
239
|
+
return { symbol, decimals: 18, rawBalance, humanBalance };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Batch query balances for multiple ERC-20 tokens.
|
|
244
|
+
*
|
|
245
|
+
* @param ctx - Transfer context
|
|
246
|
+
* @param tokenAddresses - List of ERC-20 addresses to query (or null/empty for all registry tokens)
|
|
247
|
+
* @param holder - Address to check (defaults to ctx.account)
|
|
248
|
+
*/
|
|
249
|
+
export async function getBalances(
|
|
250
|
+
ctx: TransferContext,
|
|
251
|
+
tokenAddresses?: Address[],
|
|
252
|
+
holder?: Address,
|
|
253
|
+
): Promise<TokenBalanceResult[]> {
|
|
254
|
+
const target = holder ?? ctx.account;
|
|
255
|
+
|
|
256
|
+
let addresses = tokenAddresses;
|
|
257
|
+
|
|
258
|
+
// If no addresses provided and chainId is known, use all registry tokens
|
|
259
|
+
if (!addresses || addresses.length === 0) {
|
|
260
|
+
if (ctx.chainId != null) {
|
|
261
|
+
const tokens = getGlobalRegistry().listTokens(ctx.chainId);
|
|
262
|
+
addresses = tokens.filter((t) => !t.isNative).map((t) => t.address);
|
|
263
|
+
} else {
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Parallel balance fetches
|
|
269
|
+
const results = await Promise.allSettled(
|
|
270
|
+
addresses.map((addr) => getTokenBalance(ctx, addr, target)),
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
return results
|
|
274
|
+
.filter(
|
|
275
|
+
(r): r is PromiseFulfilledResult<TokenBalanceResult> =>
|
|
276
|
+
r.status === "fulfilled",
|
|
277
|
+
)
|
|
278
|
+
.map((r) => r.value);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
282
|
+
|
|
283
|
+
async function fetchTokenDecimals(
|
|
284
|
+
publicClient: PublicClient,
|
|
285
|
+
tokenAddress: Address,
|
|
286
|
+
): Promise<number> {
|
|
287
|
+
return publicClient.readContract({
|
|
288
|
+
address: tokenAddress,
|
|
289
|
+
abi: ERC20_ABI,
|
|
290
|
+
functionName: "decimals",
|
|
291
|
+
}) as Promise<number>;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function buildGasOptions(options: TransferOptions) {
|
|
295
|
+
const gas: Record<string, bigint> = {};
|
|
296
|
+
if (options.gas != null) gas.gas = options.gas;
|
|
297
|
+
if (options.gasPrice != null) gas.gasPrice = options.gasPrice;
|
|
298
|
+
if (options.maxFeePerGas != null) gas.maxFeePerGas = options.maxFeePerGas;
|
|
299
|
+
if (options.maxPriorityFeePerGas != null)
|
|
300
|
+
gas.maxPriorityFeePerGas = options.maxPriorityFeePerGas;
|
|
301
|
+
return gas;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function requirePublicClientChain(ctx: TransferContext): Chain {
|
|
305
|
+
const chain = ctx.publicClient.chain;
|
|
306
|
+
if (!chain) {
|
|
307
|
+
throw new Error(
|
|
308
|
+
"TransferContext.publicClient must be created with chain (required for walletClient.sendTransaction).",
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
return chain;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Encode an ERC-20 transfer call as raw calldata.
|
|
316
|
+
* Useful for building calldata for agentExecute() or multicall.
|
|
317
|
+
*/
|
|
318
|
+
export function encodeERC20Transfer(
|
|
319
|
+
to: Address,
|
|
320
|
+
amount: bigint,
|
|
321
|
+
): `0x${string}` {
|
|
322
|
+
return encodeFunctionData({
|
|
323
|
+
abi: ERC20_ABI,
|
|
324
|
+
functionName: "transfer",
|
|
325
|
+
args: [to, amount],
|
|
326
|
+
});
|
|
327
|
+
}
|
package/src/sdk/types.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module types
|
|
3
|
+
* Core type definitions for the AgentWallet SDK.
|
|
4
|
+
*
|
|
5
|
+
* Contains shared interfaces, constants, and type utilities used across all
|
|
6
|
+
* SDK modules: spending policies, wallet config, chain identifiers, and
|
|
7
|
+
* value-add diagnostic types (BudgetForecast, WalletHealth, ActivityEntry).
|
|
8
|
+
*
|
|
9
|
+
* Supported chains: Base, Ethereum, Arbitrum, Polygon, Optimism, Avalanche,
|
|
10
|
+
* Unichain, Linea, Sonic, Worldchain, and Base Sepolia (testnet).
|
|
11
|
+
*/
|
|
12
|
+
import type { JsonValue } from "@elizaos/core";
|
|
13
|
+
import type { Address, Hash, Hex } from "viem";
|
|
14
|
+
|
|
15
|
+
/** Spend policy for a single token */
|
|
16
|
+
export interface SpendPolicy {
|
|
17
|
+
token: Address; // address(0) for native ETH
|
|
18
|
+
perTxLimit: bigint; // max single tx amount (0 = no autonomous spending)
|
|
19
|
+
periodLimit: bigint; // max total per rolling window (0 = no autonomous spending)
|
|
20
|
+
periodLength: number; // window duration in seconds (default 86400)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** On-chain spend policy state (includes tracking fields) */
|
|
24
|
+
export interface SpendPolicyState extends SpendPolicy {
|
|
25
|
+
periodSpent: bigint;
|
|
26
|
+
periodStart: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** A pending over-limit transaction awaiting owner approval */
|
|
30
|
+
export interface PendingTx {
|
|
31
|
+
txId: bigint;
|
|
32
|
+
to: Address;
|
|
33
|
+
value: bigint;
|
|
34
|
+
data: Hex;
|
|
35
|
+
token: Address;
|
|
36
|
+
amount: bigint;
|
|
37
|
+
createdAt: number;
|
|
38
|
+
executed: boolean;
|
|
39
|
+
cancelled: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Budget remaining for a token */
|
|
43
|
+
export interface BudgetStatus {
|
|
44
|
+
token: Address;
|
|
45
|
+
perTxLimit: bigint;
|
|
46
|
+
remainingInPeriod: bigint;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Result of agentExecute — either executed or queued */
|
|
50
|
+
export interface ExecuteResult {
|
|
51
|
+
executed: boolean;
|
|
52
|
+
txHash: Hash;
|
|
53
|
+
pendingTxId?: bigint; // set if queued
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Config for creating an AgentWallet client */
|
|
57
|
+
export interface AgentWalletConfig {
|
|
58
|
+
accountAddress: Address;
|
|
59
|
+
chain:
|
|
60
|
+
| "base"
|
|
61
|
+
| "base-sepolia"
|
|
62
|
+
| "ethereum"
|
|
63
|
+
| "arbitrum"
|
|
64
|
+
| "polygon"
|
|
65
|
+
| "optimism"
|
|
66
|
+
| "avalanche"
|
|
67
|
+
| "unichain"
|
|
68
|
+
| "linea"
|
|
69
|
+
| "sonic"
|
|
70
|
+
| "worldchain";
|
|
71
|
+
rpcUrl?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Event emitted when a transaction exceeds spend limits */
|
|
75
|
+
export interface QueuedEvent {
|
|
76
|
+
txId: bigint;
|
|
77
|
+
to: Address;
|
|
78
|
+
value: bigint;
|
|
79
|
+
token: Address;
|
|
80
|
+
amount: bigint;
|
|
81
|
+
blockNumber: bigint | null;
|
|
82
|
+
transactionHash: Hash | null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ─── [MAX-ADDED] Value-add types for agent customers ───
|
|
86
|
+
|
|
87
|
+
/** Budget forecast with time-aware remaining capacity */
|
|
88
|
+
export interface BudgetForecast {
|
|
89
|
+
token: Address;
|
|
90
|
+
perTxLimit: bigint;
|
|
91
|
+
remainingInPeriod: bigint;
|
|
92
|
+
periodLimit: bigint;
|
|
93
|
+
periodLength: number;
|
|
94
|
+
periodSpent: bigint;
|
|
95
|
+
periodStart: number;
|
|
96
|
+
/** Seconds until the current period resets (budget refills) */
|
|
97
|
+
secondsUntilReset: number;
|
|
98
|
+
/** Percentage of period budget already used (0-100) */
|
|
99
|
+
utilizationPercent: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Wallet health diagnostic snapshot */
|
|
103
|
+
export interface WalletHealth {
|
|
104
|
+
/** Wallet contract address */
|
|
105
|
+
address: Address;
|
|
106
|
+
/** NFT token contract bound to this wallet */
|
|
107
|
+
tokenContract: Address;
|
|
108
|
+
/** NFT token ID */
|
|
109
|
+
tokenId: bigint;
|
|
110
|
+
/** Current operator epoch (increments on invalidateAll) */
|
|
111
|
+
operatorEpoch: bigint;
|
|
112
|
+
/** Which operators from the checklist are currently active */
|
|
113
|
+
activeOperators: { address: Address; active: boolean }[];
|
|
114
|
+
/** Number of pending (unexecuted, uncancelled) transactions in queue */
|
|
115
|
+
pendingQueueDepth: number;
|
|
116
|
+
/** Budget status for each requested token */
|
|
117
|
+
budgets: BudgetForecast[];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** A decoded activity log entry from on-chain events */
|
|
121
|
+
export interface ActivityEntry {
|
|
122
|
+
type:
|
|
123
|
+
| "execution"
|
|
124
|
+
| "queued"
|
|
125
|
+
| "approved"
|
|
126
|
+
| "cancelled"
|
|
127
|
+
| "policy_update"
|
|
128
|
+
| "operator_update";
|
|
129
|
+
blockNumber: bigint;
|
|
130
|
+
transactionHash: Hash;
|
|
131
|
+
/** Decoded event args (varies by type) */
|
|
132
|
+
args: Record<string, JsonValue>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Params for a single transfer in a batch */
|
|
136
|
+
export interface BatchTransfer {
|
|
137
|
+
token: Address;
|
|
138
|
+
to: Address;
|
|
139
|
+
amount: bigint;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Supported chain IDs */
|
|
143
|
+
export const CHAIN_IDS = {
|
|
144
|
+
base: 8453,
|
|
145
|
+
"base-sepolia": 84532,
|
|
146
|
+
ethereum: 1,
|
|
147
|
+
arbitrum: 42161,
|
|
148
|
+
polygon: 137,
|
|
149
|
+
optimism: 10,
|
|
150
|
+
avalanche: 43114,
|
|
151
|
+
unichain: 130,
|
|
152
|
+
linea: 59144,
|
|
153
|
+
sonic: 146,
|
|
154
|
+
worldchain: 480,
|
|
155
|
+
} as const;
|
|
156
|
+
|
|
157
|
+
/** Supported chain name type */
|
|
158
|
+
export type SupportedChain = keyof typeof CHAIN_IDS;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Address,
|
|
3
|
+
type Chain,
|
|
4
|
+
createPublicClient,
|
|
5
|
+
getContract,
|
|
6
|
+
type Hash,
|
|
7
|
+
http,
|
|
8
|
+
type WalletClient,
|
|
9
|
+
zeroAddress,
|
|
10
|
+
} from "viem";
|
|
11
|
+
import { arbitrum, base, baseSepolia, mainnet, polygon } from "viem/chains";
|
|
12
|
+
import { AgentAccountV2Abi } from "./abi.js";
|
|
13
|
+
import type { AgentWalletConfig, BudgetStatus, SpendPolicy } from "./types.js";
|
|
14
|
+
|
|
15
|
+
const CHAINS: Record<string, Chain> = {
|
|
16
|
+
base,
|
|
17
|
+
"base-sepolia": baseSepolia,
|
|
18
|
+
ethereum: mainnet,
|
|
19
|
+
arbitrum,
|
|
20
|
+
polygon,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Asserts the viem wallet client has a selected account (required for writes). */
|
|
24
|
+
export function requireWalletAccount(client: WalletClient) {
|
|
25
|
+
const { account } = client;
|
|
26
|
+
if (!account) {
|
|
27
|
+
throw new Error("WalletClient.account is required for this operation");
|
|
28
|
+
}
|
|
29
|
+
return account;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Native ETH token address (zero address) */
|
|
33
|
+
export const NATIVE_TOKEN: Address = zeroAddress;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create a wallet client connected to an existing AgentAccountV2.
|
|
37
|
+
*/
|
|
38
|
+
export function createWallet(
|
|
39
|
+
config: AgentWalletConfig & { walletClient: WalletClient },
|
|
40
|
+
) {
|
|
41
|
+
const chain = CHAINS[config.chain];
|
|
42
|
+
if (!chain) throw new Error(`Unsupported chain: ${config.chain}`);
|
|
43
|
+
|
|
44
|
+
const publicClient = createPublicClient({
|
|
45
|
+
chain,
|
|
46
|
+
transport: http(config.rpcUrl),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const contract = getContract({
|
|
50
|
+
address: config.accountAddress,
|
|
51
|
+
abi: AgentAccountV2Abi,
|
|
52
|
+
client: { public: publicClient, wallet: config.walletClient },
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
address: config.accountAddress,
|
|
57
|
+
contract,
|
|
58
|
+
publicClient,
|
|
59
|
+
walletClient: config.walletClient,
|
|
60
|
+
chain,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type AgentWallet = ReturnType<typeof createWallet>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Set a spend policy for a token. Only callable by the NFT owner.
|
|
68
|
+
* Use NATIVE_TOKEN (address(0)) for native ETH.
|
|
69
|
+
*/
|
|
70
|
+
export async function setSpendPolicy(
|
|
71
|
+
wallet: AgentWallet,
|
|
72
|
+
policy: SpendPolicy,
|
|
73
|
+
): Promise<Hash> {
|
|
74
|
+
const periodLength = policy.periodLength || 86400;
|
|
75
|
+
|
|
76
|
+
const hash = await wallet.contract.write.setSpendPolicy(
|
|
77
|
+
[policy.token, policy.perTxLimit, policy.periodLimit, BigInt(periodLength)],
|
|
78
|
+
{ account: requireWalletAccount(wallet.walletClient), chain: wallet.chain },
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
return hash;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Check remaining autonomous budget for a token.
|
|
86
|
+
*/
|
|
87
|
+
export async function checkBudget(
|
|
88
|
+
wallet: AgentWallet,
|
|
89
|
+
token: Address = NATIVE_TOKEN,
|
|
90
|
+
): Promise<BudgetStatus> {
|
|
91
|
+
const [perTxLimit, remainingInPeriod] =
|
|
92
|
+
await wallet.contract.read.remainingBudget([token]);
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
token,
|
|
96
|
+
perTxLimit,
|
|
97
|
+
remainingInPeriod,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Transfer ERC20 tokens as the agent, respecting spend limits.
|
|
103
|
+
*/
|
|
104
|
+
export async function agentTransferToken(
|
|
105
|
+
wallet: AgentWallet,
|
|
106
|
+
params: { token: Address; to: Address; amount: bigint },
|
|
107
|
+
): Promise<Hash> {
|
|
108
|
+
return wallet.contract.write.agentTransferToken(
|
|
109
|
+
[params.token, params.to, params.amount],
|
|
110
|
+
{
|
|
111
|
+
account: requireWalletAccount(wallet.walletClient),
|
|
112
|
+
chain: wallet.chain,
|
|
113
|
+
},
|
|
114
|
+
);
|
|
115
|
+
}
|