@agenticprimitives/contracts 0.1.0-alpha.3 → 1.0.0-alpha.5

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 (57) hide show
  1. package/AUDIT.md +304 -47
  2. package/README.md +19 -8
  3. package/deployments-base-sepolia.json +1 -0
  4. package/dist/abi/AgentAccount.json +1647 -0
  5. package/dist/abi/AgentAccountFactory.json +472 -0
  6. package/dist/abi/AgentNameRegistry.json +46 -0
  7. package/dist/abi/AgreementRegistry.json +432 -0
  8. package/dist/abi/AttestationRegistry.json +436 -0
  9. package/dist/abi/CallDataHashEnforcer.json +119 -0
  10. package/dist/abi/CustodyPolicy.json +1111 -0
  11. package/dist/abi/DelegationManager.json +645 -0
  12. package/dist/abi/GeoFeatureRegistry.json +625 -0
  13. package/dist/abi/IAgentAccount.json +262 -0
  14. package/dist/abi/IAgentAccountFactoryAccessor.json +15 -0
  15. package/dist/abi/IAgentAccountFactoryView.json +41 -0
  16. package/dist/abi/IAgentAccountPauseView.json +15 -0
  17. package/dist/abi/IAgenticPrimitivesAgentAccount.json +15 -0
  18. package/dist/abi/IApprovedHashRegistryView.json +26 -0
  19. package/dist/abi/ICustodyPolicyFactoryView.json +15 -0
  20. package/dist/abi/ICustodyPolicyPauseView.json +15 -0
  21. package/dist/abi/IDelegationManager.json +171 -0
  22. package/dist/abi/IERC7579HookLike.json +44 -0
  23. package/dist/abi/IERC7579ModuleLike.json +28 -0
  24. package/dist/abi/PermissionlessSubregistry.json +5 -0
  25. package/dist/abi/QuorumEnforcer.json +295 -0
  26. package/dist/abi/SignatureSlotRecovery.json +88 -0
  27. package/dist/abi/SkillDefinitionRegistry.json +491 -0
  28. package/dist/abi/SmartAgentPaymaster.json +664 -0
  29. package/dist/abi/UniversalSignatureValidator.json +65 -0
  30. package/dist/abi/index.d.ts +23 -0
  31. package/dist/abi/index.js +23 -0
  32. package/dist/deployments/base-sepolia.d.ts +37 -0
  33. package/dist/deployments/base-sepolia.js +35 -0
  34. package/dist/deployments/index.d.ts +8 -0
  35. package/dist/deployments/index.js +13 -0
  36. package/package.json +20 -3
  37. package/src/AgentAccount.sol +130 -9
  38. package/src/AgentAccountFactory.sol +34 -5
  39. package/src/SmartAgentPaymaster.sol +37 -8
  40. package/src/UniversalSignatureValidator.sol +3 -0
  41. package/src/agency/DelegationManager.sol +155 -0
  42. package/src/agency/IDelegationManager.sol +35 -0
  43. package/src/agreement/AgreementRegistry.sol +306 -0
  44. package/src/attestation/AttestationRegistry.sol +320 -0
  45. package/src/custody/CustodyPolicy.sol +79 -2
  46. package/src/enforcers/AllowedMethodsEnforcer.sol +6 -0
  47. package/src/enforcers/AllowedTargetsEnforcer.sol +6 -0
  48. package/src/enforcers/CallDataHashEnforcer.sol +61 -0
  49. package/src/enforcers/QuorumEnforcer.sol +8 -0
  50. package/src/enforcers/TimestampEnforcer.sol +7 -0
  51. package/src/enforcers/ValueEnforcer.sol +6 -0
  52. package/src/geo/GeoFeatureRegistry.sol +190 -0
  53. package/src/naming/AgentNameRegistry.sol +25 -13
  54. package/src/naming/AgentNameUniversalResolver.sol +1 -1
  55. package/src/naming/PermissionlessSubregistry.sol +19 -2
  56. package/src/relationships/AgentRelationship.sol +8 -0
  57. package/src/skills/SkillDefinitionRegistry.sol +181 -0
@@ -0,0 +1,65 @@
1
+ [
2
+ {
3
+ "type": "function",
4
+ "name": "isValidSig",
5
+ "inputs": [
6
+ {
7
+ "name": "signer",
8
+ "type": "address",
9
+ "internalType": "address"
10
+ },
11
+ {
12
+ "name": "hash",
13
+ "type": "bytes32",
14
+ "internalType": "bytes32"
15
+ },
16
+ {
17
+ "name": "sig",
18
+ "type": "bytes",
19
+ "internalType": "bytes"
20
+ }
21
+ ],
22
+ "outputs": [
23
+ {
24
+ "name": "",
25
+ "type": "bool",
26
+ "internalType": "bool"
27
+ }
28
+ ],
29
+ "stateMutability": "nonpayable"
30
+ },
31
+ {
32
+ "type": "function",
33
+ "name": "isValidSigView",
34
+ "inputs": [
35
+ {
36
+ "name": "signer",
37
+ "type": "address",
38
+ "internalType": "address"
39
+ },
40
+ {
41
+ "name": "hash",
42
+ "type": "bytes32",
43
+ "internalType": "bytes32"
44
+ },
45
+ {
46
+ "name": "sig",
47
+ "type": "bytes",
48
+ "internalType": "bytes"
49
+ }
50
+ ],
51
+ "outputs": [
52
+ {
53
+ "name": "",
54
+ "type": "bool",
55
+ "internalType": "bool"
56
+ }
57
+ ],
58
+ "stateMutability": "view"
59
+ },
60
+ {
61
+ "type": "error",
62
+ "name": "DeployFailed",
63
+ "inputs": []
64
+ }
65
+ ]
@@ -1,6 +1,8 @@
1
1
  // Generated by scripts/build-abi.mjs — do not edit by hand.
