@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,250 @@
|
|
|
1
|
+
import type { Chain, Hex } from "viem";
|
|
2
|
+
import {
|
|
3
|
+
type Address,
|
|
4
|
+
encodeFunctionData,
|
|
5
|
+
keccak256,
|
|
6
|
+
stringToHex,
|
|
7
|
+
} from "viem";
|
|
8
|
+
import governorArtifacts from "./contracts/artifacts/OZGovernor.json";
|
|
9
|
+
import { buildSendTxParams } from "./actions/helpers";
|
|
10
|
+
import { initWalletProvider, type WalletProvider } from "./providers/wallet";
|
|
11
|
+
import type {
|
|
12
|
+
WalletRouterContext,
|
|
13
|
+
WalletRouterExecution,
|
|
14
|
+
WalletRouterParams,
|
|
15
|
+
} from "../../types/wallet-router.js";
|
|
16
|
+
import type { SupportedChain } from "./types";
|
|
17
|
+
|
|
18
|
+
function isEvmAddress(value: string | undefined): value is Address {
|
|
19
|
+
return typeof value === "string" && /^0x[a-fA-F0-9]{40}$/.test(value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function requireGovernor(params: WalletRouterParams): Address {
|
|
23
|
+
if (!isEvmAddress(params.governor)) {
|
|
24
|
+
throw new Error("governor must be a valid EVM address.");
|
|
25
|
+
}
|
|
26
|
+
return params.governor;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function requireArray(
|
|
30
|
+
params: WalletRouterParams,
|
|
31
|
+
key: "targets" | "values" | "calldatas",
|
|
32
|
+
): readonly string[] {
|
|
33
|
+
const value = params[key];
|
|
34
|
+
if (!value || value.length === 0) {
|
|
35
|
+
throw new Error(`${key} is required for governance ${params.op}.`);
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function requireDescription(params: WalletRouterParams): string {
|
|
41
|
+
if (!params.description) {
|
|
42
|
+
throw new Error(`description is required for governance ${params.op}.`);
|
|
43
|
+
}
|
|
44
|
+
return params.description;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function requireProposalId(params: WalletRouterParams): string {
|
|
48
|
+
if (!params.proposalId) {
|
|
49
|
+
throw new Error(`proposalId is required for governance ${params.op}.`);
|
|
50
|
+
}
|
|
51
|
+
return params.proposalId;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function asAddressArray(values: readonly string[], key: string): Address[] {
|
|
55
|
+
return values.map((value) => {
|
|
56
|
+
if (!isEvmAddress(value)) {
|
|
57
|
+
throw new Error(`${key} must contain only valid EVM addresses.`);
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function asHexArray(values: readonly string[], key: string): Hex[] {
|
|
64
|
+
return values.map((value) => {
|
|
65
|
+
if (!/^0x[0-9a-fA-F]*$/.test(value)) {
|
|
66
|
+
throw new Error(`${key} must contain only hex calldata values.`);
|
|
67
|
+
}
|
|
68
|
+
return value as Hex;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function asBigIntArray(values: readonly string[]): bigint[] {
|
|
73
|
+
return values.map((value) => BigInt(value));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function descriptionHash(description: string): Hex {
|
|
77
|
+
return keccak256(stringToHex(description));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function validateWalletGovParams(
|
|
81
|
+
params: WalletRouterParams,
|
|
82
|
+
): string | null {
|
|
83
|
+
try {
|
|
84
|
+
if (!params.op) {
|
|
85
|
+
return "op is required for governance actions.";
|
|
86
|
+
}
|
|
87
|
+
requireGovernor(params);
|
|
88
|
+
switch (params.op) {
|
|
89
|
+
case "propose":
|
|
90
|
+
requireArray(params, "targets");
|
|
91
|
+
requireArray(params, "values");
|
|
92
|
+
requireArray(params, "calldatas");
|
|
93
|
+
requireDescription(params);
|
|
94
|
+
break;
|
|
95
|
+
case "vote":
|
|
96
|
+
requireProposalId(params);
|
|
97
|
+
if (params.support === undefined) {
|
|
98
|
+
return "support is required for governance vote.";
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
case "queue":
|
|
102
|
+
requireArray(params, "targets");
|
|
103
|
+
requireArray(params, "values");
|
|
104
|
+
requireArray(params, "calldatas");
|
|
105
|
+
requireDescription(params);
|
|
106
|
+
break;
|
|
107
|
+
case "execute":
|
|
108
|
+
requireProposalId(params);
|
|
109
|
+
requireArray(params, "targets");
|
|
110
|
+
requireArray(params, "values");
|
|
111
|
+
requireArray(params, "calldatas");
|
|
112
|
+
requireDescription(params);
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
} catch (error) {
|
|
117
|
+
return error instanceof Error ? error.message : String(error);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function encodeWalletGovData(params: WalletRouterParams): Hex {
|
|
122
|
+
const governor = requireGovernor(params);
|
|
123
|
+
void governor;
|
|
124
|
+
|
|
125
|
+
switch (params.op) {
|
|
126
|
+
case "propose":
|
|
127
|
+
return encodeFunctionData({
|
|
128
|
+
abi: governorArtifacts.abi,
|
|
129
|
+
functionName: "propose",
|
|
130
|
+
args: [
|
|
131
|
+
asAddressArray(requireArray(params, "targets"), "targets"),
|
|
132
|
+
asBigIntArray(requireArray(params, "values")),
|
|
133
|
+
asHexArray(requireArray(params, "calldatas"), "calldatas"),
|
|
134
|
+
requireDescription(params),
|
|
135
|
+
],
|
|
136
|
+
}) as Hex;
|
|
137
|
+
case "vote":
|
|
138
|
+
return encodeFunctionData({
|
|
139
|
+
abi: governorArtifacts.abi,
|
|
140
|
+
functionName: "castVote",
|
|
141
|
+
args: [BigInt(requireProposalId(params)), BigInt(params.support ?? 0)],
|
|
142
|
+
}) as Hex;
|
|
143
|
+
case "queue": {
|
|
144
|
+
const description = requireDescription(params);
|
|
145
|
+
return encodeFunctionData({
|
|
146
|
+
abi: governorArtifacts.abi,
|
|
147
|
+
functionName: "queue",
|
|
148
|
+
args: [
|
|
149
|
+
asAddressArray(requireArray(params, "targets"), "targets"),
|
|
150
|
+
asBigIntArray(requireArray(params, "values")),
|
|
151
|
+
asHexArray(requireArray(params, "calldatas"), "calldatas"),
|
|
152
|
+
descriptionHash(description),
|
|
153
|
+
],
|
|
154
|
+
}) as Hex;
|
|
155
|
+
}
|
|
156
|
+
case "execute": {
|
|
157
|
+
requireProposalId(params);
|
|
158
|
+
const description = requireDescription(params);
|
|
159
|
+
return encodeFunctionData({
|
|
160
|
+
abi: governorArtifacts.abi,
|
|
161
|
+
functionName: "execute",
|
|
162
|
+
args: [
|
|
163
|
+
asAddressArray(requireArray(params, "targets"), "targets"),
|
|
164
|
+
asBigIntArray(requireArray(params, "values")),
|
|
165
|
+
asHexArray(requireArray(params, "calldatas"), "calldatas"),
|
|
166
|
+
descriptionHash(description),
|
|
167
|
+
],
|
|
168
|
+
}) as Hex;
|
|
169
|
+
}
|
|
170
|
+
default:
|
|
171
|
+
throw new Error(
|
|
172
|
+
"Missing or invalid op (expected propose | vote | queue | execute).",
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export async function routeEvmGovernance(
|
|
178
|
+
params: WalletRouterParams,
|
|
179
|
+
context: WalletRouterContext,
|
|
180
|
+
chainKey: string,
|
|
181
|
+
chain: Chain,
|
|
182
|
+
walletProvider?: WalletProvider,
|
|
183
|
+
): Promise<WalletRouterExecution> {
|
|
184
|
+
const governor = requireGovernor(params);
|
|
185
|
+
const data = encodeWalletGovData(params);
|
|
186
|
+
|
|
187
|
+
if (params.mode === "prepare" || params.dryRun) {
|
|
188
|
+
return {
|
|
189
|
+
status: "prepared",
|
|
190
|
+
chain: chainKey,
|
|
191
|
+
chainId: String(chain.id),
|
|
192
|
+
subaction: "gov",
|
|
193
|
+
dryRun: params.dryRun,
|
|
194
|
+
mode: params.mode,
|
|
195
|
+
to: governor,
|
|
196
|
+
metadata: {
|
|
197
|
+
op: params.op,
|
|
198
|
+
governor,
|
|
199
|
+
proposalId: params.proposalId,
|
|
200
|
+
support: params.support,
|
|
201
|
+
targets: params.targets,
|
|
202
|
+
values: params.values,
|
|
203
|
+
calldatas: params.calldatas,
|
|
204
|
+
description: params.description,
|
|
205
|
+
transactionRequest: {
|
|
206
|
+
to: governor,
|
|
207
|
+
value: "0",
|
|
208
|
+
data,
|
|
209
|
+
chainId: chain.id,
|
|
210
|
+
},
|
|
211
|
+
requiresConfirmation: true,
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const provider = walletProvider ?? (await initWalletProvider(context.runtime));
|
|
217
|
+
const walletClient = provider.getWalletClient(chainKey as SupportedChain);
|
|
218
|
+
const account = walletClient.account;
|
|
219
|
+
if (!account) {
|
|
220
|
+
throw new Error("Wallet account is not available.");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const hash = await walletClient.sendTransaction(
|
|
224
|
+
buildSendTxParams({
|
|
225
|
+
account,
|
|
226
|
+
to: governor,
|
|
227
|
+
value: 0n,
|
|
228
|
+
data,
|
|
229
|
+
chain,
|
|
230
|
+
}),
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
status: "submitted",
|
|
235
|
+
chain: chainKey,
|
|
236
|
+
chainId: String(chain.id),
|
|
237
|
+
subaction: "gov",
|
|
238
|
+
dryRun: false,
|
|
239
|
+
mode: params.mode,
|
|
240
|
+
transactionHash: hash,
|
|
241
|
+
from: account.address,
|
|
242
|
+
to: governor,
|
|
243
|
+
metadata: {
|
|
244
|
+
op: params.op,
|
|
245
|
+
proposalId: params.proposalId,
|
|
246
|
+
support: params.support,
|
|
247
|
+
data,
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { IAgentRuntime, Plugin } from "@elizaos/core";
|
|
2
|
+
import { logger } from "@elizaos/core";
|
|
3
|
+
|
|
4
|
+
const pluginName = "evm";
|
|
5
|
+
|
|
6
|
+
export const evmPlugin: Plugin = {
|
|
7
|
+
name: pluginName,
|
|
8
|
+
description: "EVM plugin (browser stub; use a server proxy)",
|
|
9
|
+
async init(_config, _runtime: IAgentRuntime): Promise<void> {
|
|
10
|
+
logger.warn(
|
|
11
|
+
`[plugin-${pluginName}] This plugin is not supported directly in browsers. Use a server proxy.`
|
|
12
|
+
);
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default evmPlugin;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Action, Plugin, ServiceClass } from "@elizaos/core";
|
|
2
|
+
import { promoteSubactionsToActions } from "@elizaos/core";
|
|
3
|
+
import { walletRouterAction } from "../wallet-action";
|
|
4
|
+
import { tokenBalanceProvider } from "./providers/get-balance";
|
|
5
|
+
import { evmWalletProvider } from "./providers/wallet";
|
|
6
|
+
import { evmSignRoutes } from "./routes/sign";
|
|
7
|
+
import { EVMService } from "./service";
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
createEvmWalletChainHandler,
|
|
11
|
+
type EvmExecutedTransaction,
|
|
12
|
+
type EvmPreparedResult,
|
|
13
|
+
type EvmRouterResult,
|
|
14
|
+
EvmWalletChainHandler,
|
|
15
|
+
type EvmWalletChainHandlerOptions,
|
|
16
|
+
type EvmWalletMode,
|
|
17
|
+
type EvmWalletSubaction,
|
|
18
|
+
} from "./chain-handler";
|
|
19
|
+
export { initWalletProvider, WalletProvider } from "./providers/wallet";
|
|
20
|
+
export type { SupportedChain } from "./types";
|
|
21
|
+
|
|
22
|
+
export const evmPlugin: Plugin = {
|
|
23
|
+
name: "evm",
|
|
24
|
+
description: "EVM blockchain integration plugin",
|
|
25
|
+
providers: [evmWalletProvider, tokenBalanceProvider],
|
|
26
|
+
services: [EVMService] as ServiceClass[],
|
|
27
|
+
actions: promoteSubactionsToActions(walletRouterAction as Action) as Action[],
|
|
28
|
+
routes: evmSignRoutes,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default evmPlugin;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt templates for plugin-wallet EVM actions and providers.
|
|
3
|
+
*
|
|
4
|
+
* These prompts use Handlebars-style template syntax:
|
|
5
|
+
* - {{variableName}} for simple substitution
|
|
6
|
+
* - {{#each items}}...{{/each}} for iteration
|
|
7
|
+
* - {{#if condition}}...{{/if}} for conditionals
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export const bridgeTemplate = `Given the recent messages and wallet information below:
|
|
11
|
+
|
|
12
|
+
{{recentMessages}}
|
|
13
|
+
|
|
14
|
+
{{chainBalances}}
|
|
15
|
+
|
|
16
|
+
Extract the following information about the requested token bridge:
|
|
17
|
+
- Token symbol or address to bridge
|
|
18
|
+
- Source chain
|
|
19
|
+
- Destination chain
|
|
20
|
+
- Amount to bridge: Must be a string representing the amount in ether (only number without coin symbol, e.g., "0.1")
|
|
21
|
+
- Destination address (if specified)
|
|
22
|
+
|
|
23
|
+
Respond using plain key/value text like this:
|
|
24
|
+
token: token symbol or address, or empty if unknown
|
|
25
|
+
fromChain: source chain from {{supportedChains}}, or empty
|
|
26
|
+
toChain: destination chain from {{supportedChains}}, or empty
|
|
27
|
+
amount: amount as string (e.g. 0.1), or empty
|
|
28
|
+
toAddress: destination address, or empty
|
|
29
|
+
|
|
30
|
+
IMPORTANT: Your response must ONLY contain the key/value fields above. No preamble or explanation.`;
|
|
31
|
+
|
|
32
|
+
export const BRIDGE_TEMPLATE = bridgeTemplate;
|
|
33
|
+
|
|
34
|
+
export const executeProposalTemplate = `Given the recent messages and wallet information below:
|
|
35
|
+
|
|
36
|
+
{{recentMessages}}
|
|
37
|
+
|
|
38
|
+
{{walletInfo}}
|
|
39
|
+
|
|
40
|
+
Extract the following information about the requested proposal:
|
|
41
|
+
- Targets
|
|
42
|
+
- Values
|
|
43
|
+
- Calldatas
|
|
44
|
+
- Description
|
|
45
|
+
- Governor address
|
|
46
|
+
- Chain to execute on
|
|
47
|
+
|
|
48
|
+
Respond using plain key/value text like this. Use null for any scalar value that cannot be determined, and use empty arrays when no array values can be determined:
|
|
49
|
+
targets[2]: 0xTargetAddress1,0xTargetAddress2
|
|
50
|
+
values[2]: 0,1000000000000000000
|
|
51
|
+
calldatas[2]: 0xCalldata1,0xCalldata2
|
|
52
|
+
description: proposal description, or null
|
|
53
|
+
governor: governor contract address, or null
|
|
54
|
+
chain: chain to execute on, or null
|
|
55
|
+
|
|
56
|
+
IMPORTANT: Your response must ONLY contain the key/value fields above. No preamble or explanation.`;
|
|
57
|
+
|
|
58
|
+
export const EXECUTE_PROPOSAL_TEMPLATE = executeProposalTemplate;
|
|
59
|
+
|
|
60
|
+
export const proposeTemplate = `Given the recent messages and wallet information below:
|
|
61
|
+
|
|
62
|
+
{{recentMessages}}
|
|
63
|
+
|
|
64
|
+
{{walletInfo}}
|
|
65
|
+
|
|
66
|
+
Extract the following information about the requested proposal:
|
|
67
|
+
- Targets
|
|
68
|
+
- Values
|
|
69
|
+
- Calldatas
|
|
70
|
+
- Description
|
|
71
|
+
- Governor address
|
|
72
|
+
- Chain to execute on
|
|
73
|
+
|
|
74
|
+
Respond using plain key/value text like this. Use null for any scalar value that cannot be determined, and use empty arrays when no array values can be determined:
|
|
75
|
+
targets[2]: 0xTargetAddress1,0xTargetAddress2
|
|
76
|
+
values[2]: 0,1000000000000000000
|
|
77
|
+
calldatas[2]: 0xCalldata1,0xCalldata2
|
|
78
|
+
description: proposal description, or null
|
|
79
|
+
governor: governor contract address, or null
|
|
80
|
+
chain: chain to execute on, or null
|
|
81
|
+
|
|
82
|
+
IMPORTANT: Your response must ONLY contain the key/value fields above. No preamble or explanation.`;
|
|
83
|
+
|
|
84
|
+
export const PROPOSE_TEMPLATE = proposeTemplate;
|
|
85
|
+
|
|
86
|
+
export const queueProposalTemplate = `Given the recent messages and wallet information below:
|
|
87
|
+
|
|
88
|
+
{{recentMessages}}
|
|
89
|
+
|
|
90
|
+
{{walletInfo}}
|
|
91
|
+
|
|
92
|
+
Extract the following information about the requested proposal:
|
|
93
|
+
- Targets
|
|
94
|
+
- Values
|
|
95
|
+
- Calldatas
|
|
96
|
+
- Description
|
|
97
|
+
- Governor address
|
|
98
|
+
- Chain to execute on
|
|
99
|
+
|
|
100
|
+
Respond using plain key/value text like this. Use null for any scalar value that cannot be determined, and use empty arrays when no array values can be determined:
|
|
101
|
+
targets[2]: 0xTargetAddress1,0xTargetAddress2
|
|
102
|
+
values[2]: 0,1000000000000000000
|
|
103
|
+
calldatas[2]: 0xCalldata1,0xCalldata2
|
|
104
|
+
description: proposal description, or null
|
|
105
|
+
governor: governor contract address, or null
|
|
106
|
+
chain: chain to execute on, or null
|
|
107
|
+
|
|
108
|
+
IMPORTANT: Your response must ONLY contain the key/value fields above. No preamble or explanation.`;
|
|
109
|
+
|
|
110
|
+
export const QUEUE_PROPOSAL_TEMPLATE = queueProposalTemplate;
|
|
111
|
+
|
|
112
|
+
export const swapTemplate = `Given the recent messages and wallet information below:
|
|
113
|
+
|
|
114
|
+
{{recentMessages}}
|
|
115
|
+
|
|
116
|
+
{{chainBalances}}
|
|
117
|
+
|
|
118
|
+
Extract the following information about the requested token swap:
|
|
119
|
+
- Input token symbol or address (the token being sold)
|
|
120
|
+
- Output token symbol or address (the token being bought)
|
|
121
|
+
- Amount to swap: Must be a string representing the amount in ether (only number without coin symbol, e.g., "0.1")
|
|
122
|
+
- Chain to execute on
|
|
123
|
+
|
|
124
|
+
Respond using plain key/value text like this:
|
|
125
|
+
inputToken: token symbol or address being sold, or empty
|
|
126
|
+
outputToken: token symbol or address being bought, or empty
|
|
127
|
+
amount: amount as string (e.g. 0.1), or empty
|
|
128
|
+
chain: chain from {{supportedChains}}, or empty
|
|
129
|
+
|
|
130
|
+
IMPORTANT: Your response must ONLY contain the key/value fields above. No preamble or explanation.`;
|
|
131
|
+
|
|
132
|
+
export const SWAP_TEMPLATE = swapTemplate;
|
|
133
|
+
|
|
134
|
+
export const tokenBalanceTemplate = `Extract the token ticker and blockchain from the user's message.
|
|
135
|
+
|
|
136
|
+
User message: "{{userMessage}}"
|
|
137
|
+
|
|
138
|
+
Respond using plain key/value text like this:
|
|
139
|
+
token: TOKEN_SYMBOL
|
|
140
|
+
chain: CHAIN_NAME
|
|
141
|
+
|
|
142
|
+
If no token is mentioned or it's not a balance inquiry, return:
|
|
143
|
+
error: Not a token balance request
|
|
144
|
+
|
|
145
|
+
IMPORTANT: Your response must ONLY contain the key/value fields above. No preamble or explanation.`;
|
|
146
|
+
|
|
147
|
+
export const TOKEN_BALANCE_TEMPLATE = tokenBalanceTemplate;
|
|
148
|
+
|
|
149
|
+
export const transferTemplate = `Given the recent messages and wallet information below:
|
|
150
|
+
|
|
151
|
+
{{recentMessages}}
|
|
152
|
+
|
|
153
|
+
{{chainBalances}}
|
|
154
|
+
|
|
155
|
+
Extract the following information about the requested token transfer:
|
|
156
|
+
- Chain to execute on (must be one of the supported chains)
|
|
157
|
+
- Amount to transfer (only number without coin symbol, e.g., "0.1")
|
|
158
|
+
- Recipient address (must be a valid Ethereum address)
|
|
159
|
+
- Token symbol or address (if not a native token transfer)
|
|
160
|
+
- Additional data/calldata (if any is included)
|
|
161
|
+
|
|
162
|
+
Respond using plain key/value text like this:
|
|
163
|
+
fromChain: chain from {{supportedChains}}, or empty
|
|
164
|
+
amount: amount as string (e.g. 0.1), or empty
|
|
165
|
+
toAddress: recipient Ethereum address, or empty
|
|
166
|
+
token: token symbol or address (empty for native transfer)
|
|
167
|
+
data: additional calldata hex string, or empty
|
|
168
|
+
|
|
169
|
+
IMPORTANT: Your response must ONLY contain the key/value fields above. No preamble or explanation.`;
|
|
170
|
+
|
|
171
|
+
export const TRANSFER_TEMPLATE = transferTemplate;
|
|
172
|
+
|
|
173
|
+
export const voteTemplate = `Given the recent messages and wallet information below:
|
|
174
|
+
|
|
175
|
+
{{recentMessages}}
|
|
176
|
+
|
|
177
|
+
{{walletInfo}}
|
|
178
|
+
|
|
179
|
+
Extract the following information about the requested vote:
|
|
180
|
+
- Proposal ID
|
|
181
|
+
- Support (0 for against, 1 for yes, 2 for abstain)
|
|
182
|
+
- Governor address
|
|
183
|
+
- Chain to execute on
|
|
184
|
+
|
|
185
|
+
Respond using plain key/value text like this. Use null for any value that cannot be determined:
|
|
186
|
+
proposalId: proposal ID, or null
|
|
187
|
+
support: 0 for against, 1 for yes, 2 for abstain, or null
|
|
188
|
+
governor: governor contract address, or null
|
|
189
|
+
chain: chain to execute on, or null
|
|
190
|
+
|
|
191
|
+
IMPORTANT: Your response must ONLY contain the key/value fields above. No preamble or explanation.`;
|
|
192
|
+
|
|
193
|
+
export const VOTE_TEMPLATE = voteTemplate;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type IAgentRuntime,
|
|
3
|
+
type Memory,
|
|
4
|
+
ModelType,
|
|
5
|
+
type Provider,
|
|
6
|
+
type ProviderResult,
|
|
7
|
+
parseJSONObjectFromText,
|
|
8
|
+
} from "@elizaos/core";
|
|
9
|
+
import { getToken } from "@lifi/sdk";
|
|
10
|
+
import { type Address, formatUnits, parseAbi } from "viem";
|
|
11
|
+
import { runIntentModel } from "../../../utils/intent-trajectory";
|
|
12
|
+
import { requireProviderSpec } from "../generated/specs/spec-helpers";
|
|
13
|
+
import { tokenBalanceTemplate } from "../prompts";
|
|
14
|
+
import { EVMError, EVMErrorCode, type SupportedChain } from "../types";
|
|
15
|
+
import { initWalletProvider } from "./wallet";
|
|
16
|
+
|
|
17
|
+
const spec = requireProviderSpec("get-balance");
|
|
18
|
+
|
|
19
|
+
export const tokenBalanceProvider: Provider = {
|
|
20
|
+
name: spec.name,
|
|
21
|
+
description: "Token balance for ERC20 tokens when onchain actions are requested",
|
|
22
|
+
descriptionCompressed: "ERC20 token balance for onchain actions.",
|
|
23
|
+
contexts: ["finance", "crypto", "wallet"],
|
|
24
|
+
contextGate: { anyOf: ["finance", "crypto", "wallet"] },
|
|
25
|
+
cacheStable: false,
|
|
26
|
+
cacheScope: "turn",
|
|
27
|
+
roleGate: { minRole: "OWNER" },
|
|
28
|
+
dynamic: true,
|
|
29
|
+
get: async (runtime: IAgentRuntime, message: Memory): Promise<ProviderResult> => {
|
|
30
|
+
const inputText =
|
|
31
|
+
typeof message.content === "string"
|
|
32
|
+
? message.content
|
|
33
|
+
: typeof message.content?.text === "string"
|
|
34
|
+
? message.content.text
|
|
35
|
+
: "";
|
|
36
|
+
const normalizedText = inputText.toLowerCase();
|
|
37
|
+
const keywordMatch =
|
|
38
|
+
normalizedText.includes("balance") ||
|
|
39
|
+
normalizedText.includes("token") ||
|
|
40
|
+
normalizedText.includes("erc20") ||
|
|
41
|
+
normalizedText.includes("wallet");
|
|
42
|
+
const regexMatch = /\b(?:balance|token|erc20|wallet|chain)\b/i.test(inputText);
|
|
43
|
+
if (!keywordMatch || !regexMatch) {
|
|
44
|
+
return { text: "", data: {}, values: {} };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const prompt = tokenBalanceTemplate.replace("{{userMessage}}", inputText);
|
|
49
|
+
|
|
50
|
+
const response = await runIntentModel({
|
|
51
|
+
runtime,
|
|
52
|
+
taskName: "evm.token-balance.intent",
|
|
53
|
+
purpose: "provider",
|
|
54
|
+
template: prompt,
|
|
55
|
+
modelType: ModelType.TEXT_SMALL,
|
|
56
|
+
maxTokens: 100,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const parsed = parseJSONObjectFromText(response) as Record<string, unknown> | null;
|
|
60
|
+
|
|
61
|
+
if (!parsed || parsed.error || !parsed.token || !parsed.chain) {
|
|
62
|
+
return { text: "", data: {}, values: {} };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const token = String(parsed.token).toUpperCase();
|
|
66
|
+
const chain = String(parsed.chain).toLowerCase();
|
|
67
|
+
|
|
68
|
+
const walletProvider = await initWalletProvider(runtime);
|
|
69
|
+
|
|
70
|
+
if (!walletProvider.chains[chain]) {
|
|
71
|
+
throw new EVMError(EVMErrorCode.CHAIN_NOT_CONFIGURED, `Chain ${chain} is not configured`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const chainConfig = walletProvider.getChainConfigs(chain as SupportedChain);
|
|
75
|
+
const address = walletProvider.getAddress();
|
|
76
|
+
const tokenData = await getToken(chainConfig.id, token);
|
|
77
|
+
const publicClient = walletProvider.getPublicClient(chain as SupportedChain);
|
|
78
|
+
const balanceAbi = parseAbi(["function balanceOf(address) view returns (uint256)"]);
|
|
79
|
+
|
|
80
|
+
const balance = BigInt(
|
|
81
|
+
await publicClient.readContract({
|
|
82
|
+
address: tokenData.address as Address,
|
|
83
|
+
abi: balanceAbi,
|
|
84
|
+
functionName: "balanceOf",
|
|
85
|
+
args: [address],
|
|
86
|
+
authorizationList: undefined,
|
|
87
|
+
})
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const formattedBalance = formatUnits(balance, tokenData.decimals);
|
|
91
|
+
const hasBalance = parseFloat(formattedBalance) > 0;
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
text: `${token} balance on ${chain} for ${address}: ${formattedBalance}`,
|
|
95
|
+
data: {
|
|
96
|
+
token: tokenData.symbol,
|
|
97
|
+
chain,
|
|
98
|
+
balance: formattedBalance,
|
|
99
|
+
decimals: tokenData.decimals,
|
|
100
|
+
address: tokenData.address,
|
|
101
|
+
hasBalance,
|
|
102
|
+
},
|
|
103
|
+
values: {
|
|
104
|
+
token: tokenData.symbol,
|
|
105
|
+
chain,
|
|
106
|
+
balance: formattedBalance,
|
|
107
|
+
hasBalance: String(hasBalance),
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
} catch (error) {
|
|
111
|
+
return {
|
|
112
|
+
text: `Token balance unavailable: ${
|
|
113
|
+
error instanceof Error ? error.message : String(error)
|
|
114
|
+
}`,
|
|
115
|
+
data: {},
|
|
116
|
+
values: {
|
|
117
|
+
tokenBalanceAvailable: false,
|
|
118
|
+
tokenBalanceError: error instanceof Error ? error.name : "TokenBalanceProviderError",
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
};
|