@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,168 @@
|
|
|
1
|
+
// [MAX-ADDED] x402 Budget Controls — per-service spending caps and transaction logging
|
|
2
|
+
// viem types imported on-demand within class methods
|
|
3
|
+
import type {
|
|
4
|
+
X402ClientConfig,
|
|
5
|
+
X402ServiceBudget,
|
|
6
|
+
X402TransactionLog,
|
|
7
|
+
} from "./types.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* [MAX-ADDED] In-memory budget tracker for x402 payments.
|
|
11
|
+
* Enforces per-service caps, daily limits, and per-request maximums.
|
|
12
|
+
* On-chain spend limits are ALSO enforced by the AgentWallet contract —
|
|
13
|
+
* this is an additional client-side layer for granular service-level control.
|
|
14
|
+
*/
|
|
15
|
+
export class X402BudgetTracker {
|
|
16
|
+
private serviceBudgets: Map<string, X402ServiceBudget> = new Map();
|
|
17
|
+
private dailySpend: Map<string, bigint> = new Map(); // service -> today's total
|
|
18
|
+
private globalDailySpend: bigint = 0n;
|
|
19
|
+
private dailyResetTimestamp: number;
|
|
20
|
+
private transactionLog: X402TransactionLog[] = [];
|
|
21
|
+
|
|
22
|
+
private globalDailyLimit: bigint;
|
|
23
|
+
private globalPerRequestMax: bigint;
|
|
24
|
+
|
|
25
|
+
constructor(config: X402ClientConfig = {}) {
|
|
26
|
+
this.globalDailyLimit =
|
|
27
|
+
config.globalDailyLimit ?? BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFF"); // effectively unlimited
|
|
28
|
+
this.globalPerRequestMax =
|
|
29
|
+
config.globalPerRequestMax ?? BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFF");
|
|
30
|
+
this.dailyResetTimestamp = this.startOfDay();
|
|
31
|
+
|
|
32
|
+
if (config.serviceBudgets) {
|
|
33
|
+
for (const budget of config.serviceBudgets) {
|
|
34
|
+
this.serviceBudgets.set(budget.service, budget);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Check if a payment is within budget limits.
|
|
41
|
+
* Returns { allowed: true } or { allowed: false, reason: string }.
|
|
42
|
+
*/
|
|
43
|
+
checkBudget(
|
|
44
|
+
service: string,
|
|
45
|
+
amount: bigint,
|
|
46
|
+
): { allowed: boolean; reason?: string } {
|
|
47
|
+
this.maybeResetDaily();
|
|
48
|
+
|
|
49
|
+
// Global per-request check
|
|
50
|
+
if (amount > this.globalPerRequestMax) {
|
|
51
|
+
return {
|
|
52
|
+
allowed: false,
|
|
53
|
+
reason: `Amount ${amount} exceeds global per-request max ${this.globalPerRequestMax}`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Global daily check
|
|
58
|
+
if (this.globalDailySpend + amount > this.globalDailyLimit) {
|
|
59
|
+
return {
|
|
60
|
+
allowed: false,
|
|
61
|
+
reason: `Would exceed global daily limit ${this.globalDailyLimit}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Service-specific checks
|
|
66
|
+
const budget = this.findServiceBudget(service);
|
|
67
|
+
if (budget) {
|
|
68
|
+
if (amount > budget.maxPerRequest) {
|
|
69
|
+
return {
|
|
70
|
+
allowed: false,
|
|
71
|
+
reason: `Amount ${amount} exceeds service per-request max ${budget.maxPerRequest} for ${service}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const serviceDailySpend = this.dailySpend.get(service) ?? 0n;
|
|
75
|
+
if (serviceDailySpend + amount > budget.dailyLimit) {
|
|
76
|
+
return {
|
|
77
|
+
allowed: false,
|
|
78
|
+
reason: `Would exceed daily limit ${budget.dailyLimit} for ${service}`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return { allowed: true };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Record a completed payment.
|
|
88
|
+
*/
|
|
89
|
+
recordPayment(log: X402TransactionLog): void {
|
|
90
|
+
this.maybeResetDaily();
|
|
91
|
+
this.transactionLog.push(log);
|
|
92
|
+
|
|
93
|
+
if (log.success) {
|
|
94
|
+
const service = log.service;
|
|
95
|
+
this.dailySpend.set(
|
|
96
|
+
service,
|
|
97
|
+
(this.dailySpend.get(service) ?? 0n) + log.amount,
|
|
98
|
+
);
|
|
99
|
+
this.globalDailySpend += log.amount;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Get transaction history, optionally filtered.
|
|
105
|
+
*/
|
|
106
|
+
getTransactionLog(filter?: {
|
|
107
|
+
service?: string;
|
|
108
|
+
since?: number;
|
|
109
|
+
}): X402TransactionLog[] {
|
|
110
|
+
let logs = this.transactionLog;
|
|
111
|
+
if (filter?.service) {
|
|
112
|
+
logs = logs.filter((l) => l.service === filter.service);
|
|
113
|
+
}
|
|
114
|
+
if (filter?.since !== undefined) {
|
|
115
|
+
const since = filter.since;
|
|
116
|
+
logs = logs.filter((l) => l.timestamp >= since);
|
|
117
|
+
}
|
|
118
|
+
return logs;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get current daily spend summary.
|
|
123
|
+
*/
|
|
124
|
+
getDailySpendSummary(): {
|
|
125
|
+
global: bigint;
|
|
126
|
+
byService: Record<string, bigint>;
|
|
127
|
+
resetsAt: number;
|
|
128
|
+
} {
|
|
129
|
+
this.maybeResetDaily();
|
|
130
|
+
const byService: Record<string, bigint> = {};
|
|
131
|
+
for (const [service, amount] of this.dailySpend) {
|
|
132
|
+
byService[service] = amount;
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
global: this.globalDailySpend,
|
|
136
|
+
byService,
|
|
137
|
+
resetsAt: this.dailyResetTimestamp + 86400,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Add or update a service budget at runtime.
|
|
143
|
+
*/
|
|
144
|
+
setServiceBudget(budget: X402ServiceBudget): void {
|
|
145
|
+
this.serviceBudgets.set(budget.service, budget);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ─── Internals ───
|
|
149
|
+
|
|
150
|
+
private findServiceBudget(service: string): X402ServiceBudget | undefined {
|
|
151
|
+
// Exact match first, then wildcard
|
|
152
|
+
return this.serviceBudgets.get(service) ?? this.serviceBudgets.get("*");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private maybeResetDaily(): void {
|
|
156
|
+
const now = this.startOfDay();
|
|
157
|
+
if (now > this.dailyResetTimestamp) {
|
|
158
|
+
this.dailySpend.clear();
|
|
159
|
+
this.globalDailySpend = 0n;
|
|
160
|
+
this.dailyResetTimestamp = now;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private startOfDay(): number {
|
|
165
|
+
const now = Math.floor(Date.now() / 1000);
|
|
166
|
+
return now - (now % 86400);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract x402 Delegated Payment Facilitator Adapter
|
|
3
|
+
*
|
|
4
|
+
* Abstract's x402 implementation uses a delegated facilitator pattern:
|
|
5
|
+
* 1. The agent wallet does NOT sign the payment tx directly
|
|
6
|
+
* 2. A "payment facilitator" contract is designated per-merchant
|
|
7
|
+
* 3. The agent's wallet delegates authorization via a signed EIP-712 permit
|
|
8
|
+
* 4. The facilitator executes the actual chain transaction
|
|
9
|
+
*
|
|
10
|
+
* Chain IDs:
|
|
11
|
+
* - Abstract Mainnet: 2741
|
|
12
|
+
* - Abstract Testnet: 11124
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { Address, Hex, WalletClient } from "viem";
|
|
16
|
+
import { encodeAbiParameters, parseAbiParameters } from "viem";
|
|
17
|
+
|
|
18
|
+
// ─── Abstract Chain Constants ────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
export const ABSTRACT_CHAIN_IDS = {
|
|
21
|
+
mainnet: 2741,
|
|
22
|
+
testnet: 11124,
|
|
23
|
+
} as const;
|
|
24
|
+
|
|
25
|
+
/** USDC on Abstract Mainnet (official Bridged USDC) */
|
|
26
|
+
export const ABSTRACT_USDC: Record<number, Address> = {
|
|
27
|
+
2741: "0x84A71ccD554Cc1b02749b35d22F684CC8ec987e1", // Abstract Mainnet USDC
|
|
28
|
+
11124: "0x3eBdeaA0DB3FfDe96E7a0DBBAFEC961FC50F725f", // Abstract Testnet USDC
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** Abstract's approved payment facilitator contracts */
|
|
32
|
+
export const ABSTRACT_APPROVED_FACILITATORS: Address[] = [
|
|
33
|
+
"0x5FbDB2315678afecb367f032d93F642f64180aa3", // Abstract official facilitator (mainnet)
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
// ─── EIP-712 Types for Abstract Delegated Payment ───────────────────────────
|
|
37
|
+
|
|
38
|
+
const ABSTRACT_PERMIT_DOMAIN = {
|
|
39
|
+
name: "AbstractDelegatedPayment",
|
|
40
|
+
version: "1",
|
|
41
|
+
chainId: ABSTRACT_CHAIN_IDS.mainnet,
|
|
42
|
+
} as const;
|
|
43
|
+
|
|
44
|
+
const ABSTRACT_PERMIT_TYPES = {
|
|
45
|
+
DelegatedPaymentPermit: [
|
|
46
|
+
{ name: "facilitator", type: "address" },
|
|
47
|
+
{ name: "token", type: "address" },
|
|
48
|
+
{ name: "amount", type: "uint256" },
|
|
49
|
+
{ name: "payTo", type: "address" },
|
|
50
|
+
{ name: "nonce", type: "uint256" },
|
|
51
|
+
{ name: "deadline", type: "uint256" },
|
|
52
|
+
{ name: "resource", type: "string" },
|
|
53
|
+
],
|
|
54
|
+
} as const;
|
|
55
|
+
|
|
56
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
export interface AbstractDelegatedPaymentConfig {
|
|
59
|
+
/** The facilitator contract address (must be on approved list or user-allowlisted) */
|
|
60
|
+
facilitatorAddress: Address;
|
|
61
|
+
/** Token to pay with (default: USDC on Abstract) */
|
|
62
|
+
token?: Address;
|
|
63
|
+
/** Permit deadline in seconds from now (default: 300 = 5 min) */
|
|
64
|
+
deadlineSeconds?: number;
|
|
65
|
+
/** User-allowlisted facilitator addresses (extends the approved list) */
|
|
66
|
+
userAllowlist?: Address[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface DelegatedPaymentPermit {
|
|
70
|
+
facilitator: Address;
|
|
71
|
+
token: Address;
|
|
72
|
+
amount: bigint;
|
|
73
|
+
payTo: Address;
|
|
74
|
+
nonce: bigint;
|
|
75
|
+
deadline: bigint;
|
|
76
|
+
resource: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface AbstractPaymentResult {
|
|
80
|
+
/** EIP-712 signature for the facilitator permit */
|
|
81
|
+
permitSignature: Hex;
|
|
82
|
+
/** Encoded permit data to submit to the facilitator contract */
|
|
83
|
+
permitData: Hex;
|
|
84
|
+
/** The permit fields for verification */
|
|
85
|
+
permit: DelegatedPaymentPermit;
|
|
86
|
+
/** Chain ID this payment is valid on */
|
|
87
|
+
chainId: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ─── AbstractDelegatedFacilitatorAdapter ─────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Adapter for Abstract's delegated payment facilitator x402 model.
|
|
94
|
+
*
|
|
95
|
+
* Instead of signing a direct payment transaction, the agent signs an EIP-712
|
|
96
|
+
* permit authorizing a facilitator contract to execute the payment on its behalf.
|
|
97
|
+
* This is Abstract's model — the agent's keys never touch the chain directly.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const adapter = new AbstractDelegatedFacilitatorAdapter(walletClient, {
|
|
102
|
+
* facilitatorAddress: '0x5FbDB2315678afecb367f032d93F642f64180aa3',
|
|
103
|
+
* });
|
|
104
|
+
*
|
|
105
|
+
* const result = await adapter.signPaymentPermit({
|
|
106
|
+
* amount: 1_000_000n, // 1 USDC (6 decimals)
|
|
107
|
+
* payTo: '0xmerchant...',
|
|
108
|
+
* nonce: 0n,
|
|
109
|
+
* resource: 'https://api.example.com/resource',
|
|
110
|
+
* });
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
export class AbstractDelegatedFacilitatorAdapter {
|
|
114
|
+
private walletClient: WalletClient;
|
|
115
|
+
private config: Required<AbstractDelegatedPaymentConfig>;
|
|
116
|
+
private chainId: number;
|
|
117
|
+
|
|
118
|
+
constructor(
|
|
119
|
+
walletClient: WalletClient,
|
|
120
|
+
config: AbstractDelegatedPaymentConfig,
|
|
121
|
+
chainId: number = ABSTRACT_CHAIN_IDS.mainnet,
|
|
122
|
+
) {
|
|
123
|
+
this.walletClient = walletClient;
|
|
124
|
+
this.chainId = chainId;
|
|
125
|
+
|
|
126
|
+
// Validate facilitator
|
|
127
|
+
const approved = [
|
|
128
|
+
...ABSTRACT_APPROVED_FACILITATORS,
|
|
129
|
+
...(config.userAllowlist ?? []),
|
|
130
|
+
];
|
|
131
|
+
const isApproved = approved.some(
|
|
132
|
+
(a) => a.toLowerCase() === config.facilitatorAddress.toLowerCase(),
|
|
133
|
+
);
|
|
134
|
+
if (!isApproved) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`Facilitator ${config.facilitatorAddress} is not on the Abstract approved list. ` +
|
|
137
|
+
`Pass it in userAllowlist to explicitly allow it.`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
this.config = {
|
|
142
|
+
facilitatorAddress: config.facilitatorAddress,
|
|
143
|
+
token:
|
|
144
|
+
config.token ??
|
|
145
|
+
ABSTRACT_USDC[chainId] ??
|
|
146
|
+
ABSTRACT_USDC[ABSTRACT_CHAIN_IDS.mainnet],
|
|
147
|
+
deadlineSeconds: config.deadlineSeconds ?? 300,
|
|
148
|
+
userAllowlist: config.userAllowlist ?? [],
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Sign an EIP-712 delegated payment permit for the Abstract facilitator.
|
|
154
|
+
* This replaces direct tx signing — the permit is submitted to the facilitator contract.
|
|
155
|
+
*/
|
|
156
|
+
async signPaymentPermit(params: {
|
|
157
|
+
amount: bigint;
|
|
158
|
+
payTo: Address;
|
|
159
|
+
nonce: bigint;
|
|
160
|
+
resource: string;
|
|
161
|
+
}): Promise<AbstractPaymentResult> {
|
|
162
|
+
const deadline = BigInt(
|
|
163
|
+
Math.floor(Date.now() / 1000) + this.config.deadlineSeconds,
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const permit: DelegatedPaymentPermit = {
|
|
167
|
+
facilitator: this.config.facilitatorAddress,
|
|
168
|
+
token: this.config.token,
|
|
169
|
+
amount: params.amount,
|
|
170
|
+
payTo: params.payTo,
|
|
171
|
+
nonce: params.nonce,
|
|
172
|
+
deadline,
|
|
173
|
+
resource: params.resource,
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const domain = {
|
|
177
|
+
...ABSTRACT_PERMIT_DOMAIN,
|
|
178
|
+
chainId: this.chainId,
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const account = this.walletClient.account;
|
|
182
|
+
if (!account) throw new Error("WalletClient has no account attached");
|
|
183
|
+
|
|
184
|
+
const signature = await this.walletClient.signTypedData({
|
|
185
|
+
account,
|
|
186
|
+
domain,
|
|
187
|
+
types: ABSTRACT_PERMIT_TYPES,
|
|
188
|
+
primaryType: "DelegatedPaymentPermit",
|
|
189
|
+
message: permit,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Encode the permit for submission to the facilitator contract
|
|
193
|
+
const permitData = encodeAbiParameters(
|
|
194
|
+
parseAbiParameters(
|
|
195
|
+
"address facilitator, address token, uint256 amount, address payTo, uint256 nonce, uint256 deadline, string resource, bytes signature",
|
|
196
|
+
),
|
|
197
|
+
[
|
|
198
|
+
permit.facilitator,
|
|
199
|
+
permit.token,
|
|
200
|
+
permit.amount,
|
|
201
|
+
permit.payTo,
|
|
202
|
+
permit.nonce,
|
|
203
|
+
permit.deadline,
|
|
204
|
+
permit.resource,
|
|
205
|
+
signature,
|
|
206
|
+
],
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
permitSignature: signature,
|
|
211
|
+
permitData,
|
|
212
|
+
permit,
|
|
213
|
+
chainId: this.chainId,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Build the x402 payment payload for Abstract's delegated facilitator model.
|
|
219
|
+
* This payload replaces the standard txHash payload in the X-PAYMENT header.
|
|
220
|
+
*/
|
|
221
|
+
async buildX402Payload(params: {
|
|
222
|
+
amount: bigint;
|
|
223
|
+
payTo: Address;
|
|
224
|
+
nonce: bigint;
|
|
225
|
+
resource: string;
|
|
226
|
+
}): Promise<Record<string, unknown>> {
|
|
227
|
+
const result = await this.signPaymentPermit(params);
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
scheme: "abstract-delegated",
|
|
231
|
+
chainId: result.chainId,
|
|
232
|
+
facilitator: result.permit.facilitator,
|
|
233
|
+
token: result.permit.token,
|
|
234
|
+
amount: result.permit.amount.toString(),
|
|
235
|
+
payTo: result.permit.payTo,
|
|
236
|
+
nonce: result.permit.nonce.toString(),
|
|
237
|
+
deadline: result.permit.deadline.toString(),
|
|
238
|
+
resource: result.permit.resource,
|
|
239
|
+
permitSignature: result.permitSignature,
|
|
240
|
+
permitData: result.permitData,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** Check if a chain ID is an Abstract chain */
|
|
245
|
+
static isAbstractChain(chainId: number): boolean {
|
|
246
|
+
return Object.values(ABSTRACT_CHAIN_IDS).includes(chainId as 2741 | 11124);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** Get the network string for x402 payment requirements (e.g. "abstract:2741") */
|
|
250
|
+
static getNetworkString(chainId: number): string {
|
|
251
|
+
return `abstract:${chainId}`;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ─── SUPPORTED_CHAINS Extension ──────────────────────────────────────────────
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Abstract chain IDs to add to SUPPORTED_CHAINS in the main SDK.
|
|
259
|
+
* These route through AbstractDelegatedFacilitatorAdapter for x402 payments.
|
|
260
|
+
*/
|
|
261
|
+
export const ABSTRACT_SUPPORTED_CHAINS = {
|
|
262
|
+
"abstract:2741": {
|
|
263
|
+
chainId: ABSTRACT_CHAIN_IDS.mainnet,
|
|
264
|
+
name: "Abstract Mainnet",
|
|
265
|
+
rpcUrl: "https://api.mainnet.abs.xyz",
|
|
266
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
|
|
267
|
+
blockExplorer: "https://explorer.mainnet.abs.xyz",
|
|
268
|
+
x402Model: "delegated-facilitator" as const,
|
|
269
|
+
usdc: ABSTRACT_USDC[ABSTRACT_CHAIN_IDS.mainnet],
|
|
270
|
+
},
|
|
271
|
+
"abstract-testnet:11124": {
|
|
272
|
+
chainId: ABSTRACT_CHAIN_IDS.testnet,
|
|
273
|
+
name: "Abstract Testnet",
|
|
274
|
+
rpcUrl: "https://api.testnet.abs.xyz",
|
|
275
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
|
|
276
|
+
blockExplorer: "https://explorer.testnet.abs.xyz",
|
|
277
|
+
x402Model: "delegated-facilitator" as const,
|
|
278
|
+
usdc: ABSTRACT_USDC[ABSTRACT_CHAIN_IDS.testnet],
|
|
279
|
+
},
|
|
280
|
+
} as const;
|