2
2
  import type { Abi } from 'viem';
3
3
 
4
+ export declare const AgentAccount: Abi;
5
+ export declare const AgentAccountFactory: Abi;
4
6
  export declare const AgenticGovernance: Abi;
5
7
  export declare const AgentNameAttributeResolver: Abi;
6
8
  export declare const AgentNamePredicates: Abi;
@@ -10,26 +12,47 @@ export declare const AgentProfilePredicates: Abi;
10
12
  export declare const AgentProfileResolver: Abi;
11
13
  export declare const AgentRelationship: Abi;
12
14
  export declare const AgentRelationshipPredicates: Abi;
15
+ export declare const AgreementRegistry: Abi;
13
16
  export declare const AllowedMethodsEnforcer: Abi;
14
17
  export declare const AllowedTargetsEnforcer: Abi;
15
18
  export declare const ApprovedHashRegistry: Abi;
19
+ export declare const AttestationRegistry: Abi;
16
20
  export declare const AttributeStorage: Abi;
21
+ export declare const CallDataHashEnforcer: Abi;
17
22
  export declare const CaveatEnforcerBase: Abi;
23
+ export declare const CustodyPolicy: Abi;
24
+ export declare const DelegationManager: Abi;
25
+ export declare const GeoFeatureRegistry: Abi;
18
26
  export declare const GovernanceManaged: Abi;
27
+ export declare const IAgentAccount: Abi;
28
+ export declare const IAgentAccountFactoryAccessor: Abi;
29
+ export declare const IAgentAccountFactoryView: Abi;
30
+ export declare const IAgentAccountPauseView: Abi;
31
+ export declare const IAgenticPrimitivesAgentAccount: Abi;
32
+ export declare const IApprovedHashRegistryView: Abi;
19
33
  export declare const IAttributeReader: Abi;
20
34
  export declare const ICaveatEnforcer: Abi;
35
+ export declare const ICustodyPolicyFactoryView: Abi;
36
+ export declare const ICustodyPolicyPauseView: Abi;
21
37
  export declare const IDelegationManager: Abi;
38
+ export declare const IERC7579HookLike: Abi;
22
39
  export declare const IERC7579Module: Abi;
23
40
  export declare const IERC7579ModuleLifecycle: Abi;
41
+ export declare const IERC7579ModuleLike: Abi;
24
42
  export declare const IGovernanceView: Abi;
25
43
  export declare const MultiSendCallOnly: Abi;
26
44
  export declare const MultiSendCallOnlyHarness: Abi;
27
45
  export declare const OntologyTermRegistry: Abi;
28
46
  export declare const P256Verifier: Abi;
29
47
  export declare const PermissionlessSubregistry: Abi;
48
+ export declare const QuorumEnforcer: Abi;
30
49
  export declare const RelationshipTypeRegistry: Abi;
31
50
  export declare const ShapeRegistry: Abi;
51
+ export declare const SignatureSlotRecovery: Abi;
52
+ export declare const SkillDefinitionRegistry: Abi;
32
53
  export declare const SmartAgentModuleTypes: Abi;
54
+ export declare const SmartAgentPaymaster: Abi;
33
55
  export declare const TimestampEnforcer: Abi;
56
+ export declare const UniversalSignatureValidator: Abi;
34
57
  export declare const ValueEnforcer: Abi;
35
58
  export declare const WebAuthnLib: Abi;
package/dist/abi/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  // Generated by scripts/build-abi.mjs — do not edit by hand.
2
2
  // Each export is a viem-compatible ABI array.
3
3
 
4
+ export { default as AgentAccount } from './AgentAccount.json' with { type: 'json' };
5
+ export { default as AgentAccountFactory } from './AgentAccountFactory.json' with { type: 'json' };
4
6
  export { default as AgenticGovernance } from './AgenticGovernance.json' with { type: 'json' };
5
7
  export { default as AgentNameAttributeResolver } from './AgentNameAttributeResolver.json' with { type: 'json' };
6
8
  export { default as AgentNamePredicates } from './AgentNamePredicates.json' with { type: 'json' };
@@ -10,26 +12,47 @@ export { default as AgentProfilePredicates } from './AgentProfilePredicates.json
10
12
  export { default as AgentProfileResolver } from './AgentProfileResolver.json' with { type: 'json' };
11
13
  export { default as AgentRelationship } from './AgentRelationship.json' with { type: 'json' };
