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,30 @@
|
|
|
1
|
+
import { type NativeYieldPlan, type NativeYieldDeployment } from './native-yield-definition.js';
|
|
2
|
+
import type { NativeYieldRuntime } from './native-yield.js';
|
|
3
|
+
export interface VerifiedNativeYieldPlan {
|
|
4
|
+
readonly plan: NativeYieldPlan;
|
|
5
|
+
readonly verificationOnly: true;
|
|
6
|
+
}
|
|
7
|
+
export interface NativeYieldVerificationContext {
|
|
8
|
+
/** Resolved from the actual signing account/session, never copied from plan metadata. */
|
|
9
|
+
readonly account: {
|
|
10
|
+
readonly address: string;
|
|
11
|
+
readonly chainId: number;
|
|
12
|
+
};
|
|
13
|
+
/** Owner-approved/engine-bounded amount for this action, in the exact input token's units. */
|
|
14
|
+
readonly maximumInputAtomic: bigint;
|
|
15
|
+
}
|
|
16
|
+
export declare function verifyNativeYieldPlan(runtime: NativeYieldRuntime, rawPlan: unknown, rawInput: unknown, context: NativeYieldVerificationContext): Promise<VerifiedNativeYieldPlan>;
|
|
17
|
+
/** Protocol verification only. This cannot produce the opaque EOA-verifier capability. */
|
|
18
|
+
export declare function verifyNativeYieldProtocolPlan(runtime: NativeYieldRuntime, rawPlan: unknown, rawInput: unknown, context: NativeYieldVerificationContext, requireEoaGas?: boolean): Promise<NativeYieldPlan>;
|
|
19
|
+
/** Synchronous age check for the actual independent read, including time spent waiting on locks.
|
|
20
|
+
* Metadata is process-local and cannot be supplied by a stored plan or caller. */
|
|
21
|
+
export declare function assertFreshNativeYieldProtocolPlan(plan: NativeYieldPlan, nowMs: number): void;
|
|
22
|
+
export declare function assertVerifiedNativeYieldPlan(value: VerifiedNativeYieldPlan): NativeYieldPlan;
|
|
23
|
+
/** Explicit recovery transaction. Caller must reconcile unknown execution first and ask its signer to approve this action. */
|
|
24
|
+
export declare function nativeYieldAllowanceRevocation(rawPlan: NativeYieldPlan, context: Pick<NativeYieldVerificationContext, 'account'>, deployments?: readonly NativeYieldDeployment[]): {
|
|
25
|
+
chainId: import("./hybrid-yield-markets.js").HybridYieldChainId;
|
|
26
|
+
from: `0x${string}`;
|
|
27
|
+
to: `0x${string}`;
|
|
28
|
+
value: "0";
|
|
29
|
+
data: `0x${string}`;
|
|
30
|
+
};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/** Independent decode-and-reject boundary for a native plan. Verification is not wallet authority. */
|
|
2
|
+
import { decodeFunctionData, encodeFunctionData, getAddress, keccak256, parseAbi, stringToHex } from 'viem';
|
|
3
|
+
import { freezeHybridValue, getHybridYieldMarket, hybridYieldCommitment } from './hybrid-yield-markets.js';
|
|
4
|
+
import { NATIVE_YIELD_DEPLOYMENTS, NATIVE_YIELD_FEE_RECIPIENT, NATIVE_YIELD_PLAN_SCHEMA, NATIVE_YIELD_STATE_MAX_AGE_MS, NATIVE_YIELD_TTL_SECONDS, PREPARE_NATIVE_YIELD_INPUT_SCHEMA, nativeYieldFee, refuseNative, } from './native-yield-definition.js';
|
|
5
|
+
import { assertNativeYieldProtocolState } from './native-yield.js';
|
|
6
|
+
const APPROVE = parseAbi(['function approve(address spender, uint256 amount) returns (bool)']);
|
|
7
|
+
const EXECUTE = parseAbi([
|
|
8
|
+
'function execute(bytes32 marketId, bool isDeposit, uint256 amount, uint256 minOutput, uint256 nonce, uint256 deadline) returns (uint256)',
|
|
9
|
+
]);
|
|
10
|
+
const verified = new WeakSet();
|
|
11
|
+
const protocolFreshness = new WeakMap();
|
|
12
|
+
function ensure(value, code, message) {
|
|
13
|
+
if (!value)
|
|
14
|
+
refuseNative(code, message);
|
|
15
|
+
}
|
|
16
|
+
export async function verifyNativeYieldPlan(runtime, rawPlan, rawInput, context) {
|
|
17
|
+
const plan = await verifyNativeYieldProtocolPlan(runtime, rawPlan, rawInput, context, true);
|
|
18
|
+
const result = freezeHybridValue({ plan, verificationOnly: true });
|
|
19
|
+
verified.add(result);
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
/** Protocol verification only. This cannot produce the opaque EOA-verifier capability. */
|
|
23
|
+
export async function verifyNativeYieldProtocolPlan(runtime, rawPlan, rawInput, context, requireEoaGas = false) {
|
|
24
|
+
const plan = NATIVE_YIELD_PLAN_SCHEMA.parse(rawPlan);
|
|
25
|
+
const input = PREPARE_NATIVE_YIELD_INPUT_SCHEMA.parse(rawInput);
|
|
26
|
+
const now = (runtime.nowMs ?? Date.now)();
|
|
27
|
+
const { planCommitment, ...core } = plan;
|
|
28
|
+
ensure(hybridYieldCommitment(core) === planCommitment, 'NATIVE_PLAN_TAMPERED', 'Plan commitment mismatch');
|
|
29
|
+
ensure(plan.intentCommitment === hybridYieldCommitment(input), 'NATIVE_INTENT_MISMATCH', 'Plan belongs to different review input');
|
|
30
|
+
const market = getHybridYieldMarket(input.marketId);
|
|
31
|
+
ensure(market && hybridYieldCommitment(market) === input.registryCommitment &&
|
|
32
|
+
plan.registryCommitment === input.registryCommitment && plan.marketId === market.id, 'NATIVE_REGISTRY_MISMATCH', 'Exact current market record is required');
|
|
33
|
+
ensure(plan.action === input.action && plan.amount === input.amount &&
|
|
34
|
+
(input.action !== 'deposit' || market.capabilities.native.deposit !== 'unavailable'), 'NATIVE_ACTION_MISMATCH', 'Action or amount changed, or new deposits are unavailable');
|
|
35
|
+
const owner = getAddress(context.account.address);
|
|
36
|
+
ensure(owner === getAddress(input.accountProfile.address) && owner === getAddress(plan.owner) &&
|
|
37
|
+
context.account.chainId === market.chainId && input.accountProfile.chainId === market.chainId &&
|
|
38
|
+
plan.chainId === market.chainId, 'NATIVE_OWNER_MISMATCH', 'Actual account or chain is not the reviewed payer/owner');
|
|
39
|
+
const amount = BigInt(input.amount);
|
|
40
|
+
ensure(context.maximumInputAtomic > 0n && context.maximumInputAtomic < (1n << 256n) &&
|
|
41
|
+
amount <= context.maximumInputAtomic, 'NATIVE_CAP_EXCEEDED', 'Input exceeds the separately approved action limit');
|
|
42
|
+
ensure(plan.preparedAtMs <= now && plan.deadline > Math.floor(now / 1000) &&
|
|
43
|
+
plan.deadline === Math.floor(plan.preparedAtMs / 1000) + NATIVE_YIELD_TTL_SECONDS &&
|
|
44
|
+
plan.snapshot.observedAtMs <= plan.preparedAtMs &&
|
|
45
|
+
plan.preparedAtMs - plan.snapshot.observedAtMs <= NATIVE_YIELD_STATE_MAX_AGE_MS, 'NATIVE_PLAN_EXPIRED', 'Native plan is stale or has an invalid lifetime');
|
|
46
|
+
const deployment = (runtime.deployments ?? NATIVE_YIELD_DEPLOYMENTS).find((d) => d.chainId === market.chainId);
|
|
47
|
+
ensure(deployment && hybridYieldCommitment(deployment) === hybridYieldCommitment(plan.deployment), 'NATIVE_DEPLOYMENT_REQUIRED', 'No exact approved deployment matches the plan');
|
|
48
|
+
const executor = getAddress(deployment.address);
|
|
49
|
+
const isDeposit = input.action === 'deposit';
|
|
50
|
+
const inputToken = isDeposit ? market.asset.address : market.position.tokenAddress;
|
|
51
|
+
const outputToken = isDeposit ? market.position.tokenAddress : market.asset.address;
|
|
52
|
+
ensure(getAddress(plan.inputToken) === inputToken && getAddress(plan.outputToken) === outputToken, 'NATIVE_TOKEN_MISMATCH', 'Input/output token differs from the registry');
|
|
53
|
+
ensure(getAddress(plan.fee.recipient) === NATIVE_YIELD_FEE_RECIPIENT &&
|
|
54
|
+
getAddress(plan.fee.token) === market.asset.address, 'NATIVE_FEE_MISMATCH', 'Fee recipient or asset changed');
|
|
55
|
+
const protocolOutput = BigInt(plan.protocolOutput);
|
|
56
|
+
const fee = nativeYieldFee(isDeposit ? amount : protocolOutput);
|
|
57
|
+
const expected = isDeposit ? protocolOutput : protocolOutput - fee;
|
|
58
|
+
const floor = expected * BigInt(10_000 - input.slippage.maxBps) / 10000n;
|
|
59
|
+
const min = BigInt(plan.minimumOutput);
|
|
60
|
+
ensure(plan.fee.amount === fee.toString() && plan.expectedOutput === expected.toString(), 'NATIVE_FEE_MISMATCH', 'Preview silently changes the approved fee');
|
|
61
|
+
ensure(min > 0n && min >= floor && min <= expected &&
|
|
62
|
+
(input.slippage.minOutput === undefined || min >= BigInt(input.slippage.minOutput)), 'NATIVE_MINIMUM_INVALID', 'Reviewed minimum or slippage bound weakened');
|
|
63
|
+
for (const index of [0, 1]) {
|
|
64
|
+
const step = plan.steps[index];
|
|
65
|
+
ensure(step.kind === (index === 0 ? 'approve_reset' : 'approve') &&
|
|
66
|
+
getAddress(step.to) === inputToken && step.value === '0', 'NATIVE_APPROVAL_INVALID', 'Approval step has wrong token, sequence or native value');
|
|
67
|
+
const decoded = decodeFunctionData({ abi: APPROVE, data: step.data });
|
|
68
|
+
const [spender, approved] = decoded.args;
|
|
69
|
+
ensure(decoded.functionName === 'approve' && getAddress(spender) === executor &&
|
|
70
|
+
approved === (index === 0 ? 0n : amount) &&
|
|
71
|
+
encodeFunctionData({ abi: APPROVE, functionName: 'approve', args: [spender, approved] }).toLowerCase() === step.data.toLowerCase(), 'NATIVE_APPROVAL_INVALID', 'Approval spender, amount or canonical bytes differ');
|
|
72
|
+
}
|
|
73
|
+
const call = plan.steps[2];
|
|
74
|
+
ensure(call.kind === 'call' && getAddress(call.to) === executor && call.value === '0', 'NATIVE_CALL_INVALID', 'Action target or native value changed');
|
|
75
|
+
const decoded = decodeFunctionData({ abi: EXECUTE, data: call.data });
|
|
76
|
+
const [id, deposit, quantity, minimum, nonce, deadline] = decoded.args;
|
|
77
|
+
ensure(decoded.functionName === 'execute' && id === keccak256(stringToHex(market.id)) &&
|
|
78
|
+
deposit === isDeposit && quantity === amount && minimum === min &&
|
|
79
|
+
nonce === BigInt(plan.nonce) && deadline === BigInt(plan.deadline) &&
|
|
80
|
+
encodeFunctionData({ abi: EXECUTE, functionName: 'execute', args: decoded.args }).toLowerCase() === call.data.toLowerCase(), 'NATIVE_CALL_INVALID', 'Decoded market/action/amount/minimum/nonce/deadline or canonical bytes differ');
|
|
81
|
+
// Fresh independent protocol/account read immediately before the caller's signing boundary.
|
|
82
|
+
// Begin the span before the reader captures its block and observation, including all later awaited RPCs.
|
|
83
|
+
const readStartedMonotonicMs = performance.now();
|
|
84
|
+
const readStartedAtMs = (runtime.nowMs ?? Date.now)();
|
|
85
|
+
ensure(Number.isFinite(readStartedMonotonicMs) && readStartedMonotonicMs >= 0 &&
|
|
86
|
+
Number.isSafeInteger(readStartedAtMs) && readStartedAtMs >= now, 'NATIVE_STATE_STALE', 'A valid monotonic protocol-read span is required before signing');
|
|
87
|
+
const state = await runtime.reader.read(market, owner, input.action, amount, deployment);
|
|
88
|
+
const afterRead = (runtime.nowMs ?? Date.now)();
|
|
89
|
+
const monotonicAtMs = performance.now();
|
|
90
|
+
ensure(Number.isSafeInteger(afterRead) && afterRead >= readStartedAtMs &&
|
|
91
|
+
Number.isFinite(monotonicAtMs) && monotonicAtMs >= readStartedMonotonicMs, 'NATIVE_STATE_STALE', 'A valid monotonic protocol-read span is required before signing');
|
|
92
|
+
const effectiveAfterRead = Math.max(afterRead, readStartedAtMs + monotonicAtMs - readStartedMonotonicMs);
|
|
93
|
+
assertNativeYieldProtocolState(state, market, input, effectiveAfterRead);
|
|
94
|
+
ensure(effectiveAfterRead < plan.deadline * 1000 && state.observedAtMs <= effectiveAfterRead &&
|
|
95
|
+
effectiveAfterRead - state.observedAtMs <= NATIVE_YIELD_STATE_MAX_AGE_MS &&
|
|
96
|
+
state.blockTimestampMs <= effectiveAfterRead + 5000 &&
|
|
97
|
+
effectiveAfterRead - state.blockTimestampMs <= NATIVE_YIELD_STATE_MAX_AGE_MS, 'NATIVE_STATE_STALE', 'Fresh protocol state is required before signing');
|
|
98
|
+
ensure(state.chainId === market.chainId && state.marketId === market.id &&
|
|
99
|
+
getAddress(state.owner) === owner && state.routerNonce === nonce, 'NATIVE_NONCE_OR_OWNER_CHANGED', 'Execution nonce or owning account changed; reconcile before preparing again');
|
|
100
|
+
ensure(state.inputBalance >= amount && state.maxInput >= amount && (!requireEoaGas || state.nativeBalance > 0n), 'NATIVE_BALANCE_OR_LIQUIDITY', 'Balance, liquidity or native gas is no longer sufficient');
|
|
101
|
+
const currentExpected = isDeposit ? state.protocolOutput : state.protocolOutput - nativeYieldFee(state.protocolOutput);
|
|
102
|
+
ensure(currentExpected >= min && min >= currentExpected * BigInt(10_000 - input.slippage.maxBps) / 10000n, 'NATIVE_PARITY_CHANGED', 'Fresh protocol preview is outside the reviewed bound; prepare and review again');
|
|
103
|
+
const result = freezeHybridValue(plan);
|
|
104
|
+
protocolFreshness.set(result, { observedAtMs: state.observedAtMs, blockTimestampMs: state.blockTimestampMs,
|
|
105
|
+
checkedAtMs: afterRead, effectiveAtMs: effectiveAfterRead, monotonicAtMs });
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
/** Synchronous age check for the actual independent read, including time spent waiting on locks.
|
|
109
|
+
* Metadata is process-local and cannot be supplied by a stored plan or caller. */
|
|
110
|
+
export function assertFreshNativeYieldProtocolPlan(plan, nowMs) {
|
|
111
|
+
const facts = protocolFreshness.get(plan), monotonicNow = performance.now();
|
|
112
|
+
ensure(facts && Number.isSafeInteger(nowMs) && nowMs >= facts.checkedAtMs &&
|
|
113
|
+
Number.isFinite(monotonicNow) && monotonicNow >= facts.monotonicAtMs, 'NATIVE_STATE_STALE', 'Fresh protocol state is required before signing');
|
|
114
|
+
// The read span is already included in effectiveAtMs; add only elapsed time since its endpoint.
|
|
115
|
+
const current = Math.max(nowMs, facts.effectiveAtMs + monotonicNow - facts.monotonicAtMs);
|
|
116
|
+
ensure(current < plan.deadline * 1000 && current - facts.observedAtMs <= NATIVE_YIELD_STATE_MAX_AGE_MS &&
|
|
117
|
+
current - facts.blockTimestampMs <= NATIVE_YIELD_STATE_MAX_AGE_MS, 'NATIVE_STATE_STALE', 'Fresh protocol state is required before signing');
|
|
118
|
+
}
|
|
119
|
+
export function assertVerifiedNativeYieldPlan(value) {
|
|
120
|
+
ensure(value && verified.has(value) && Object.isFrozen(value), 'NATIVE_UNVERIFIED_PLAN', 'Native plan lacks independent verification');
|
|
121
|
+
return value.plan;
|
|
122
|
+
}
|
|
123
|
+
/** Explicit recovery transaction. Caller must reconcile unknown execution first and ask its signer to approve this action. */
|
|
124
|
+
export function nativeYieldAllowanceRevocation(rawPlan, context, deployments = NATIVE_YIELD_DEPLOYMENTS) {
|
|
125
|
+
const plan = NATIVE_YIELD_PLAN_SCHEMA.parse(rawPlan);
|
|
126
|
+
const { planCommitment, ...core } = plan;
|
|
127
|
+
ensure(hybridYieldCommitment(core) === planCommitment, 'NATIVE_PLAN_TAMPERED', 'Recovery plan commitment mismatch');
|
|
128
|
+
const market = getHybridYieldMarket(plan.marketId);
|
|
129
|
+
ensure(market && hybridYieldCommitment(market) === plan.registryCommitment, 'NATIVE_REGISTRY_MISMATCH', 'Unknown recovery market');
|
|
130
|
+
ensure(plan.chainId === market.chainId && context.account.chainId === market.chainId &&
|
|
131
|
+
getAddress(context.account.address) === getAddress(plan.owner), 'NATIVE_OWNER_MISMATCH', 'Recovery must use the actual owning account and chain');
|
|
132
|
+
const deployment = deployments.find((d) => d.chainId === market.chainId);
|
|
133
|
+
ensure(deployment && hybridYieldCommitment(deployment) === hybridYieldCommitment(plan.deployment), 'NATIVE_DEPLOYMENT_REQUIRED', 'Recovery target is not the approved executor');
|
|
134
|
+
const inputToken = plan.action === 'deposit' ? market.asset.address : market.position.tokenAddress;
|
|
135
|
+
ensure(getAddress(plan.inputToken) === inputToken, 'NATIVE_TOKEN_MISMATCH', 'Recovery token changed');
|
|
136
|
+
return freezeHybridValue({
|
|
137
|
+
chainId: market.chainId, from: getAddress(context.account.address), to: inputToken, value: '0',
|
|
138
|
+
data: encodeFunctionData({ abi: APPROVE, functionName: 'approve', args: [getAddress(deployment.address), 0n] }),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=native-yield-verify.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type HybridYieldMarket } from './hybrid-yield-markets.js';
|
|
2
|
+
import { type NativeYieldDeployment, type NativeYieldPlan, type NativeYieldReader, type NativeYieldState, type PrepareNativeYieldInput } from './native-yield-definition.js';
|
|
3
|
+
export interface NativeYieldRuntime {
|
|
4
|
+
readonly reader: NativeYieldReader;
|
|
5
|
+
/** Server-owned deployment manifest. No request or environment-address seam. */
|
|
6
|
+
readonly deployments?: readonly NativeYieldDeployment[];
|
|
7
|
+
readonly nowMs?: () => number;
|
|
8
|
+
}
|
|
9
|
+
export declare function resolveNativeYieldMarket(input: PrepareNativeYieldInput): HybridYieldMarket;
|
|
10
|
+
export declare function assertNativeYieldState(state: NativeYieldState, market: HybridYieldMarket, input: PrepareNativeYieldInput, now: number): void;
|
|
11
|
+
/** Protocol-only checks for the separately authorized UserOp path; never grants EOA signing authority. */
|
|
12
|
+
export declare function assertNativeYieldProtocolState(state: NativeYieldState, market: HybridYieldMarket, input: PrepareNativeYieldInput, now: number): void;
|
|
13
|
+
/** Pure construction from a reader-validated state; the independent verifier decodes the resulting bytes. */
|
|
14
|
+
export declare function buildNativeYieldPlan(input: PrepareNativeYieldInput, market: HybridYieldMarket, deployment: NativeYieldDeployment, state: NativeYieldState, now: number): NativeYieldPlan;
|
|
15
|
+
/** Exact protocol recipe. Its caller must establish the separate gas-payer and account authority. */
|
|
16
|
+
export declare function buildNativeYieldProtocolPlan(input: PrepareNativeYieldInput, market: HybridYieldMarket, deployment: NativeYieldDeployment, state: NativeYieldState, now: number): NativeYieldPlan;
|
|
17
|
+
export declare function prepareNativeYield(runtime: NativeYieldRuntime, rawInput: unknown): Promise<NativeYieldPlan>;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/** Native protocol constructor: fixed protocol, exact amounts, current state and account. Never signs. */
|
|
2
|
+
import { encodeFunctionData, getAddress, keccak256, stringToHex } from 'viem';
|
|
3
|
+
import { freezeHybridValue, getHybridYieldMarket, hybridYieldCommitment } from './hybrid-yield-markets.js';
|
|
4
|
+
import { NATIVE_YIELD_DEPLOYMENTS, NATIVE_YIELD_DEPLOYMENT_SCHEMA, NATIVE_YIELD_ERC20_ABI, NATIVE_YIELD_FEE_RECIPIENT, NATIVE_YIELD_FEE_VERSION, NATIVE_YIELD_PLAN_SCHEMA, NATIVE_YIELD_ROUTER_ABI, NATIVE_YIELD_STATE_MAX_AGE_MS, NATIVE_YIELD_TTL_SECONDS, PREPARE_NATIVE_YIELD_INPUT_SCHEMA, nativeYieldFee, refuseNative, } from './native-yield-definition.js';
|
|
5
|
+
export function resolveNativeYieldMarket(input) {
|
|
6
|
+
const market = getHybridYieldMarket(input.marketId);
|
|
7
|
+
if (!market)
|
|
8
|
+
return refuseNative('NATIVE_MARKET_UNKNOWN', 'Unknown exact native yield market');
|
|
9
|
+
if (hybridYieldCommitment(market) !== input.registryCommitment) {
|
|
10
|
+
return refuseNative('NATIVE_REGISTRY_MISMATCH', 'Re-read this market; its registry commitment changed');
|
|
11
|
+
}
|
|
12
|
+
if (market.chainId !== input.accountProfile.chainId) {
|
|
13
|
+
return refuseNative('NATIVE_CHAIN_MISMATCH', 'Native execution requires the position chain and exact underlying asset');
|
|
14
|
+
}
|
|
15
|
+
if (input.action === 'deposit' && market.capabilities.native.deposit === 'unavailable') {
|
|
16
|
+
return refuseNative('NATIVE_DEPOSIT_UNAVAILABLE', 'This legacy market supports exit, not a new native allocation');
|
|
17
|
+
}
|
|
18
|
+
return market;
|
|
19
|
+
}
|
|
20
|
+
export function assertNativeYieldState(state, market, input, now) {
|
|
21
|
+
assertNativeYieldProtocolState(state, market, input, now);
|
|
22
|
+
if (state.nativeBalance === 0n) {
|
|
23
|
+
refuseNative('NATIVE_GAS_REQUIRED', 'This EOA needs native gas on the selected network; sponsorship is not assumed');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Protocol-only checks for the separately authorized UserOp path; never grants EOA signing authority. */
|
|
27
|
+
export function assertNativeYieldProtocolState(state, market, input, now) {
|
|
28
|
+
if (state.chainId !== market.chainId || state.marketId !== market.id ||
|
|
29
|
+
getAddress(state.owner) !== getAddress(input.accountProfile.address)) {
|
|
30
|
+
refuseNative('NATIVE_STATE_BINDING', 'Protocol reads belong to a different market, chain or owner');
|
|
31
|
+
}
|
|
32
|
+
for (const value of [state.blockNumber, state.routerNonce, state.inputBalance, state.inputAllowance,
|
|
33
|
+
state.positionBalance, state.assetBalance, state.nativeBalance, state.maxInput, state.protocolOutput]) {
|
|
34
|
+
if (typeof value !== 'bigint' || value < 0n || value >= (1n << 256n)) {
|
|
35
|
+
refuseNative('NATIVE_STATE_INVALID', 'Protocol read returned an invalid atomic quantity');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(state.blockHash) ||
|
|
39
|
+
!Number.isSafeInteger(state.observedAtMs) || !Number.isSafeInteger(state.blockTimestampMs) ||
|
|
40
|
+
state.observedAtMs > now || now - state.observedAtMs > NATIVE_YIELD_STATE_MAX_AGE_MS ||
|
|
41
|
+
state.blockTimestampMs > now + 5000 || now - state.blockTimestampMs > NATIVE_YIELD_STATE_MAX_AGE_MS) {
|
|
42
|
+
refuseNative('NATIVE_STATE_STALE', 'Current anchored protocol state is required');
|
|
43
|
+
}
|
|
44
|
+
const amount = BigInt(input.amount);
|
|
45
|
+
if (state.inputBalance < amount || state.maxInput < amount) {
|
|
46
|
+
refuseNative('NATIVE_BALANCE_OR_LIQUIDITY', 'Insufficient exact input balance or currently redeemable liquidity');
|
|
47
|
+
}
|
|
48
|
+
if (state.protocolOutput === 0n)
|
|
49
|
+
refuseNative('NATIVE_ZERO_OUTPUT', 'Protocol preview returns zero output');
|
|
50
|
+
}
|
|
51
|
+
/** Pure construction from a reader-validated state; the independent verifier decodes the resulting bytes. */
|
|
52
|
+
export function buildNativeYieldPlan(input, market, deployment, state, now) {
|
|
53
|
+
assertNativeYieldState(state, market, input, now);
|
|
54
|
+
return buildNativeYieldProtocolPlan(input, market, deployment, state, now);
|
|
55
|
+
}
|
|
56
|
+
/** Exact protocol recipe. Its caller must establish the separate gas-payer and account authority. */
|
|
57
|
+
export function buildNativeYieldProtocolPlan(input, market, deployment, state, now) {
|
|
58
|
+
assertNativeYieldProtocolState(state, market, input, now);
|
|
59
|
+
const owner = getAddress(input.accountProfile.address);
|
|
60
|
+
const executor = getAddress(deployment.address);
|
|
61
|
+
const amount = BigInt(input.amount);
|
|
62
|
+
const isDeposit = input.action === 'deposit';
|
|
63
|
+
const fee = nativeYieldFee(isDeposit ? amount : state.protocolOutput);
|
|
64
|
+
const expectedOutput = isDeposit ? state.protocolOutput : state.protocolOutput - fee;
|
|
65
|
+
if (expectedOutput <= 0n)
|
|
66
|
+
return refuseNative('NATIVE_ZERO_OUTPUT', 'Output after the approved fee is zero');
|
|
67
|
+
const floor = expectedOutput * BigInt(10_000 - input.slippage.maxBps) / 10000n;
|
|
68
|
+
const requestedFloor = input.slippage.minOutput === undefined ? 0n : BigInt(input.slippage.minOutput);
|
|
69
|
+
const minOutput = requestedFloor > floor ? requestedFloor : floor;
|
|
70
|
+
if (minOutput <= 0n || minOutput > expectedOutput) {
|
|
71
|
+
return refuseNative('NATIVE_MINIMUM_INVALID', 'The minimum output is zero or exceeds the fresh protocol preview');
|
|
72
|
+
}
|
|
73
|
+
const inputToken = isDeposit ? market.asset.address : market.position.tokenAddress;
|
|
74
|
+
const outputToken = isDeposit ? market.position.tokenAddress : market.asset.address;
|
|
75
|
+
const deadline = Math.floor(now / 1000) + NATIVE_YIELD_TTL_SECONDS;
|
|
76
|
+
const core = {
|
|
77
|
+
schemaVersion: '1', kind: 'native-yield-plan', transport: 'native-protocol',
|
|
78
|
+
marketId: market.id, registryCommitment: input.registryCommitment, owner, chainId: market.chainId,
|
|
79
|
+
action: input.action, amount: amount.toString(), inputToken, outputToken,
|
|
80
|
+
expectedOutput: expectedOutput.toString(), minimumOutput: minOutput.toString(),
|
|
81
|
+
protocolOutput: state.protocolOutput.toString(),
|
|
82
|
+
fee: {
|
|
83
|
+
bps: 10, recipient: NATIVE_YIELD_FEE_RECIPIENT, token: market.asset.address,
|
|
84
|
+
amount: fee.toString(), version: NATIVE_YIELD_FEE_VERSION, rounding: 'floor',
|
|
85
|
+
},
|
|
86
|
+
nonce: state.routerNonce.toString(), deadline, preparedAtMs: now,
|
|
87
|
+
snapshot: { blockNumber: state.blockNumber.toString(), blockHash: state.blockHash, observedAtMs: state.observedAtMs },
|
|
88
|
+
deployment,
|
|
89
|
+
steps: [
|
|
90
|
+
{ kind: 'approve_reset', to: inputToken, value: '0', data: encodeFunctionData({
|
|
91
|
+
abi: NATIVE_YIELD_ERC20_ABI, functionName: 'approve', args: [executor, 0n],
|
|
92
|
+
}) },
|
|
93
|
+
{ kind: 'approve', to: inputToken, value: '0', data: encodeFunctionData({
|
|
94
|
+
abi: NATIVE_YIELD_ERC20_ABI, functionName: 'approve', args: [executor, amount],
|
|
95
|
+
}) },
|
|
96
|
+
{ kind: 'call', to: executor, value: '0', data: encodeFunctionData({
|
|
97
|
+
abi: NATIVE_YIELD_ROUTER_ABI, functionName: 'execute',
|
|
98
|
+
args: [keccak256(stringToHex(market.id)), isDeposit, amount, minOutput, state.routerNonce, BigInt(deadline)],
|
|
99
|
+
}) },
|
|
100
|
+
],
|
|
101
|
+
authorization: 'requires-separate-account-authority',
|
|
102
|
+
allowanceRecovery: 'approval-is-separate-and-may-remain-after-failure',
|
|
103
|
+
intentCommitment: hybridYieldCommitment(input),
|
|
104
|
+
};
|
|
105
|
+
return freezeHybridValue(NATIVE_YIELD_PLAN_SCHEMA.parse({ ...core, planCommitment: hybridYieldCommitment(core) }));
|
|
106
|
+
}
|
|
107
|
+
export async function prepareNativeYield(runtime, rawInput) {
|
|
108
|
+
const input = PREPARE_NATIVE_YIELD_INPUT_SCHEMA.parse(rawInput);
|
|
109
|
+
const market = resolveNativeYieldMarket(input);
|
|
110
|
+
const deployment = (runtime.deployments ?? NATIVE_YIELD_DEPLOYMENTS).find((d) => d.chainId === market.chainId);
|
|
111
|
+
if (!deployment) {
|
|
112
|
+
return refuseNative('NATIVE_DEPLOYMENT_REQUIRED', 'Native protocol construction is implemented; this chain has no approved executor deployment');
|
|
113
|
+
}
|
|
114
|
+
const pin = NATIVE_YIELD_DEPLOYMENT_SCHEMA.parse(deployment);
|
|
115
|
+
const owner = getAddress(input.accountProfile.address);
|
|
116
|
+
const state = await runtime.reader.read(market, owner, input.action, BigInt(input.amount), pin);
|
|
117
|
+
return buildNativeYieldPlan(input, market, pin, state, (runtime.nowMs ?? Date.now)());
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=native-yield.js.map
|
package/dist/stdio-main.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `otto_prepare_stock_buy` — a tokenized-stock BUY (Coinbase B20 on Base) as a thin constructor over
|
|
3
|
+
* `otto_prepare_swap` (Founder word: delegation beyond swaps, 2026-09-03).
|
|
4
|
+
*
|
|
5
|
+
* WHY IT IS A SWAP, PROVEN LIVE (li.quest, 2026-09-03, production params `integrator=ottowallet&fee=0.001`):
|
|
6
|
+
* $10 USDC → AAPLc quoted as a same-chain route whose transactionRequest targets the reviewed LI.FI
|
|
7
|
+
* diamond with selector 0x5fd9ae2e = `swapTokensMultipleV3ERC20ToERC20` — one of the two fenced
|
|
8
|
+
* GenericSwapV3 entry points — USDC is the v1 allow-listed input token, and the receiver is the signing
|
|
9
|
+
* account. A B20 buy is therefore INSIDE the delegation fence as it stands (v1/v2, unchanged); the SELL
|
|
10
|
+
* direction needs a B20-token approve to the diamond, which fence v2 grants only to the two vault share
|
|
11
|
+
* tokens — a sell is fence v3, sized in docs/0903_delegation_empire_scope.md, not shipped here.
|
|
12
|
+
*
|
|
13
|
+
* WHAT THIS TOOL PINS THAT A RAW SWAP DOES NOT:
|
|
14
|
+
* - the OUTPUT token is the registry row's B20 contract, never a caller input;
|
|
15
|
+
* - the row is the CURRENT registry record (caller's commitment must match the recomputed one);
|
|
16
|
+
* - chain 8453 / venue COINBASE_B20 / asset USDC, from the row, refused otherwise;
|
|
17
|
+
* - PRICE PARITY on the WORST PERMISSIBLE FILL: `amount / minTokens` (the floor the router
|
|
18
|
+
* enforces) may not exceed the row's own Chainlink total-return mark by more than the pinned
|
|
19
|
+
* tolerance, and the slippage band is capped — a thin or poisoned pool, or a wide floor, can
|
|
20
|
+
* never execute a delegated buy far over the venue's own mark;
|
|
21
|
+
* - ORACLE FRESHNESS: a frozen feed (> 24 h — the dashboard's own frozen threshold; feeds hold their
|
|
22
|
+
* last value off-hours) cannot anchor parity, so the buy is refused by name. Off-hours the pool may
|
|
23
|
+
* legitimately trade away from Friday's close; a delegated buy waits for a live reference.
|
|
24
|
+
* The generic `otto_prepare_swap` refuses every executable-equity token address in either direction
|
|
25
|
+
* (the same discipline as the yield share tokens): this constructor is the only delegated path.
|
|
26
|
+
*/
|
|
27
|
+
import { z } from 'zod';
|
|
28
|
+
export declare const STOCK_BUY_TOOL_NAME: "otto_prepare_stock_buy";
|
|
29
|
+
/**
|
|
30
|
+
* 🔴 PINNED PRICE-PARITY TOLERANCE, in basis points of the Chainlink mark, on the WORST PERMISSIBLE
|
|
31
|
+
* FILL (`fromAmount / minTokens` — the floor the router actually enforces on-chain, fees included).
|
|
32
|
+
*
|
|
33
|
+
* Gate G1: a guard on the QUOTE alone lets the permitted slippage carry the executed fill past the
|
|
34
|
+
* tolerance (quote at 0 bps + 1,000-bps floor = an 11% overpay the guard never saw). So parity is
|
|
35
|
+
* checked against the FLOOR, and the floor's own room is bounded: this constructor caps
|
|
36
|
+
* `slippage.maxBps` at 100 (the generic swap's 1..1000 range is not a stock buy's).
|
|
37
|
+
*
|
|
38
|
+
* Derivation (live li.quest quotes 2026-09-03/04, production params):
|
|
39
|
+
* - LI.FI fixed integrator fee 0.25% of the input → 25 bps
|
|
40
|
+
* - observed B20 pool spread over the oracle mark (~21 bps AAPLc · ~34 bps NVDAc
|
|
41
|
+
* at small size; thin pools move with size) → ~50 bps p95
|
|
42
|
+
* - the slippage floor this schema permits → ≤ 100 bps
|
|
43
|
+
* = 175 bps on the worst permissible fill: whatever routing and slippage do, a delegated buy can
|
|
44
|
+
* never execute more than 1.75% over the venue's own mark. A test pins this value; widening it
|
|
45
|
+
* must redden that test.
|
|
46
|
+
*/
|
|
47
|
+
export declare const STOCK_BUY_PARITY_TOLERANCE_BPS: 175;
|
|
48
|
+
/** Gate G1: the tightest slippage band of any constructor — the tolerance above assumes it. */
|
|
49
|
+
export declare const STOCK_BUY_MAX_SLIPPAGE_BPS: 100;
|
|
50
|
+
/** The dashboard's frozen threshold (freshness.ts STALE_MAX_MIN): beyond this the feed cannot anchor parity. */
|
|
51
|
+
export declare const STOCK_BUY_MAX_ORACLE_AGE_SEC: number;
|
|
52
|
+
export declare const PREPARE_STOCK_BUY_INPUT_SCHEMA: z.ZodObject<{
|
|
53
|
+
accountProfile: z.ZodObject<{
|
|
54
|
+
kind: z.ZodEnum<{
|
|
55
|
+
eoa: "eoa";
|
|
56
|
+
safe: "safe";
|
|
57
|
+
}>;
|
|
58
|
+
address: z.ZodString;
|
|
59
|
+
chainId: z.ZodNumber;
|
|
60
|
+
}, z.core.$strict>;
|
|
61
|
+
executableEquityId: z.ZodString;
|
|
62
|
+
registryCommitment: z.ZodString;
|
|
63
|
+
amount: z.ZodString;
|
|
64
|
+
slippage: z.ZodObject<{
|
|
65
|
+
maxBps: z.ZodNumber;
|
|
66
|
+
}, z.core.$strict>;
|
|
67
|
+
client_ref: z.ZodOptional<z.ZodString>;
|
|
68
|
+
}, z.core.$strict>;
|
|
69
|
+
export type PrepareStockBuyInput = z.infer<typeof PREPARE_STOCK_BUY_INPUT_SCHEMA>;
|
|
70
|
+
export declare const STOCK_BUY_PREVIEW_SCHEMA: z.ZodObject<{
|
|
71
|
+
equity_id: z.ZodString;
|
|
72
|
+
venue: z.ZodLiteral<"COINBASE_B20">;
|
|
73
|
+
chain_id: z.ZodLiteral<8453>;
|
|
74
|
+
underlying: z.ZodString;
|
|
75
|
+
symbol: z.ZodString;
|
|
76
|
+
token: z.ZodString;
|
|
77
|
+
asset: z.ZodString;
|
|
78
|
+
amount: z.ZodString;
|
|
79
|
+
expected_tokens: z.ZodString;
|
|
80
|
+
min_tokens: z.ZodString;
|
|
81
|
+
oracle_price: z.ZodString;
|
|
82
|
+
oracle_age_sec: z.ZodNumber;
|
|
83
|
+
parity_premium_bps: z.ZodNumber;
|
|
84
|
+
parity_tolerance_bps: z.ZodLiteral<175>;
|
|
85
|
+
quoted_fees: z.ZodArray<z.ZodObject<{
|
|
86
|
+
name: z.ZodString;
|
|
87
|
+
amount_usd: z.ZodString;
|
|
88
|
+
}, z.core.$strict>>;
|
|
89
|
+
quoted_gas_usd: z.ZodOptional<z.ZodString>;
|
|
90
|
+
}, z.core.$strict>;
|
|
91
|
+
export declare const PREPARE_STOCK_BUY_OUTPUT_SCHEMA: z.ZodObject<{
|
|
92
|
+
envelope: z.ZodObject<{
|
|
93
|
+
schema_version: z.ZodLiteral<"1">;
|
|
94
|
+
artifact_id: z.ZodString;
|
|
95
|
+
rail: z.ZodLiteral<"lifi">;
|
|
96
|
+
operation: z.ZodLiteral<"swap">;
|
|
97
|
+
intent_digest: z.ZodString;
|
|
98
|
+
account_binding: z.ZodObject<{
|
|
99
|
+
kind: z.ZodEnum<{
|
|
100
|
+
eoa: "eoa";
|
|
101
|
+
safe: "safe";
|
|
102
|
+
}>;
|
|
103
|
+
address: z.ZodString;
|
|
104
|
+
chainId: z.ZodNumber;
|
|
105
|
+
protocol_roles: z.ZodObject<{
|
|
106
|
+
lifi: z.ZodObject<{
|
|
107
|
+
sender: z.ZodString;
|
|
108
|
+
receiver: z.ZodString;
|
|
109
|
+
}, z.core.$strict>;
|
|
110
|
+
}, z.core.$strict>;
|
|
111
|
+
}, z.core.$strict>;
|
|
112
|
+
required_capabilities: z.ZodArray<z.ZodEnum<{
|
|
113
|
+
send_evm_transaction: "send_evm_transaction";
|
|
114
|
+
submit_evm_batch: "submit_evm_batch";
|
|
115
|
+
}>>;
|
|
116
|
+
payload: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
117
|
+
kind: z.ZodLiteral<"evm_execution_plan">;
|
|
118
|
+
chain_id: z.ZodNumber;
|
|
119
|
+
steps: z.ZodArray<z.ZodObject<{
|
|
120
|
+
to: z.ZodString;
|
|
121
|
+
value: z.ZodString;
|
|
122
|
+
data: z.ZodString;
|
|
123
|
+
kind: z.ZodEnum<{
|
|
124
|
+
approve: "approve";
|
|
125
|
+
approve_reset: "approve_reset";
|
|
126
|
+
call: "call";
|
|
127
|
+
}>;
|
|
128
|
+
}, z.core.$strict>>;
|
|
129
|
+
}, z.core.$strict>], "kind">;
|
|
130
|
+
fee_attribution: z.ZodObject<{
|
|
131
|
+
mechanism: z.ZodLiteral<"lifi_integrator_fee">;
|
|
132
|
+
config_version: z.ZodString;
|
|
133
|
+
}, z.core.$strict>;
|
|
134
|
+
replay_disclosure: z.ZodObject<{
|
|
135
|
+
artifact_role: z.ZodLiteral<"construction_aid">;
|
|
136
|
+
freshness_boundary: z.ZodLiteral<"valid_until">;
|
|
137
|
+
onchain_replay_boundary: z.ZodLiteral<"signer_account_nonce">;
|
|
138
|
+
tool_guarantees_single_execution: z.ZodLiteral<false>;
|
|
139
|
+
}, z.core.$strict>;
|
|
140
|
+
assertions: z.ZodArray<z.ZodObject<{
|
|
141
|
+
id: z.ZodString;
|
|
142
|
+
result: z.ZodLiteral<"passed">;
|
|
143
|
+
}, z.core.$strict>>;
|
|
144
|
+
valid_until: z.ZodString;
|
|
145
|
+
submission: z.ZodObject<{
|
|
146
|
+
method: z.ZodEnum<{
|
|
147
|
+
send_evm_transaction: "send_evm_transaction";
|
|
148
|
+
submit_evm_batch: "submit_evm_batch";
|
|
149
|
+
}>;
|
|
150
|
+
chain_id: z.ZodNumber;
|
|
151
|
+
artifact_id: z.ZodString;
|
|
152
|
+
payload_digest: z.ZodString;
|
|
153
|
+
artifact_digest: z.ZodString;
|
|
154
|
+
adapter_owned_fields: z.ZodTuple<[z.ZodLiteral<"nonce">, z.ZodLiteral<"gas">, z.ZodLiteral<"serialization">], null>;
|
|
155
|
+
client_ref: z.ZodOptional<z.ZodString>;
|
|
156
|
+
}, z.core.$strict>;
|
|
157
|
+
}, z.core.$strict>;
|
|
158
|
+
prepareInput: z.ZodObject<{
|
|
159
|
+
accountProfile: z.ZodObject<{
|
|
160
|
+
kind: z.ZodEnum<{
|
|
161
|
+
eoa: "eoa";
|
|
162
|
+
safe: "safe";
|
|
163
|
+
}>;
|
|
164
|
+
address: z.ZodString;
|
|
165
|
+
chainId: z.ZodNumber;
|
|
166
|
+
}, z.core.$strict>;
|
|
167
|
+
chainId: z.ZodNumber;
|
|
168
|
+
fromToken: z.ZodString;
|
|
169
|
+
toToken: z.ZodString;
|
|
170
|
+
fromAmount: z.ZodString;
|
|
171
|
+
slippage: z.ZodObject<{
|
|
172
|
+
maxBps: z.ZodNumber;
|
|
173
|
+
minAmountOut: z.ZodOptional<z.ZodString>;
|
|
174
|
+
}, z.core.$strict>;
|
|
175
|
+
client_ref: z.ZodOptional<z.ZodString>;
|
|
176
|
+
}, z.core.$strict>;
|
|
177
|
+
preview: z.ZodObject<{
|
|
178
|
+
equity_id: z.ZodString;
|
|
179
|
+
venue: z.ZodLiteral<"COINBASE_B20">;
|
|
180
|
+
chain_id: z.ZodLiteral<8453>;
|
|
181
|
+
underlying: z.ZodString;
|
|
182
|
+
symbol: z.ZodString;
|
|
183
|
+
token: z.ZodString;
|
|
184
|
+
asset: z.ZodString;
|
|
185
|
+
amount: z.ZodString;
|
|
186
|
+
expected_tokens: z.ZodString;
|
|
187
|
+
min_tokens: z.ZodString;
|
|
188
|
+
oracle_price: z.ZodString;
|
|
189
|
+
oracle_age_sec: z.ZodNumber;
|
|
190
|
+
parity_premium_bps: z.ZodNumber;
|
|
191
|
+
parity_tolerance_bps: z.ZodLiteral<175>;
|
|
192
|
+
quoted_fees: z.ZodArray<z.ZodObject<{
|
|
193
|
+
name: z.ZodString;
|
|
194
|
+
amount_usd: z.ZodString;
|
|
195
|
+
}, z.core.$strict>>;
|
|
196
|
+
quoted_gas_usd: z.ZodOptional<z.ZodString>;
|
|
197
|
+
}, z.core.$strict>;
|
|
198
|
+
registry_commitment: z.ZodString;
|
|
199
|
+
}, z.core.$strict>;
|
|
200
|
+
export type PrepareStockBuyOutput = z.infer<typeof PREPARE_STOCK_BUY_OUTPUT_SCHEMA>;
|
|
201
|
+
/** The one on-chain read this constructor needs: the row's Chainlink feed, price + updatedAt. */
|
|
202
|
+
export interface EquityOracleReader {
|
|
203
|
+
latestRoundData(feed: `0x${string}`): Promise<{
|
|
204
|
+
readonly answer: bigint;
|
|
205
|
+
readonly updatedAt: bigint;
|
|
206
|
+
}>;
|
|
207
|
+
}
|
|
208
|
+
export declare const STOCK_BUY_TOOL_DEFINITION: Readonly<{
|
|
209
|
+
name: "otto_prepare_stock_buy";
|
|
210
|
+
title: "Prepare a tokenized-stock buy (Coinbase B20 on Base) as a delegable swap pair";
|
|
211
|
+
description: "Prepare the EXACT otto_prepare_swap pair (envelope + prepareInput) that buys one of the executable Coinbase B20 tokenized equities on Base with USDC, as a LI.FI route through the fenced diamond whose receiver is the signing account. The token comes from the registry row named by executableEquityId and is never an input; the caller's registryCommitment must equal the commitment recomputed over the current record. The WORST PERMISSIBLE FILL (amount over the route's own floor) is checked against the equity's own Chainlink total-return mark and refused when it exceeds the pinned tolerance, or when the feed is frozen (> 24 h). Returns the pair unchanged plus a preview; never signs or submits — submit the pair through otto_submit_under_delegation under the end user's per-swap cap.";
|
|
212
|
+
inputSchema: z.ZodObject<{
|
|
213
|
+
accountProfile: z.ZodObject<{
|
|
214
|
+
kind: z.ZodEnum<{
|
|
215
|
+
eoa: "eoa";
|
|
216
|
+
safe: "safe";
|
|
217
|
+
}>;
|
|
218
|
+
address: z.ZodString;
|
|
219
|
+
chainId: z.ZodNumber;
|
|
220
|
+
}, z.core.$strict>;
|
|
221
|
+
executableEquityId: z.ZodString;
|
|
222
|
+
registryCommitment: z.ZodString;
|
|
223
|
+
amount: z.ZodString;
|
|
224
|
+
slippage: z.ZodObject<{
|
|
225
|
+
maxBps: z.ZodNumber;
|
|
226
|
+
}, z.core.$strict>;
|
|
227
|
+
client_ref: z.ZodOptional<z.ZodString>;
|
|
228
|
+
}, z.core.$strict>;
|
|
229
|
+
outputSchema: z.ZodObject<{
|
|
230
|
+
envelope: z.ZodObject<{
|
|
231
|
+
schema_version: z.ZodLiteral<"1">;
|
|
232
|
+
artifact_id: z.ZodString;
|
|
233
|
+
rail: z.ZodLiteral<"lifi">;
|
|
234
|
+
operation: z.ZodLiteral<"swap">;
|
|
235
|
+
intent_digest: z.ZodString;
|
|
236
|
+
account_binding: z.ZodObject<{
|
|
237
|
+
kind: z.ZodEnum<{
|
|
238
|
+
eoa: "eoa";
|
|
239
|
+
safe: "safe";
|
|
240
|
+
}>;
|
|
241
|
+
address: z.ZodString;
|
|
242
|
+
chainId: z.ZodNumber;
|
|
243
|
+
protocol_roles: z.ZodObject<{
|
|
244
|
+
lifi: z.ZodObject<{
|
|
245
|
+
sender: z.ZodString;
|
|
246
|
+
receiver: z.ZodString;
|
|
247
|
+
}, z.core.$strict>;
|
|
248
|
+
}, z.core.$strict>;
|
|
249
|
+
}, z.core.$strict>;
|
|
250
|
+
required_capabilities: z.ZodArray<z.ZodEnum<{
|
|
251
|
+
send_evm_transaction: "send_evm_transaction";
|
|
252
|
+
submit_evm_batch: "submit_evm_batch";
|
|
253
|
+
}>>;
|
|
254
|
+
payload: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
255
|
+
kind: z.ZodLiteral<"evm_execution_plan">;
|
|
256
|
+
chain_id: z.ZodNumber;
|
|
257
|
+
steps: z.ZodArray<z.ZodObject<{
|
|
258
|
+
to: z.ZodString;
|
|
259
|
+
value: z.ZodString;
|
|
260
|
+
data: z.ZodString;
|
|
261
|
+
kind: z.ZodEnum<{
|
|
262
|
+
approve: "approve";
|
|
263
|
+
approve_reset: "approve_reset";
|
|
264
|
+
call: "call";
|
|
265
|
+
}>;
|
|
266
|
+
}, z.core.$strict>>;
|
|
267
|
+
}, z.core.$strict>], "kind">;
|
|
268
|
+
fee_attribution: z.ZodObject<{
|
|
269
|
+
mechanism: z.ZodLiteral<"lifi_integrator_fee">;
|
|
270
|
+
config_version: z.ZodString;
|
|
271
|
+
}, z.core.$strict>;
|
|
272
|
+
replay_disclosure: z.ZodObject<{
|
|
273
|
+
artifact_role: z.ZodLiteral<"construction_aid">;
|
|
274
|
+
freshness_boundary: z.ZodLiteral<"valid_until">;
|
|
275
|
+
onchain_replay_boundary: z.ZodLiteral<"signer_account_nonce">;
|
|
276
|
+
tool_guarantees_single_execution: z.ZodLiteral<false>;
|
|
277
|
+
}, z.core.$strict>;
|
|
278
|
+
assertions: z.ZodArray<z.ZodObject<{
|
|
279
|
+
id: z.ZodString;
|
|
280
|
+
result: z.ZodLiteral<"passed">;
|
|
281
|
+
}, z.core.$strict>>;
|
|
282
|
+
valid_until: z.ZodString;
|
|
283
|
+
submission: z.ZodObject<{
|
|
284
|
+
method: z.ZodEnum<{
|
|
285
|
+
send_evm_transaction: "send_evm_transaction";
|
|
286
|
+
submit_evm_batch: "submit_evm_batch";
|
|
287
|
+
}>;
|
|
288
|
+
chain_id: z.ZodNumber;
|
|
289
|
+
artifact_id: z.ZodString;
|
|
290
|
+
payload_digest: z.ZodString;
|
|
291
|
+
artifact_digest: z.ZodString;
|
|
292
|
+
adapter_owned_fields: z.ZodTuple<[z.ZodLiteral<"nonce">, z.ZodLiteral<"gas">, z.ZodLiteral<"serialization">], null>;
|
|
293
|
+
client_ref: z.ZodOptional<z.ZodString>;
|
|
294
|
+
}, z.core.$strict>;
|
|
295
|
+
}, z.core.$strict>;
|
|
296
|
+
prepareInput: z.ZodObject<{
|
|
297
|
+
accountProfile: z.ZodObject<{
|
|
298
|
+
kind: z.ZodEnum<{
|
|
299
|
+
eoa: "eoa";
|
|
300
|
+
safe: "safe";
|
|
301
|
+
}>;
|
|
302
|
+
address: z.ZodString;
|
|
303
|
+
chainId: z.ZodNumber;
|
|
304
|
+
}, z.core.$strict>;
|
|
305
|
+
chainId: z.ZodNumber;
|
|
306
|
+
fromToken: z.ZodString;
|
|
307
|
+
toToken: z.ZodString;
|
|
308
|
+
fromAmount: z.ZodString;
|
|
309
|
+
slippage: z.ZodObject<{
|
|
310
|
+
maxBps: z.ZodNumber;
|
|
311
|
+
minAmountOut: z.ZodOptional<z.ZodString>;
|
|
312
|
+
}, z.core.$strict>;
|
|
313
|
+
client_ref: z.ZodOptional<z.ZodString>;
|
|
314
|
+
}, z.core.$strict>;
|
|
315
|
+
preview: z.ZodObject<{
|
|
316
|
+
equity_id: z.ZodString;
|
|
317
|
+
venue: z.ZodLiteral<"COINBASE_B20">;
|
|
318
|
+
chain_id: z.ZodLiteral<8453>;
|
|
319
|
+
underlying: z.ZodString;
|
|
320
|
+
symbol: z.ZodString;
|
|
321
|
+
token: z.ZodString;
|
|
322
|
+
asset: z.ZodString;
|
|
323
|
+
amount: z.ZodString;
|
|
324
|
+
expected_tokens: z.ZodString;
|
|
325
|
+
min_tokens: z.ZodString;
|
|
326
|
+
oracle_price: z.ZodString;
|
|
327
|
+
oracle_age_sec: z.ZodNumber;
|
|
328
|
+
parity_premium_bps: z.ZodNumber;
|
|
329
|
+
parity_tolerance_bps: z.ZodLiteral<175>;
|
|
330
|
+
quoted_fees: z.ZodArray<z.ZodObject<{
|
|
331
|
+
name: z.ZodString;
|
|
332
|
+
amount_usd: z.ZodString;
|
|
333
|
+
}, z.core.$strict>>;
|
|
334
|
+
quoted_gas_usd: z.ZodOptional<z.ZodString>;
|
|
335
|
+
}, z.core.$strict>;
|
|
336
|
+
registry_commitment: z.ZodString;
|
|
337
|
+
}, z.core.$strict>;
|
|
338
|
+
}>;
|