otto-intel-mcp 0.1.3 → 0.1.4
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/README.md +74 -18
- package/dist/account-userop-policy-definition.d.ts +14 -0
- package/dist/account-userop-policy-definition.js +12 -0
- package/dist/account-userop-policy-relation.d.ts +371 -0
- package/dist/account-userop-policy-relation.js +87 -0
- package/dist/adapter/cdp-signer.d.ts +32 -4
- package/dist/adapter/cdp-signer.js +128 -37
- package/dist/adapter-cdp-index.d.ts +1 -1
- package/dist/execution-account-gas-quote.d.ts +141 -0
- package/dist/execution-account-gas-quote.js +443 -0
- package/dist/execution-account-gas-review.d.ts +123 -0
- package/dist/execution-account-gas-review.js +104 -0
- package/dist/execution-account-gas-runtime.d.ts +33 -0
- package/dist/execution-account-gas-runtime.js +131 -0
- package/dist/execution-account-gas-view.d.ts +936 -0
- package/dist/execution-account-gas-view.js +56 -0
- package/dist/execution-config.d.ts +3 -0
- package/dist/execution-config.js +4 -0
- package/dist/execution-delegated-definition.d.ts +6 -6
- package/dist/execution-delegated-definition.js +1 -1
- package/dist/execution-delegation-admin-definition.d.ts +12 -11
- package/dist/execution-delegation-admin-definition.js +6 -5
- package/dist/execution-delegation-admin.d.ts +5 -5
- package/dist/execution-delegation-admin.js +157 -49
- package/dist/execution-delegation-cap-store.d.ts +22 -5
- package/dist/execution-delegation-cap-store.js +74 -7
- package/dist/execution-delegation-exit-definition.d.ts +309 -0
- package/dist/execution-delegation-exit-definition.js +204 -0
- package/dist/execution-delegation-exit-store.d.ts +114 -0
- package/dist/execution-delegation-exit-store.js +671 -0
- package/dist/execution-delegation-exit.d.ts +4 -0
- package/dist/execution-delegation-exit.js +614 -0
- package/dist/execution-delegation-finality.d.ts +22 -0
- package/dist/execution-delegation-finality.js +90 -0
- package/dist/execution-delegation-operation-store.d.ts +129 -0
- package/dist/execution-delegation-operation-store.js +1107 -0
- package/dist/execution-delegation-operations-definition.d.ts +282 -0
- package/dist/execution-delegation-operations-definition.js +117 -0
- package/dist/execution-delegation-operations.d.ts +6 -0
- package/dist/execution-delegation-operations.js +282 -0
- package/dist/execution-delegation-policy.d.ts +1 -2
- package/dist/execution-delegation-policy.js +13 -24
- package/dist/execution-delegation.d.ts +16 -0
- package/dist/execution-delegation.js +221 -26
- package/dist/execution-errors.d.ts +1 -1
- package/dist/execution-errors.js +27 -3
- package/dist/execution-index.d.ts +4 -0
- package/dist/execution-index.js +4 -0
- package/dist/execution-journal-schema.d.ts +96 -0
- package/dist/execution-journal-schema.js +368 -0
- package/dist/execution-journal-tables.d.ts +14 -0
- package/dist/execution-journal-tables.js +227 -0
- package/dist/execution-policy-compatibility.d.ts +34 -0
- package/dist/execution-policy-compatibility.js +76 -0
- package/dist/execution-registration.d.ts +8 -5
- package/dist/execution-registration.js +106 -3
- package/dist/execution-sponsored-account-profile.d.ts +32 -0
- package/dist/execution-sponsored-account-profile.js +59 -0
- package/dist/execution-sponsored-account.d.ts +1519 -0
- package/dist/execution-sponsored-account.js +222 -0
- package/dist/execution-sponsored-definition.d.ts +1713 -0
- package/dist/execution-sponsored-definition.js +185 -0
- package/dist/execution-sponsored-gas-policy.d.ts +27 -0
- package/dist/execution-sponsored-gas-policy.js +110 -0
- package/dist/execution-sponsored-hosted.d.ts +3 -0
- package/dist/execution-sponsored-hosted.js +71 -0
- package/dist/execution-sponsored-index.d.ts +1322 -0
- package/dist/execution-sponsored-index.js +102 -0
- package/dist/execution-sponsored-mcp-definition.d.ts +1662 -0
- package/dist/execution-sponsored-mcp-definition.js +94 -0
- package/dist/execution-sponsored-receipt.d.ts +47 -0
- package/dist/execution-sponsored-receipt.js +74 -0
- package/dist/execution-sponsored-registration.d.ts +14 -0
- package/dist/execution-sponsored-registration.js +77 -0
- package/dist/execution-sponsored-runtime.d.ts +84 -0
- package/dist/execution-sponsored-runtime.js +149 -0
- package/dist/execution-sponsored-settlement.d.ts +15 -0
- package/dist/execution-sponsored-settlement.js +88 -0
- package/dist/execution-sponsored-store.d.ts +67 -0
- package/dist/execution-sponsored-store.js +517 -0
- package/dist/execution-sponsored-transport.d.ts +90 -0
- package/dist/execution-sponsored-transport.js +180 -0
- package/dist/execution-tool-definitions.d.ts +21 -21
- package/dist/execution-tool-definitions.js +0 -7
- package/dist/execution-tools.d.ts +9 -0
- package/dist/execution-tools.js +14 -0
- package/dist/execution-worker-guard.d.ts +28 -0
- package/dist/execution-worker-guard.js +124 -0
- package/dist/hybrid-yield-index.d.ts +10 -0
- package/dist/hybrid-yield-index.js +11 -0
- package/dist/hybrid-yield-markets.d.ts +96 -0
- package/dist/hybrid-yield-markets.js +124 -0
- package/dist/hybrid-yield.d.ts +411 -0
- package/dist/hybrid-yield.js +155 -0
- package/dist/hyperliquid-order-builder.js +4 -0
- package/dist/lp-userop-account.d.ts +461 -0
- package/dist/lp-userop-account.js +417 -0
- package/dist/lp-userop-authority.d.ts +49 -0
- package/dist/lp-userop-authority.js +211 -0
- package/dist/lp-userop-definition.d.ts +233 -0
- package/dist/lp-userop-definition.js +85 -0
- package/dist/lp-userop-hosted.d.ts +3 -0
- package/dist/lp-userop-hosted.js +73 -0
- package/dist/lp-userop-index.d.ts +1569 -0
- package/dist/lp-userop-index.js +112 -0
- package/dist/lp-userop-mcp-definition.d.ts +1220 -0
- package/dist/lp-userop-mcp-definition.js +46 -0
- package/dist/lp-userop-operation.d.ts +1230 -0
- package/dist/lp-userop-operation.js +140 -0
- package/dist/lp-userop-registration.d.ts +14 -0
- package/dist/lp-userop-registration.js +70 -0
- package/dist/lp-userop-settlement.d.ts +89 -0
- package/dist/lp-userop-settlement.js +184 -0
- package/dist/lp-userop.d.ts +643 -0
- package/dist/lp-userop.js +343 -0
- package/dist/native-yield-account-definition.d.ts +1192 -0
- package/dist/native-yield-account-definition.js +232 -0
- package/dist/native-yield-account-gas.d.ts +58 -0
- package/dist/native-yield-account-gas.js +228 -0
- package/dist/native-yield-account-index.d.ts +23 -0
- package/dist/native-yield-account-index.js +28 -0
- package/dist/native-yield-account-policy.d.ts +168 -0
- package/dist/native-yield-account-policy.js +525 -0
- package/dist/native-yield-account-rpc.d.ts +8 -0
- package/dist/native-yield-account-rpc.js +128 -0
- package/dist/native-yield-account-runtime.d.ts +71 -0
- package/dist/native-yield-account-runtime.js +125 -0
- package/dist/native-yield-account-store.d.ts +40 -0
- package/dist/native-yield-account-store.js +307 -0
- package/dist/native-yield-account.d.ts +662 -0
- package/dist/native-yield-account.js +371 -0
- package/dist/native-yield-consent-store.d.ts +20 -0
- package/dist/native-yield-consent-store.js +317 -0
- package/dist/native-yield-definition.d.ts +288 -0
- package/dist/native-yield-definition.js +105 -0
- package/dist/native-yield-reader.d.ts +4 -0
- package/dist/native-yield-reader.js +137 -0
- package/dist/native-yield-settlement.d.ts +48 -0
- package/dist/native-yield-settlement.js +167 -0
- package/dist/native-yield-simulation.d.ts +18 -0
- package/dist/native-yield-simulation.js +45 -0
- package/dist/native-yield-userop-account.d.ts +675 -0
- package/dist/native-yield-userop-account.js +357 -0
- package/dist/native-yield-userop-authority.d.ts +214 -0
- package/dist/native-yield-userop-authority.js +296 -0
- package/dist/native-yield-userop-definition.d.ts +331 -0
- package/dist/native-yield-userop-definition.js +105 -0
- package/dist/native-yield-userop-hosted.d.ts +3 -0
- package/dist/native-yield-userop-hosted.js +71 -0
- package/dist/native-yield-userop-index.d.ts +1522 -0
- package/dist/native-yield-userop-index.js +142 -0
- package/dist/native-yield-userop-mcp-definition.d.ts +1356 -0
- package/dist/native-yield-userop-mcp-definition.js +50 -0
- package/dist/native-yield-userop-operation.d.ts +845 -0
- package/dist/native-yield-userop-operation.js +127 -0
- package/dist/native-yield-userop-policy.d.ts +23 -0
- package/dist/native-yield-userop-policy.js +25 -0
- package/dist/native-yield-userop-registration.d.ts +17 -0
- package/dist/native-yield-userop-registration.js +76 -0
- package/dist/native-yield-userop-settlement.d.ts +8 -0
- package/dist/native-yield-userop-settlement.js +79 -0
- package/dist/native-yield-userop-simulation.d.ts +18 -0
- package/dist/native-yield-userop-simulation.js +34 -0
- package/dist/native-yield-userop.d.ts +35 -0
- package/dist/native-yield-userop.js +156 -0
- package/dist/native-yield-verify.d.ts +30 -0
- package/dist/native-yield-verify.js +141 -0
- package/dist/native-yield.d.ts +17 -0
- package/dist/native-yield.js +119 -0
- package/dist/stdio-main.js +0 -0
- package/dist/stock-buy-definition.d.ts +10 -10
- package/dist/tool-definitions.d.ts +3 -1
- package/dist/tool-definitions.js +54 -1
- package/dist/vendor/lp-v3/lp-v3-atomic-contract.d.ts +445 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-contract.js +90 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-evidence.d.ts +14 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-evidence.js +82 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-index.d.ts +80 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-index.js +19 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-plan.d.ts +43 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-plan.js +112 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-read-contract.d.ts +312 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-read-contract.js +41 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-read-index.d.ts +3 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-read-index.js +3 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-read-rpc.d.ts +49 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-read-rpc.js +88 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-read.d.ts +17 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-read.js +232 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-settlement.d.ts +105 -0
- package/dist/vendor/lp-v3/lp-v3-atomic-settlement.js +162 -0
- package/dist/vendor/lp-v3/lp-v3-collect-protocol-contract.d.ts +606 -0
- package/dist/vendor/lp-v3/lp-v3-collect-protocol-contract.js +59 -0
- package/dist/vendor/lp-v3/lp-v3-collect-protocol-index.d.ts +168 -0
- package/dist/vendor/lp-v3/lp-v3-collect-protocol-index.js +23 -0
- package/dist/vendor/lp-v3/lp-v3-collect-protocol-observation.d.ts +32 -0
- package/dist/vendor/lp-v3/lp-v3-collect-protocol-observation.js +228 -0
- package/dist/vendor/lp-v3/lp-v3-collect-protocol-plan.d.ts +11 -0
- package/dist/vendor/lp-v3/lp-v3-collect-protocol-plan.js +91 -0
- package/dist/vendor/lp-v3/lp-v3-collect-protocol-reconcile.d.ts +9 -0
- package/dist/vendor/lp-v3/lp-v3-collect-protocol-reconcile.js +124 -0
- package/dist/vendor/lp-v3/lp-v3-contract.d.ts +538 -0
- package/dist/vendor/lp-v3/lp-v3-contract.js +137 -0
- package/dist/vendor/lp-v3/lp-v3-evidence.d.ts +25 -0
- package/dist/vendor/lp-v3/lp-v3-evidence.js +168 -0
- package/dist/vendor/lp-v3/lp-v3-plan.d.ts +22 -0
- package/dist/vendor/lp-v3/lp-v3-plan.js +135 -0
- package/dist/vendor/lp-v3/types.d.ts +131 -0
- package/dist/vendor/lp-v3/types.js +6 -0
- package/dist/vendor/lp-v3/v4-math.d.ts +18 -0
- package/dist/vendor/lp-v3/v4-math.js +90 -0
- package/dist/yield-deposit-definition.d.ts +65 -14
- package/dist/yield-deposit-definition.js +6 -4
- package/dist/yield-deposit.js +8 -0
- package/dist/yield-route-semantics.d.ts +27 -0
- package/dist/yield-route-semantics.js +71 -0
- package/dist/yield-withdraw-definition.d.ts +62 -11
- package/dist/yield-withdraw-definition.js +3 -1
- package/dist/yield-withdraw.d.ts +0 -10
- package/dist/yield-withdraw.js +2 -0
- package/package.json +215 -7
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/** Review-only payer selection. Quotes are estimates; this module never authorizes a send. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { ACCOUNT_GAS_QUOTE_SCHEMA } from './execution-account-gas-quote.js';
|
|
4
|
+
import { SPONSORED_GAS_POLICY_MAX_AGE_MS, SPONSORED_INITIAL_GAS_CAP_USD_MICROS } from './execution-sponsored-gas-policy.js';
|
|
5
|
+
const CAP_MICROS = BigInt(SPONSORED_INITIAL_GAS_CAP_USD_MICROS);
|
|
6
|
+
const payerSchema = z.enum(['sponsor', 'account']);
|
|
7
|
+
const statusSchema = z.enum(['eligible', 'above-limit', 'unavailable', 'price-unavailable']);
|
|
8
|
+
export const ACCOUNT_GAS_REVIEW_SCHEMA = z.object({
|
|
9
|
+
version: z.literal(1), revision: z.number().int().positive().safe(),
|
|
10
|
+
payer: payerSchema, sponsorStatus: statusSchema,
|
|
11
|
+
subsidyCapUsdMicros: z.literal('100000'), quote: ACCOUNT_GAS_QUOTE_SCHEMA,
|
|
12
|
+
}).strict().superRefine((review, context) => {
|
|
13
|
+
const invalid = () => context.addIssue({ code: 'custom', message: 'Gas payer and sponsorship status do not match the estimate' });
|
|
14
|
+
try {
|
|
15
|
+
const cost = review.quote.sponsoredEstimate?.estimatedGasCostUsdMicros;
|
|
16
|
+
if ((review.payer === 'sponsor' && review.sponsorStatus !== 'eligible') ||
|
|
17
|
+
(review.sponsorStatus === 'eligible' && (cost === undefined || BigInt(cost) > CAP_MICROS)) ||
|
|
18
|
+
(review.sponsorStatus === 'price-unavailable' && (!review.quote.sponsoredEstimate || cost !== undefined)) ||
|
|
19
|
+
(review.sponsorStatus === 'above-limit' && cost === undefined))
|
|
20
|
+
invalid();
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
invalid();
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
export class AccountGasReviewError extends Error {
|
|
27
|
+
code;
|
|
28
|
+
constructor(code) {
|
|
29
|
+
super(code);
|
|
30
|
+
this.code = code;
|
|
31
|
+
this.name = 'AccountGasReviewError';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function refuse(code) { throw new AccountGasReviewError(code); }
|
|
35
|
+
function quoteIsCurrent(quote, nowMs) {
|
|
36
|
+
return Number.isSafeInteger(nowMs) && nowMs >= quote.observedAtMs &&
|
|
37
|
+
nowMs >= quote.providerEstimate.completedAtMs &&
|
|
38
|
+
nowMs >= (quote.sponsoredEstimate?.providerEstimate.completedAtMs ?? quote.providerEstimate.completedAtMs) &&
|
|
39
|
+
nowMs < quote.expiresAtMs;
|
|
40
|
+
}
|
|
41
|
+
function policyIsCurrent(policy, quote, nowMs) {
|
|
42
|
+
return !!policy && policy.chainId === quote.chainId && typeof policy.sponsorshipPolicyId === 'string' && /^[a-zA-Z0-9_-]{1,128}$/.test(policy.sponsorshipPolicyId) &&
|
|
43
|
+
Number.isSafeInteger(policy.maximumGasCostUsdMicros) && policy.maximumGasCostUsdMicros >= 10_000 &&
|
|
44
|
+
policy.maximumGasCostUsdMicros <= SPONSORED_INITIAL_GAS_CAP_USD_MICROS && policy.maximumGasCostUsdMicros % 10_000 === 0 &&
|
|
45
|
+
Number.isSafeInteger(policy.checkedAtMs) && Number.isSafeInteger(policy.validUntilMs) &&
|
|
46
|
+
policy.checkedAtMs >= 0 && policy.checkedAtMs <= nowMs && nowMs < policy.validUntilMs &&
|
|
47
|
+
policy.validUntilMs <= policy.checkedAtMs + SPONSORED_GAS_POLICY_MAX_AGE_MS;
|
|
48
|
+
}
|
|
49
|
+
export function createAccountGasReview(input) {
|
|
50
|
+
const parsed = ACCOUNT_GAS_QUOTE_SCHEMA.safeParse(input.quote), previousRevision = input.previousRevision ?? 0;
|
|
51
|
+
if (!parsed.success || !Number.isSafeInteger(previousRevision) || previousRevision < 0 || previousRevision >= Number.MAX_SAFE_INTEGER ||
|
|
52
|
+
!['auto', 'sponsor', 'account'].includes(input.preference))
|
|
53
|
+
return refuse('ACCOUNT_GAS_REVIEW_INVALID');
|
|
54
|
+
const quote = parsed.data;
|
|
55
|
+
if (!quoteIsCurrent(quote, input.nowMs))
|
|
56
|
+
return refuse('ACCOUNT_GAS_REVIEW_STALE');
|
|
57
|
+
const currentPolicy = policyIsCurrent(input.sponsorPolicy, quote, input.nowMs) ? input.sponsorPolicy : undefined;
|
|
58
|
+
const sponsored = quote.sponsoredEstimate;
|
|
59
|
+
const cost = sponsored?.estimatedGasCostUsdMicros;
|
|
60
|
+
const sponsorStatus = !currentPolicy || !sponsored || sponsored.sponsorshipPolicyId !== currentPolicy.sponsorshipPolicyId
|
|
61
|
+
? 'unavailable' : cost === undefined ? 'price-unavailable'
|
|
62
|
+
: BigInt(cost) > CAP_MICROS || BigInt(cost) > BigInt(currentPolicy.maximumGasCostUsdMicros) ? 'above-limit' : 'eligible';
|
|
63
|
+
if (input.preference === 'sponsor' && sponsorStatus !== 'eligible')
|
|
64
|
+
return refuse('ACCOUNT_GAS_SPONSOR_INELIGIBLE');
|
|
65
|
+
const payer = input.preference === 'account' ? 'account' : sponsorStatus === 'eligible' ? 'sponsor' : 'account';
|
|
66
|
+
const review = ACCOUNT_GAS_REVIEW_SCHEMA.safeParse({ version: 1, revision: previousRevision + 1, payer, sponsorStatus,
|
|
67
|
+
subsidyCapUsdMicros: '100000', quote });
|
|
68
|
+
if (!review.success)
|
|
69
|
+
return refuse('ACCOUNT_GAS_REVIEW_INVALID');
|
|
70
|
+
return Object.freeze(review.data);
|
|
71
|
+
}
|
|
72
|
+
/** A fresh review is necessary, but caller-owned consent and live final checks remain required. */
|
|
73
|
+
export function accountGasReviewCanSubmit(input, nowMs) {
|
|
74
|
+
const parsed = ACCOUNT_GAS_REVIEW_SCHEMA.safeParse(input);
|
|
75
|
+
return parsed.success && quoteIsCurrent(parsed.data.quote, nowMs) &&
|
|
76
|
+
(parsed.data.payer === 'sponsor' || parsed.data.quote.balance.shortfallWei === '0');
|
|
77
|
+
}
|
|
78
|
+
/** Native-currency review tolerates fee movement within its displayed 25% funding cushion.
|
|
79
|
+
* This comparison is a consent threshold, not an enforceable maximum network fee. */
|
|
80
|
+
export function accountGasReviewNeedsRenewal(previous, fresh) {
|
|
81
|
+
const oldResult = ACCOUNT_GAS_REVIEW_SCHEMA.safeParse(previous), newResult = ACCOUNT_GAS_REVIEW_SCHEMA.safeParse(fresh);
|
|
82
|
+
if (!oldResult.success || !newResult.success)
|
|
83
|
+
return true;
|
|
84
|
+
const oldReview = oldResult.data, newReview = newResult.data, oldQuote = oldReview.quote, newQuote = newReview.quote;
|
|
85
|
+
if (newReview.revision < oldReview.revision || oldReview.payer !== newReview.payer ||
|
|
86
|
+
oldQuote.chainId !== newQuote.chainId || oldQuote.account.toLowerCase() !== newQuote.account.toLowerCase() ||
|
|
87
|
+
oldQuote.entryPoint.toLowerCase() !== newQuote.entryPoint.toLowerCase() || oldQuote.callsCommitment !== newQuote.callsCommitment ||
|
|
88
|
+
oldQuote.nonce !== newQuote.nonce)
|
|
89
|
+
return true;
|
|
90
|
+
// Otto remains the payer while fresh sponsorship is eligible under its policy cap.
|
|
91
|
+
if (oldReview.payer === 'sponsor')
|
|
92
|
+
return newReview.sponsorStatus !== 'eligible';
|
|
93
|
+
if (BigInt(newQuote.gas.estimatedPrefundWei) > BigInt(oldQuote.gas.estimatedRequiredWei))
|
|
94
|
+
return true;
|
|
95
|
+
const oldBufferedUsd = oldQuote.estimatedGasCostUsdMicros, newPrice = newQuote.usdPrice;
|
|
96
|
+
// USD is secondary to the native estimate, so losing its price does not invalidate native consent.
|
|
97
|
+
if (oldBufferedUsd === undefined || !newPrice)
|
|
98
|
+
return false;
|
|
99
|
+
const numerator = BigInt(newQuote.gas.estimatedPrefundWei) * BigInt(newPrice.amountAtomic) * 1000000n;
|
|
100
|
+
const denominator = 10n ** BigInt(18 + newPrice.decimals);
|
|
101
|
+
const freshPrefundUsd = numerator / denominator + (numerator % denominator === 0n ? 0n : 1n);
|
|
102
|
+
return freshPrefundUsd > BigInt(oldBufferedUsd);
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=execution-account-gas-review.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type SponsoredGasPolicyProof } from './execution-sponsored-gas-policy.js';
|
|
2
|
+
/** Read-only fee planning for the existing CDP UserOperation transport. Estimates grant no signing authority. */
|
|
3
|
+
import { type PublicClient } from 'viem';
|
|
4
|
+
import { prepareAccountGasQuote, type AccountGasQuote } from './execution-account-gas-quote.js';
|
|
5
|
+
import { type AccountGasReview } from './execution-account-gas-review.js';
|
|
6
|
+
import { type SponsoredActivation } from './execution-sponsored-definition.js';
|
|
7
|
+
import type { createSponsoredCdpTransport, SponsoredCall, SponsoredChainId, SponsoredProviderConfig } from './execution-sponsored-transport.js';
|
|
8
|
+
export interface AccountGasOperation {
|
|
9
|
+
readonly gasReview?: AccountGasReview;
|
|
10
|
+
readonly context: {
|
|
11
|
+
readonly account: string;
|
|
12
|
+
readonly chainId: SponsoredChainId;
|
|
13
|
+
readonly activation: SponsoredActivation;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export declare class AccountGasReviewError extends Error {
|
|
17
|
+
readonly code: 'ACCOUNT_GAS_REVIEW_UNAVAILABLE' | 'ACCOUNT_GAS_REVIEW_REQUIRED' | 'ACCOUNT_GAS_REVIEW_CHANGED' | 'ACCOUNT_GAS_FUNDING_REQUIRED';
|
|
18
|
+
constructor(code: 'ACCOUNT_GAS_REVIEW_UNAVAILABLE' | 'ACCOUNT_GAS_REVIEW_REQUIRED' | 'ACCOUNT_GAS_REVIEW_CHANGED' | 'ACCOUNT_GAS_FUNDING_REQUIRED');
|
|
19
|
+
}
|
|
20
|
+
export declare class AccountGasPaymentRuntime {
|
|
21
|
+
private readonly clients;
|
|
22
|
+
private readonly providers;
|
|
23
|
+
private readonly transport;
|
|
24
|
+
private readonly now;
|
|
25
|
+
private readonly quote;
|
|
26
|
+
private readonly verifiedQuotes;
|
|
27
|
+
private readonly freshQuotes;
|
|
28
|
+
constructor(clients: Readonly<Partial<Record<SponsoredChainId, PublicClient>>>, providers: readonly SponsoredProviderConfig[], transport: ReturnType<typeof createSponsoredCdpTransport>, now?: () => number, quote?: typeof prepareAccountGasQuote);
|
|
29
|
+
review(operation: AccountGasOperation, calls: readonly SponsoredCall[], preference?: 'auto' | 'sponsor' | 'account', checkSponsor?: boolean): Promise<AccountGasReview>;
|
|
30
|
+
private assertPilotExposure;
|
|
31
|
+
revalidate(operation: AccountGasOperation, calls: readonly SponsoredCall[]): Promise<AccountGasQuote | undefined>;
|
|
32
|
+
assertFresh(operation: AccountGasOperation, calls: readonly SponsoredCall[], quote?: AccountGasQuote, gasPolicy?: SponsoredGasPolicyProof): void;
|
|
33
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { assertSponsoredGasPolicyCurrent } from './execution-sponsored-gas-policy.js';
|
|
2
|
+
/** Read-only fee planning for the existing CDP UserOperation transport. Estimates grant no signing authority. */
|
|
3
|
+
import { getAddress, parseAbi } from 'viem';
|
|
4
|
+
import { prepareAccountGasQuote, assertFreshAccountGasQuote } from './execution-account-gas-quote.js';
|
|
5
|
+
import { createAccountGasReview, accountGasReviewCanSubmit, accountGasReviewNeedsRenewal } from './execution-account-gas-review.js';
|
|
6
|
+
import { sponsoredChainTerms } from './execution-sponsored-definition.js';
|
|
7
|
+
export class AccountGasReviewError extends Error {
|
|
8
|
+
code;
|
|
9
|
+
constructor(code) {
|
|
10
|
+
super(code);
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.name = 'AccountGasReviewError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const FEED_ABI = parseAbi([
|
|
16
|
+
'function decimals() view returns (uint8)',
|
|
17
|
+
'function latestRoundData() view returns (uint80 roundId,int256 answer,uint256 startedAt,uint256 updatedAt,uint80 answeredInRound)',
|
|
18
|
+
]);
|
|
19
|
+
/** Source-pinned oracle data is only an advisory conversion. Pimlico independently enforces the subsidy limit. */
|
|
20
|
+
async function gasUsdPrice(client, activation, chainId, now) {
|
|
21
|
+
const feed = sponsoredChainTerms(activation, chainId).nativeGasUsdFeed;
|
|
22
|
+
if (!feed)
|
|
23
|
+
return undefined;
|
|
24
|
+
try {
|
|
25
|
+
const block = await client.getBlock({ blockTag: 'latest' });
|
|
26
|
+
if (block.number === null || !block.hash)
|
|
27
|
+
return undefined;
|
|
28
|
+
const [decimals, round] = await Promise.all([
|
|
29
|
+
client.readContract({ address: getAddress(feed.address), abi: FEED_ABI, functionName: 'decimals', blockNumber: block.number }),
|
|
30
|
+
client.readContract({ address: getAddress(feed.address), abi: FEED_ABI, functionName: 'latestRoundData', blockNumber: block.number }),
|
|
31
|
+
]);
|
|
32
|
+
const [roundId, answer, startedAt, updatedAt, answeredInRound] = round;
|
|
33
|
+
const observedAtMs = Number(updatedAt * 1000n), current = now();
|
|
34
|
+
if (decimals !== feed.decimals || answer <= 0n || roundId <= 0n || answeredInRound < roundId ||
|
|
35
|
+
startedAt <= 0n || startedAt > updatedAt || !Number.isSafeInteger(observedAtMs) || observedAtMs > current ||
|
|
36
|
+
current - observedAtMs >= feed.maxAgeSeconds * 1000 ||
|
|
37
|
+
await client.getChainId() !== chainId || (await client.getBlock({ blockNumber: block.number })).hash !== block.hash)
|
|
38
|
+
return undefined;
|
|
39
|
+
return { amountAtomic: answer.toString(), decimals, observedAtMs: current,
|
|
40
|
+
expiresAtMs: Math.min(observedAtMs + feed.maxAgeSeconds * 1000, current + 30_000) };
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export class AccountGasPaymentRuntime {
|
|
47
|
+
clients;
|
|
48
|
+
providers;
|
|
49
|
+
transport;
|
|
50
|
+
now;
|
|
51
|
+
quote;
|
|
52
|
+
verifiedQuotes = new WeakSet();
|
|
53
|
+
freshQuotes = new WeakMap();
|
|
54
|
+
constructor(clients, providers, transport, now = Date.now, quote = prepareAccountGasQuote) {
|
|
55
|
+
this.clients = clients;
|
|
56
|
+
this.providers = providers;
|
|
57
|
+
this.transport = transport;
|
|
58
|
+
this.now = now;
|
|
59
|
+
this.quote = quote;
|
|
60
|
+
}
|
|
61
|
+
async review(operation, calls, preference = 'auto', checkSponsor = true) {
|
|
62
|
+
const { context } = operation, { chainId, account, activation } = context;
|
|
63
|
+
const client = this.clients[chainId], providers = this.providers.filter(provider => provider.chainId === chainId);
|
|
64
|
+
if (!activation.gasPaymentReviewEnabled || !client || providers.length !== 1)
|
|
65
|
+
throw new AccountGasReviewError('ACCOUNT_GAS_REVIEW_UNAVAILABLE');
|
|
66
|
+
const terms = sponsoredChainTerms(activation, chainId);
|
|
67
|
+
const usdPrice = await gasUsdPrice(client, activation, chainId, this.now);
|
|
68
|
+
const quote = await this.quote({ account, chainId, entryPoint: terms.entryPoint, calls, client,
|
|
69
|
+
paymasterUrl: providers[0].paymasterUrl, sponsor: { paymaster: terms.paymaster, sponsorshipPolicyId: terms.sponsorshipPolicyId }, nowMs: this.now, ...(usdPrice ? { usdPrice } : {}) });
|
|
70
|
+
let sponsorPolicy;
|
|
71
|
+
try {
|
|
72
|
+
if (checkSponsor)
|
|
73
|
+
sponsorPolicy = await this.transport.checkGasPolicy(chainId);
|
|
74
|
+
}
|
|
75
|
+
catch { /* Self-pay remains explicit and independent. */ }
|
|
76
|
+
const review = createAccountGasReview({ quote, previousRevision: operation.gasReview?.revision ?? 0,
|
|
77
|
+
preference, ...(sponsorPolicy ? { sponsorPolicy } : {}), nowMs: this.now() });
|
|
78
|
+
if (review.payer === 'account')
|
|
79
|
+
this.assertPilotExposure(operation, quote);
|
|
80
|
+
this.freshQuotes.set(review, quote);
|
|
81
|
+
return review;
|
|
82
|
+
}
|
|
83
|
+
assertPilotExposure(operation, quote) {
|
|
84
|
+
const { account, chainId, activation } = operation.context;
|
|
85
|
+
const pins = activation.userPaidGasPilot?.filter(pin => pin.chainId === chainId && pin.account.toLowerCase() === account.toLowerCase()) ?? [];
|
|
86
|
+
// A moment-in-time designated-pilot admission check, not a request-bound fee maximum.
|
|
87
|
+
if (pins.length !== 1 || BigInt(quote.balance.nativeWei) + BigInt(quote.balance.entryPointDepositWei) > BigInt(pins[0].maximumObservedExposureWei))
|
|
88
|
+
throw new AccountGasReviewError('ACCOUNT_GAS_REVIEW_UNAVAILABLE');
|
|
89
|
+
}
|
|
90
|
+
async revalidate(operation, calls) {
|
|
91
|
+
if (!operation.context.activation.gasPaymentReviewEnabled) {
|
|
92
|
+
if (operation.gasReview)
|
|
93
|
+
throw new AccountGasReviewError('ACCOUNT_GAS_REVIEW_UNAVAILABLE');
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
if (!operation.gasReview)
|
|
97
|
+
throw new AccountGasReviewError('ACCOUNT_GAS_REVIEW_REQUIRED');
|
|
98
|
+
const current = await this.review(operation, calls, operation.gasReview.payer, operation.gasReview.payer === 'sponsor');
|
|
99
|
+
if (accountGasReviewNeedsRenewal(operation.gasReview, current))
|
|
100
|
+
throw new AccountGasReviewError('ACCOUNT_GAS_REVIEW_CHANGED');
|
|
101
|
+
if (!accountGasReviewCanSubmit(current, this.now()))
|
|
102
|
+
throw new AccountGasReviewError('ACCOUNT_GAS_FUNDING_REQUIRED');
|
|
103
|
+
const original = this.freshQuotes.get(current);
|
|
104
|
+
if (!original)
|
|
105
|
+
throw new AccountGasReviewError('ACCOUNT_GAS_REVIEW_UNAVAILABLE');
|
|
106
|
+
this.verifiedQuotes.add(original);
|
|
107
|
+
return original;
|
|
108
|
+
}
|
|
109
|
+
assertFresh(operation, calls, quote, gasPolicy) {
|
|
110
|
+
if (!operation.context.activation.gasPaymentReviewEnabled)
|
|
111
|
+
return;
|
|
112
|
+
if (!quote)
|
|
113
|
+
throw new AccountGasReviewError('ACCOUNT_GAS_REVIEW_REQUIRED');
|
|
114
|
+
if (!this.verifiedQuotes.has(quote))
|
|
115
|
+
throw new AccountGasReviewError('ACCOUNT_GAS_REVIEW_UNAVAILABLE');
|
|
116
|
+
if (operation.gasReview?.payer === 'account')
|
|
117
|
+
this.assertPilotExposure(operation, quote);
|
|
118
|
+
else {
|
|
119
|
+
const estimate = quote.sponsoredEstimate, terms = sponsoredChainTerms(operation.context.activation, operation.context.chainId);
|
|
120
|
+
if (!gasPolicy || !estimate || estimate.estimatedGasCostUsdMicros === undefined ||
|
|
121
|
+
gasPolicy.chainId !== quote.chainId || gasPolicy.sponsorshipPolicyId !== terms.sponsorshipPolicyId ||
|
|
122
|
+
estimate.sponsorshipPolicyId !== gasPolicy.sponsorshipPolicyId || estimate.paymaster !== terms.paymaster.toLowerCase() ||
|
|
123
|
+
BigInt(estimate.estimatedGasCostUsdMicros) > BigInt(gasPolicy.maximumGasCostUsdMicros))
|
|
124
|
+
throw new AccountGasReviewError('ACCOUNT_GAS_REVIEW_CHANGED');
|
|
125
|
+
assertSponsoredGasPolicyCurrent(gasPolicy, this.now());
|
|
126
|
+
}
|
|
127
|
+
assertFreshAccountGasQuote(quote, { account: operation.context.account, chainId: operation.context.chainId,
|
|
128
|
+
entryPoint: sponsoredChainTerms(operation.context.activation, operation.context.chainId).entryPoint, calls }, this.now());
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=execution-account-gas-runtime.js.map
|