12
14
  export { default as AgentRelationshipPredicates } from './AgentRelationshipPredicates.json' with { type: 'json' };
15
+ export { default as AgreementRegistry } from './AgreementRegistry.json' with { type: 'json' };
13
16
  export { default as AllowedMethodsEnforcer } from './AllowedMethodsEnforcer.json' with { type: 'json' };
14
17
  export { default as AllowedTargetsEnforcer } from './AllowedTargetsEnforcer.json' with { type: 'json' };
15
18
  export { default as ApprovedHashRegistry } from './ApprovedHashRegistry.json' with { type: 'json' };
19
+ export { default as AttestationRegistry } from './AttestationRegistry.json' with { type: 'json' };
16
20
  export { default as AttributeStorage } from './AttributeStorage.json' with { type: 'json' };
21
+ export { default as CallDataHashEnforcer } from './CallDataHashEnforcer.json' with { type: 'json' };
17
22
  export { default as CaveatEnforcerBase } from './CaveatEnforcerBase.json' with { type: 'json' };
23
+ export { default as CustodyPolicy } from './CustodyPolicy.json' with { type: 'json' };
24
+ export { default as DelegationManager } from './DelegationManager.json' with { type: 'json' };
25
+ export { default as GeoFeatureRegistry } from './GeoFeatureRegistry.json' with { type: 'json' };
18
26
  export { default as GovernanceManaged } from './GovernanceManaged.json' with { type: 'json' };
27
+ export { default as IAgentAccount } from './IAgentAccount.json' with { type: 'json' };
28
+ export { default as IAgentAccountFactoryAccessor } from './IAgentAccountFactoryAccessor.json' with { type: 'json' };
29
+ export { default as IAgentAccountFactoryView } from './IAgentAccountFactoryView.json' with { type: 'json' };
30
+ export { default as IAgentAccountPauseView } from './IAgentAccountPauseView.json' with { type: 'json' };
31
+ export { default as IAgenticPrimitivesAgentAccount } from './IAgenticPrimitivesAgentAccount.json' with { type: 'json' };
32
+ export { default as IApprovedHashRegistryView } from './IApprovedHashRegistryView.json' with { type: 'json' };
19
33
  export { default as IAttributeReader } from './IAttributeReader.json' with { type: 'json' };
20
34
  export { default as ICaveatEnforcer } from './ICaveatEnforcer.json' with { type: 'json' };
35
+ export { default as ICustodyPolicyFactoryView } from './ICustodyPolicyFactoryView.json' with { type: 'json' };
36
+ export { default as ICustodyPolicyPauseView } from './ICustodyPolicyPauseView.json' with { type: 'json' };
21
37
  export { default as IDelegationManager } from './IDelegationManager.json' with { type: 'json' };
38
+ export { default as IERC7579HookLike } from './IERC7579HookLike.json' with { type: 'json' };
22
39
  export { default as IERC7579Module } from './IERC7579Module.json' with { type: 'json' };
23
40
  export { default as IERC7579ModuleLifecycle } from './IERC7579ModuleLifecycle.json' with { type: 'json' };
41
+ export { default as IERC7579ModuleLike } from './IERC7579ModuleLike.json' with { type: 'json' };
24
42
  export { default as IGovernanceView } from './IGovernanceView.json' with { type: 'json' };
25
43
  export { default as MultiSendCallOnly } from './MultiSendCallOnly.json' with { type: 'json' };
26
44
  export { default as MultiSendCallOnlyHarness } from './MultiSendCallOnlyHarness.json' with { type: 'json' };
27
45
  export { default as OntologyTermRegistry } from './OntologyTermRegistry.json' with { type: 'json' };
28
46
  export { default as P256Verifier } from './P256Verifier.json' with { type: 'json' };
29
47
  export { default as PermissionlessSubregistry } from './PermissionlessSubregistry.json' with { type: 'json' };
48
+ export { default as QuorumEnforcer } from './QuorumEnforcer.json' with { type: 'json' };
30
49
  export { default as RelationshipTypeRegistry } from './RelationshipTypeRegistry.json' with { type: 'json' };
31
50
  export { default as ShapeRegistry } from './ShapeRegistry.json' with { type: 'json' };
51
+ export { default as SignatureSlotRecovery } from './SignatureSlotRecovery.json' with { type: 'json' };
52
+ export { default as SkillDefinitionRegistry } from './SkillDefinitionRegistry.json' with { type: 'json' };
32
53
  export { default as SmartAgentModuleTypes } from './SmartAgentModuleTypes.json' with { type: 'json' };
54
+ export { default as SmartAgentPaymaster } from './SmartAgentPaymaster.json' with { type: 'json' };
33
55
  export { default as TimestampEnforcer } from './TimestampEnforcer.json' with { type: 'json' };
56
+ export { default as UniversalSignatureValidator } from './UniversalSignatureValidator.json' with { type: 'json' };
34
57
  export { default as ValueEnforcer } from './ValueEnforcer.json' with { type: 'json' };
35
58
  export { default as WebAuthnLib } from './WebAuthnLib.json' with { type: 'json' };
