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,525 @@
1
+ /** Native account policy compilation, exact readback fences and approved amount/oracle limits. */
2
+ import { createHash } from 'node:crypto';
3
+ import { getAddress, keccak256, stringToHex, } from 'viem';
4
+ import { MODEL_B_CAP_RULESET_VERSION, MODEL_B_PER_SWAP_CAP_MIN_USD, MODEL_B_PER_SWAP_CAP_USD, MODEL_B_POLICY_DIGEST_V2, MODEL_B_POLICY_NAME_V2, modelBProjectPolicyRules, } from './execution-delegation-policy.js';
5
+ import { policyRulesDigest } from './execution-policy-compatibility.js';
6
+ import { NATIVE_ACCOUNT_ACTIVATION_SCHEMA, NATIVE_ACCOUNT_AUTHORITY_SCHEMA, NATIVE_ACCOUNT_POLICY_NAME, NATIVE_ACCOUNT_SCOPES, NATIVE_YIELD_ACCOUNT_ACTIVATIONS, } from './native-yield-account-definition.js';
7
+ import { NATIVE_YIELD_STATE_MAX_AGE_MS, refuseNative, } from './native-yield-definition.js';
8
+ import { freezeHybridValue, getHybridYieldMarket, hybridYieldCommitment, } from './hybrid-yield-markets.js';
9
+ const UINT256_MAX = (1n << 256n) - 1n;
10
+ const ZERO_ADDRESS = /^0x0{40}$/i;
11
+ const ZERO_HASH = /^0x0{64}$/i;
12
+ const BLOCK_FUTURE_SKEW_MS = 5_000;
13
+ /** The only custom call shape admitted by the native project-policy leaves. */
14
+ export const NATIVE_ACCOUNT_ROUTER_EXECUTE_ABI = [
15
+ {
16
+ type: 'function',
17
+ name: 'execute',
18
+ stateMutability: 'nonpayable',
19
+ inputs: [
20
+ { name: 'marketId', type: 'bytes32' },
21
+ { name: 'isDeposit', type: 'bool' },
22
+ { name: 'amount', type: 'uint256' },
23
+ { name: 'minOutput', type: 'uint256' },
24
+ { name: 'nonce', type: 'uint256' },
25
+ { name: 'deadline', type: 'uint256' },
26
+ ],
27
+ outputs: [{ name: 'outputAmount', type: 'uint256' }],
28
+ },
29
+ ];
30
+ function canonical(value) {
31
+ if (value === null || ['string', 'boolean'].includes(typeof value))
32
+ return JSON.stringify(value);
33
+ if (typeof value === 'number' && Number.isFinite(value))
34
+ return JSON.stringify(value);
35
+ if (Array.isArray(value))
36
+ return `[${value.map(canonical).join(',')}]`;
37
+ if (typeof value === 'object') {
38
+ return `{${Object.entries(value)
39
+ .filter(([, item]) => item !== undefined)
40
+ .sort(([a], [b]) => a.localeCompare(b))
41
+ .map(([key, item]) => `${JSON.stringify(key)}:${canonical(item)}`)
42
+ .join(',')}}`;
43
+ }
44
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', 'Activation contains a non-canonical value');
45
+ }
46
+ function activationSnapshot(raw) {
47
+ try {
48
+ return freezeHybridValue(NATIVE_ACCOUNT_ACTIVATION_SCHEMA.parse(raw));
49
+ }
50
+ catch {
51
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', 'Native account activation does not match its strict schema');
52
+ }
53
+ }
54
+ function exactAddress(raw, label) {
55
+ try {
56
+ const value = getAddress(raw);
57
+ if (ZERO_ADDRESS.test(value))
58
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', `${label} cannot be zero`);
59
+ return value;
60
+ }
61
+ catch {
62
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', `${label} is not an exact EVM address`);
63
+ }
64
+ }
65
+ function configuration(raw) {
66
+ const activation = activationSnapshot(raw);
67
+ if (activation.policyId.trim() !== activation.policyId || activation.reviewId.trim() !== activation.reviewId) {
68
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', 'Activation identifiers must be exact non-whitespace values');
69
+ }
70
+ const deployments = new Map();
71
+ for (const deployment of activation.deployments) {
72
+ if (deployments.has(deployment.chainId)) {
73
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', 'Activation carries more than one router for a chain');
74
+ }
75
+ exactAddress(deployment.address, 'Router deployment');
76
+ if (ZERO_HASH.test(deployment.runtimeCodeHash)) {
77
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', 'Router runtime-code hash cannot be zero');
78
+ }
79
+ deployments.set(deployment.chainId, deployment);
80
+ }
81
+ const gasLimits = new Map();
82
+ for (const limits of activation.gasLimits) {
83
+ if (gasLimits.has(limits.chainId)) {
84
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', 'Activation carries duplicate gas limits for a chain');
85
+ }
86
+ if (BigInt(limits.maxPriorityFeePerGasWei) > BigInt(limits.maxFeePerGasWei) ||
87
+ BigInt(limits.maxEstimatedTotalCostWei) > BigInt(limits.maxOperationEstimatedCostWei)) {
88
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', 'Approved gas limits are internally inconsistent');
89
+ }
90
+ gasLimits.set(limits.chainId, limits);
91
+ }
92
+ const keys = new Set();
93
+ const usedChains = new Set();
94
+ const markets = [];
95
+ for (const rule of activation.marketRules) {
96
+ const key = `${rule.marketId}\u0000${rule.action}`;
97
+ if (keys.has(key)) {
98
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', 'Activation carries a duplicate market/action limit');
99
+ }
100
+ keys.add(key);
101
+ const market = getHybridYieldMarket(rule.marketId);
102
+ if (!market || hybridYieldCommitment(market) !== rule.registryCommitment) {
103
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', `Activation market ${rule.marketId} is absent or has drifted`);
104
+ }
105
+ if (!deployments.has(market.chainId) || !gasLimits.has(market.chainId)) {
106
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', `Activation lacks router or gas limits for ${rule.marketId}`);
107
+ }
108
+ // Recovery mode retains reviewed policy terms so exact old approvals can still be cleared.
109
+ // It is an application stop, not provider-level removal of native capability.
110
+ if (rule.action === 'deposit' &&
111
+ market.capabilities.native.deposit !== 'gated') {
112
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', `Deposit is not approved for ${rule.marketId}`);
113
+ }
114
+ if (rule.action === 'withdraw' && market.capabilities.native.withdraw !== 'gated') {
115
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', `Withdrawal is not approved for ${rule.marketId}`);
116
+ }
117
+ usedChains.add(market.chainId);
118
+ markets.push(Object.freeze({ rule, market }));
119
+ }
120
+ if (deployments.size !== usedChains.size || gasLimits.size !== usedChains.size ||
121
+ [...deployments.keys()].some((chainId) => !usedChains.has(chainId)) ||
122
+ [...gasLimits.keys()].some((chainId) => !usedChains.has(chainId))) {
123
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', 'Router, market and gas chain coverage must match exactly');
124
+ }
125
+ const requiredPrices = new Map();
126
+ for (const binding of markets) {
127
+ if (binding.rule.action === 'deposit' && binding.market.asset.symbol === 'WETH') {
128
+ requiredPrices.set(`${binding.market.chainId}:${binding.market.asset.address.toLowerCase()}`, binding.market);
129
+ }
130
+ }
131
+ const seenPrices = new Set();
132
+ for (const price of activation.priceRules) {
133
+ const asset = exactAddress(price.asset, 'Price-rule asset');
134
+ exactAddress(price.feed, 'Price feed');
135
+ const key = `${price.chainId}:${asset.toLowerCase()}`;
136
+ const market = requiredPrices.get(key);
137
+ if (!market || seenPrices.has(key) || BigInt(price.minimumAnswer) > BigInt(price.maximumAnswer)) {
138
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', 'Price rules must exactly cover approved WETH deposits with a valid corridor');
139
+ }
140
+ seenPrices.add(key);
141
+ }
142
+ if (seenPrices.size !== requiredPrices.size) {
143
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', 'Every approved WETH deposit needs one exact price rule');
144
+ }
145
+ return Object.freeze({
146
+ activation,
147
+ deployments,
148
+ gasLimits,
149
+ markets: Object.freeze(markets),
150
+ });
151
+ }
152
+ function orderedBindings(config, chainId) {
153
+ return config.markets
154
+ .filter((binding) => binding.market.chainId === chainId)
155
+ .slice()
156
+ .sort((a, b) => a.market.id.localeCompare(b.market.id) || a.rule.action.localeCompare(b.rule.action));
157
+ }
158
+ function network(chainId) {
159
+ return chainId === 8453 ? 'base' : 'arbitrum';
160
+ }
161
+ /** Compile only the native leaves. Every leaf binds the CDP request network explicitly. */
162
+ export function compileNativeYieldAccountPolicyRules(raw) {
163
+ const config = configuration(raw);
164
+ const rules = [];
165
+ const chains = [...config.deployments.keys()].sort((a, b) => a - b);
166
+ for (const chainId of chains) {
167
+ const bindings = orderedBindings(config, chainId);
168
+ const deployment = config.deployments.get(chainId);
169
+ const tokens = new Map();
170
+ let chainMaximum = 0n;
171
+ for (const binding of bindings) {
172
+ const token = exactAddress(binding.rule.action === 'deposit'
173
+ ? binding.market.asset.address
174
+ : binding.market.position.tokenAddress, 'Native approval token');
175
+ tokens.set(token.toLowerCase(), token);
176
+ const maximum = BigInt(binding.rule.maximumInputAtomic);
177
+ if (maximum > chainMaximum)
178
+ chainMaximum = maximum;
179
+ }
180
+ const tokenAddresses = [...tokens.values()].sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
181
+ const router = exactAddress(deployment.address, 'Native router');
182
+ const chainNetwork = network(chainId);
183
+ rules.push({
184
+ action: 'accept',
185
+ operation: 'sendEndUserEvmTransaction',
186
+ criteria: [
187
+ { type: 'evmNetwork', networks: [chainNetwork], operator: 'in' },
188
+ { type: 'evmAddress', addresses: tokenAddresses, operator: 'in' },
189
+ { type: 'ethValue', ethValue: '0', operator: '<=' },
190
+ {
191
+ type: 'evmData',
192
+ abi: 'erc20',
193
+ conditions: [{
194
+ function: 'approve',
195
+ params: [
196
+ { name: 'spender', operator: 'in', values: [router] },
197
+ { name: 'value', operator: '<=', value: chainMaximum.toString() },
198
+ ],
199
+ }],
200
+ },
201
+ ],
202
+ });
203
+ rules.push({
204
+ action: 'accept',
205
+ operation: 'sendEndUserEvmTransaction',
206
+ criteria: [
207
+ { type: 'evmNetwork', networks: [chainNetwork], operator: 'in' },
208
+ { type: 'evmAddress', addresses: [router], operator: 'in' },
209
+ { type: 'ethValue', ethValue: '0', operator: '<=' },
210
+ {
211
+ type: 'evmData',
212
+ abi: NATIVE_ACCOUNT_ROUTER_EXECUTE_ABI,
213
+ conditions: bindings.map((binding) => ({
214
+ function: 'execute',
215
+ params: [
216
+ {
217
+ name: 'marketId',
218
+ operator: 'in',
219
+ values: [keccak256(stringToHex(binding.market.id))],
220
+ },
221
+ {
222
+ name: 'isDeposit',
223
+ operator: 'in',
224
+ values: [binding.rule.action === 'deposit' ? 'true' : 'false'],
225
+ },
226
+ {
227
+ name: 'amount',
228
+ operator: '<=',
229
+ value: binding.rule.maximumInputAtomic,
230
+ },
231
+ ],
232
+ })),
233
+ },
234
+ ],
235
+ });
236
+ }
237
+ return freezeHybridValue(rules);
238
+ }
239
+ /**
240
+ * Compile exact legacy-v2 leaves followed by native leaves. Coinbase project policies apply
241
+ * retroactively: parsing or digesting this body does not authorize attaching it. Before any update,
242
+ * every live grant needs a separate consent audit for this exact policy id/digest and activation.
243
+ */
244
+ export function compileNativeYieldAccountCompositePolicy(activation) {
245
+ const legacyRules = modelBProjectPolicyRules();
246
+ const nativeRules = compileNativeYieldAccountPolicyRules(activation);
247
+ const rules = freezeHybridValue([...legacyRules, ...nativeRules]);
248
+ if (rules.length > 10) {
249
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', 'Composite policy exceeds the CDP ten-rule ceiling');
250
+ }
251
+ const body = freezeHybridValue({
252
+ scope: 'project',
253
+ description: NATIVE_ACCOUNT_POLICY_NAME,
254
+ rules,
255
+ });
256
+ return Object.freeze({
257
+ body,
258
+ legacyRules,
259
+ nativeRules,
260
+ policyDigest: policyRulesDigest(rules),
261
+ legacyRulesDigest: policyRulesDigest(legacyRules),
262
+ nativeRulesDigest: policyRulesDigest(nativeRules),
263
+ });
264
+ }
265
+ /** Validate all trusted pins and the full/leaf policy digests. */
266
+ export function validateNativeYieldAccountActivation(raw) {
267
+ const activation = configuration(raw).activation;
268
+ const compiled = compileNativeYieldAccountCompositePolicy(activation);
269
+ if (compiled.legacyRulesDigest !== MODEL_B_POLICY_DIGEST_V2 ||
270
+ activation.legacyRulesDigest !== compiled.legacyRulesDigest ||
271
+ activation.nativeRulesDigest !== compiled.nativeRulesDigest ||
272
+ activation.policyDigest !== compiled.policyDigest) {
273
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_INVALID', 'Activation policy or leaf digest does not match the deterministic composite');
274
+ }
275
+ return compiled;
276
+ }
277
+ /** Domain-separated commitment used by persisted native-scope consent. */
278
+ export function nativeYieldAccountActivationCommitment(raw) {
279
+ const activation = configuration(raw).activation;
280
+ validateNativeYieldAccountActivation(activation);
281
+ return `sha256:${createHash('sha256')
282
+ .update(`otto:native-yield-account-activation:v1:${canonical(activation)}`)
283
+ .digest('hex')}`;
284
+ }
285
+ /** Resolve only an exact reviewed constant/test manifest; the production default is empty. */
286
+ export function resolveNativeYieldAccountActivation(chainId, activations = NATIVE_YIELD_ACCOUNT_ACTIVATIONS) {
287
+ if (chainId !== 8453 && chainId !== 42161) {
288
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_UNAVAILABLE', 'Native account chain is unsupported');
289
+ }
290
+ const parsed = activations.map((activation) => {
291
+ const snapshot = configuration(activation).activation;
292
+ validateNativeYieldAccountActivation(snapshot);
293
+ return snapshot;
294
+ });
295
+ const matches = parsed.filter((activation) => activation.deployments.some((deployment) => deployment.chainId === chainId));
296
+ if (matches.length !== 1) {
297
+ return refuseNative('NATIVE_ACCOUNT_ACTIVATION_UNAVAILABLE', matches.length === 0
298
+ ? 'No reviewed native account activation exists for this chain'
299
+ : 'More than one native account activation claims this chain');
300
+ }
301
+ return matches[0];
302
+ }
303
+ function exactProjectPolicy(policies) {
304
+ const project = policies.filter((policy) => policy.scope === 'project');
305
+ if (project.length !== 1) {
306
+ return refuseNative('NATIVE_ACCOUNT_POLICY_MISMATCH', project.length === 0
307
+ ? 'No project policy is installed'
308
+ : 'Project policy readback is ambiguous');
309
+ }
310
+ return project[0];
311
+ }
312
+ function targetFence(activation) {
313
+ return Object.freeze({
314
+ policyId: activation.policyId,
315
+ policyName: activation.policyName,
316
+ policyDigest: activation.policyDigest,
317
+ legacyRulesDigest: activation.legacyRulesDigest,
318
+ nativeRulesDigest: activation.nativeRulesDigest,
319
+ });
320
+ }
321
+ function assertExactComposite(policy, activation, compiled) {
322
+ if (policy.id !== activation.policyId || policy.description !== activation.policyName || !Array.isArray(policy.rules) ||
323
+ policy.rules.length !== compiled.body.rules.length) {
324
+ return refuseNative('NATIVE_ACCOUNT_POLICY_MISMATCH', 'Installed project policy has the wrong id, name or rule count');
325
+ }
326
+ const full = policyRulesDigest(policy.rules);
327
+ const legacy = policyRulesDigest(policy.rules.slice(0, compiled.legacyRules.length));
328
+ const native = policyRulesDigest(policy.rules.slice(compiled.legacyRules.length));
329
+ if (full !== activation.policyDigest || legacy !== activation.legacyRulesDigest || native !== activation.nativeRulesDigest ||
330
+ full !== compiled.policyDigest || legacy !== compiled.legacyRulesDigest || native !== compiled.nativeRulesDigest) {
331
+ return refuseNative('NATIVE_ACCOUNT_POLICY_MISMATCH', 'Installed project policy does not match the exact full and leaf digests');
332
+ }
333
+ return full;
334
+ }
335
+ /**
336
+ * Consent may be challenged immediately before an in-place v2→v3 attach at the same policy id. The
337
+ * returned common fields always name the prospective exact v3; observed fields identify what was read.
338
+ */
339
+ export function assertNativeConsentPolicyContext(policies, raw) {
340
+ const activation = configuration(raw).activation;
341
+ const compiled = validateNativeYieldAccountActivation(activation);
342
+ const policy = exactProjectPolicy(policies);
343
+ if (policy.id !== activation.policyId) {
344
+ return refuseNative('NATIVE_ACCOUNT_POLICY_MISMATCH', 'Consent policy id differs from the planned in-place composite policy');
345
+ }
346
+ const observedPolicyDigest = policyRulesDigest(policy.rules);
347
+ if (policy.description === MODEL_B_POLICY_NAME_V2 && observedPolicyDigest === MODEL_B_POLICY_DIGEST_V2) {
348
+ return Object.freeze({
349
+ ...targetFence(activation),
350
+ phase: 'legacy-v2',
351
+ observedPolicyName: MODEL_B_POLICY_NAME_V2,
352
+ observedPolicyDigest,
353
+ });
354
+ }
355
+ const full = assertExactComposite(policy, activation, compiled);
356
+ return Object.freeze({
357
+ ...targetFence(activation),
358
+ phase: 'native-v3',
359
+ observedPolicyName: activation.policyName,
360
+ observedPolicyDigest: full,
361
+ });
362
+ }
363
+ /** A sender proceeds only while the exact v3 id, name, full digest and both leaf digests read back. */
364
+ export function assertNativeAccountSendFence(policies, raw) {
365
+ const activation = configuration(raw).activation;
366
+ const compiled = validateNativeYieldAccountActivation(activation);
367
+ const policy = exactProjectPolicy(policies);
368
+ assertExactComposite(policy, activation, compiled);
369
+ return targetFence(activation);
370
+ }
371
+ export function deriveExactApprovedNativeMarketLimits(raw, input) {
372
+ const config = configuration(raw);
373
+ validateNativeYieldAccountActivation(config.activation);
374
+ const binding = config.markets.find(({ market, rule }) => market.chainId === input.chainId && market.id === input.marketId &&
375
+ rule.action === input.action && rule.registryCommitment === input.registryCommitment);
376
+ if (!binding || hybridYieldCommitment(binding.market) !== input.registryCommitment) {
377
+ return refuseNative('NATIVE_ACCOUNT_OUTSIDE_FENCE', 'Market, action, chain or registry commitment is outside the approved activation');
378
+ }
379
+ if (input.action === 'deposit' && config.activation.mode !== 'enabled') {
380
+ return refuseNative('NATIVE_ACCOUNT_OUTSIDE_FENCE', 'Recovery-only activation cannot create a new position');
381
+ }
382
+ const deployment = config.deployments.get(input.chainId);
383
+ const gasLimits = config.gasLimits.get(input.chainId);
384
+ const inputToken = exactAddress(input.action === 'deposit' ? binding.market.asset.address : binding.market.position.tokenAddress, 'Native input token');
385
+ return Object.freeze({
386
+ activation: config.activation,
387
+ deployment,
388
+ market: binding.market,
389
+ marketRule: binding.rule,
390
+ gasLimits,
391
+ network: network(input.chainId),
392
+ inputToken,
393
+ maximumInputAtomic: BigInt(binding.rule.maximumInputAtomic),
394
+ });
395
+ }
396
+ function boundedAmount(amount) {
397
+ if (typeof amount !== 'bigint' || amount <= 0n || amount > UINT256_MAX) {
398
+ return refuseNative('NATIVE_ACCOUNT_OUTSIDE_FENCE', 'Input amount must be an exact positive uint256');
399
+ }
400
+ return amount;
401
+ }
402
+ /** Applies to deposits and withdrawals; withdrawals need no price conversion. */
403
+ export function assertNativeInputWithinApprovedAtomicCeiling(amountAtomic, limits) {
404
+ const amount = boundedAmount(amountAtomic);
405
+ const expected = deriveExactApprovedNativeMarketLimits(limits.activation, {
406
+ chainId: limits.market.chainId,
407
+ marketId: limits.market.id,
408
+ registryCommitment: limits.marketRule.registryCommitment,
409
+ action: limits.marketRule.action,
410
+ });
411
+ if (expected.maximumInputAtomic !== limits.maximumInputAtomic ||
412
+ expected.inputToken !== limits.inputToken ||
413
+ expected.deployment.address.toLowerCase() !== limits.deployment.address.toLowerCase()) {
414
+ return refuseNative('NATIVE_ACCOUNT_OUTSIDE_FENCE', 'Resolved native limits were altered after trusted activation lookup');
415
+ }
416
+ if (amount > expected.maximumInputAtomic) {
417
+ return refuseNative('NATIVE_ACCOUNT_OUTSIDE_FENCE', 'Input amount exceeds the exact approved market/action ceiling');
418
+ }
419
+ return Object.freeze({ maximumInputAtomic: expected.maximumInputAtomic });
420
+ }
421
+ function exactAuthority(raw, activation, nowMs) {
422
+ let authority;
423
+ try {
424
+ authority = NATIVE_ACCOUNT_AUTHORITY_SCHEMA.parse(raw);
425
+ }
426
+ catch {
427
+ return refuseNative('NATIVE_ACCOUNT_OUTSIDE_FENCE', 'Native account authority is not a strict consent record');
428
+ }
429
+ if (!Number.isSafeInteger(nowMs) || nowMs <= 0 || Date.parse(authority.grantExpiresAt) <= nowMs ||
430
+ authority.capRulesetVersion !== MODEL_B_CAP_RULESET_VERSION ||
431
+ authority.policyId !== activation.policyId || authority.policyName !== activation.policyName ||
432
+ authority.policyDigest !== activation.policyDigest || authority.legacyRulesDigest !== activation.legacyRulesDigest ||
433
+ authority.nativeRulesDigest !== activation.nativeRulesDigest ||
434
+ authority.activationCommitment !== nativeYieldAccountActivationCommitment(activation) ||
435
+ authority.scopes.length !== NATIVE_ACCOUNT_SCOPES.length ||
436
+ NATIVE_ACCOUNT_SCOPES.some((scope, index) => authority.scopes[index] !== scope) ||
437
+ !Number.isInteger(authority.perSwapCapUsd) ||
438
+ authority.perSwapCapUsd < MODEL_B_PER_SWAP_CAP_MIN_USD ||
439
+ authority.perSwapCapUsd > MODEL_B_PER_SWAP_CAP_USD) {
440
+ return refuseNative('NATIVE_ACCOUNT_OUTSIDE_FENCE', 'Native account authority is expired or differs from the current activation and cap ruleset');
441
+ }
442
+ return freezeHybridValue(authority);
443
+ }
444
+ function ceilDiv(numerator, denominator) {
445
+ if (denominator <= 0n)
446
+ return refuseNative('NATIVE_ACCOUNT_ORACLE_INVALID', 'Price denominator must be positive');
447
+ return (numerator + denominator - 1n) / denominator;
448
+ }
449
+ function exactPriceObservation(raw, limits, nowMs) {
450
+ if (!raw)
451
+ return refuseNative('NATIVE_ACCOUNT_ORACLE_UNAVAILABLE', 'An approved current Chainlink WETH observation is required');
452
+ const rule = limits.activation.priceRules.find((candidate) => candidate.chainId === limits.market.chainId &&
453
+ candidate.asset.toLowerCase() === limits.market.asset.address.toLowerCase());
454
+ if (!rule)
455
+ return refuseNative('NATIVE_ACCOUNT_ORACLE_UNAVAILABLE', 'No approved WETH price rule exists for this market');
456
+ let asset;
457
+ let feed;
458
+ try {
459
+ asset = getAddress(raw.asset);
460
+ feed = getAddress(raw.feed);
461
+ }
462
+ catch {
463
+ return refuseNative('NATIVE_ACCOUNT_ORACLE_INVALID', 'Price observation carries an invalid address');
464
+ }
465
+ const timesValid = Number.isSafeInteger(raw.blockTimestampMs) && raw.blockTimestampMs > 0 &&
466
+ Number.isSafeInteger(raw.observedAtMs) && raw.observedAtMs > 0 &&
467
+ raw.observedAtMs <= nowMs && nowMs - raw.observedAtMs < NATIVE_YIELD_STATE_MAX_AGE_MS &&
468
+ raw.blockTimestampMs <= nowMs + BLOCK_FUTURE_SKEW_MS &&
469
+ nowMs - raw.blockTimestampMs < NATIVE_YIELD_STATE_MAX_AGE_MS &&
470
+ raw.blockTimestampMs <= raw.observedAtMs + BLOCK_FUTURE_SKEW_MS;
471
+ const bigintsValid = [raw.roundId, raw.answer, raw.startedAt, raw.updatedAt,
472
+ raw.answeredInRound, raw.blockNumber].every((value) => typeof value === 'bigint' && value >= 0n);
473
+ if (raw.chainId !== limits.market.chainId || asset !== getAddress(rule.asset) || feed !== getAddress(rule.feed) ||
474
+ raw.feedDecimals !== rule.feedDecimals || !timesValid || !bigintsValid ||
475
+ raw.roundId === 0n || raw.answer === 0n || raw.startedAt === 0n || raw.updatedAt === 0n ||
476
+ raw.blockNumber === 0n || raw.answeredInRound < raw.roundId || raw.startedAt > raw.updatedAt ||
477
+ !/^0x[0-9a-fA-F]{64}$/.test(raw.blockHash) || ZERO_HASH.test(raw.blockHash)) {
478
+ return refuseNative('NATIVE_ACCOUNT_ORACLE_INVALID', 'Price observation identity, round or block anchor is invalid');
479
+ }
480
+ const blockSeconds = BigInt(Math.floor(raw.blockTimestampMs / 1000));
481
+ if (raw.updatedAt > blockSeconds || blockSeconds - raw.updatedAt > BigInt(rule.maxAgeSeconds) ||
482
+ raw.answer < BigInt(rule.minimumAnswer) || raw.answer > BigInt(rule.maximumAnswer)) {
483
+ return refuseNative('NATIVE_ACCOUNT_ORACLE_INVALID', 'Price observation is stale or outside the approved corridor');
484
+ }
485
+ return Object.freeze({ observation: raw, rule });
486
+ }
487
+ /** Deposits apply the owner USD cap; withdrawals apply only their exact activation atomic ceiling. */
488
+ export function assertNativeDepositWithinOwnerUsdCap(args) {
489
+ const amount = boundedAmount(args.amountAtomic);
490
+ assertNativeInputWithinApprovedAtomicCeiling(amount, args.limits);
491
+ const authority = exactAuthority(args.authority, args.limits.activation, args.nowMs);
492
+ const capUsdCents = BigInt(authority.perSwapCapUsd) * 100n;
493
+ if (args.limits.marketRule.action === 'withdraw') {
494
+ return Object.freeze({ capUsd: authority.perSwapCapUsd, capUsdCents });
495
+ }
496
+ if (args.limits.market.asset.symbol === 'USDC' && args.limits.market.asset.decimals === 6) {
497
+ const capAtomic = BigInt(authority.perSwapCapUsd) * 1000000n;
498
+ if (amount > capAtomic) {
499
+ return refuseNative('NATIVE_ACCOUNT_ABOVE_USER_CAP', 'USDC deposit exceeds the owner-confirmed USD cap');
500
+ }
501
+ return Object.freeze({
502
+ capUsd: authority.perSwapCapUsd,
503
+ capUsdCents,
504
+ valuedUsdCents: ceilDiv(amount * 100n, 1000000n),
505
+ });
506
+ }
507
+ if (args.limits.market.asset.symbol !== 'WETH' || args.limits.market.asset.decimals !== 18) {
508
+ return refuseNative('NATIVE_ACCOUNT_ORACLE_UNAVAILABLE', 'Only exact six-decimal USDC and approved WETH deposits have USD cap rules');
509
+ }
510
+ const { observation, rule } = exactPriceObservation(args.priceObservation, args.limits, args.nowMs);
511
+ const adjustedPrice = ceilDiv(observation.answer * BigInt(10_000 + rule.upwardMarginBps), 10000n);
512
+ const denominator = 10n ** 18n * 10n ** BigInt(rule.feedDecimals);
513
+ const valuedUsdCents = ceilDiv(amount * adjustedPrice * 100n, denominator);
514
+ if (valuedUsdCents > capUsdCents) {
515
+ return refuseNative('NATIVE_ACCOUNT_ABOVE_USER_CAP', 'WETH deposit exceeds the owner-confirmed USD cap after conservative valuation');
516
+ }
517
+ return Object.freeze({
518
+ capUsd: authority.perSwapCapUsd,
519
+ capUsdCents,
520
+ valuedUsdCents,
521
+ adjustedPrice,
522
+ priceRuleReviewId: rule.reviewId,
523
+ });
524
+ }
525
+ //# sourceMappingURL=native-yield-account-policy.js.map
@@ -0,0 +1,8 @@
1
+ /** Read-only transaction identity and canonical receipt proof; no signing or retry. */
2
+ import { type Hex, type PublicClient } from 'viem';
3
+ import { type NativeYieldAccountReceipt, type NativeYieldAccountSendRequest } from './native-yield-account-definition.js';
4
+ /**
5
+ * Transport proof only. Native protocol events, output, fees and allowance recovery
6
+ * remain the responsibility of native-yield-settlement.ts. A mined proof is not finality.
7
+ */
8
+ export declare function proveNativeYieldAccountTransaction(pub: PublicClient, rawRequest: NativeYieldAccountSendRequest, rawHash: Hex, finality: 'mined' | 'finalized'): Promise<NativeYieldAccountReceipt>;
@@ -0,0 +1,128 @@
1
+ /** Read-only transaction identity and canonical receipt proof; no signing or retry. */
2
+ import { isAddress, parseTransaction, serializeTransaction, } from 'viem';
3
+ import { NATIVE_ACCOUNT_HASH, NATIVE_ACCOUNT_RECEIPT_SCHEMA, NATIVE_ACCOUNT_SEND_REQUEST_SCHEMA, } from './native-yield-account-definition.js';
4
+ import { NativeYieldRefusal, refuseNative } from './native-yield-definition.js';
5
+ const UINT256_MAX = (1n << 256n) - 1n;
6
+ function same(a, b) { return typeof a === 'string' && a.toLowerCase() === b.toLowerCase(); }
7
+ function uint(value) {
8
+ return typeof value === 'bigint' && value >= 0n && value <= UINT256_MAX;
9
+ }
10
+ function index(value) { return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0; }
11
+ function sealed(block, number, hash) {
12
+ if (!block || block.number !== number || !same(block.hash, hash))
13
+ refuseNative('NATIVE_ACCOUNT_TRANSACTION_MISMATCH', 'Receipt block is not the expected canonical block');
14
+ }
15
+ function checkChain(pub, actual, expected) {
16
+ if (actual !== expected || (pub.chain && pub.chain.id !== expected))
17
+ refuseNative('NATIVE_CHAIN_MISMATCH', 'Receipt RPC or client configuration differs from the durable request network');
18
+ }
19
+ function expectedTransaction(request) {
20
+ try {
21
+ const decoded = parseTransaction(request.transaction);
22
+ const chainId = request.network === 'base' ? 8453 : 42161;
23
+ if (decoded.type !== 'eip1559' || decoded.chainId !== chainId || !decoded.to ||
24
+ !isAddress(decoded.to, { strict: false }) || !index(decoded.nonce) ||
25
+ !uint(decoded.gas) || decoded.gas === 0n || decoded.gas >= (1n << 64n) ||
26
+ !uint(decoded.maxFeePerGas) || decoded.maxFeePerGas === 0n ||
27
+ !uint(decoded.maxPriorityFeePerGas ?? 0n) || (decoded.maxPriorityFeePerGas ?? 0n) > decoded.maxFeePerGas ||
28
+ !uint(decoded.value ?? 0n))
29
+ refuseNative('NATIVE_ACCOUNT_REQUEST_INVALID', 'Durable request is not a complete supported EIP-1559 transaction');
30
+ const expected = {
31
+ type: 'eip1559', chainId, to: decoded.to, data: decoded.data ?? '0x', value: decoded.value ?? 0n,
32
+ nonce: decoded.nonce, gas: decoded.gas, maxFeePerGas: decoded.maxFeePerGas,
33
+ maxPriorityFeePerGas: decoded.maxPriorityFeePerGas ?? 0n, accessList: decoded.accessList ?? [],
34
+ };
35
+ // Rebuilding only unsigned fields rejects signatures and noncanonical RLP in durable input.
36
+ if (!same(serializeTransaction(expected), request.transaction))
37
+ refuseNative('NATIVE_ACCOUNT_REQUEST_INVALID', 'Durable transaction must contain exact canonical unsigned bytes');
38
+ return expected;
39
+ }
40
+ catch (error) {
41
+ if (error instanceof NativeYieldRefusal)
42
+ throw error;
43
+ return refuseNative('NATIVE_ACCOUNT_REQUEST_INVALID', 'Durable transaction could not be decoded');
44
+ }
45
+ }
46
+ function exactTransaction(transaction, expected, request, hash) {
47
+ if (transaction.type !== 'eip1559' || !same(transaction.hash, hash) ||
48
+ !same(transaction.from, request.address) || !same(transaction.to, expected.to) ||
49
+ !same(transaction.input, expected.data) || transaction.value !== expected.value ||
50
+ transaction.nonce !== expected.nonce || transaction.gas !== expected.gas ||
51
+ transaction.maxFeePerGas !== expected.maxFeePerGas ||
52
+ transaction.maxPriorityFeePerGas !== expected.maxPriorityFeePerGas ||
53
+ transaction.chainId !== expected.chainId || !Array.isArray(transaction.accessList))
54
+ return false;
55
+ try {
56
+ // The access list also affects signed identity; compare the entire reconstructed unsigned RLP.
57
+ return same(serializeTransaction({ ...expected, accessList: transaction.accessList }), request.transaction);
58
+ }
59
+ catch {
60
+ return false;
61
+ }
62
+ }
63
+ /**
64
+ * Transport proof only. Native protocol events, output, fees and allowance recovery
65
+ * remain the responsibility of native-yield-settlement.ts. A mined proof is not finality.
66
+ */
67
+ export async function proveNativeYieldAccountTransaction(pub, rawRequest, rawHash, finality) {
68
+ const parsed = NATIVE_ACCOUNT_SEND_REQUEST_SCHEMA.safeParse(rawRequest);
69
+ if (!parsed.success || !NATIVE_ACCOUNT_HASH.safeParse(rawHash).success ||
70
+ (finality !== 'mined' && finality !== 'finalized'))
71
+ refuseNative('NATIVE_ACCOUNT_REQUEST_INVALID', 'Invalid durable request, transaction hash or finality requirement');
72
+ const request = parsed.data, hash = rawHash.toLowerCase();
73
+ const expected = expectedTransaction(request);
74
+ try {
75
+ checkChain(pub, await pub.getChainId(), expected.chainId);
76
+ const [transaction, receipt] = await Promise.all([
77
+ pub.getTransaction({ hash }), pub.getTransactionReceipt({ hash }),
78
+ ]);
79
+ if (!transaction || !receipt || transaction.blockHash === null || transaction.blockNumber === null)
80
+ refuseNative('NATIVE_ACCOUNT_TRANSACTION_UNKNOWN', 'A mined transaction and receipt are not both available');
81
+ if (!exactTransaction(transaction, expected, request, hash))
82
+ refuseNative('NATIVE_ACCOUNT_TRANSACTION_MISMATCH', 'RPC transaction differs from the exact durable request');
83
+ if (!uint(receipt.blockNumber) || !uint(receipt.gasUsed) || !uint(receipt.effectiveGasPrice))
84
+ refuseNative('NATIVE_ACCOUNT_TRANSACTION_UNKNOWN', 'Receipt has missing or invalid numeric fields');
85
+ const observed = NATIVE_ACCOUNT_RECEIPT_SCHEMA.safeParse({
86
+ transactionHash: receipt.transactionHash, blockHash: receipt.blockHash, blockNumber: receipt.blockNumber.toString(),
87
+ status: receipt.status, gasUsed: receipt.gasUsed.toString(), effectiveGasPrice: receipt.effectiveGasPrice.toString(),
88
+ });
89
+ if (!observed.success)
90
+ refuseNative('NATIVE_ACCOUNT_TRANSACTION_UNKNOWN', 'Receipt is incomplete or has unknown execution status');
91
+ if (receipt.type !== 'eip1559' || !same(receipt.transactionHash, hash) ||
92
+ !same(receipt.from, request.address) || !same(receipt.to, expected.to) ||
93
+ !same(transaction.blockHash, receipt.blockHash) || transaction.blockNumber !== receipt.blockNumber ||
94
+ !index(receipt.transactionIndex) || transaction.transactionIndex !== receipt.transactionIndex ||
95
+ receipt.gasUsed > expected.gas || receipt.effectiveGasPrice > expected.maxFeePerGas)
96
+ refuseNative('NATIVE_ACCOUNT_TRANSACTION_MISMATCH', 'Receipt identity or gas accounting differs from the durable transaction');
97
+ sealed(await pub.getBlock({ blockNumber: receipt.blockNumber }), receipt.blockNumber, receipt.blockHash);
98
+ let finalized;
99
+ if (finality === 'finalized') {
100
+ finalized = await pub.getBlock({ blockTag: 'finalized' });
101
+ if (!finalized || !uint(finalized.number) || !NATIVE_ACCOUNT_HASH.safeParse(finalized.hash).success)
102
+ refuseNative('NATIVE_ACCOUNT_TRANSACTION_UNKNOWN', 'Finalized block is unavailable or unsealed');
103
+ if (finalized.number < receipt.blockNumber)
104
+ refuseNative('NATIVE_ACCOUNT_NOT_FINAL', 'Transaction is mined but not yet covered by the finalized head');
105
+ if (finalized.number === receipt.blockNumber && !same(finalized.hash, receipt.blockHash))
106
+ refuseNative('NATIVE_ACCOUNT_TRANSACTION_MISMATCH', 'Finalized block disagrees with the receipt block');
107
+ }
108
+ // Recheck the canonical anchors after collecting finality, as the native settlement reader does.
109
+ const [anchor, chainId, finalAnchor] = await Promise.all([
110
+ pub.getBlock({ blockNumber: receipt.blockNumber }), pub.getChainId(),
111
+ finalized ? pub.getBlock({ blockNumber: finalized.number }) : Promise.resolve(undefined),
112
+ ]);
113
+ checkChain(pub, chainId, expected.chainId);
114
+ sealed(anchor, receipt.blockNumber, receipt.blockHash);
115
+ if (finalized) {
116
+ if (!finalAnchor)
117
+ refuseNative('NATIVE_ACCOUNT_TRANSACTION_UNKNOWN', 'Finalized block could not be rechecked');
118
+ sealed(finalAnchor, finalized.number, finalized.hash);
119
+ }
120
+ return Object.freeze(observed.data);
121
+ }
122
+ catch (error) {
123
+ if (error instanceof NativeYieldRefusal)
124
+ throw error;
125
+ return refuseNative('NATIVE_ACCOUNT_TRANSACTION_UNKNOWN', 'Canonical transaction evidence could not be established');
126
+ }
127
+ }
128
+ //# sourceMappingURL=native-yield-account-rpc.js.map