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.
Files changed (239) hide show
  1. package/README.md +76 -18
  2. package/dist/account-userop-policy-definition.d.ts +14 -0
  3. package/dist/account-userop-policy-definition.js +12 -0
  4. package/dist/account-userop-policy-relation.d.ts +371 -0
  5. package/dist/account-userop-policy-relation.js +87 -0
  6. package/dist/adapter/cdp-signer.d.ts +76 -9
  7. package/dist/adapter/cdp-signer.js +274 -33
  8. package/dist/adapter/evm-call-failure.d.ts +29 -0
  9. package/dist/adapter/evm-call-failure.js +109 -0
  10. package/dist/adapter/refusal.d.ts +1 -1
  11. package/dist/adapter/refusal.js +13 -0
  12. package/dist/adapter/route-simulator.d.ts +91 -0
  13. package/dist/adapter/route-simulator.js +143 -0
  14. package/dist/adapter-cdp-index.d.ts +1 -1
  15. package/dist/executable-equities.d.ts +55 -0
  16. package/dist/executable-equities.js +116 -0
  17. package/dist/executable-yield-markets.d.ts +261 -0
  18. package/dist/executable-yield-markets.js +154 -0
  19. package/dist/execution-account-gas-quote.d.ts +141 -0
  20. package/dist/execution-account-gas-quote.js +443 -0
  21. package/dist/execution-account-gas-review.d.ts +123 -0
  22. package/dist/execution-account-gas-review.js +104 -0
  23. package/dist/execution-account-gas-runtime.d.ts +33 -0
  24. package/dist/execution-account-gas-runtime.js +131 -0
  25. package/dist/execution-account-gas-view.d.ts +936 -0
  26. package/dist/execution-account-gas-view.js +56 -0
  27. package/dist/execution-config.d.ts +3 -0
  28. package/dist/execution-config.js +4 -0
  29. package/dist/execution-delegated-definition.d.ts +7 -6
  30. package/dist/execution-delegated-definition.js +13 -2
  31. package/dist/execution-delegation-admin-definition.d.ts +127 -5
  32. package/dist/execution-delegation-admin-definition.js +155 -5
  33. package/dist/execution-delegation-admin.d.ts +48 -2
  34. package/dist/execution-delegation-admin.js +422 -12
  35. package/dist/execution-delegation-cap-store.d.ts +386 -0
  36. package/dist/execution-delegation-cap-store.js +1150 -0
  37. package/dist/execution-delegation-exit-definition.d.ts +309 -0
  38. package/dist/execution-delegation-exit-definition.js +204 -0
  39. package/dist/execution-delegation-exit-store.d.ts +114 -0
  40. package/dist/execution-delegation-exit-store.js +671 -0
  41. package/dist/execution-delegation-exit.d.ts +4 -0
  42. package/dist/execution-delegation-exit.js +614 -0
  43. package/dist/execution-delegation-finality.d.ts +22 -0
  44. package/dist/execution-delegation-finality.js +90 -0
  45. package/dist/execution-delegation-operation-store.d.ts +129 -0
  46. package/dist/execution-delegation-operation-store.js +1107 -0
  47. package/dist/execution-delegation-operations-definition.d.ts +282 -0
  48. package/dist/execution-delegation-operations-definition.js +117 -0
  49. package/dist/execution-delegation-operations.d.ts +6 -0
  50. package/dist/execution-delegation-operations.js +282 -0
  51. package/dist/execution-delegation-policy.d.ts +154 -8
  52. package/dist/execution-delegation-policy.js +273 -40
  53. package/dist/execution-delegation.d.ts +51 -0
  54. package/dist/execution-delegation.js +441 -31
  55. package/dist/execution-errors.d.ts +1 -1
  56. package/dist/execution-errors.js +122 -0
  57. package/dist/execution-index.d.ts +7 -2
  58. package/dist/execution-index.js +7 -2
  59. package/dist/execution-journal-schema.d.ts +96 -0
  60. package/dist/execution-journal-schema.js +368 -0
  61. package/dist/execution-journal-tables.d.ts +14 -0
  62. package/dist/execution-journal-tables.js +227 -0
  63. package/dist/execution-policy-compatibility.d.ts +34 -0
  64. package/dist/execution-policy-compatibility.js +76 -0
  65. package/dist/execution-registration.d.ts +54 -2
  66. package/dist/execution-registration.js +151 -5
  67. package/dist/execution-sponsored-account-profile.d.ts +32 -0
  68. package/dist/execution-sponsored-account-profile.js +59 -0
  69. package/dist/execution-sponsored-account.d.ts +1519 -0
  70. package/dist/execution-sponsored-account.js +222 -0
  71. package/dist/execution-sponsored-definition.d.ts +1713 -0
  72. package/dist/execution-sponsored-definition.js +185 -0
  73. package/dist/execution-sponsored-gas-policy.d.ts +27 -0
  74. package/dist/execution-sponsored-gas-policy.js +110 -0
  75. package/dist/execution-sponsored-hosted.d.ts +3 -0
  76. package/dist/execution-sponsored-hosted.js +71 -0
  77. package/dist/execution-sponsored-index.d.ts +1322 -0
  78. package/dist/execution-sponsored-index.js +102 -0
  79. package/dist/execution-sponsored-mcp-definition.d.ts +1662 -0
  80. package/dist/execution-sponsored-mcp-definition.js +94 -0
  81. package/dist/execution-sponsored-receipt.d.ts +47 -0
  82. package/dist/execution-sponsored-receipt.js +74 -0
  83. package/dist/execution-sponsored-registration.d.ts +14 -0
  84. package/dist/execution-sponsored-registration.js +77 -0
  85. package/dist/execution-sponsored-runtime.d.ts +84 -0
  86. package/dist/execution-sponsored-runtime.js +149 -0
  87. package/dist/execution-sponsored-settlement.d.ts +15 -0
  88. package/dist/execution-sponsored-settlement.js +88 -0
  89. package/dist/execution-sponsored-store.d.ts +67 -0
  90. package/dist/execution-sponsored-store.js +517 -0
  91. package/dist/execution-sponsored-transport.d.ts +90 -0
  92. package/dist/execution-sponsored-transport.js +180 -0
  93. package/dist/execution-tool-definitions.d.ts +21 -21
  94. package/dist/execution-tool-definitions.js +0 -7
  95. package/dist/execution-tools.d.ts +53 -1
  96. package/dist/execution-tools.js +171 -13
  97. package/dist/execution-worker-guard.d.ts +28 -0
  98. package/dist/execution-worker-guard.js +124 -0
  99. package/dist/hybrid-yield-index.d.ts +10 -0
  100. package/dist/hybrid-yield-index.js +11 -0
  101. package/dist/hybrid-yield-markets.d.ts +96 -0
  102. package/dist/hybrid-yield-markets.js +124 -0
  103. package/dist/hybrid-yield.d.ts +411 -0
  104. package/dist/hybrid-yield.js +155 -0
  105. package/dist/hyperliquid-order-builder.js +4 -0
  106. package/dist/lifi-execution-client.d.ts +6 -0
  107. package/dist/lifi-execution-client.js +3 -0
  108. package/dist/lp-userop-account.d.ts +461 -0
  109. package/dist/lp-userop-account.js +417 -0
  110. package/dist/lp-userop-authority.d.ts +49 -0
  111. package/dist/lp-userop-authority.js +211 -0
  112. package/dist/lp-userop-definition.d.ts +233 -0
  113. package/dist/lp-userop-definition.js +85 -0
  114. package/dist/lp-userop-hosted.d.ts +3 -0
  115. package/dist/lp-userop-hosted.js +73 -0
  116. package/dist/lp-userop-index.d.ts +1569 -0
  117. package/dist/lp-userop-index.js +112 -0
  118. package/dist/lp-userop-mcp-definition.d.ts +1220 -0
  119. package/dist/lp-userop-mcp-definition.js +46 -0
  120. package/dist/lp-userop-operation.d.ts +1230 -0
  121. package/dist/lp-userop-operation.js +140 -0
  122. package/dist/lp-userop-registration.d.ts +14 -0
  123. package/dist/lp-userop-registration.js +70 -0
  124. package/dist/lp-userop-settlement.d.ts +89 -0
  125. package/dist/lp-userop-settlement.js +184 -0
  126. package/dist/lp-userop.d.ts +643 -0
  127. package/dist/lp-userop.js +343 -0
  128. package/dist/native-yield-account-definition.d.ts +1192 -0
  129. package/dist/native-yield-account-definition.js +232 -0
  130. package/dist/native-yield-account-gas.d.ts +58 -0
  131. package/dist/native-yield-account-gas.js +228 -0
  132. package/dist/native-yield-account-index.d.ts +23 -0
  133. package/dist/native-yield-account-index.js +28 -0
  134. package/dist/native-yield-account-policy.d.ts +168 -0
  135. package/dist/native-yield-account-policy.js +525 -0
  136. package/dist/native-yield-account-rpc.d.ts +8 -0
  137. package/dist/native-yield-account-rpc.js +128 -0
  138. package/dist/native-yield-account-runtime.d.ts +71 -0
  139. package/dist/native-yield-account-runtime.js +125 -0
  140. package/dist/native-yield-account-store.d.ts +40 -0
  141. package/dist/native-yield-account-store.js +307 -0
  142. package/dist/native-yield-account.d.ts +662 -0
  143. package/dist/native-yield-account.js +371 -0
  144. package/dist/native-yield-consent-store.d.ts +20 -0
  145. package/dist/native-yield-consent-store.js +317 -0
  146. package/dist/native-yield-definition.d.ts +288 -0
  147. package/dist/native-yield-definition.js +105 -0
  148. package/dist/native-yield-reader.d.ts +4 -0
  149. package/dist/native-yield-reader.js +137 -0
  150. package/dist/native-yield-settlement.d.ts +48 -0
  151. package/dist/native-yield-settlement.js +167 -0
  152. package/dist/native-yield-simulation.d.ts +18 -0
  153. package/dist/native-yield-simulation.js +45 -0
  154. package/dist/native-yield-userop-account.d.ts +675 -0
  155. package/dist/native-yield-userop-account.js +357 -0
  156. package/dist/native-yield-userop-authority.d.ts +214 -0
  157. package/dist/native-yield-userop-authority.js +296 -0
  158. package/dist/native-yield-userop-definition.d.ts +331 -0
  159. package/dist/native-yield-userop-definition.js +105 -0
  160. package/dist/native-yield-userop-hosted.d.ts +3 -0
  161. package/dist/native-yield-userop-hosted.js +71 -0
  162. package/dist/native-yield-userop-index.d.ts +1522 -0
  163. package/dist/native-yield-userop-index.js +142 -0
  164. package/dist/native-yield-userop-mcp-definition.d.ts +1356 -0
  165. package/dist/native-yield-userop-mcp-definition.js +50 -0
  166. package/dist/native-yield-userop-operation.d.ts +845 -0
  167. package/dist/native-yield-userop-operation.js +127 -0
  168. package/dist/native-yield-userop-policy.d.ts +23 -0
  169. package/dist/native-yield-userop-policy.js +25 -0
  170. package/dist/native-yield-userop-registration.d.ts +17 -0
  171. package/dist/native-yield-userop-registration.js +76 -0
  172. package/dist/native-yield-userop-settlement.d.ts +8 -0
  173. package/dist/native-yield-userop-settlement.js +79 -0
  174. package/dist/native-yield-userop-simulation.d.ts +18 -0
  175. package/dist/native-yield-userop-simulation.js +34 -0
  176. package/dist/native-yield-userop.d.ts +35 -0
  177. package/dist/native-yield-userop.js +156 -0
  178. package/dist/native-yield-verify.d.ts +30 -0
  179. package/dist/native-yield-verify.js +141 -0
  180. package/dist/native-yield.d.ts +17 -0
  181. package/dist/native-yield.js +119 -0
  182. package/dist/stdio-main.js +0 -0
  183. package/dist/stock-buy-definition.d.ts +338 -0
  184. package/dist/stock-buy-definition.js +127 -0
  185. package/dist/stock-buy-oracle.d.ts +8 -0
  186. package/dist/stock-buy-oracle.js +22 -0
  187. package/dist/stock-buy.d.ts +17 -0
  188. package/dist/stock-buy.js +164 -0
  189. package/dist/tool-definitions.d.ts +3 -1
  190. package/dist/tool-definitions.js +55 -2
  191. package/dist/vendor/lp-v3/lp-v3-atomic-contract.d.ts +445 -0
  192. package/dist/vendor/lp-v3/lp-v3-atomic-contract.js +90 -0
  193. package/dist/vendor/lp-v3/lp-v3-atomic-evidence.d.ts +14 -0
  194. package/dist/vendor/lp-v3/lp-v3-atomic-evidence.js +82 -0
  195. package/dist/vendor/lp-v3/lp-v3-atomic-index.d.ts +80 -0
  196. package/dist/vendor/lp-v3/lp-v3-atomic-index.js +19 -0
  197. package/dist/vendor/lp-v3/lp-v3-atomic-plan.d.ts +43 -0
  198. package/dist/vendor/lp-v3/lp-v3-atomic-plan.js +112 -0
  199. package/dist/vendor/lp-v3/lp-v3-atomic-read-contract.d.ts +312 -0
  200. package/dist/vendor/lp-v3/lp-v3-atomic-read-contract.js +41 -0
  201. package/dist/vendor/lp-v3/lp-v3-atomic-read-index.d.ts +3 -0
  202. package/dist/vendor/lp-v3/lp-v3-atomic-read-index.js +3 -0
  203. package/dist/vendor/lp-v3/lp-v3-atomic-read-rpc.d.ts +49 -0
  204. package/dist/vendor/lp-v3/lp-v3-atomic-read-rpc.js +88 -0
  205. package/dist/vendor/lp-v3/lp-v3-atomic-read.d.ts +17 -0
  206. package/dist/vendor/lp-v3/lp-v3-atomic-read.js +232 -0
  207. package/dist/vendor/lp-v3/lp-v3-atomic-settlement.d.ts +105 -0
  208. package/dist/vendor/lp-v3/lp-v3-atomic-settlement.js +162 -0
  209. package/dist/vendor/lp-v3/lp-v3-collect-protocol-contract.d.ts +606 -0
  210. package/dist/vendor/lp-v3/lp-v3-collect-protocol-contract.js +59 -0
  211. package/dist/vendor/lp-v3/lp-v3-collect-protocol-index.d.ts +168 -0
  212. package/dist/vendor/lp-v3/lp-v3-collect-protocol-index.js +23 -0
  213. package/dist/vendor/lp-v3/lp-v3-collect-protocol-observation.d.ts +32 -0
  214. package/dist/vendor/lp-v3/lp-v3-collect-protocol-observation.js +228 -0
  215. package/dist/vendor/lp-v3/lp-v3-collect-protocol-plan.d.ts +11 -0
  216. package/dist/vendor/lp-v3/lp-v3-collect-protocol-plan.js +91 -0
  217. package/dist/vendor/lp-v3/lp-v3-collect-protocol-reconcile.d.ts +9 -0
  218. package/dist/vendor/lp-v3/lp-v3-collect-protocol-reconcile.js +124 -0
  219. package/dist/vendor/lp-v3/lp-v3-contract.d.ts +538 -0
  220. package/dist/vendor/lp-v3/lp-v3-contract.js +137 -0
  221. package/dist/vendor/lp-v3/lp-v3-evidence.d.ts +25 -0
  222. package/dist/vendor/lp-v3/lp-v3-evidence.js +168 -0
  223. package/dist/vendor/lp-v3/lp-v3-plan.d.ts +22 -0
  224. package/dist/vendor/lp-v3/lp-v3-plan.js +135 -0
  225. package/dist/vendor/lp-v3/types.d.ts +131 -0
  226. package/dist/vendor/lp-v3/types.js +6 -0
  227. package/dist/vendor/lp-v3/v4-math.d.ts +18 -0
  228. package/dist/vendor/lp-v3/v4-math.js +90 -0
  229. package/dist/yield-deposit-definition.d.ts +374 -0
  230. package/dist/yield-deposit-definition.js +123 -0
  231. package/dist/yield-deposit.d.ts +16 -0
  232. package/dist/yield-deposit.js +149 -0
  233. package/dist/yield-route-semantics.d.ts +27 -0
  234. package/dist/yield-route-semantics.js +71 -0
  235. package/dist/yield-withdraw-definition.d.ts +357 -0
  236. package/dist/yield-withdraw-definition.js +90 -0
  237. package/dist/yield-withdraw.d.ts +11 -0
  238. package/dist/yield-withdraw.js +122 -0
  239. package/package.json +239 -7