@@ -0,0 +1,37 @@
1
+ // Generated by scripts/build-deployments.mjs — do not edit by hand.
2
+ // Source: deployments-base-sepolia.json
3
+ import type { Address } from 'viem';
4
+ export interface Deployments {
5
+ readonly "agentAccountFactory": Address;
6
+ readonly "agentAccountImplementation": Address;
7
+ readonly "agentNameRegistry": Address;
8
+ readonly "agentNameResolver": Address;
9
+ readonly "agentNameUniversalResolver": Address;
10
+ readonly "agentProfileResolver": Address;
11
+ readonly "agentRelationship": Address;
12
+ readonly "agreementRegistry": Address;
13
+ readonly "allowedMethodsEnforcer": Address;
14
+ readonly "allowedTargetsEnforcer": Address;
15
+ readonly "approvedHashRegistry": Address;
16
+ readonly "attestationRegistry": Address;
17
+ readonly "callDataHashEnforcer": Address;
18
+ readonly "custodyPolicy": Address;
19
+ readonly "delegationManager": Address;
20
+ readonly "deployer": Address;
21
+ readonly "entryPoint": Address;
22
+ readonly "geoFeatureRegistry": Address;
23
+ readonly "ontologyTermRegistry": Address;
24
+ readonly "permissionlessSubregistry": Address;
25
+ readonly "permissionlessSubregistryDemoAgent": Address;
26
+ readonly "quorumEnforcer": Address;
27
+ readonly "relationshipTypeRegistry": Address;
28
+ readonly "shapeRegistry": Address;
29
+ readonly "skillDefinitionRegistry": Address;
30
+ readonly "smartAgentPaymaster": Address;
31
+ readonly "timestampEnforcer": Address;
32
+ readonly "universalSignatureValidator": Address;
33
+ readonly "valueEnforcer": Address;
34
+ readonly "chainId": number;
35
+ }
36
+ export declare const CONTRACTS: Deployments;
37
+ export default CONTRACTS;
@@ -0,0 +1,35 @@
1
+ // Generated by scripts/build-deployments.mjs — do not edit by hand.
2
+ // Source: deployments-base-sepolia.json
3
+ export const CONTRACTS = {
4
+ "agentAccountFactory": "0x6f7Fc9B36977F55666548e0a73D9063F0D88A760",
5
+ "agentAccountImplementation": "0x11f1523D9883BdF382993d70C601D307ED0F1f13",
6
+ "agentNameRegistry": "0x6e660e41CFd0B410827fb96D21c26600AF6abF2f",
7
+ "agentNameResolver": "0x324F5A60c5DE45244c70a43cA3A6B1462d80fF5f",
8
+ "agentNameUniversalResolver": "0x40587e3591F7051ba7534177aB1F0B366034040e",
9
+ "agentProfileResolver": "0x748D005E8B3b366132F209F066821B2713A6e19e",
10
+ "agentRelationship": "0x5c3bf13822a37c84Dc617C920dB61a8217f6311d",
11
+ "agreementRegistry": "0x3B1DB6AC972b649E9E0960F0816F4D1EC3264c22",
12
+ "allowedMethodsEnforcer": "0x1500601201aA339249e2B78c42952Cf26CD12Ea7",
13
+ "allowedTargetsEnforcer": "0xfA1c40F9dC4ACC4d339D2eDE0003872154292CEa",
14
+ "approvedHashRegistry": "0xE01c1356F4B10FEfa8Ab210020B802cf3e900759",
15
+ "attestationRegistry": "0x16EB207C65A63E3ae256F49a4B11e785fE001139",
16
+ "callDataHashEnforcer": "0x7267eF129fCf341717D7f3469DDf7A0135d00b61",
17
+ "chainId": 84532,
18
+ "custodyPolicy": "0x5e3e3Bda33c799f2403a30aE35bf81deff236283",
19
+ "delegationManager": "0xBC5AE6213E91E076232a6c8e3942746f06A50154",
20
+ "deployer": "0x31ed17fb99e82E02085Ab4B3cbdaB05489098b44",
21
+ "entryPoint": "0x7707C2b483CcADc3E72C2d39d216aC1C337FCd9d",
22
+ "geoFeatureRegistry": "0x0A9f10cb72D6Fb5C89Aa5865f397957729cF71F0",
23
+ "ontologyTermRegistry": "0xa9635EbfDb993395df6CD03b0DEE21E5b2A66Ec1",
24
+ "permissionlessSubregistry": "0xF38fdcd8eC83360C2F73CEEa52ae419D37aCaB5F",
25
+ "permissionlessSubregistryDemoAgent": "0x1c698cBFE2733301614a245a505E20eB5597a972",
26
+ "quorumEnforcer": "0xeB88df4492FB8Eb254f6017eD0463d42CF6FC8e7",
27
+ "relationshipTypeRegistry": "0x7c5FfD0aB55C52f6aa00c04D2a30457579A3083B",
28
+ "shapeRegistry": "0xAe431c6F000235d30ae28f507493215815eF88E2",
29
+ "skillDefinitionRegistry": "0xc0A26f8bac0482E0F8e3a61762F5862Bc21a2D11",
30
+ "smartAgentPaymaster": "0x0e54A8Cc986C86530f0593817E8CafE01FC52983",
31
+ "timestampEnforcer": "0xf9AeF60b8cb4939bF5B1AF48E777dad99Ef1084f",
32
+ "universalSignatureValidator": "0x7A282fFf06E6DC73613A31F55345535e24CB6832",
33
+ "valueEnforcer": "0x4be1B537b9583E69D9baBf8af1dc5371A4a750C5"
34
+ };
35
+ export default CONTRACTS;
@@ -0,0 +1,8 @@
1
+ // Generated by scripts/build-deployments.mjs — do not edit by hand.
2
+ import type { Address } from 'viem';
3
+ import type { Deployments } from './base-sepolia';
4
+ export type { Deployments };
5
+ export declare const BASE_SEPOLIA: Deployments;
6
+
7
+ export type Network = 'base-sepolia';
8
+ export declare function getDeployments(network: Network): Deployments;
@@ -0,0 +1,13 @@
1
+ // Generated by scripts/build-deployments.mjs — do not edit by hand.
2
+ import { CONTRACTS as BASE_SEPOLIA } from './base-sepolia.js';
3
+ export { BASE_SEPOLIA };
4
+
5
+ const TABLE = {
6
+ "base-sepolia": BASE_SEPOLIA,
7
+ };
8
+
9
+ export function getDeployments(network) {
10
+ const c = TABLE[network];
11
+ if (!c) throw new Error('[@agenticprimitives/contracts] no deployments for network ' + network);
12
+ return c;
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenticprimitives/contracts",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "1.0.0-alpha.5",
4
4
  "description": "Solidity contracts + ABIs + flattened sources + per-network deployment addresses for the agenticprimitives stack.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -15,7 +15,15 @@
15
15
  "exports": {
16
16
  "./abi": "./dist/abi/index.js",
17
17
  "./abi/*": "./dist/abi/*.json",
18
- "./deployments/*": "./deployments-*.json"
18
+ "./deployments": {
19
+ "types": "./dist/deployments/index.d.ts",
20
+ "default": "./dist/deployments/index.js"
21
+ },
22
+ "./deployments/*": {
23
+ "types": "./dist/deployments/*.d.ts",
24
+ "default": "./dist/deployments/*.js"
25
+ },
26
+ "./deployments-json/*": "./deployments-*.json"
19
27
  },
20
28
  "files": [
21
29
  "LICENSE",
@@ -25,18 +33,27 @@
25
33
  "spec.md",
26
34
  "src",
27
35
  "dist/abi",
36
+ "dist/deployments",
28
37
  "dist/flat",
29
38
  "deployments-*.json"
30
39
  ],
40
+ "devDependencies": {
41
+ "solhint": "^5.0.5"
42
+ },
31
43
  "publishConfig": {
32
44
  "access": "public"
33
45
  },
34
46
  "scripts": {
35
47
  "setup": "bash setup.sh",
36
- "build": "forge build && pnpm run build:abi",
48
+ "build": "forge build && pnpm run build:abi && pnpm run build:deployments",
37
49
  "build:abi": "node scripts/build-abi.mjs",
50
+ "build:deployments": "node scripts/build-deployments.mjs",
38
51
  "build:flat": "node scripts/build-flat.mjs",
39
52
  "test": "forge test",
53
+ "halmos": "halmos",
54
+ "echidna": "echidna test/echidna/CustodyPolicyEchidna.t.sol --contract CustodyPolicyEchidna --config echidna.yaml",
55
+ "medusa": "medusa fuzz --config medusa.json",
56
+ "lint": "solhint 'src/**/*.sol'",
40
57
  "typecheck": "echo 'no TS in this package; ABIs are JSON' && exit 0",
41
58
  "deploy:anvil": "forge script script/Deploy.s.sol --rpc-url http://127.0.0.1:8545 --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
42
59
  "deploy:base-sepolia": "DEPLOY_NETWORK=base-sepolia forge script script/Deploy.s.sol --rpc-url $BASE_SEPOLIA_RPC --broadcast --private-key $PRIVATE_KEY",
@@ -22,6 +22,33 @@ import "./libraries/WebAuthnLib.sol";
22
22
  interface IAgentAccountFactoryView {
23
23
  function bundlerSigner() external view returns (address);
24
24
  function sessionIssuer() external view returns (address);
25
+ /// @dev R6.5 — the factory inherits `GovernanceManaged`; its
26
+ /// `governance()` getter returns the AgenticGovernance pointer
27
+ /// shared across every account it creates. AgentAccount reads
28
+ /// this address to call `IGovernanceView.isPaused()` from
29
+ /// `whenNotPaused`-guarded entrypoints.
30
+ function governance() external view returns (address);
31
+ }
32
+
33
+ /// @dev R6.5 — minimal interface for the pause read. Mirrors the same
34
+ /// selector `GovernanceManaged._pausedSafe()` uses so an EOA or
35
+ /// non-conforming governance contract is treated as "not paused"
36
+ /// (legacy / test deploys still work). Production deploys ALWAYS
37
+ /// use `AgenticGovernance` which implements this interface.
38
+ interface IAgentAccountPauseView {
39
+ function isPaused() external view returns (bool);
40
+ }
41
+
42
+ /// @dev Spec 253 — minimal read surface of `ApprovedHashRegistry`. The
43
+ /// account consults it ONLY from `isValidSignature` (the ERC-1271
44
+ /// entrypoint), under the `0x03` sentinel, so a hash the account
45
+ /// itself pre-approved (inside its own custody-gated execute/batch)
46
+ /// validates as an ERC-1271 signature. Address is bound IMMUTABLE in
47
+ /// the impl (see constructor) — never an owner-mutable view — so a
48
+ /// factory/governance key compromise cannot re-point it at an
49
+ /// attacker registry to forge signatures.
50
+ interface IApprovedHashRegistryView {
51
+ function isApproved(address signer, bytes32 hash) external view returns (bool);
25
52
  }
26
53
 
27
54
  /**
@@ -60,6 +87,14 @@ contract AgentAccount is
60
87
  /// @dev The ERC-4337 EntryPoint contract
61
88
  IEntryPoint private immutable _entryPoint;
62
89
 
90
+ /// @dev Spec 253 — the `ApprovedHashRegistry` consulted by the `0x03`
91
+ /// sentinel branch of `isValidSignature`. IMMUTABLE (baked into
92
+ /// impl bytecode, shared by every proxy, changeable only via a
93
+ /// custody-gated UUPS upgrade). May be `address(0)` on legacy/test
94
+ /// deploys that don't use the sentinel — in which case the
95
+ /// sentinel fails CLOSED (see `isValidSignature`).
96
+ address private immutable _approvedHashRegistry;
97
+
63
98
  /// @dev Authorized DelegationManager (ERC-7710 executor)
64
99
  address private _delegationManager;
65
100
 
@@ -127,6 +162,9 @@ contract AgentAccount is
127
162
 
128
163
  error NotFromSelf();
129
164
  error NotCustodianOrSelf();
165
+ /// @notice R6.5 — thrown when a `whenNotPaused`-guarded entrypoint
166
+ /// is called while `AgenticGovernance.isPaused() == true`.
167
+ error SystemPaused();
130
168
  error CustodianAlreadyExists(address owner);
131
169
  error CustodianDoesNotExist(address owner);
132
170
  error CannotRemoveLastCustodian();
@@ -200,10 +238,53 @@ contract AgentAccount is
200
238
  _;
201
239
  }
202
240
 
241
+ // ─── R6.5 / CON-AgentAccount-005 — system-wide pause modifier ──
242
+ //
243
+ // When `AgenticGovernance.isPaused() == true`, every mutating
244
+ // external entrypoint guarded by this modifier reverts with
245
+ // `SystemPaused`. Recovery-shaped entrypoints
246
+ // (`uninstallModule`, `cancelPendingUpgrade`, `removeCustodian`,
247
+ // the three `onlySelf` ceremonies) are deliberately NOT guarded
248
+ // — an operator must always be able to remove attack surface
249
+ // even during an incident.
250
+ //
251
+ // Reads `governance()` through the factory at each check so a
252
+ // factory-level governance rotation propagates to every account
253
+ // without per-account migration. Legacy / direct-deploy accounts
254
+ // (no factory) and EOA-governance / non-conforming-governance
255
+ // deploys are treated as "not paused" so existing test fixtures
256
+ // keep working — mirrors `GovernanceManaged._pausedSafe()`.
257
+ modifier whenNotPaused() {
258
+ if (_systemPaused()) revert SystemPaused();
259
+ _;
260
+ }
261
+
262
+ /// @dev R6.5 — `staticcall` chain: factory → governance.isPaused().
263
+ /// Returns `false` on any non-conforming hop (legacy
264
+ /// compatibility). Production deploys MUST pass a real
265
+ /// `AgenticGovernance` to the factory; the production-deploy
266
+ /// preflight enforces that invariant.
267
+ function _systemPaused() internal view returns (bool) {
268
+ address f = _factory;
269
+ if (f == address(0)) return false;
270
+ (bool okF, bytes memory dataF) = f.staticcall(
271
+ abi.encodeWithSelector(IAgentAccountFactoryView.governance.selector)
272
+ );
273
+ if (!okF || dataF.length < 32) return false;
274
+ address g = abi.decode(dataF, (address));
275
+ if (g == address(0) || g.code.length == 0) return false;
276
+ (bool okG, bytes memory dataG) = g.staticcall(
277
+ abi.encodeWithSelector(IAgentAccountPauseView.isPaused.selector)
278
+ );
279
+ if (!okG || dataG.length < 32) return false;
280
+ return abi.decode(dataG, (bool));
281
+ }
282
+
203
283
  // ─── Constructor / Initializer ──────────────────────────────────
204
284
 
205
- constructor(IEntryPoint entryPoint_) {
285
+ constructor(IEntryPoint entryPoint_, address approvedHashRegistry_) {
206
286
  _entryPoint = entryPoint_;
287
+ _approvedHashRegistry = approvedHashRegistry_;
207
288
  _disableInitializers();
208
289
  }
209
290
 
@@ -361,7 +442,7 @@ contract AgentAccount is
361
442
  /// @notice Execute a previously-queued upgrade. Permissionless once
362
443
  /// the timelock has expired — anyone can pay the gas, but
363
444
  /// the implementation address was bound at queue time.
364
- function executePendingUpgrade() external {
445
+ function executePendingUpgrade() external whenNotPaused {
365
446
  PendingUpgrade memory p = _pendingUpgrade;
366
447
  if (p.readyAt == 0) revert NoPendingUpgrade();
367
448
  if (block.timestamp < p.readyAt) revert UpgradeNotReady(p.readyAt, block.timestamp);
@@ -689,7 +770,7 @@ contract AgentAccount is
689
770
  uint256 moduleTypeId,
690
771
  address module,
691
772
  bytes calldata initData
692
- ) external onlySelfOrFactoryInit {
773
+ ) external onlySelfOrFactoryInit whenNotPaused {
693
774
  if (module == address(0)) revert ZeroAddress();
694
775
  if (!_isSupportedModuleType(moduleTypeId)) revert UnsupportedModuleType(moduleTypeId);
695
776
 
@@ -837,6 +918,7 @@ contract AgentAccount is
837
918
  function executeFromModule(address target, uint256 value, bytes calldata data)
838
919
  external
839
920
  nonReentrant
921
+ whenNotPaused
840
922
  returns (bytes memory)
841
923
  {
842
924
  ModulesStorage storage $ = _modulesStorage();
@@ -891,7 +973,7 @@ contract AgentAccount is
891
973
  /// EntryPoint / self / DelegationManager; the guard hardens
892
974
  /// against a malicious target re-entering through one of those
893
975
  /// callers.
894
- function execute(address target, uint256 value, bytes calldata data) external override nonReentrant {
976
+ function execute(address target, uint256 value, bytes calldata data) external override nonReentrant whenNotPaused {
895
977
  _requireForExecute();
896
978
 
897
979
  ModulesStorage storage $ = _modulesStorage();
@@ -944,7 +1026,7 @@ contract AgentAccount is
944
1026
  /// OUTER `execute` already holds the guard, so external re-entry
945
1027
  /// is blocked; `_requireForExecute` restricts entry to
946
1028
  /// EntryPoint / self / DM (DM has its own `nonReentrant`).
947
- function executeBatch(Call[] calldata calls) external override {
1029
+ function executeBatch(Call[] calldata calls) external override whenNotPaused {
948
1030
  _requireForExecute();
949
1031
 
950
1032
  ModulesStorage storage $ = _modulesStorage();
@@ -1018,6 +1100,21 @@ contract AgentAccount is
1018
1100
  bytes32 hash,
1019
1101
  bytes calldata signature
1020
1102
  ) external view override(IAgentAccount, IERC1271) returns (bytes4) {
1103
+ // Spec 253 — approved-hash sentinel (ERC-1271 ONLY). A bare 1-byte
1104
+ // 0x03 validates iff THIS account pre-approved `hash` in the
1105
+ // (immutable) ApprovedHashRegistry — letting an org batch its
1106
+ // outbound-delegation approvals into one deploy userOp. Checked on
1107
+ // the RAW signature before the ERC-6492 unwrap: a 1-byte sig can't
1108
+ // carry a 32-byte 6492 suffix, so there's no smuggling path. This
1109
+ // branch is unreachable from `_validateSignature`/`_validateSig`
1110
+ // (the userOp-auth path), where 0x03 is an unknown type → false.
1111
+ // Fails CLOSED if the registry is unset/not-a-contract (ADR-0013).
1112
+ if (signature.length == 1 && uint8(signature[0]) == SIG_TYPE_APPROVED_HASH) {
1113
+ if (_approvedHashRegistry.code.length == 0) return bytes4(0xffffffff);
1114
+ return IApprovedHashRegistryView(_approvedHashRegistry).isApproved(address(this), hash)
1115
+ ? ERC1271_MAGIC_VALUE
1116
+ : bytes4(0xffffffff);
1117
+ }
1021
1118
  bytes memory inner = signature;
1022
1119
  if (signature.length >= 32 && bytes32(signature[signature.length - 32:]) == ERC6492_MAGIC) {
1023
1120
  (, , bytes memory unwrapped) = abi.decode(
@@ -1033,6 +1130,12 @@ contract AgentAccount is
1033
1130
 
1034
1131
  uint8 internal constant SIG_TYPE_ECDSA = 0x00;
1035
1132
  uint8 internal constant SIG_TYPE_WEBAUTHN = 0x01;
1133
+ /// @dev Spec 253 — approved-hash sentinel. Honored ONLY by
1134
+ /// `isValidSignature` (ERC-1271), NEVER by `_validateSig` /
1135
+ /// `_validateSignature` (the userOp-auth path) — there `0x03` is an
1136
+ /// unknown type and returns false. A bare 1-byte `0x03` means
1137
+ /// "this hash is pre-approved in the ApprovedHashRegistry".
1138
+ uint8 internal constant SIG_TYPE_APPROVED_HASH = 0x03;
1036
1139
 
1037
1140
  /// @dev Internal dispatcher. Accepts plain 65-byte ECDSA sigs as legacy
1038
1141
  /// form AND type-prefixed sigs (first byte = SIG_TYPE_*).
@@ -1061,11 +1164,14 @@ contract AgentAccount is
1061
1164
 
1062
1165
  function _verifyEcdsa(bytes32 hash, bytes memory sig) internal view returns (bool) {
1063
1166
  // Try raw hash first — matches EntryPoint v0.8 (EIP-712 userOpHash signed directly).
1167
+ // R6.3: third return (sigVersion) intentionally discarded; we rely on `err` + custodian-set membership.
1168
+ // slither-disable-next-line unused-return
1064
1169
  (address recovered, ECDSA.RecoverError err,) = ECDSA.tryRecover(hash, sig);
1065
1170
  if (err == ECDSA.RecoverError.NoError && _externalCustodians[recovered]) return true;
1066
1171
  // Fall back to eth-signed-message wrap — matches v0.7 and legacy ERC-1271
1067
1172
  // callers that pre-prefix the digest.
1068
1173
  bytes32 ethSigned = hash.toEthSignedMessageHash();
1174
+ // slither-disable-next-line unused-return
1069
1175
  (recovered, err,) = ECDSA.tryRecover(ethSigned, sig);
1070
1176
  return err == ECDSA.RecoverError.NoError && _externalCustodians[recovered];
1071
1177
  }
@@ -1079,9 +1185,12 @@ contract AgentAccount is
1079
1185
  bytes memory sig,
1080
1186
  address expected
1081
1187
  ) internal pure returns (bool) {
1188
+ // R6.3: third return (sigVersion) intentionally discarded; the `err` discriminant + `recovered == expected` is the auth.
1189
+ // slither-disable-next-line unused-return
1082
1190
  (address recovered, ECDSA.RecoverError err,) = ECDSA.tryRecover(hash, sig);
1083
1191
  if (err == ECDSA.RecoverError.NoError && recovered == expected) return true;
1084
1192
  bytes32 ethSigned = MessageHashUtils.toEthSignedMessageHash(hash);
1193
+ // slither-disable-next-line unused-return
1085
1194
  (recovered, err,) = ECDSA.tryRecover(ethSigned, sig);
1086
1195
  return err == ECDSA.RecoverError.NoError && recovered == expected;
1087
1196
  }
@@ -1105,11 +1214,23 @@ contract AgentAccount is
1105
1214
  PasskeyEntry storage key = $.keys[a.credentialIdDigest];
1106
1215
  if (key.x == 0 && key.y == 0) return false;
1107
1216
  // H7-C.1 / CON-WEBAUTHN-001: pin per-credential rpIdHash + require UP.
1108
- // UV is not required at the library layer; account policy can layer
1109
- // UV requirement in via a future policy module if needed.
1217
+ // R8.2 / ATL-SEC-03: require UV (User Verification) at the library
1218
+ // layer. Wave H1 made the JS-side ceremony pass
1219
+ // `userVerification: 'required'` for custody-grade flows
1220
+ // (demo-sso, demo-sso-next, demo-org, demo-web-recovery); the
1221
+ // third-party audit (2026-05-31) correctly observed that the
1222
+ // contract still passed `requireUv: false` here. That meant a
1223
+ // permissive authenticator could produce a UP-only assertion
1224
+ // and we'd accept it. R8.2 makes UV strictly required on every
1225
+ // ERC-1271 verify. Browser ceremonies that pass
1226
+ // `userVerification: 'preferred'` will be REJECTED at the
1227
+ // signature step — those apps (demo-web, demo-web-pro) MUST
1228
+ // upgrade to `'required'` for production deployments. Tests
1229
+ // exercising lower-assurance flows can install a separate
1230
+ // passkey-validator module that relaxes this check.
1110
1231
  bytes32 rpIdHash = $.rpIdHashOf[a.credentialIdDigest];
1111
1232
  if (rpIdHash == bytes32(0)) return false;
1112
- return WebAuthnLib.verify(a, hash, key.x, key.y, rpIdHash, false);
1233
+ return WebAuthnLib.verify(a, hash, key.x, key.y, rpIdHash, /*requireUv*/ true);
1113
1234
  } catch {
1114
1235
  return false;
1115
1236
  }
@@ -1178,7 +1299,7 @@ contract AgentAccount is
1178
1299
  /// agenticprimitives AgentAccount is forbidden — enforced via
1179
1300
  /// the ERC-165 marker. Passkey custodians are not added here;
1180
1301
  /// use `addPasskey` instead.
1181
- function addCustodian(address owner) external override onlySelf {
1302
+ function addCustodian(address owner) external override onlySelf whenNotPaused {
1182
1303
  if (owner == address(0)) revert ZeroAddress();
1183
1304
  if (_externalCustodians[owner]) revert CustodianAlreadyExists(owner);
1184
1305
  if (_isAgenticPrimitivesAgent(owner)) {