otto-intel-mcp 0.1.2 → 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 +76 -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 +76 -9
- package/dist/adapter/cdp-signer.js +274 -33
- package/dist/adapter/evm-call-failure.d.ts +29 -0
- package/dist/adapter/evm-call-failure.js +109 -0
- package/dist/adapter/refusal.d.ts +1 -1
- package/dist/adapter/refusal.js +13 -0
- package/dist/adapter/route-simulator.d.ts +91 -0
- package/dist/adapter/route-simulator.js +143 -0
- package/dist/adapter-cdp-index.d.ts +1 -1
- package/dist/executable-equities.d.ts +55 -0
- package/dist/executable-equities.js +116 -0
- package/dist/executable-yield-markets.d.ts +261 -0
- package/dist/executable-yield-markets.js +154 -0
- 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 +7 -6
- package/dist/execution-delegated-definition.js +13 -2
- package/dist/execution-delegation-admin-definition.d.ts +127 -5
- package/dist/execution-delegation-admin-definition.js +155 -5
- package/dist/execution-delegation-admin.d.ts +48 -2
- package/dist/execution-delegation-admin.js +422 -12
- package/dist/execution-delegation-cap-store.d.ts +386 -0
- package/dist/execution-delegation-cap-store.js +1150 -0
- 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 +154 -8
- package/dist/execution-delegation-policy.js +273 -40
- package/dist/execution-delegation.d.ts +51 -0
- package/dist/execution-delegation.js +441 -31
- package/dist/execution-errors.d.ts +1 -1
- package/dist/execution-errors.js +122 -0
- package/dist/execution-index.d.ts +7 -2
- package/dist/execution-index.js +7 -2
- 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 +54 -2
- package/dist/execution-registration.js +151 -5
- 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 +53 -1
- package/dist/execution-tools.js +171 -13
- 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/lifi-execution-client.d.ts +6 -0
- package/dist/lifi-execution-client.js +3 -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 +338 -0
- package/dist/stock-buy-definition.js +127 -0
- package/dist/stock-buy-oracle.d.ts +8 -0
- package/dist/stock-buy-oracle.js +22 -0
- package/dist/stock-buy.d.ts +17 -0
- package/dist/stock-buy.js +164 -0
- package/dist/tool-definitions.d.ts +3 -1
- package/dist/tool-definitions.js +55 -2
- 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 +374 -0
- package/dist/yield-deposit-definition.js +123 -0
- package/dist/yield-deposit.d.ts +16 -0
- package/dist/yield-deposit.js +149 -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 +357 -0
- package/dist/yield-withdraw-definition.js +90 -0
- package/dist/yield-withdraw.d.ts +11 -0
- package/dist/yield-withdraw.js +122 -0
- package/package.json +239 -7
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { ACCOUNT_GAS_PUBLIC_SCHEMA, ACCOUNT_GAS_FAILURE_CODES, accountGasViewMatches } from './execution-account-gas-view.js';
|
|
2
|
+
/** Closed protected tool contract. Tokens stay in requests; raw provider responses never reach callers. */
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { DELEGATED_TOOL_TRANSPORT_SCHEMA } from './execution-delegated-definition.js';
|
|
5
|
+
import { SPONSORED_PREPARE_INPUT, SPONSORED_READ_INPUT, SPONSORED_SUBMIT_INPUT, SPONSORED_GAS_REVIEW_INPUT, SPONSORED_CHAIN_SCHEMA, SPONSORED_RECEIPT_SCHEMA, SPONSORED_SETTLEMENT_SCHEMA } from './execution-sponsored-definition.js';
|
|
6
|
+
const address = z.string().regex(/^0x[0-9a-fA-F]{40}$/), hash = z.string().regex(/^0x[0-9a-fA-F]{64}$/);
|
|
7
|
+
const atomic = z.string().regex(/^(0|[1-9][0-9]*)$/).refine(v => /^(0|[1-9][0-9]*)$/.test(v) && BigInt(v) < 2n ** 256n);
|
|
8
|
+
const positive = atomic.refine(v => /^(0|[1-9][0-9]*)$/.test(v) && BigInt(v) > 0n);
|
|
9
|
+
const operationId = z.string().regex(/^sp_[a-f0-9-]{36}$/);
|
|
10
|
+
const digest = z.string().regex(/^[0-9a-f]{64}$/);
|
|
11
|
+
export const SPONSORED_TOOL_NAME = 'otto_sponsored_account';
|
|
12
|
+
export const SPONSORED_ACTION_INPUT = z.discriminatedUnion('action', [
|
|
13
|
+
z.object({ action: z.literal('availability') }).strict(),
|
|
14
|
+
SPONSORED_GAS_REVIEW_INPUT.extend({ action: z.literal('reviewGas') }).strict(),
|
|
15
|
+
SPONSORED_PREPARE_INPUT.extend({ action: z.literal('prepare') }).strict(),
|
|
16
|
+
SPONSORED_SUBMIT_INPUT.extend({ action: z.literal('submit') }).strict(),
|
|
17
|
+
SPONSORED_READ_INPUT.extend({ action: z.literal('read') }).strict(),
|
|
18
|
+
SPONSORED_READ_INPUT.extend({ action: z.literal('reconcile') }).strict(),
|
|
19
|
+
]);
|
|
20
|
+
export const SPONSORED_REFUSAL_CODES = [
|
|
21
|
+
'SPONSOR_ACTIVATION_UNCONFIGURED', 'SPONSOR_ACTIVATION_UNAVAILABLE', 'SPONSOR_RECOVERY_ONLY', 'SPONSOR_CAPABILITY_UNAVAILABLE',
|
|
22
|
+
'SPONSOR_RUNTIME_UNAVAILABLE', 'SPONSOR_JOURNAL_UNAVAILABLE', 'SPONSOR_REQUEST_INVALID',
|
|
23
|
+
'SPONSOR_REQUEST_REFUSED', 'SPONSOR_SESSION_REQUIRED', 'SPONSOR_SESSION_INVALID',
|
|
24
|
+
'SPONSOR_OWNER_MISMATCH', 'SPONSOR_EXPLICIT_WALLET_UPGRADE_REQUIRED', 'SPONSOR_CURRENT_GRANT_REQUIRED',
|
|
25
|
+
'SPONSOR_CAP_UNAVAILABLE', 'SPONSOR_POLICY_CHANGED', 'SPONSOR_CHAIN_UNAVAILABLE',
|
|
26
|
+
'SPONSOR_ACCOUNT_PROOF_UNAVAILABLE', 'SPONSOR_ACCOUNT_PROOF_MISMATCH',
|
|
27
|
+
'SPONSOR_INPUT_OUTSIDE_REVIEWED_CAP', 'SPONSOR_REVIEW_AUTHORITY_CHANGED', 'SPONSOR_REVIEW_EXPIRED',
|
|
28
|
+
'SPONSOR_STOP_OR_CAP_CHANGED', 'SPONSOR_BALANCE_INSUFFICIENT', 'SPONSOR_OUTPUT_TOKEN_UNREVIEWED',
|
|
29
|
+
'SPONSOR_BUDGET_HALTED', 'SPONSOR_NOT_SUBMITTED', 'SPONSOR_USER_OPERATION_REVERTED',
|
|
30
|
+
'SPONSOR_GAS_CAP_EXCEEDED', ...ACCOUNT_GAS_FAILURE_CODES,
|
|
31
|
+
];
|
|
32
|
+
/** A named enum keeps generated public declarations compact without broadening accepted codes. */
|
|
33
|
+
export const SPONSORED_REFUSAL_SCHEMA = z.enum(SPONSORED_REFUSAL_CODES);
|
|
34
|
+
export const SPONSORED_AVAILABILITY_RESULT = z.object({
|
|
35
|
+
schemaVersion: z.literal('1'), configured: z.boolean(), executionEnabled: z.boolean(),
|
|
36
|
+
recoveryAvailable: z.boolean(),
|
|
37
|
+
reason: SPONSORED_REFUSAL_SCHEMA.optional(),
|
|
38
|
+
requiresSeparateWalletUpgrade: z.literal(true), requiresOperationReview: z.literal(true),
|
|
39
|
+
automaticExecutionEnabled: z.literal(false),
|
|
40
|
+
supportedSameAddressChains: z.array(SPONSORED_CHAIN_SCHEMA).max(5),
|
|
41
|
+
}).strict().refine(value => !value.executionEnabled || (value.configured && value.recoveryAvailable && value.reason === undefined));
|
|
42
|
+
export const SPONSORED_OPERATION_RESULT = z.object({
|
|
43
|
+
schemaVersion: z.literal('1'), operationId, account: address, chainId: SPONSORED_CHAIN_SCHEMA,
|
|
44
|
+
state: z.enum(['review', 'active', 'unknown', 'submitted', 'completed', 'failed']), reviewConsumed: z.boolean(),
|
|
45
|
+
reviewCommitment: digest, validUntilMs: z.number().int().positive().safe(),
|
|
46
|
+
input: z.object({ token: address, amount: positive }).strict(),
|
|
47
|
+
output: z.object({ token: address, minimum: positive }).strict(), ottoFee: atomic,
|
|
48
|
+
gas: ACCOUNT_GAS_PUBLIC_SCHEMA,
|
|
49
|
+
walletAuthorityChangeIncluded: z.literal(false), automaticExecutionEnabled: z.literal(false),
|
|
50
|
+
userOpHash: hash.optional(), transactionHash: hash.optional(),
|
|
51
|
+
receipt: SPONSORED_RECEIPT_SCHEMA.optional(), settlement: SPONSORED_SETTLEMENT_SCHEMA.optional(),
|
|
52
|
+
failureCode: SPONSORED_REFUSAL_SCHEMA.optional(), attention: z.literal('The original provider request is unresolved. No replacement is permitted.').optional(),
|
|
53
|
+
requiresOperationReview: z.literal(true).optional(),
|
|
54
|
+
terms: z.object({ activationId: z.string().regex(/^[a-zA-Z0-9_-]{8,100}$/),
|
|
55
|
+
perSwapCapUsdc: z.number().int().min(1).max(5000), grantExpiresAt: z.string().datetime(),
|
|
56
|
+
scope: z.literal('one reviewed same-chain USDC swap into an explicitly reviewed ERC20, with allowance cleared in the same batch; native output is unsupported'),
|
|
57
|
+
walletAuthorityChangeIncluded: z.literal(false), providerPolicyId: z.string().regex(/^[a-zA-Z0-9_-]{1,128}$/),
|
|
58
|
+
}).strict().optional(),
|
|
59
|
+
}).strict().refine(value => accountGasViewMatches(value) &&
|
|
60
|
+
(value.state === 'review') === !value.reviewConsumed &&
|
|
61
|
+
(value.state !== 'review' || (value.requiresOperationReview === true && !!value.terms)) &&
|
|
62
|
+
(value.state !== 'completed' || (!!value.receipt && value.receipt.status === 'success' && !!value.settlement)) &&
|
|
63
|
+
(!value.transactionHash || !!value.userOpHash) &&
|
|
64
|
+
(value.gas.payer !== 'sponsor' || !value.gas.activationChainHalted || (value.failureCode === 'SPONSOR_GAS_CAP_EXCEEDED' && value.state === 'submitted')), 'Sponsored operation state must agree with its finality and review evidence');
|
|
65
|
+
export const SPONSORED_UNCERTAIN_RESULT = z.object({
|
|
66
|
+
schemaVersion: z.literal('1'), status: z.literal('outcome-unknown'), operationId,
|
|
67
|
+
requiresReconciliation: z.literal(true), replacementPermitted: z.literal(false),
|
|
68
|
+
attention: z.literal('The outcome of the original submission is unknown. Read or reconcile this operation; do not submit a replacement.'),
|
|
69
|
+
}).strict();
|
|
70
|
+
export const SPONSORED_TOOL_RESULT = z.union([
|
|
71
|
+
SPONSORED_AVAILABILITY_RESULT, SPONSORED_OPERATION_RESULT, SPONSORED_UNCERTAIN_RESULT,
|
|
72
|
+
]);
|
|
73
|
+
/** The pinned MCP SDK requires an object at the top level; strict union validation remains mandatory. */
|
|
74
|
+
export const SPONSORED_TRANSPORT_RESULT = z.object({
|
|
75
|
+
...SPONSORED_AVAILABILITY_RESULT.shape, ...SPONSORED_OPERATION_RESULT.shape, ...SPONSORED_UNCERTAIN_RESULT.shape,
|
|
76
|
+
// Public descriptor schemas contain no checksum transforms. The handler has already normalized
|
|
77
|
+
// and validated these values; the SDK must be able to emit ordinary JSON Schema for tools/list.
|
|
78
|
+
receipt: z.object({ ...SPONSORED_RECEIPT_SCHEMA.shape, account: address, paymaster: address }).strict().optional(),
|
|
79
|
+
settlement: z.object({ ...SPONSORED_SETTLEMENT_SCHEMA.shape, inputToken: address, outputToken: address }).strict().optional(),
|
|
80
|
+
attention: z.union([SPONSORED_OPERATION_RESULT.shape.attention.unwrap(), SPONSORED_UNCERTAIN_RESULT.shape.attention]).optional(),
|
|
81
|
+
}).partial().extend({ schemaVersion: z.literal('1') }).strict().superRefine((value, context) => {
|
|
82
|
+
if (!SPONSORED_TOOL_RESULT.safeParse(value).success)
|
|
83
|
+
context.addIssue({
|
|
84
|
+
code: 'custom', message: 'The sponsored account result does not match a supported public outcome.',
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
export const SPONSORED_TOOL_DEFINITION = Object.freeze({
|
|
88
|
+
name: SPONSORED_TOOL_NAME, title: 'Review or recover an account transaction',
|
|
89
|
+
description: 'Protected account action: availability, prepare, reviewGas for current gas payer and estimate, explicit submit, owned read or reconcile. Gas refresh is read-only planning and requires new confirmation before any send. Wallet upgrade is separate. Sponsorship requires a reviewed source activation; current availability is authoritative. A missing submission response is unknown and must never cause a replacement submission.',
|
|
90
|
+
inputSchema: DELEGATED_TOOL_TRANSPORT_SCHEMA,
|
|
91
|
+
outputSchema: SPONSORED_TRANSPORT_RESULT,
|
|
92
|
+
annotations: Object.freeze({ readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true }),
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=execution-sponsored-mcp-definition.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** A bundler transaction can succeed while an individual UserOperation reverts. */
|
|
2
|
+
import { type Address, type Hex, type TransactionReceipt } from 'viem';
|
|
3
|
+
import type { SponsoredChainId } from './execution-sponsored-transport.js';
|
|
4
|
+
export interface SponsoredReceiptBinding {
|
|
5
|
+
readonly payer?: 'sponsor' | 'account';
|
|
6
|
+
readonly chainId: SponsoredChainId;
|
|
7
|
+
readonly account: Address;
|
|
8
|
+
readonly userOpHash: Hex;
|
|
9
|
+
readonly transactionHash: Hex;
|
|
10
|
+
readonly entryPoint: Address;
|
|
11
|
+
readonly paymaster: Address;
|
|
12
|
+
/** Operator-approved per-operation cap in the chain's native atomic units. No default. */
|
|
13
|
+
readonly maxGasCostWei: bigint;
|
|
14
|
+
}
|
|
15
|
+
export interface SponsoredReceiptClient {
|
|
16
|
+
getChainId(): Promise<number>;
|
|
17
|
+
getTransactionReceipt(args: {
|
|
18
|
+
hash: Hex;
|
|
19
|
+
}): Promise<TransactionReceipt>;
|
|
20
|
+
getBlock(args: {
|
|
21
|
+
blockNumber: bigint;
|
|
22
|
+
} | {
|
|
23
|
+
blockTag: 'finalized';
|
|
24
|
+
}): Promise<{
|
|
25
|
+
number: bigint | null;
|
|
26
|
+
hash: Hex | null;
|
|
27
|
+
}>;
|
|
28
|
+
}
|
|
29
|
+
export interface ConfirmedSponsoredReceipt {
|
|
30
|
+
readonly chainId: SponsoredChainId;
|
|
31
|
+
readonly account: Address;
|
|
32
|
+
readonly userOpHash: Hex;
|
|
33
|
+
readonly transactionHash: Hex;
|
|
34
|
+
readonly blockHash: Hex;
|
|
35
|
+
readonly blockNumber: string;
|
|
36
|
+
readonly nonce: string;
|
|
37
|
+
readonly paymaster: Address;
|
|
38
|
+
readonly actualGasCostWei: string;
|
|
39
|
+
readonly actualGasUsed: string;
|
|
40
|
+
readonly status: 'success' | 'reverted';
|
|
41
|
+
}
|
|
42
|
+
export declare class SponsoredReceiptUnconfirmedError extends Error {
|
|
43
|
+
readonly code: 'SPONSOR_RECEIPT_UNCONFIRMED' | 'SPONSOR_GAS_CAP_EXCEEDED';
|
|
44
|
+
readonly breachedReceipt?: ConfirmedSponsoredReceipt | undefined;
|
|
45
|
+
constructor(code?: 'SPONSOR_RECEIPT_UNCONFIRMED' | 'SPONSOR_GAS_CAP_EXCEEDED', breachedReceipt?: ConfirmedSponsoredReceipt | undefined);
|
|
46
|
+
}
|
|
47
|
+
export declare function readConfirmedSponsoredReceipt(binding: SponsoredReceiptBinding, client: SponsoredReceiptClient): Promise<ConfirmedSponsoredReceipt>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** A bundler transaction can succeed while an individual UserOperation reverts. */
|
|
2
|
+
import { decodeEventLog, parseAbiItem } from 'viem';
|
|
3
|
+
const USER_OPERATION_EVENT = parseAbiItem('event UserOperationEvent(bytes32 indexed userOpHash, address indexed sender, address indexed paymaster, uint256 nonce, bool success, uint256 actualGasCost, uint256 actualGasUsed)');
|
|
4
|
+
export class SponsoredReceiptUnconfirmedError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
breachedReceipt;
|
|
7
|
+
constructor(code = 'SPONSOR_RECEIPT_UNCONFIRMED', breachedReceipt) {
|
|
8
|
+
super(code === 'SPONSOR_GAS_CAP_EXCEEDED'
|
|
9
|
+
? 'The sponsored receipt exceeded the approved gas cap; keep the operation locked for review.'
|
|
10
|
+
: 'The exact sponsored operation has no matching canonical finalized receipt yet.');
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.breachedReceipt = breachedReceipt;
|
|
13
|
+
this.name = 'SponsoredReceiptUnconfirmedError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export async function readConfirmedSponsoredReceipt(binding, client) {
|
|
17
|
+
try {
|
|
18
|
+
const isAddress = (value) => /^0x[0-9a-fA-F]{40}$/.test(value);
|
|
19
|
+
const isHash = (value) => /^0x[0-9a-fA-F]{64}$/.test(value);
|
|
20
|
+
if (![binding.account, binding.entryPoint, binding.paymaster].every(isAddress) ||
|
|
21
|
+
![binding.userOpHash, binding.transactionHash].every(isHash) ||
|
|
22
|
+
(binding.payer !== undefined && !['sponsor', 'account'].includes(binding.payer)) ||
|
|
23
|
+
(binding.payer === 'account' ? !/^0x0{40}$/i.test(binding.paymaster) : /^0x0{40}$/i.test(binding.paymaster)) ||
|
|
24
|
+
binding.maxGasCostWei <= 0n || await client.getChainId() !== binding.chainId)
|
|
25
|
+
throw new Error();
|
|
26
|
+
// Establish finality before reading the receipt and its canonical block; a reorg during a
|
|
27
|
+
// later finalized-head read must never promote stale receipt evidence to settlement.
|
|
28
|
+
const finalized = await client.getBlock({ blockTag: 'finalized' });
|
|
29
|
+
const receipt = await client.getTransactionReceipt({ hash: binding.transactionHash });
|
|
30
|
+
if (receipt.transactionHash.toLowerCase() !== binding.transactionHash.toLowerCase() || receipt.status !== 'success' ||
|
|
31
|
+
receipt.to?.toLowerCase() !== binding.entryPoint.toLowerCase())
|
|
32
|
+
throw new Error();
|
|
33
|
+
const block = await client.getBlock({ blockNumber: receipt.blockNumber });
|
|
34
|
+
if (block.hash !== receipt.blockHash || block.number !== receipt.blockNumber ||
|
|
35
|
+
finalized.number === null || finalized.number < receipt.blockNumber)
|
|
36
|
+
throw new Error();
|
|
37
|
+
const matching = receipt.logs.flatMap(log => {
|
|
38
|
+
if (log.address.toLowerCase() !== binding.entryPoint.toLowerCase())
|
|
39
|
+
return [];
|
|
40
|
+
try {
|
|
41
|
+
const decoded = decodeEventLog({ abi: [USER_OPERATION_EVENT], data: log.data, topics: log.topics, strict: true });
|
|
42
|
+
if (decoded.args.userOpHash.toLowerCase() !== binding.userOpHash.toLowerCase())
|
|
43
|
+
return [];
|
|
44
|
+
if (log.removed || log.transactionHash !== receipt.transactionHash || log.blockHash !== receipt.blockHash || log.blockNumber !== receipt.blockNumber)
|
|
45
|
+
throw new SponsoredReceiptUnconfirmedError();
|
|
46
|
+
return [decoded.args];
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (error instanceof SponsoredReceiptUnconfirmedError)
|
|
50
|
+
throw error;
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
if (matching.length !== 1)
|
|
55
|
+
throw new Error();
|
|
56
|
+
const event = matching[0];
|
|
57
|
+
if (event.sender.toLowerCase() !== binding.account.toLowerCase() || event.paymaster.toLowerCase() !== binding.paymaster.toLowerCase() ||
|
|
58
|
+
event.actualGasCost <= 0n || event.actualGasUsed <= 0n)
|
|
59
|
+
throw new Error();
|
|
60
|
+
const confirmed = Object.freeze({ chainId: binding.chainId, account: binding.account, userOpHash: binding.userOpHash,
|
|
61
|
+
transactionHash: binding.transactionHash, blockHash: receipt.blockHash, blockNumber: receipt.blockNumber.toString(),
|
|
62
|
+
nonce: event.nonce.toString(), paymaster: event.paymaster, actualGasCostWei: event.actualGasCost.toString(),
|
|
63
|
+
actualGasUsed: event.actualGasUsed.toString(), status: event.success ? 'success' : 'reverted' });
|
|
64
|
+
if (binding.payer !== 'account' && event.actualGasCost > binding.maxGasCostWei)
|
|
65
|
+
throw new SponsoredReceiptUnconfirmedError('SPONSOR_GAS_CAP_EXCEEDED', confirmed);
|
|
66
|
+
return confirmed;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (error instanceof SponsoredReceiptUnconfirmedError)
|
|
70
|
+
throw error;
|
|
71
|
+
throw new SponsoredReceiptUnconfirmedError();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=execution-sponsored-receipt.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Authenticate before parsing, availability or provider/journal work on every protected action. */
|
|
2
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { type SponsoredAvailabilityResult } from './execution-sponsored-mcp-definition.js';
|
|
4
|
+
import type { ExecutionToolRuntime } from './execution-tools.js';
|
|
5
|
+
export interface SponsoredAccountBinding {
|
|
6
|
+
availability(): Promise<SponsoredAvailabilityResult>;
|
|
7
|
+
reviewGas(input: unknown): Promise<unknown>;
|
|
8
|
+
prepare(input: unknown): Promise<unknown>;
|
|
9
|
+
submit(input: unknown): Promise<unknown>;
|
|
10
|
+
read(input: unknown): Promise<unknown>;
|
|
11
|
+
reconcile(input: unknown): Promise<unknown>;
|
|
12
|
+
}
|
|
13
|
+
export declare function unavailableSponsoredBinding(reason?: NonNullable<SponsoredAvailabilityResult['reason']>): SponsoredAccountBinding;
|
|
14
|
+
export declare function callSponsoredAccount(runtime: ExecutionToolRuntime, raw: unknown, headers: Readonly<Record<string, string | string[] | undefined>> | undefined): Promise<CallToolResult>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { accountGasFailure } from './execution-account-gas-view.js';
|
|
2
|
+
import { ZodError } from 'zod';
|
|
3
|
+
import { assertDelegationCaller, callerFromHeaders } from './execution-delegation.js';
|
|
4
|
+
import { ExecutionRefusal, isExecutionRefusal } from './execution-errors.js';
|
|
5
|
+
import { SponsoredAccountRefusal } from './execution-sponsored-runtime.js';
|
|
6
|
+
import { sponsoredAccountAvailability } from './execution-sponsored-index.js';
|
|
7
|
+
import { SPONSORED_ACTION_INPUT, SPONSORED_REFUSAL_CODES, SPONSORED_TOOL_RESULT, SPONSORED_AVAILABILITY_RESULT } from './execution-sponsored-mcp-definition.js';
|
|
8
|
+
export function unavailableSponsoredBinding(reason = 'SPONSOR_ACTIVATION_UNCONFIGURED') {
|
|
9
|
+
const refuse = async () => { throw new SponsoredAccountRefusal(reason); };
|
|
10
|
+
return Object.freeze({
|
|
11
|
+
availability: async () => SPONSORED_AVAILABILITY_RESULT.parse({ ...sponsoredAccountAvailability(), executionEnabled: false, recoveryAvailable: false, reason }),
|
|
12
|
+
reviewGas: refuse, prepare: refuse, submit: refuse, read: refuse, reconcile: refuse,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function success(value) {
|
|
16
|
+
const output = SPONSORED_TOOL_RESULT.parse(value);
|
|
17
|
+
return { content: [{ type: 'text', text: JSON.stringify(output) }], structuredContent: output };
|
|
18
|
+
}
|
|
19
|
+
function unknownSubmission(operationId) {
|
|
20
|
+
return success({ schemaVersion: '1', status: 'outcome-unknown', operationId,
|
|
21
|
+
requiresReconciliation: true, replacementPermitted: false,
|
|
22
|
+
attention: 'The outcome of the original submission is unknown. Read or reconcile this operation; do not submit a replacement.' });
|
|
23
|
+
}
|
|
24
|
+
// These service refusals are proved before any operation claim/handoff. Everything else after invoking
|
|
25
|
+
// submit is conservatively unknown, including a malformed output or journal failure after a POST.
|
|
26
|
+
const BEFORE_HANDOFF_REFUSALS = new Set([
|
|
27
|
+
'SPONSOR_ACTIVATION_UNCONFIGURED', 'SPONSOR_ACTIVATION_UNAVAILABLE', 'SPONSOR_RECOVERY_ONLY', 'SPONSOR_CAPABILITY_UNAVAILABLE',
|
|
28
|
+
'SPONSOR_RUNTIME_UNAVAILABLE', 'SPONSOR_JOURNAL_UNAVAILABLE', 'SPONSOR_SESSION_REQUIRED', 'SPONSOR_SESSION_INVALID',
|
|
29
|
+
'SPONSOR_OWNER_MISMATCH', 'SPONSOR_EXPLICIT_WALLET_UPGRADE_REQUIRED', 'SPONSOR_CURRENT_GRANT_REQUIRED',
|
|
30
|
+
'SPONSOR_CAP_UNAVAILABLE', 'SPONSOR_POLICY_CHANGED', 'SPONSOR_CHAIN_UNAVAILABLE',
|
|
31
|
+
]);
|
|
32
|
+
export async function callSponsoredAccount(runtime, raw, headers) {
|
|
33
|
+
let submitId, invoked = false;
|
|
34
|
+
try {
|
|
35
|
+
const delegation = runtime.delegation;
|
|
36
|
+
if (!delegation)
|
|
37
|
+
throw new ExecutionRefusal('DELEGATION_UNAUTHORIZED', 'protected account caller is not authorized');
|
|
38
|
+
assertDelegationCaller(delegation, callerFromHeaders(headers));
|
|
39
|
+
const input = SPONSORED_ACTION_INPUT.parse(raw);
|
|
40
|
+
const binding = runtime.sponsoredAccount ?? unavailableSponsoredBinding();
|
|
41
|
+
if (input.action === 'availability')
|
|
42
|
+
return success(SPONSORED_AVAILABILITY_RESULT.parse(await binding.availability()));
|
|
43
|
+
const { action, ...body } = input;
|
|
44
|
+
if (action === 'submit')
|
|
45
|
+
submitId = input.operationId;
|
|
46
|
+
invoked = true;
|
|
47
|
+
const result = SPONSORED_TOOL_RESULT.parse(await binding[action](body));
|
|
48
|
+
if (!('operationId' in result) || !('state' in result))
|
|
49
|
+
throw new Error('unexpected action result');
|
|
50
|
+
if (action === 'prepare') {
|
|
51
|
+
if (result.state !== 'review' || result.account.toLowerCase() !== input.account.toLowerCase() ||
|
|
52
|
+
result.chainId !== input.chainId)
|
|
53
|
+
throw new Error('mismatched preparation result');
|
|
54
|
+
}
|
|
55
|
+
else if (result.operationId !== input.operationId)
|
|
56
|
+
throw new Error('mismatched operation result');
|
|
57
|
+
if (input.action === 'reviewGas' && (result.state !== 'review' || result.reviewConsumed || result.gas.reviewRequired !== true || !result.gas.paymentReview ||
|
|
58
|
+
result.reviewCommitment === input.reviewCommitment || (input.preference !== 'auto' && result.gas.payer !== input.preference)))
|
|
59
|
+
throw new Error('mismatched gas review');
|
|
60
|
+
if (input.action === 'submit' && (!result.reviewConsumed || result.reviewCommitment !== input.reviewCommitment))
|
|
61
|
+
throw new Error('mismatched consumed review');
|
|
62
|
+
return success(result);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
const code = accountGasFailure(error) ?? (error instanceof SponsoredAccountRefusal && SPONSORED_REFUSAL_CODES.includes(error.code)
|
|
66
|
+
? error.code : error instanceof ZodError && !invoked ? 'SPONSOR_REQUEST_INVALID' : 'SPONSOR_REQUEST_REFUSED');
|
|
67
|
+
if (submitId && invoked && !BEFORE_HANDOFF_REFUSALS.has(code))
|
|
68
|
+
return unknownSubmission(submitId);
|
|
69
|
+
const refusal = isExecutionRefusal(error) && error.code === 'DELEGATION_UNAUTHORIZED' && !invoked
|
|
70
|
+
? { code: 'DELEGATION_UNAUTHORIZED', message: 'The protected account caller is not authorized.' }
|
|
71
|
+
: { code, message: code === 'SPONSOR_REQUEST_INVALID' ? 'The sponsored account request is invalid.'
|
|
72
|
+
: code === 'SPONSOR_EXPLICIT_WALLET_UPGRADE_REQUIRED' ? 'This account requires a separately approved wallet upgrade.'
|
|
73
|
+
: 'The sponsored account action is unavailable or refused. Read current availability and the original operation before continuing.' };
|
|
74
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: 'refused', ...refusal }) }] };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=execution-sponsored-registration.js.map
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { type Address, type Hex, type PublicClient } from 'viem';
|
|
2
|
+
import type { DelegationCapStore } from './execution-delegation-cap-store.js';
|
|
3
|
+
import { type SponsoredCapability, type SponsoredActivation, type SponsoredAuthority, type SponsoredOperation } from './execution-sponsored-definition.js';
|
|
4
|
+
import { type SponsoredChainId, type SponsoredCall, type SponsoredAcknowledgement } from './execution-sponsored-transport.js';
|
|
5
|
+
interface EndUserIdentity {
|
|
6
|
+
userId: string;
|
|
7
|
+
evmAccountObjects?: readonly {
|
|
8
|
+
address: string;
|
|
9
|
+
}[];
|
|
10
|
+
evmSmartAccountObjects?: readonly {
|
|
11
|
+
address: string;
|
|
12
|
+
ownerAddresses: readonly string[];
|
|
13
|
+
}[];
|
|
14
|
+
}
|
|
15
|
+
export interface SponsoredAccountCdp {
|
|
16
|
+
endUser: {
|
|
17
|
+
validateAccessToken(input: {
|
|
18
|
+
accessToken: string;
|
|
19
|
+
}): Promise<EndUserIdentity>;
|
|
20
|
+
getEndUser(input: {
|
|
21
|
+
userId: string;
|
|
22
|
+
}): Promise<EndUserIdentity>;
|
|
23
|
+
getDelegationForEndUserAccount(input: {
|
|
24
|
+
userId: string;
|
|
25
|
+
address: string;
|
|
26
|
+
}): Promise<{
|
|
27
|
+
expiresAt: string;
|
|
28
|
+
}>;
|
|
29
|
+
};
|
|
30
|
+
policies: {
|
|
31
|
+
listPolicies(input: {
|
|
32
|
+
scope: 'project';
|
|
33
|
+
}): Promise<{
|
|
34
|
+
policies?: readonly {
|
|
35
|
+
id: string;
|
|
36
|
+
scope: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
rules: unknown;
|
|
39
|
+
}[];
|
|
40
|
+
}>;
|
|
41
|
+
};
|
|
42
|
+
evm: {
|
|
43
|
+
getUserOperation(input: {
|
|
44
|
+
smartAccount: Address;
|
|
45
|
+
userOpHash: Hex;
|
|
46
|
+
}): Promise<{
|
|
47
|
+
network: string;
|
|
48
|
+
userOpHash: string;
|
|
49
|
+
transactionHash?: string;
|
|
50
|
+
status: string;
|
|
51
|
+
calls: readonly {
|
|
52
|
+
to: string;
|
|
53
|
+
data: string;
|
|
54
|
+
value: string | bigint;
|
|
55
|
+
}[];
|
|
56
|
+
}>;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export declare class SponsoredAccountRefusal extends Error {
|
|
60
|
+
readonly code: string;
|
|
61
|
+
constructor(code: string);
|
|
62
|
+
}
|
|
63
|
+
export declare class SponsoredAccountRuntime {
|
|
64
|
+
readonly cdp: SponsoredAccountCdp;
|
|
65
|
+
private readonly caps;
|
|
66
|
+
readonly clients: Readonly<Partial<Record<SponsoredChainId, PublicClient>>>;
|
|
67
|
+
readonly projectId: string;
|
|
68
|
+
readonly now: () => number;
|
|
69
|
+
constructor(cdp: SponsoredAccountCdp, caps: DelegationCapStore, clients: Readonly<Partial<Record<SponsoredChainId, PublicClient>>>, projectId: string, now?: () => number);
|
|
70
|
+
client(chainId: SponsoredChainId): PublicClient;
|
|
71
|
+
identity(accessToken: string, account: Address): Promise<{
|
|
72
|
+
userId: string;
|
|
73
|
+
current: EndUserIdentity;
|
|
74
|
+
}>;
|
|
75
|
+
authority(accessToken: string, account: Address, chainId: SponsoredChainId, rawActivation: SponsoredActivation, outputToken: Address, capability?: SponsoredCapability): Promise<SponsoredAuthority>;
|
|
76
|
+
/** Called synchronously under the operation handoff lock. Stop and request start are ordered by caps.db. */
|
|
77
|
+
withCurrentCap<T>(authority: SponsoredAuthority, start: () => T): T;
|
|
78
|
+
assertCurrentCap(authority: SponsoredAuthority): Promise<void>;
|
|
79
|
+
preflight(operation: SponsoredOperation): Promise<void>;
|
|
80
|
+
readAcknowledgement(operation: Pick<SponsoredOperation, 'userOpHash'> & {
|
|
81
|
+
context: Pick<SponsoredOperation['context'], 'account' | 'chainId'>;
|
|
82
|
+
}, expectedCalls: readonly SponsoredCall[]): Promise<SponsoredAcknowledgement>;
|
|
83
|
+
}
|
|
84
|
+
export {};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { getAddress, keccak256, parseAbi } from 'viem';
|
|
2
|
+
import { MODEL_B_CAP_RULESET_VERSION } from './execution-delegation-cap-store.js';
|
|
3
|
+
import { policyRulesDigest } from './execution-policy-compatibility.js';
|
|
4
|
+
import { SPONSORED_AUTHORITY_SCHEMA, SPONSORED_ACTIVATION_SCHEMA, sponsoredDigest, sponsoredChainTerms, sponsoredOutputToken, sponsoredActivationSupports, SPONSORED_USDC } from './execution-sponsored-definition.js';
|
|
5
|
+
import { SPONSORED_CDP_NETWORKS } from './execution-sponsored-transport.js';
|
|
6
|
+
export class SponsoredAccountRefusal extends Error {
|
|
7
|
+
code;
|
|
8
|
+
constructor(code) {
|
|
9
|
+
super(code);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.name = 'SponsoredAccountRefusal';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function refuse(code) { throw new SponsoredAccountRefusal(code); }
|
|
15
|
+
function owns(user, account) {
|
|
16
|
+
return (user.evmAccountObjects ?? []).some(a => getAddress(a.address) === account);
|
|
17
|
+
}
|
|
18
|
+
function sameAddressSmartAccount(user, account) {
|
|
19
|
+
const matches = (user.evmSmartAccountObjects ?? []).filter(a => getAddress(a.address) === account);
|
|
20
|
+
return matches.length === 1 && matches[0].ownerAddresses.length === 1 && getAddress(matches[0].ownerAddresses[0]) === account;
|
|
21
|
+
}
|
|
22
|
+
export class SponsoredAccountRuntime {
|
|
23
|
+
cdp;
|
|
24
|
+
caps;
|
|
25
|
+
clients;
|
|
26
|
+
projectId;
|
|
27
|
+
now;
|
|
28
|
+
constructor(cdp, caps, clients, projectId, now = Date.now) {
|
|
29
|
+
this.cdp = cdp;
|
|
30
|
+
this.caps = caps;
|
|
31
|
+
this.clients = clients;
|
|
32
|
+
this.projectId = projectId;
|
|
33
|
+
this.now = now;
|
|
34
|
+
}
|
|
35
|
+
client(chainId) {
|
|
36
|
+
return this.clients[chainId] ?? refuse('SPONSOR_CHAIN_UNAVAILABLE');
|
|
37
|
+
}
|
|
38
|
+
async identity(accessToken, account) {
|
|
39
|
+
if (!accessToken || accessToken.length > 16384)
|
|
40
|
+
return refuse('SPONSOR_SESSION_REQUIRED');
|
|
41
|
+
try {
|
|
42
|
+
const token = await this.cdp.endUser.validateAccessToken({ accessToken });
|
|
43
|
+
if (!/^[a-zA-Z0-9-]{1,100}$/.test(token.userId))
|
|
44
|
+
return refuse('SPONSOR_SESSION_INVALID');
|
|
45
|
+
const current = await this.cdp.endUser.getEndUser({ userId: token.userId });
|
|
46
|
+
if (current.userId !== token.userId || !owns(token, account) || !owns(current, account))
|
|
47
|
+
return refuse('SPONSOR_OWNER_MISMATCH');
|
|
48
|
+
return { userId: token.userId, current };
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (error instanceof SponsoredAccountRefusal)
|
|
52
|
+
throw error;
|
|
53
|
+
return refuse('SPONSOR_SESSION_INVALID');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async authority(accessToken, account, chainId, rawActivation, outputToken, capability = 'swap') {
|
|
57
|
+
const activation = SPONSORED_ACTIVATION_SCHEMA.parse(rawActivation);
|
|
58
|
+
if (!sponsoredActivationSupports(activation, capability))
|
|
59
|
+
return refuse('SPONSOR_CAPABILITY_UNAVAILABLE');
|
|
60
|
+
const output = sponsoredOutputToken(activation, chainId, outputToken);
|
|
61
|
+
if (activation.projectId !== this.projectId || activation.mode !== 'enabled' ||
|
|
62
|
+
activation.approvedAtMs > this.now() || activation.expiresAtMs <= this.now())
|
|
63
|
+
return refuse('SPONSOR_ACTIVATION_UNAVAILABLE');
|
|
64
|
+
if (!this.caps.available)
|
|
65
|
+
return refuse('SPONSOR_CAP_UNAVAILABLE');
|
|
66
|
+
const who = await this.identity(accessToken, account);
|
|
67
|
+
if (!sameAddressSmartAccount(who.current, account))
|
|
68
|
+
return refuse('SPONSOR_EXPLICIT_WALLET_UPGRADE_REQUIRED');
|
|
69
|
+
const [cap, generation, grant, policyReply] = await Promise.all([
|
|
70
|
+
this.caps.readActive(who.userId, this.now()), this.caps.readRevokeGeneration(who.userId),
|
|
71
|
+
this.cdp.endUser.getDelegationForEndUserAccount({ userId: who.userId, address: account }),
|
|
72
|
+
this.cdp.policies.listPolicies({ scope: 'project' }),
|
|
73
|
+
]);
|
|
74
|
+
if (!cap || cap.state !== 'confirmed_active' || cap.requiredVersion !== MODEL_B_CAP_RULESET_VERSION ||
|
|
75
|
+
cap.revokeGeneration !== generation || Date.parse(cap.expiresAt) !== Date.parse(grant.expiresAt) ||
|
|
76
|
+
!Number.isFinite(Date.parse(grant.expiresAt)) || Date.parse(grant.expiresAt) <= this.now() ||
|
|
77
|
+
Date.parse(grant.expiresAt) > this.now() + 180 * 24 * 60 * 60 * 1000)
|
|
78
|
+
return refuse('SPONSOR_CURRENT_GRANT_REQUIRED');
|
|
79
|
+
const projectPolicies = (policyReply.policies ?? []).filter(p => p.scope === 'project');
|
|
80
|
+
if (projectPolicies.length !== 1 || projectPolicies[0].id !== activation.policyId ||
|
|
81
|
+
projectPolicies[0].description !== activation.policyName ||
|
|
82
|
+
policyRulesDigest(projectPolicies[0].rules) !== activation.policyRulesDigest)
|
|
83
|
+
return refuse('SPONSOR_POLICY_CHANGED');
|
|
84
|
+
const terms = sponsoredChainTerms(activation, chainId), client = this.client(chainId);
|
|
85
|
+
const block = await client.getBlock({ blockTag: 'latest' });
|
|
86
|
+
if (!block.number || !block.hash)
|
|
87
|
+
return refuse('SPONSOR_ACCOUNT_PROOF_UNAVAILABLE');
|
|
88
|
+
const [network, ownerCode, delegateCode, entryPointCode, paymasterCode, outputCode] = await Promise.all([
|
|
89
|
+
client.getChainId(), client.getCode({ address: account, blockNumber: block.number }),
|
|
90
|
+
client.getCode({ address: terms.delegate, blockNumber: block.number }),
|
|
91
|
+
client.getCode({ address: terms.entryPoint, blockNumber: block.number }),
|
|
92
|
+
client.getCode({ address: terms.paymaster, blockNumber: block.number }),
|
|
93
|
+
client.getCode({ address: output.address, blockNumber: block.number }),
|
|
94
|
+
]);
|
|
95
|
+
if (network !== chainId || ownerCode?.toLowerCase() !== `0xef0100${terms.delegate.slice(2).toLowerCase()}` ||
|
|
96
|
+
!delegateCode || delegateCode === '0x' || keccak256(delegateCode).toLowerCase() !== terms.delegateCodeHash.toLowerCase() ||
|
|
97
|
+
!entryPointCode || entryPointCode === '0x' || keccak256(entryPointCode).toLowerCase() !== terms.entryPointCodeHash.toLowerCase() ||
|
|
98
|
+
!paymasterCode || paymasterCode === '0x' || keccak256(paymasterCode).toLowerCase() !== terms.paymasterCodeHash.toLowerCase() ||
|
|
99
|
+
!outputCode || outputCode === '0x' || keccak256(outputCode).toLowerCase() !== output.codeHash.toLowerCase() ||
|
|
100
|
+
(await client.getBlock({ blockNumber: block.number })).hash !== block.hash)
|
|
101
|
+
return refuse('SPONSOR_ACCOUNT_PROOF_MISMATCH');
|
|
102
|
+
const authority = SPONSORED_AUTHORITY_SCHEMA.parse({ userId: who.userId, account, mintKey: cap.mintKey,
|
|
103
|
+
grantExpiresAt: new Date(Date.parse(grant.expiresAt)).toISOString(), revokeGeneration: generation,
|
|
104
|
+
capVersion: cap.requiredVersion, perSwapCapUsd: cap.perSwapCapUsd,
|
|
105
|
+
activationDigest: sponsoredDigest(activation), policyRulesDigest: activation.policyRulesDigest });
|
|
106
|
+
await this.assertCurrentCap(authority);
|
|
107
|
+
return authority;
|
|
108
|
+
}
|
|
109
|
+
/** Called synchronously under the operation handoff lock. Stop and request start are ordered by caps.db. */
|
|
110
|
+
withCurrentCap(authority, start) {
|
|
111
|
+
if (!this.caps.available || !this.caps.withCurrentActiveCap)
|
|
112
|
+
return refuse('SPONSOR_CAP_UNAVAILABLE');
|
|
113
|
+
return this.caps.withCurrentActiveCap({ userId: authority.userId, mintKey: authority.mintKey,
|
|
114
|
+
expiresAt: authority.grantExpiresAt, perSwapCapUsd: authority.perSwapCapUsd,
|
|
115
|
+
requiredVersion: authority.capVersion, revokeGeneration: authority.revokeGeneration }, this.now, start);
|
|
116
|
+
}
|
|
117
|
+
async assertCurrentCap(authority) {
|
|
118
|
+
const [cap, generation] = await Promise.all([
|
|
119
|
+
this.caps.readActive(authority.userId, this.now()), this.caps.readRevokeGeneration(authority.userId),
|
|
120
|
+
]);
|
|
121
|
+
if (!cap || cap.state !== 'confirmed_active' || cap.mintKey !== authority.mintKey ||
|
|
122
|
+
cap.requiredVersion !== authority.capVersion || cap.revokeGeneration !== generation || generation !== authority.revokeGeneration ||
|
|
123
|
+
cap.perSwapCapUsd !== authority.perSwapCapUsd || Date.parse(cap.expiresAt) !== Date.parse(authority.grantExpiresAt) ||
|
|
124
|
+
Date.parse(cap.expiresAt) <= this.now())
|
|
125
|
+
return refuse('SPONSOR_STOP_OR_CAP_CHANGED');
|
|
126
|
+
}
|
|
127
|
+
async preflight(operation) {
|
|
128
|
+
const client = this.client(operation.context.chainId);
|
|
129
|
+
const balance = await client.readContract({ address: SPONSORED_USDC[operation.context.chainId],
|
|
130
|
+
abi: parseAbi(['function balanceOf(address owner) view returns(uint256)']), functionName: 'balanceOf', args: [operation.context.account] });
|
|
131
|
+
if (balance < BigInt(operation.context.intent.fromAmount))
|
|
132
|
+
return refuse('SPONSOR_BALANCE_INSUFFICIENT');
|
|
133
|
+
}
|
|
134
|
+
async readAcknowledgement(operation, expectedCalls) {
|
|
135
|
+
if (!operation.userOpHash)
|
|
136
|
+
return refuse('SPONSOR_SUBMISSION_UNRESOLVED');
|
|
137
|
+
const result = await this.cdp.evm.getUserOperation({ smartAccount: operation.context.account, userOpHash: operation.userOpHash });
|
|
138
|
+
const calls = result.calls.map(call => ({ to: getAddress(call.to).toLowerCase(), data: call.data.toLowerCase(), value: call.value.toString() }));
|
|
139
|
+
if (result.userOpHash.toLowerCase() !== operation.userOpHash.toLowerCase() ||
|
|
140
|
+
result.network !== SPONSORED_CDP_NETWORKS[operation.context.chainId] ||
|
|
141
|
+
JSON.stringify(calls) !== JSON.stringify(expectedCalls) ||
|
|
142
|
+
!['pending', 'signed', 'broadcast', 'complete', 'dropped', 'failed'].includes(result.status) ||
|
|
143
|
+
(result.transactionHash && !/^0x[0-9a-fA-F]{64}$/.test(result.transactionHash)))
|
|
144
|
+
return refuse('SPONSOR_USER_OPERATION_MISMATCH');
|
|
145
|
+
return { userOpHash: result.userOpHash, status: result.status,
|
|
146
|
+
...(result.transactionHash ? { transactionHash: result.transactionHash } : {}) };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=execution-sponsored-runtime.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Address, type Hex, type TransactionReceipt, type PublicClient } from 'viem';
|
|
2
|
+
import { type SponsoredOperation } from './execution-sponsored-definition.js';
|
|
3
|
+
import type { ConfirmedSponsoredReceipt } from './execution-sponsored-receipt.js';
|
|
4
|
+
/** Isolate execution logs belonging to this UserOp, excluding every other operation in its bundle. */
|
|
5
|
+
export declare function sponsoredOperationLogs(receipt: TransactionReceipt, entryPoint: Address, userOpHash: Hex): import("viem").Log<bigint, number, false>[];
|
|
6
|
+
export declare function readSponsoredSwapSettlement(operation: SponsoredOperation, confirmed: ConfirmedSponsoredReceipt, client: PublicClient): Promise<{
|
|
7
|
+
inputToken: `0x${string}`;
|
|
8
|
+
outputToken: `0x${string}`;
|
|
9
|
+
inputDebited: string;
|
|
10
|
+
outputReceived: string;
|
|
11
|
+
ottoFeeReceived: string;
|
|
12
|
+
allowanceAfter: "0";
|
|
13
|
+
userOpHash: `0x${string}`;
|
|
14
|
+
transactionHash: `0x${string}`;
|
|
15
|
+
}>;
|