@@ -0,0 +1,56 @@
1
+ /** Public fee terms keep the user's estimate separate from Otto's sponsorship budgets. */
2
+ import { z } from 'zod';
3
+ import { ACCOUNT_GAS_REVIEW_SCHEMA } from './execution-account-gas-review.js';
4
+ export const ACCOUNT_GAS_FAILURE_CODES = [
5
+ 'ACCOUNT_GAS_REVIEW_REQUIRED', 'ACCOUNT_GAS_REVIEW_CHANGED', 'ACCOUNT_GAS_REVIEW_STALE',
6
+ 'ACCOUNT_GAS_REVIEW_UNAVAILABLE', 'ACCOUNT_GAS_REVIEW_INVALID', 'ACCOUNT_GAS_FUNDING_REQUIRED',
7
+ 'ACCOUNT_GAS_SPONSOR_INELIGIBLE', 'ACCOUNT_GAS_QUOTE_UNAVAILABLE',
8
+ ];
9
+ export const ACCOUNT_GAS_FAILURE_SCHEMA = z.enum(ACCOUNT_GAS_FAILURE_CODES);
10
+ /** Closed codes only; provider payloads and URLs are never exposed. */
11
+ export function accountGasFailure(error) {
12
+ if (!(error instanceof Error))
13
+ return undefined;
14
+ const code = 'code' in error ? error.code : error.message;
15
+ if (['SPONSOR_GAS_POLICY_UNAVAILABLE', 'SPONSOR_GAS_POLICY_INVALID', 'SPONSOR_GAS_POLICY_INACTIVE', 'SPONSOR_GAS_POLICY_STALE'].includes(String(code)))
16
+ return 'ACCOUNT_GAS_REVIEW_UNAVAILABLE';
17
+ const parsed = ACCOUNT_GAS_FAILURE_SCHEMA.safeParse(code);
18
+ return parsed.success ? parsed.data : undefined;
19
+ }
20
+ /** Emitted only before a claim when the affirmative payer statement differs from the owned review. */
21
+ export class AccountGasConfirmationRefusal extends Error {
22
+ code = 'ACCOUNT_GAS_REVIEW_CHANGED';
23
+ constructor() { super('ACCOUNT_GAS_REVIEW_CHANGED'); this.name = 'AccountGasConfirmationRefusal'; }
24
+ }
25
+ const uint = z.string().regex(/^(0|[1-9][0-9]*)$/).refine(value => /^(0|[1-9][0-9]*)$/.test(value) && BigInt(value) < 2n ** 256n);
26
+ const positive = uint.refine(value => /^(0|[1-9][0-9]*)$/.test(value) && BigInt(value) > 0n);
27
+ function publicGasParts(amount) {
28
+ const common = { actualCostWei: amount.optional(), reviewRequired: z.literal(true).optional(), reviewFailure: ACCOUNT_GAS_FAILURE_SCHEMA.optional() };
29
+ const sponsor = { ...common, payer: z.literal('sponsor'), paymentReview: ACCOUNT_GAS_REVIEW_SCHEMA.refine(review => review.payer === 'sponsor').optional(),
30
+ maximumCostWei: amount, activationChainHalted: z.literal(true).optional() };
31
+ const account = z.object({ ...common, payer: z.literal('account'), paymentReview: ACCOUNT_GAS_REVIEW_SCHEMA.refine(review => review.payer === 'account') }).strict();
32
+ return { sponsor, account };
33
+ }
34
+ export function accountGasPublicSchema(amount) {
35
+ const { sponsor, account } = publicGasParts(amount);
36
+ return z.discriminatedUnion('payer', [z.object(sponsor).strict(), account]);
37
+ }
38
+ export function accountGasBudgetPublicSchema(amount) {
39
+ const { sponsor, account } = publicGasParts(amount);
40
+ return z.discriminatedUnion('payer', [z.object({ ...sponsor, maximumUserCostWei: amount, maximumActivationCostWei: amount }).strict(), account]);
41
+ }
42
+ export const ACCOUNT_GAS_PUBLIC_SCHEMA = accountGasPublicSchema(positive);
43
+ export function accountGasViewMatches(value) {
44
+ const review = value.gas.paymentReview;
45
+ return !review || (review.payer === value.gas.payer && review.quote.account.toLowerCase() === value.account.toLowerCase() && review.quote.chainId === value.chainId);
46
+ }
47
+ export function accountGasView(operation, budgets) {
48
+ const common = { ...(operation.context.activation.gasPaymentReviewEnabled ? { reviewRequired: true } : {}),
49
+ ...(operation.gasReviewFailure ? { reviewFailure: operation.gasReviewFailure } : {}),
50
+ ...(operation.receipt ? { actualCostWei: operation.receipt.actualGasCostWei } : {}) };
51
+ if (operation.gasReview?.payer === 'account')
52
+ return { ...common, payer: 'account', paymentReview: operation.gasReview };
53
+ return { ...common, payer: 'sponsor', ...(operation.gasReview ? { paymentReview: operation.gasReview } : {}),
54
+ ...budgets, ...(operation.gasCapBreach ? { actualCostWei: operation.gasCapBreach.actualGasCostWei, activationChainHalted: true } : {}) };
55
+ }
56
+ //# sourceMappingURL=execution-account-gas-view.js.map
@@ -22,6 +22,9 @@ export declare const LIFI_DIAMOND_ADDRESS: `0x${string}`;
22
22
  * (EXSC-737) (#2226)"), `src/Periphery/FeeForwarder.sol` `@custom:version 2.0.0`; 3037 bytes,
23
23
  * byte-identical on Base and Arbitrum (CREATE2); same `collectTokenFees` selector; live legs
24
24
  * carry unchanged distributions (LI.FI platform + Otto). Reviewed 2026-08-26.
25
+ * - Optimism (10), v2 only: reviewed 2026-09-11 against official deployment commit
26
+ * 58d815734effc6e7878a43279f01933fb9cf1847, exact on-chain code and a decoded live fee leg.
27
+ * Evidence: docs/0911_optimism_lifi_evidence.md. This does not expand the CCTP route set.
25
28
  *
26
29
  * Adding a deployment here is a REVIEW, not a config edit: confirm the registry entry, read the
27
30
  * bytecode, decode one live leg's distributions, then add — never widen to a pattern.
@@ -23,6 +23,9 @@ export const LIFI_DIAMOND_ADDRESS = getAddress('0x1231DEB6f5749EF6cE6943a275A1D3
23
23
  * (EXSC-737) (#2226)"), `src/Periphery/FeeForwarder.sol` `@custom:version 2.0.0`; 3037 bytes,
24
24
  * byte-identical on Base and Arbitrum (CREATE2); same `collectTokenFees` selector; live legs
25
25
  * carry unchanged distributions (LI.FI platform + Otto). Reviewed 2026-08-26.
26
+ * - Optimism (10), v2 only: reviewed 2026-09-11 against official deployment commit
27
+ * 58d815734effc6e7878a43279f01933fb9cf1847, exact on-chain code and a decoded live fee leg.
28
+ * Evidence: docs/0911_optimism_lifi_evidence.md. This does not expand the CCTP route set.
26
29
  *
27
30
  * Adding a deployment here is a REVIEW, not a config edit: confirm the registry entry, read the
28
31
  * bytecode, decode one live leg's distributions, then add — never widen to a pattern.
@@ -32,6 +35,7 @@ export const LIFI_FEE_FORWARDER_V1 = getAddress('0xC18D9E84b8687A2645447A61e52c4
32
35
  export const LIFI_FEE_FORWARDER_V2 = getAddress('0xCE40449B773a3E6E5e769ADb4e567179d4828cbd');
33
36
  export const LIFI_FEE_FORWARDERS_BY_CHAIN = Object.freeze({
34
37
  1: Object.freeze([LIFI_FEE_FORWARDER_V1_MAINNET, LIFI_FEE_FORWARDER_V2]),
38
+ 10: Object.freeze([LIFI_FEE_FORWARDER_V2]),
35
39
  56: Object.freeze([LIFI_FEE_FORWARDER_V1, LIFI_FEE_FORWARDER_V2]),
36
40
  137: Object.freeze([LIFI_FEE_FORWARDER_V1, LIFI_FEE_FORWARDER_V2]),
37
41
  8453: Object.freeze([LIFI_FEE_FORWARDER_V1, LIFI_FEE_FORWARDER_V2]),
@@ -18,8 +18,8 @@ export declare const SUBMIT_UNDER_DELEGATION_INPUT_SCHEMA: z.ZodObject<{
18
18
  intent_digest: z.ZodString;
19
19
  account_binding: z.ZodObject<{
20
20
  kind: z.ZodEnum<{
21
- safe: "safe";
22
21
  eoa: "eoa";
22
+ safe: "safe";
23
23
  }>;
24
24
  address: z.ZodString;
25
25
  chainId: z.ZodNumber;
@@ -42,9 +42,9 @@ export declare const SUBMIT_UNDER_DELEGATION_INPUT_SCHEMA: z.ZodObject<{
42
42
  value: z.ZodString;
43
43
  data: z.ZodString;
44
44
  kind: z.ZodEnum<{
45
- call: "call";
46
- approve_reset: "approve_reset";
47
45
  approve: "approve";
46
+ approve_reset: "approve_reset";
47
+ call: "call";
48
48
  }>;
49
49
  }, z.core.$strict>>;
50
50
  }, z.core.$strict>], "kind">;
@@ -79,8 +79,8 @@ export declare const SUBMIT_UNDER_DELEGATION_INPUT_SCHEMA: z.ZodObject<{
79
79
  prepareInput: z.ZodObject<{
80
80
  accountProfile: z.ZodObject<{
81
81
  kind: z.ZodEnum<{
82
- safe: "safe";
83
82
  eoa: "eoa";
83
+ safe: "safe";
84
84
  }>;
85
85
  address: z.ZodString;
86
86
  chainId: z.ZodNumber;
@@ -114,9 +114,9 @@ export declare const DELEGATED_SEND_RESULT_SCHEMA: z.ZodObject<{
114
114
  steps: z.ZodArray<z.ZodObject<{
115
115
  index: z.ZodNumber;
116
116
  kind: z.ZodEnum<{
117
- call: "call";
118
- approve_reset: "approve_reset";
119
117
  approve: "approve";
118
+ approve_reset: "approve_reset";
119
+ call: "call";
120
120
  }>;
121
121
  to: z.ZodString;
122
122
  transaction_hash: z.ZodString;
@@ -129,6 +129,7 @@ export declare const DELEGATED_SEND_RESULT_SCHEMA: z.ZodObject<{
129
129
  policy_name: z.ZodString;
130
130
  rules_digest: z.ZodString;
131
131
  per_swap_cap_usd: z.ZodLiteral<5000>;
132
+ user_cap_usd: z.ZodNumber;
132
133
  }, z.core.$strict>;
133
134
  delegation: z.ZodObject<{
134
135
  expires_at: z.ZodString;
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { z } from 'zod';
8
8
  import { EXECUTION_ENVELOPE_SCHEMA, PREPARE_SWAP_INPUT_SCHEMA, } from './execution-tool-definitions.js';
9
- import { MODEL_B_PER_SWAP_CAP_USD } from './execution-delegation-policy.js';
9
+ import { MODEL_B_PER_SWAP_CAP_MIN_USD, MODEL_B_PER_SWAP_CAP_USD, } from './execution-delegation-policy.js';
10
10
  export const DELEGATED_EXECUTION_TOOL_NAME = 'otto_submit_under_delegation';
11
11
  /** Per-request caller authentication rides THIS header — never a tool argument (arguments are logged). */
12
12
  export const DELEGATION_AUTH_HEADER = 'x-otto-delegation-auth';
@@ -78,7 +78,18 @@ export const DELEGATED_SEND_RESULT_SCHEMA = z
78
78
  policy_id: z.string(),
79
79
  policy_name: z.string(),
80
80
  rules_digest: z.string().regex(/^[0-9a-f]{64}$/),
81
+ /** The ENGINE's ceiling — the constant in the one shared project policy. Still a literal. */
81
82
  per_swap_cap_usd: z.literal(MODEL_B_PER_SWAP_CAP_USD),
83
+ /**
84
+ * The cap THIS person chose when they minted, enforced by Otto's server on top of the ceiling.
85
+ * A bounded integer rather than a literal, because it is the whole point that it can be lower —
86
+ * but it can never exceed the ceiling, and that bound is here rather than left to the caller.
87
+ */
88
+ user_cap_usd: z
89
+ .number()
90
+ .int()
91
+ .min(MODEL_B_PER_SWAP_CAP_MIN_USD)
92
+ .max(MODEL_B_PER_SWAP_CAP_USD),
82
93
  })
83
94
  .strict(),
84
95
  delegation: z.object({ expires_at: z.string() }).strict(),
@@ -108,7 +119,7 @@ export const DELEGATED_TOOL_ANNOTATIONS = Object.freeze({
108
119
  export const DELEGATED_EXECUTION_TOOL_DEFINITION = Object.freeze({
109
120
  name: DELEGATED_EXECUTION_TOOL_NAME,
110
121
  title: 'Submit an Otto-prepared swap under a CDP end-user delegation',
111
- description: `Submit a verified otto_prepare_swap envelope on Base under the end user's CDP delegation. Arguments: { userId, envelope (the otto_prepare_swap result), prepareInput (the exact otto_prepare_swap request, with slippage.minAmountOut) } — validated strictly AFTER the caller is authenticated, so the listed input schema is intentionally permissive. Server-to-server only: the caller presents Otto's delegation secret in the \`${DELEGATION_AUTH_HEADER}\` request header (never in arguments); a call without it is refused before anything is read. Before any send the server confirms, in this order: the Model-B project policy is installed and reads back by name and rules digest; the user's grant is active past the envelope's valid_until; the account is one of that end user's own CDP accounts as CDP reports them; the envelope passes the 13-check verifier for exactly the request that produced it; the plan is inside the fence (allow-listed input token, reviewed spender, gross at or below the ${MODEL_B_PER_SWAP_CAP_USD} USD per-swap cap). Then the three steps (allowance reset, approval, swap) are submitted in order under the delegation, each waited to a sealed canonical block; a halt clears the allowance and reports the read-back. One delegated plan at a time per user. Coinbase's engine bounds the delegated key to Model-B swap shapes through LI.FI up to the per-swap cap; the receiver binding is Otto's server-side check, and the user can revoke at any time.`,
122
+ description: `Submit a verified otto_prepare_swap envelope on Base under the end user's CDP delegation. Arguments: { userId, envelope (the otto_prepare_swap result), prepareInput (the exact otto_prepare_swap request, with slippage.minAmountOut) } — validated strictly AFTER the caller is authenticated, so the listed input schema is intentionally permissive. Server-to-server only: the caller presents Otto's delegation secret in the \`${DELEGATION_AUTH_HEADER}\` request header (never in arguments); a call without it is refused before anything is read. Before any send the server confirms, in this order: the Model-B project policy is installed and reads back by name and rules digest; the user's grant is active past the envelope's valid_until; the account is one of that end user's own CDP accounts as CDP reports them; the envelope passes the 13-check verifier for exactly the request that produced it; the plan is inside the fence (allow-listed input token, reviewed spender, gross at or below the ${MODEL_B_PER_SWAP_CAP_USD} USD engine ceiling); and the plan is at or below the per-swap cap THIS user chose when they minted, which is recorded against their grant on this server. A delegation with no recorded cap is REFUSED (DELEGATION_CAP_UNRECORDED) rather than defaulted to the ceiling \u2014 the grant cannot be used for delegated sends; check status and use Stop if it remains active. For an eligible confirmed grant, the three steps (allowance reset, approval, swap) are submitted in order under the delegation, each waited to a sealed canonical block; a halt clears the allowance and reports the read-back. One delegated plan at a time per user. Coinbase's engine bounds the delegated key to Model-B swap shapes through LI.FI up to the ${MODEL_B_PER_SWAP_CAP_USD} USD ceiling, which is shared by every delegated user and cannot be narrowed per user by the engine; the user's own lower cap and the receiver binding are Otto's server-side checks, and the user can revoke at any time.`,
112
123
  inputSchema: DELEGATED_TOOL_TRANSPORT_SCHEMA,
113
124
  strictInputSchema: SUBMIT_UNDER_DELEGATION_INPUT_SCHEMA,
114
125
  outputSchema: DELEGATED_SEND_RESULT_SCHEMA,
@@ -1,6 +1,8 @@
1
1
  /**
2
- * execution-delegation-admin-definition.ts — the three header-authed delegation ADMIN tools (PR-1b, seat ruling
3
- * D10 = (a), 2026-08-29): `otto_delegation_fence`, `otto_delegation_status`, `otto_delegation_revoke`.
2
+ * execution-delegation-admin-definition.ts — the four header-authed delegation ADMIN tools (PR-1b, seat ruling
3
+ * D10 = (a), 2026-08-29): `otto_delegation_fence`, `otto_delegation_status`, `otto_delegation_revoke`, and
4
+ * `otto_delegation_cap` (Founder word `delegate cap choice`, 2026-09-02 — the per-swap cap a person chose,
5
+ * recorded against the grant they just minted).
4
6
  *
5
7
  * Same seam and admission as `otto_submit_under_delegation`: they register only with a rig, the caller presents
6
8
  * Otto's server secret in the `x-otto-delegation-auth` request header (never in arguments), the registered
@@ -18,7 +20,9 @@ import { DELEGATED_TOOL_TRANSPORT_SCHEMA } from './execution-delegated-definitio
18
20
  export declare const DELEGATION_FENCE_TOOL_NAME: "otto_delegation_fence";
19
21
  export declare const DELEGATION_STATUS_TOOL_NAME: "otto_delegation_status";
20
22
  export declare const DELEGATION_REVOKE_TOOL_NAME: "otto_delegation_revoke";
21
- export declare const DELEGATION_ADMIN_TOOL_NAMES: readonly ["otto_delegation_fence", "otto_delegation_status", "otto_delegation_revoke"];
23
+ /** Records the per-swap cap the person chose, against the grant they just minted. */
24
+ export declare const DELEGATION_CAP_TOOL_NAME: "otto_delegation_cap";
25
+ export declare const DELEGATION_ADMIN_TOOL_NAMES: readonly ["otto_delegation_fence", "otto_delegation_status", "otto_delegation_revoke", "otto_delegation_cap"];
22
26
  /** The one PUBLIC delegation tool: the fence's public promise (present / name / digest / cap) — never user or grant data. */
23
27
  export declare const DELEGATION_FENCE_STATUS_TOOL_NAME: "otto_delegation_fence_status";
24
28
  export declare const DELEGATION_FENCE_INPUT_SCHEMA: z.ZodObject<{}, z.core.$strict>;
@@ -49,9 +53,75 @@ export declare const DELEGATION_STATUS_RESULT_SCHEMA: z.ZodObject<{
49
53
  delegation: z.ZodObject<{
50
54
  active: z.ZodBoolean;
51
55
  expires_at: z.ZodOptional<z.ZodString>;
56
+ per_swap_cap_usd: z.ZodOptional<z.ZodNumber>;
52
57
  }, z.core.$strict>;
53
58
  revocation_requested_here: z.ZodBoolean;
59
+ ruleset_version: z.ZodNumber;
60
+ mint_enabled: z.ZodBoolean;
54
61
  }, z.core.$strict>;
62
+ /**
63
+ * 🔴 TWO PHASES, BECAUSE THE RECORD NOW COMES BEFORE THE GRANT.
64
+ *
65
+ * Rounds 1 and 2 recorded a cap against a grant that already existed, and the codex gate broke both the
66
+ * same way: an expiry is the only thing a send can learn about a live grant, so two grants that share one
67
+ * are indistinguishable at enforcement however the row is keyed. Round 3 removes the collision instead of
68
+ * describing it.
69
+ *
70
+ * `reserve` — the SERVER picks a whole-second instant at or BEFORE the person's chosen duration that no
71
+ * durable row for this user occupies, writes the cap against it, and answers with the instant. The
72
+ * caller then mints with `mint_expires_at`, which is that instant plus a one-millisecond filler CDP
73
+ * truncates away (a bare `.000Z` is refused upstream — see `mintExpiryFor`).
74
+ * `confirm` — after the mint, the server re-reads the grant from CDP and refuses unless the instant CDP
75
+ * reports IS the reserved one and the exact generation-bound mint claim still stands. A mismatch or
76
+ * stale confirm stays unconfirmed and authorises nothing. CDP exposes only a user-wide revoke, so the
77
+ * server does not risk deleting a newer permission; the person uses a fresh explicit Stop instead.
78
+ *
79
+ * The user is still never named by the caller — both phases resolve the identity from the access token.
80
+ */
81
+ export declare const DELEGATION_CAP_RESERVE_INPUT_SCHEMA: z.ZodObject<{
82
+ phase: z.ZodLiteral<"reserve">;
83
+ accessToken: z.ZodString;
84
+ perSwapCapUsd: z.ZodNumber;
85
+ requestedDays: z.ZodNumber;
86
+ mintKey: z.ZodString;
87
+ }, z.core.$strict>;
88
+ export declare const DELEGATION_CAP_CONFIRM_INPUT_SCHEMA: z.ZodObject<{
89
+ phase: z.ZodLiteral<"confirm">;
90
+ accessToken: z.ZodString;
91
+ mintKey: z.ZodString;
92
+ }, z.core.$strict>;
93
+ export declare const DELEGATION_CAP_INPUT_SCHEMA: z.ZodDiscriminatedUnion<[z.ZodObject<{
94
+ phase: z.ZodLiteral<"reserve">;
95
+ accessToken: z.ZodString;
96
+ perSwapCapUsd: z.ZodNumber;
97
+ requestedDays: z.ZodNumber;
98
+ mintKey: z.ZodString;
99
+ }, z.core.$strict>, z.ZodObject<{
100
+ phase: z.ZodLiteral<"confirm">;
101
+ accessToken: z.ZodString;
102
+ mintKey: z.ZodString;
103
+ }, z.core.$strict>], "phase">;
104
+ export declare const DELEGATION_CAP_RESULT_SCHEMA: z.ZodObject<{
105
+ phase: z.ZodEnum<{
106
+ reserve: "reserve";
107
+ confirm: "confirm";
108
+ }>;
109
+ user_id: z.ZodString;
110
+ expires_at: z.ZodString;
111
+ mint_expires_at: z.ZodOptional<z.ZodString>;
112
+ per_swap_cap_usd: z.ZodNumber;
113
+ state: z.ZodEnum<{
114
+ revoked: "revoked";
115
+ superseded: "superseded";
116
+ reserved: "reserved";
117
+ confirmed_active: "confirmed_active";
118
+ expired: "expired";
119
+ legacy: "legacy";
120
+ }>;
121
+ ruleset_version: z.ZodNumber;
122
+ recorded: z.ZodBoolean;
123
+ }, z.core.$strict>;
124
+ export type DelegationCapResult = z.infer<typeof DELEGATION_CAP_RESULT_SCHEMA>;
55
125
  export declare const DELEGATION_REVOKE_INPUT_SCHEMA: z.ZodUnion<readonly [z.ZodObject<{
56
126
  accessToken: z.ZodString;
57
127
  }, z.core.$strict>, z.ZodObject<{
@@ -73,6 +143,9 @@ export declare const DELEGATION_FENCE_STATUS_RESULT_SCHEMA: z.ZodObject<{
73
143
  present: z.ZodBoolean;
74
144
  policy_name: z.ZodString;
75
145
  per_swap_cap_usd: z.ZodLiteral<5000>;
146
+ per_swap_cap_min_usd: z.ZodLiteral<1>;
147
+ ruleset_version: z.ZodNumber;
148
+ mint_enabled: z.ZodBoolean;
76
149
  project_id: z.ZodOptional<z.ZodString>;
77
150
  rules_digest: z.ZodOptional<z.ZodString>;
78
151
  reason: z.ZodOptional<z.ZodEnum<{
@@ -86,12 +159,15 @@ export type DelegationFenceStatusResult = z.infer<typeof DELEGATION_FENCE_STATUS
86
159
  export declare const DELEGATION_FENCE_STATUS_TOOL_DEFINITION: Readonly<{
87
160
  name: "otto_delegation_fence_status";
88
161
  title: "Read the Model-B delegation fence (public promise: present, name, rules digest, per-swap cap)";
89
- description: "PUBLIC and read-only, no header: whether the Model-B project policy that fences every delegated send is installed and v-current on this server, with its versioned name, rules digest, the per-swap cap in USD, and Otto's PUBLIC CDP project id (a UUID — the authority an agent binds its mint to). Exposes ONLY the fence's public promise — never an end user, a grant, an address or a policy's contents. An agent about to mint a delegation (otto-execute delegate) reads this first, mints to the published project_id and no other, and refuses to mint when the fence is not present; the server enforces fence-before-authority on every delegated send regardless. Arguments: {}.";
162
+ description: "PUBLIC and read-only, no header: reports whether the Model B project policy still fences existing delegated sends, its name and rules digest, the shared cap ceiling, and mint_enabled for new Model B trade setup. New trade-permission creation is retired, so mint_enabled is false on the serving retirement build. Existing status, revoke and exits remain available. No user, grant, address or policy contents are exposed. Arguments: {}.";
90
163
  inputSchema: z.ZodObject<{}, z.core.$strict>;
91
164
  outputSchema: z.ZodObject<{
92
165
  present: z.ZodBoolean;
93
166
  policy_name: z.ZodString;
94
167
  per_swap_cap_usd: z.ZodLiteral<5000>;
168
+ per_swap_cap_min_usd: z.ZodLiteral<1>;
169
+ ruleset_version: z.ZodNumber;
170
+ mint_enabled: z.ZodBoolean;
95
171
  project_id: z.ZodOptional<z.ZodString>;
96
172
  rules_digest: z.ZodOptional<z.ZodString>;
97
173
  reason: z.ZodOptional<z.ZodEnum<{
@@ -152,7 +228,7 @@ export declare const DELEGATION_FENCE_TOOL_DEFINITION: Readonly<{
152
228
  export declare const DELEGATION_STATUS_TOOL_DEFINITION: Readonly<{
153
229
  name: "otto_delegation_status";
154
230
  title: "Read one end user's delegation status (token-bound)";
155
- description: `Read back, for the end user identified by a CDP access token, their CDP accounts, whether the Model-B fence is present, and whether an active delegation reads back (with its expiry). Arguments: { accessToken } \u2014 the server resolves the user from the token; a client-sent user id is refused. Output is bound to that user; nothing about any other user is returned. ${string}`;
231
+ description: `Read back, for the end user identified by a CDP access token, their CDP accounts, whether the Model-B fence is present, and whether an active delegation reads back (with its expiry and the per-swap cap recorded for it). Arguments: { accessToken } \u2014 the server resolves the user from the token; a client-sent user id is refused. delegation.per_swap_cap_usd is the number THIS user chose at mint time; it is ABSENT when no cap is recorded for the grant, which means the delegated send will refuse it \u2014 say so rather than showing the shared ceiling. fence.per_swap_cap_usd is that shared ceiling and is never a per-user number. Output is bound to that user; nothing about any other user is returned. ${string}`;
156
232
  inputSchema: z.ZodObject<{}, z.core.$loose>;
157
233
  strictInputSchema: z.ZodObject<{
158
234
  accessToken: z.ZodString;
@@ -169,8 +245,11 @@ export declare const DELEGATION_STATUS_TOOL_DEFINITION: Readonly<{
169
245
  delegation: z.ZodObject<{
170
246
  active: z.ZodBoolean;
171
247
  expires_at: z.ZodOptional<z.ZodString>;
248
+ per_swap_cap_usd: z.ZodOptional<z.ZodNumber>;
172
249
  }, z.core.$strict>;
173
250
  revocation_requested_here: z.ZodBoolean;
251
+ ruleset_version: z.ZodNumber;
252
+ mint_enabled: z.ZodBoolean;
174
253
  }, z.core.$strict>;
175
254
  annotations: Readonly<{
176
255
  readOnlyHint: true;
@@ -206,3 +285,46 @@ export declare const DELEGATION_REVOKE_TOOL_DEFINITION: Readonly<{
206
285
  openWorldHint: true;
207
286
  }>;
208
287
  }>;
288
+ export declare const DELEGATION_CAP_TOOL_DEFINITION: Readonly<{
289
+ name: "otto_delegation_cap";
290
+ title: "Confirm an in-flight legacy Model B cap (new reservations retired)";
291
+ description: `Legacy Model B cap confirmation. New { phase: "reserve" } requests are retired and refused before any claim or reservation is written. { phase: "confirm", accessToken, mintKey } remains available for a permission already minted against a prior reservation: the server re-reads CDP and confirms only the exact still-current claim and reserved expiry. A mismatch or Stop overlap remains unconfirmed; a fresh explicit Stop handles the current grant. Without a confirmed per-user cap, delegated sends refuse. This tool does not issue new permissions. ${string}`;
292
+ inputSchema: z.ZodObject<{}, z.core.$loose>;
293
+ strictInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
294
+ phase: z.ZodLiteral<"reserve">;
295
+ accessToken: z.ZodString;
296
+ perSwapCapUsd: z.ZodNumber;
297
+ requestedDays: z.ZodNumber;
298
+ mintKey: z.ZodString;
299
+ }, z.core.$strict>, z.ZodObject<{
300
+ phase: z.ZodLiteral<"confirm">;
301
+ accessToken: z.ZodString;
302
+ mintKey: z.ZodString;
303
+ }, z.core.$strict>], "phase">;
304
+ outputSchema: z.ZodObject<{
305
+ phase: z.ZodEnum<{
306
+ reserve: "reserve";
307
+ confirm: "confirm";
308
+ }>;
309
+ user_id: z.ZodString;
310
+ expires_at: z.ZodString;
311
+ mint_expires_at: z.ZodOptional<z.ZodString>;
312
+ per_swap_cap_usd: z.ZodNumber;
313
+ state: z.ZodEnum<{
314
+ revoked: "revoked";
315
+ superseded: "superseded";
316
+ reserved: "reserved";
317
+ confirmed_active: "confirmed_active";
318
+ expired: "expired";
319
+ legacy: "legacy";
320
+ }>;
321
+ ruleset_version: z.ZodNumber;
322
+ recorded: z.ZodBoolean;
323
+ }, z.core.$strict>;
324
+ annotations: Readonly<{
325
+ readOnlyHint: false;
326
+ destructiveHint: false;
327
+ idempotentHint: true;
328
+ openWorldHint: true;
329
+ }>;
330
+ }>;
@@ -1,6 +1,8 @@
1
1
  /**
2
- * execution-delegation-admin-definition.ts — the three header-authed delegation ADMIN tools (PR-1b, seat ruling
3
- * D10 = (a), 2026-08-29): `otto_delegation_fence`, `otto_delegation_status`, `otto_delegation_revoke`.
2
+ * execution-delegation-admin-definition.ts — the four header-authed delegation ADMIN tools (PR-1b, seat ruling
3
+ * D10 = (a), 2026-08-29): `otto_delegation_fence`, `otto_delegation_status`, `otto_delegation_revoke`, and
4
+ * `otto_delegation_cap` (Founder word `delegate cap choice`, 2026-09-02 — the per-swap cap a person chose,
5
+ * recorded against the grant they just minted).
4
6
  *
5
7
  * Same seam and admission as `otto_submit_under_delegation`: they register only with a rig, the caller presents
6
8
  * Otto's server secret in the `x-otto-delegation-auth` request header (never in arguments), the registered
@@ -14,16 +16,26 @@
14
16
  * proxy exposes only the token variant (asserted in PR-2).
15
17
  */
16
18
  import { z } from 'zod';
17
- import { MODEL_B_PER_SWAP_CAP_USD } from './execution-delegation-policy.js';
19
+ import { MODEL_B_DELEGATION_EXPIRY_MAX_DAYS, MODEL_B_DELEGATION_EXPIRY_MIN_DAYS, MODEL_B_PER_SWAP_CAP_MIN_USD, MODEL_B_PER_SWAP_CAP_USD, } from './execution-delegation-policy.js';
18
20
  import { DELEGATION_AUTH_HEADER, DELEGATED_TOOL_TRANSPORT_SCHEMA, } from './execution-delegated-definition.js';
21
+ import { CAP_RECORD_STATES, MINT_KEY_PATTERN } from './execution-delegation-cap-store.js';
19
22
  export const DELEGATION_FENCE_TOOL_NAME = 'otto_delegation_fence';
20
23
  export const DELEGATION_STATUS_TOOL_NAME = 'otto_delegation_status';
21
24
  export const DELEGATION_REVOKE_TOOL_NAME = 'otto_delegation_revoke';
25
+ /** Records the per-swap cap the person chose, against the grant they just minted. */
26
+ export const DELEGATION_CAP_TOOL_NAME = 'otto_delegation_cap';
22
27
  export const DELEGATION_ADMIN_TOOL_NAMES = Object.freeze([
23
28
  DELEGATION_FENCE_TOOL_NAME,
24
29
  DELEGATION_STATUS_TOOL_NAME,
25
30
  DELEGATION_REVOKE_TOOL_NAME,
31
+ DELEGATION_CAP_TOOL_NAME,
26
32
  ]);
33
+ /** A chosen per-swap cap, as every schema on this surface bounds it: whole USD, 1 … the engine ceiling. */
34
+ const PER_SWAP_CAP_SCHEMA = z
35
+ .number()
36
+ .int()
37
+ .min(MODEL_B_PER_SWAP_CAP_MIN_USD)
38
+ .max(MODEL_B_PER_SWAP_CAP_USD);
27
39
  /** The one PUBLIC delegation tool: the fence's public promise (present / name / digest / cap) — never user or grant data. */
28
40
  export const DELEGATION_FENCE_STATUS_TOOL_NAME = 'otto_delegation_fence_status';
29
41
  const END_USER_ID_PATTERN = /^[a-zA-Z0-9-]{1,100}$/;
@@ -67,9 +79,118 @@ export const DELEGATION_STATUS_RESULT_SCHEMA = z
67
79
  /** Active = reads back from CDP, not expired, and no revocation was requested on this server. */
68
80
  active: z.boolean(),
69
81
  expires_at: z.string().optional(),
82
+ /**
83
+ * The per-swap cap recorded for THIS grant — the number the person chose when they minted.
84
+ * ABSENT when none is recorded, and that absence is load-bearing: a delegated send for a grant
85
+ * with no recorded cap refuses, so the surface reading this must say the permission is not usable
86
+ * rather than quietly showing the ceiling.
87
+ */
88
+ per_swap_cap_usd: PER_SWAP_CAP_SCHEMA.optional(),
70
89
  })
71
90
  .strict(),
72
91
  revocation_requested_here: z.boolean(),
92
+ /**
93
+ * The cap-ruleset version THIS worker implements. The page and the agent CLI refuse to reserve or
94
+ * mint against a server reporting less than the version they were built for — a rolling deploy runs
95
+ * two binaries at once and the Coinbase fence is identical on both, so the fence cannot tell them
96
+ * apart and this is what does.
97
+ */
98
+ ruleset_version: z.number().int().min(1),
99
+ /**
100
+ * Whether a NEW permission can be created on this worker at all (the staged-deploy gate). It never
101
+ * gates this read and never gates revoke: pausing the creation of authority must not pause its
102
+ * withdrawal, and a permission that already stands keeps working under its own cap.
103
+ */
104
+ mint_enabled: z.boolean(),
105
+ })
106
+ .strict();
107
+ /* ── cap (round 3: RESERVE an expiry and record the cap against it, then CONFIRM the mint) ── */
108
+ /**
109
+ * 🔴 TWO PHASES, BECAUSE THE RECORD NOW COMES BEFORE THE GRANT.
110
+ *
111
+ * Rounds 1 and 2 recorded a cap against a grant that already existed, and the codex gate broke both the
112
+ * same way: an expiry is the only thing a send can learn about a live grant, so two grants that share one
113
+ * are indistinguishable at enforcement however the row is keyed. Round 3 removes the collision instead of
114
+ * describing it.
115
+ *
116
+ * `reserve` — the SERVER picks a whole-second instant at or BEFORE the person's chosen duration that no
117
+ * durable row for this user occupies, writes the cap against it, and answers with the instant. The
118
+ * caller then mints with `mint_expires_at`, which is that instant plus a one-millisecond filler CDP
119
+ * truncates away (a bare `.000Z` is refused upstream — see `mintExpiryFor`).
120
+ * `confirm` — after the mint, the server re-reads the grant from CDP and refuses unless the instant CDP
121
+ * reports IS the reserved one and the exact generation-bound mint claim still stands. A mismatch or
122
+ * stale confirm stays unconfirmed and authorises nothing. CDP exposes only a user-wide revoke, so the
123
+ * server does not risk deleting a newer permission; the person uses a fresh explicit Stop instead.
124
+ *
125
+ * The user is still never named by the caller — both phases resolve the identity from the access token.
126
+ */
127
+ export const DELEGATION_CAP_RESERVE_INPUT_SCHEMA = z
128
+ .object({
129
+ phase: z.literal('reserve'),
130
+ accessToken: ACCESS_TOKEN_SCHEMA,
131
+ perSwapCapUsd: PER_SWAP_CAP_SCHEMA,
132
+ /**
133
+ * How long the person asked for. The server turns it into an instant itself — a caller-supplied expiry
134
+ * would put the choice of the enforcement key back in the browser, and it is the server choosing it
135
+ * that makes the key unique.
136
+ */
137
+ requestedDays: z
138
+ .number()
139
+ .int()
140
+ .min(MODEL_B_DELEGATION_EXPIRY_MIN_DAYS)
141
+ .max(MODEL_B_DELEGATION_EXPIRY_MAX_DAYS),
142
+ /**
143
+ * The `idempotencyKey` the caller WILL pass to `createDelegation`. It makes the reservation itself
144
+ * retry-safe: pressing again after a lost response returns the same instant rather than consuming a
145
+ * second one. It is NOT the enforcement key — `(userId, expiry)` is.
146
+ */
147
+ mintKey: z.string().regex(MINT_KEY_PATTERN, 'must be the mint idempotency key'),
148
+ })
149
+ .strict();
150
+ export const DELEGATION_CAP_CONFIRM_INPUT_SCHEMA = z
151
+ .object({
152
+ phase: z.literal('confirm'),
153
+ accessToken: ACCESS_TOKEN_SCHEMA,
154
+ /** Which reservation this mint was for. The reserved instant is read from the store, never from the caller. */
155
+ mintKey: z.string().regex(MINT_KEY_PATTERN, 'must be the mint idempotency key'),
156
+ })
157
+ .strict();
158
+ export const DELEGATION_CAP_INPUT_SCHEMA = z.discriminatedUnion('phase', [
159
+ DELEGATION_CAP_RESERVE_INPUT_SCHEMA,
160
+ DELEGATION_CAP_CONFIRM_INPUT_SCHEMA,
161
+ ]);
162
+ export const DELEGATION_CAP_RESULT_SCHEMA = z
163
+ .object({
164
+ phase: z.enum(['reserve', 'confirm']),
165
+ user_id: z.string().regex(END_USER_ID_PATTERN),
166
+ /**
167
+ * The RESERVED whole-second instant — the enforcement key. On `confirm` it is also what CDP reports for
168
+ * the live grant, because the call refuses otherwise.
169
+ */
170
+ expires_at: z.string(),
171
+ /**
172
+ * What to hand `createDelegation`: the reserved instant plus the one-millisecond filler. Present on
173
+ * `reserve` only — by `confirm` the mint has already happened.
174
+ */
175
+ mint_expires_at: z.string().optional(),
176
+ /**
177
+ * The cap IN FORCE at that instant, read back from the binding index — not necessarily the number the
178
+ * caller asked for.
179
+ */
180
+ per_swap_cap_usd: PER_SWAP_CAP_SCHEMA,
181
+ /**
182
+ * Where this permission is in its lifecycle. `reserved` authorises NOTHING — only `confirmed_active`
183
+ * does, and only while it is the one the send gate reads back.
184
+ */
185
+ state: z.enum(CAP_RECORD_STATES),
186
+ /** The cap ruleset this record requires; a worker that implements an older one refuses it. */
187
+ ruleset_version: z.number().int().min(1),
188
+ /**
189
+ * True when THIS call wrote the transition. False when it had already happened for this mint key:
190
+ * a reservation is immutable and a confirmation is one-shot, so the fields above are what already
191
+ * stands, and a caller wanting a different number mints a new permission.
192
+ */
193
+ recorded: z.boolean(),
73
194
  })
74
195
  .strict();
75
196
  /* ── revoke ── */
@@ -97,7 +218,21 @@ export const DELEGATION_FENCE_STATUS_RESULT_SCHEMA = z
97
218
  .object({
98
219
  present: z.boolean(),
99
220
  policy_name: z.string(),
221
+ /**
222
+ * The ENGINE's ceiling, shared by every delegated user — never one person's cap. A public tool has no
223
+ * user, so it can only ever publish this number and the floor below it.
224
+ */
100
225
  per_swap_cap_usd: z.literal(MODEL_B_PER_SWAP_CAP_USD),
226
+ /** The floor of the range a person may choose at mint time; their choice is enforced server-side. */
227
+ per_swap_cap_min_usd: z.literal(MODEL_B_PER_SWAP_CAP_MIN_USD),
228
+ /** The cap-ruleset version this worker implements; a client built for a newer one refuses to mint. */
229
+ ruleset_version: z.number().int().min(1),
230
+ /**
231
+ * Whether this worker will create a NEW permission at all. Published so the page and the CLI can say
232
+ * so before a person signs in, rather than discovering it at the reserve. Permissions that already
233
+ * stand keep working, and revoke always works.
234
+ */
235
+ mint_enabled: z.boolean(),
101
236
  /** Otto's PUBLIC CDP project id (a UUID): the authority the agent CLI binds its mint to. */
102
237
  project_id: z
103
238
  .string()
@@ -114,7 +249,7 @@ export const DELEGATION_FENCE_STATUS_RESULT_SCHEMA = z
114
249
  export const DELEGATION_FENCE_STATUS_TOOL_DEFINITION = Object.freeze({
115
250
  name: DELEGATION_FENCE_STATUS_TOOL_NAME,
116
251
  title: 'Read the Model-B delegation fence (public promise: present, name, rules digest, per-swap cap)',
117
- description: `PUBLIC and read-only, no header: whether the Model-B project policy that fences every delegated send is installed and v-current on this server, with its versioned name, rules digest, the per-swap cap in USD, and Otto's PUBLIC CDP project id (a UUID — the authority an agent binds its mint to). Exposes ONLY the fence's public promise — never an end user, a grant, an address or a policy's contents. An agent about to mint a delegation (otto-execute delegate) reads this first, mints to the published project_id and no other, and refuses to mint when the fence is not present; the server enforces fence-before-authority on every delegated send regardless. Arguments: {}.`,
252
+ description: `PUBLIC and read-only, no header: reports whether the Model B project policy still fences existing delegated sends, its name and rules digest, the shared cap ceiling, and mint_enabled for new Model B trade setup. New trade-permission creation is retired, so mint_enabled is false on the serving retirement build. Existing status, revoke and exits remain available. No user, grant, address or policy contents are exposed. Arguments: {}.`,
118
253
  inputSchema: DELEGATION_FENCE_STATUS_INPUT_SCHEMA,
119
254
  outputSchema: DELEGATION_FENCE_STATUS_RESULT_SCHEMA,
120
255
  annotations: Object.freeze({
@@ -142,7 +277,7 @@ export const DELEGATION_FENCE_TOOL_DEFINITION = Object.freeze({
142
277
  export const DELEGATION_STATUS_TOOL_DEFINITION = Object.freeze({
143
278
  name: DELEGATION_STATUS_TOOL_NAME,
144
279
  title: "Read one end user's delegation status (token-bound)",
145
- description: `Read back, for the end user identified by a CDP access token, their CDP accounts, whether the Model-B fence is present, and whether an active delegation reads back (with its expiry). Arguments: { accessToken } — the server resolves the user from the token; a client-sent user id is refused. Output is bound to that user; nothing about any other user is returned. ${AUTH_SENTENCE}`,
280
+ description: `Read back, for the end user identified by a CDP access token, their CDP accounts, whether the Model-B fence is present, and whether an active delegation reads back (with its expiry and the per-swap cap recorded for it). Arguments: { accessToken } — the server resolves the user from the token; a client-sent user id is refused. delegation.per_swap_cap_usd is the number THIS user chose at mint time; it is ABSENT when no cap is recorded for the grant, which means the delegated send will refuse it — say so rather than showing the shared ceiling. fence.per_swap_cap_usd is that shared ceiling and is never a per-user number. Output is bound to that user; nothing about any other user is returned. ${AUTH_SENTENCE}`,
146
281
  inputSchema: DELEGATED_TOOL_TRANSPORT_SCHEMA,
147
282
  strictInputSchema: DELEGATION_STATUS_INPUT_SCHEMA,
148
283
  outputSchema: DELEGATION_STATUS_RESULT_SCHEMA,
@@ -167,4 +302,19 @@ export const DELEGATION_REVOKE_TOOL_DEFINITION = Object.freeze({
167
302
  openWorldHint: true,
168
303
  }),
169
304
  });
305
+ export const DELEGATION_CAP_TOOL_DEFINITION = Object.freeze({
306
+ name: DELEGATION_CAP_TOOL_NAME,
307
+ title: "Confirm an in-flight legacy Model B cap (new reservations retired)",
308
+ description: `Legacy Model B cap confirmation. New { phase: "reserve" } requests are retired and refused before any claim or reservation is written. { phase: "confirm", accessToken, mintKey } remains available for a permission already minted against a prior reservation: the server re-reads CDP and confirms only the exact still-current claim and reserved expiry. A mismatch or Stop overlap remains unconfirmed; a fresh explicit Stop handles the current grant. Without a confirmed per-user cap, delegated sends refuse. This tool does not issue new permissions. ${AUTH_SENTENCE}`,
309
+ inputSchema: DELEGATED_TOOL_TRANSPORT_SCHEMA,
310
+ strictInputSchema: DELEGATION_CAP_INPUT_SCHEMA,
311
+ outputSchema: DELEGATION_CAP_RESULT_SCHEMA,
312
+ annotations: Object.freeze({
313
+ readOnlyHint: false,
314
+ destructiveHint: false,
315
+ // Idempotent by construction: the record is immutable, so a repeat returns what is already there.
316
+ idempotentHint: true,
317
+ openWorldHint: true,
318
+ }),
319
+ });
170
320
  //# sourceMappingURL=execution-delegation-admin-definition.js.map