@agenticprimitives/contracts 1.0.0-alpha.14 → 1.0.0-alpha.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deployments-base-sepolia.json +33 -33
- package/dist/abi/AgentAccount.json +19 -0
- package/dist/abi/AgentAccountFactory.json +21 -0
- package/dist/abi/CustodyPolicy.json +11 -0
- package/dist/abi/DelegationManager.json +11 -0
- package/dist/deployments/base-sepolia.d.ts +2 -2
- package/dist/deployments/base-sepolia.js +33 -33
- package/package.json +1 -1
- package/src/AgentAccount.sol +64 -25
- package/src/AgentAccountFactory.sol +13 -0
- package/src/agency/DelegationManager.sol +9 -0
- package/src/custody/CustodyPolicy.sol +28 -0
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
{
|
|
2
|
-
"agentAccountFactory": "
|
|
3
|
-
"agentAccountImplementation": "
|
|
4
|
-
"agentNameRegistry": "
|
|
5
|
-
"agentNameResolver": "
|
|
6
|
-
"agentNameUniversalResolver": "
|
|
7
|
-
"agentProfileResolver": "
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"callDataHashEnforcer": "0x4ab106b80488FE6A920D973cDb96052a933c7450",
|
|
2
|
+
"agentAccountFactory": "0xE5d2d68b510cC2325fAB5e278855F10DcF02B80A",
|
|
3
|
+
"agentAccountImplementation": "0x3C547Ad14CcB3af20b86D671B0B04E61294ad05F",
|
|
4
|
+
"agentNameRegistry": "0xD9a1eCe15F4265c2f367ccD7Df740baeDc3d0523",
|
|
5
|
+
"agentNameResolver": "0x6E749688a49C3e32B59A54d374D2C116c4Bcc2ea",
|
|
6
|
+
"agentNameUniversalResolver": "0xCbb8C3E3a0C87962dC4831152c936Ca2A8B7826b",
|
|
7
|
+
"agentProfileResolver": "0x821de228dF591089575D9186BF9b5E305f12A221",
|
|
8
|
+
"agentRelationship": "0x1c6D59DD6fd9C7AF39B5afD06FFE7FC032E3608e",
|
|
9
|
+
"agreementRegistry": "0x92c4C46619842A8DDC5F59191d5FDb2c0aFc6874",
|
|
10
|
+
"allowedMethodsEnforcer": "0xb6fa9a218F4d6d3Af3dDaE26E3639a98632d4C09",
|
|
11
|
+
"allowedTargetsEnforcer": "0xca53c91257f6Fa2d1Bc51411B8da40056c861965",
|
|
12
|
+
"approvedHashRegistry": "0x97e322FCDc233Ef4f8f81979D6e12bCdEF226eF0",
|
|
13
|
+
"attestationRegistry": "0x34eF353F7DCdad386b7DD8643248A00bFcE863b8",
|
|
14
|
+
"callDataHashEnforcer": "0x5d8e57091d716A3623c29Bd6CD07A502484dA845",
|
|
16
15
|
"chainId": 84532,
|
|
17
|
-
"custodyPolicy": "
|
|
18
|
-
"delegationManager": "
|
|
16
|
+
"custodyPolicy": "0x7d94B5DAc5d66d30e9D2Ed401BbAB237e86804E6",
|
|
17
|
+
"delegationManager": "0xd494a868B3216A307e9eCAe542D3903e3e364377",
|
|
19
18
|
"deployer": "0x31ed17fb99e82E02085Ab4B3cbdaB05489098b44",
|
|
20
|
-
"entryPoint": "
|
|
21
|
-
"geoFeatureRegistry": "
|
|
22
|
-
"mockUsdc": "
|
|
23
|
-
"ontologyTermRegistry": "
|
|
24
|
-
"paymentEnforcer": "
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
19
|
+
"entryPoint": "0x9B766cc05BD2193B5bE5dE50DB23DdB5F0B79c00",
|
|
20
|
+
"geoFeatureRegistry": "0x903c289a091CC9200811202De7dF3C22B18325d6",
|
|
21
|
+
"mockUsdc": "0xac4bf60DC027F71e70e7A821df64549e46d72Ed8",
|
|
22
|
+
"ontologyTermRegistry": "0x701F8a8521Dfa814d042781C42fA5e88fbf88F86",
|
|
23
|
+
"paymentEnforcer": "0x4680bcFBB2c2DC40254365300b922659919e3508",
|
|
24
|
+
"paymentReceiptRegistry": "0x496f9B025BB3FBcE8CDB6375176dd30B2eCE5D73",
|
|
25
|
+
"permissionlessSubregistry": "0xB4eF2166CEAccF8b2bbeAC9d0e28f991eb012385",
|
|
26
|
+
"permissionlessSubregistryDemoAgent": "0x857Bec62Dc039A9D06602335d060886206fC0972",
|
|
27
|
+
"quorumEnforcer": "0x38ffeA6A7c332a841E5fb33ED71B0BBF3387aFE1",
|
|
28
|
+
"relationshipTypeRegistry": "0x6E6ec3d0fDA798c86D324F2681ad6E16a7435658",
|
|
29
|
+
"shapeRegistry": "0xe105C57D384a62a3D465Ad6Ca2401B7117bC3415",
|
|
30
|
+
"skillDefinitionRegistry": "0xA00622b30a1cCe201C27A7a9c9dAAe1349492457",
|
|
31
|
+
"smartAgentPaymaster": "0xf40792F5b4d56931B9f77b4ae356fA89eA526224",
|
|
32
|
+
"timestampEnforcer": "0x579e5cDDd94C27688CA5A0DDd2256995e7759280",
|
|
33
|
+
"universalSignatureValidator": "0x01EC03058e98D0E56509E63b20F8454Fc31681F2",
|
|
34
|
+
"valueEnforcer": "0x8cC88ac64F3A4C5784E7F8B41cAd8E17Ea05c34B",
|
|
35
|
+
"agentRegistryBase": "0x1f8609F11fcaf0666534579EABe8B39778DFEdaA",
|
|
36
|
+
"paymentEscrow": "0xF523F7a30b22F35B2Ee506392cfA16BD8FEEe411"
|
|
37
37
|
}
|
|
@@ -590,6 +590,25 @@
|
|
|
590
590
|
],
|
|
591
591
|
"stateMutability": "view"
|
|
592
592
|
},
|
|
593
|
+
{
|
|
594
|
+
"type": "function",
|
|
595
|
+
"name": "isExternalCustodianOrPasskey",
|
|
596
|
+
"inputs": [
|
|
597
|
+
{
|
|
598
|
+
"name": "account",
|
|
599
|
+
"type": "address",
|
|
600
|
+
"internalType": "address"
|
|
601
|
+
}
|
|
602
|
+
],
|
|
603
|
+
"outputs": [
|
|
604
|
+
{
|
|
605
|
+
"name": "",
|
|
606
|
+
"type": "bool",
|
|
607
|
+
"internalType": "bool"
|
|
608
|
+
}
|
|
609
|
+
],
|
|
610
|
+
"stateMutability": "view"
|
|
611
|
+
},
|
|
593
612
|
{
|
|
594
613
|
"type": "function",
|
|
595
614
|
"name": "isModuleInstalled",
|
|
@@ -448,6 +448,27 @@
|
|
|
448
448
|
"name": "SystemPaused",
|
|
449
449
|
"inputs": []
|
|
450
450
|
},
|
|
451
|
+
{
|
|
452
|
+
"type": "error",
|
|
453
|
+
"name": "TimelockBelowFloor",
|
|
454
|
+
"inputs": [
|
|
455
|
+
{
|
|
456
|
+
"name": "tier",
|
|
457
|
+
"type": "uint8",
|
|
458
|
+
"internalType": "uint8"
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
"name": "provided",
|
|
462
|
+
"type": "uint32",
|
|
463
|
+
"internalType": "uint32"
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
"name": "floorSecs",
|
|
467
|
+
"type": "uint32",
|
|
468
|
+
"internalType": "uint32"
|
|
469
|
+
}
|
|
470
|
+
]
|
|
471
|
+
},
|
|
451
472
|
{
|
|
452
473
|
"type": "error",
|
|
453
474
|
"name": "TooManyInitialCustodians",
|
|
@@ -854,6 +854,17 @@
|
|
|
854
854
|
"name": "EmptyOwnerSet",
|
|
855
855
|
"inputs": []
|
|
856
856
|
},
|
|
857
|
+
{
|
|
858
|
+
"type": "error",
|
|
859
|
+
"name": "InfeasibleOrgConfig",
|
|
860
|
+
"inputs": [
|
|
861
|
+
{
|
|
862
|
+
"name": "nSigners",
|
|
863
|
+
"type": "uint8",
|
|
864
|
+
"internalType": "uint8"
|
|
865
|
+
}
|
|
866
|
+
]
|
|
867
|
+
},
|
|
857
868
|
{
|
|
858
869
|
"type": "error",
|
|
859
870
|
"name": "InvalidCustodyAction",
|
|
@@ -622,6 +622,17 @@
|
|
|
622
622
|
"name": "LegacyRevocationDisabled",
|
|
623
623
|
"inputs": []
|
|
624
624
|
},
|
|
625
|
+
{
|
|
626
|
+
"type": "error",
|
|
627
|
+
"name": "NoCodeEnforcer",
|
|
628
|
+
"inputs": [
|
|
629
|
+
{
|
|
630
|
+
"name": "enforcer",
|
|
631
|
+
"type": "address",
|
|
632
|
+
"internalType": "address"
|
|
633
|
+
}
|
|
634
|
+
]
|
|
635
|
+
},
|
|
625
636
|
{
|
|
626
637
|
"type": "error",
|
|
627
638
|
"name": "NotDelegatorOrDelegate",
|
|
@@ -8,7 +8,6 @@ export interface Deployments {
|
|
|
8
8
|
readonly "agentNameResolver": Address;
|
|
9
9
|
readonly "agentNameUniversalResolver": Address;
|
|
10
10
|
readonly "agentProfileResolver": Address;
|
|
11
|
-
readonly "agentRegistryBase": Address;
|
|
12
11
|
readonly "agentRelationship": Address;
|
|
13
12
|
readonly "agreementRegistry": Address;
|
|
14
13
|
readonly "allowedMethodsEnforcer": Address;
|
|
@@ -24,7 +23,6 @@ export interface Deployments {
|
|
|
24
23
|
readonly "mockUsdc": Address;
|
|
25
24
|
readonly "ontologyTermRegistry": Address;
|
|
26
25
|
readonly "paymentEnforcer": Address;
|
|
27
|
-
readonly "paymentEscrow": Address;
|
|
28
26
|
readonly "paymentReceiptRegistry": Address;
|
|
29
27
|
readonly "permissionlessSubregistry": Address;
|
|
30
28
|
readonly "permissionlessSubregistryDemoAgent": Address;
|
|
@@ -36,6 +34,8 @@ export interface Deployments {
|
|
|
36
34
|
readonly "timestampEnforcer": Address;
|
|
37
35
|
readonly "universalSignatureValidator": Address;
|
|
38
36
|
readonly "valueEnforcer": Address;
|
|
37
|
+
readonly "agentRegistryBase": Address;
|
|
38
|
+
readonly "paymentEscrow": Address;
|
|
39
39
|
readonly "chainId": number;
|
|
40
40
|
}
|
|
41
41
|
export declare const CONTRACTS: Deployments;
|
|
@@ -1,40 +1,40 @@
|
|
|
1
1
|
// Generated by scripts/build-deployments.mjs — do not edit by hand.
|
|
2
2
|
// Source: deployments-base-sepolia.json
|
|
3
3
|
export const CONTRACTS = {
|
|
4
|
-
"agentAccountFactory": "
|
|
5
|
-
"agentAccountImplementation": "
|
|
6
|
-
"agentNameRegistry": "
|
|
7
|
-
"agentNameResolver": "
|
|
8
|
-
"agentNameUniversalResolver": "
|
|
9
|
-
"agentProfileResolver": "
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"callDataHashEnforcer": "0x4ab106b80488FE6A920D973cDb96052a933c7450",
|
|
4
|
+
"agentAccountFactory": "0xE5d2d68b510cC2325fAB5e278855F10DcF02B80A",
|
|
5
|
+
"agentAccountImplementation": "0x3C547Ad14CcB3af20b86D671B0B04E61294ad05F",
|
|
6
|
+
"agentNameRegistry": "0xD9a1eCe15F4265c2f367ccD7Df740baeDc3d0523",
|
|
7
|
+
"agentNameResolver": "0x6E749688a49C3e32B59A54d374D2C116c4Bcc2ea",
|
|
8
|
+
"agentNameUniversalResolver": "0xCbb8C3E3a0C87962dC4831152c936Ca2A8B7826b",
|
|
9
|
+
"agentProfileResolver": "0x821de228dF591089575D9186BF9b5E305f12A221",
|
|
10
|
+
"agentRelationship": "0x1c6D59DD6fd9C7AF39B5afD06FFE7FC032E3608e",
|
|
11
|
+
"agreementRegistry": "0x92c4C46619842A8DDC5F59191d5FDb2c0aFc6874",
|
|
12
|
+
"allowedMethodsEnforcer": "0xb6fa9a218F4d6d3Af3dDaE26E3639a98632d4C09",
|
|
13
|
+
"allowedTargetsEnforcer": "0xca53c91257f6Fa2d1Bc51411B8da40056c861965",
|
|
14
|
+
"approvedHashRegistry": "0x97e322FCDc233Ef4f8f81979D6e12bCdEF226eF0",
|
|
15
|
+
"attestationRegistry": "0x34eF353F7DCdad386b7DD8643248A00bFcE863b8",
|
|
16
|
+
"callDataHashEnforcer": "0x5d8e57091d716A3623c29Bd6CD07A502484dA845",
|
|
18
17
|
"chainId": 84532,
|
|
19
|
-
"custodyPolicy": "
|
|
20
|
-
"delegationManager": "
|
|
18
|
+
"custodyPolicy": "0x7d94B5DAc5d66d30e9D2Ed401BbAB237e86804E6",
|
|
19
|
+
"delegationManager": "0xd494a868B3216A307e9eCAe542D3903e3e364377",
|
|
21
20
|
"deployer": "0x31ed17fb99e82E02085Ab4B3cbdaB05489098b44",
|
|
22
|
-
"entryPoint": "
|
|
23
|
-
"geoFeatureRegistry": "
|
|
24
|
-
"mockUsdc": "
|
|
25
|
-
"ontologyTermRegistry": "
|
|
26
|
-
"paymentEnforcer": "
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
21
|
+
"entryPoint": "0x9B766cc05BD2193B5bE5dE50DB23DdB5F0B79c00",
|
|
22
|
+
"geoFeatureRegistry": "0x903c289a091CC9200811202De7dF3C22B18325d6",
|
|
23
|
+
"mockUsdc": "0xac4bf60DC027F71e70e7A821df64549e46d72Ed8",
|
|
24
|
+
"ontologyTermRegistry": "0x701F8a8521Dfa814d042781C42fA5e88fbf88F86",
|
|
25
|
+
"paymentEnforcer": "0x4680bcFBB2c2DC40254365300b922659919e3508",
|
|
26
|
+
"paymentReceiptRegistry": "0x496f9B025BB3FBcE8CDB6375176dd30B2eCE5D73",
|
|
27
|
+
"permissionlessSubregistry": "0xB4eF2166CEAccF8b2bbeAC9d0e28f991eb012385",
|
|
28
|
+
"permissionlessSubregistryDemoAgent": "0x857Bec62Dc039A9D06602335d060886206fC0972",
|
|
29
|
+
"quorumEnforcer": "0x38ffeA6A7c332a841E5fb33ED71B0BBF3387aFE1",
|
|
30
|
+
"relationshipTypeRegistry": "0x6E6ec3d0fDA798c86D324F2681ad6E16a7435658",
|
|
31
|
+
"shapeRegistry": "0xe105C57D384a62a3D465Ad6Ca2401B7117bC3415",
|
|
32
|
+
"skillDefinitionRegistry": "0xA00622b30a1cCe201C27A7a9c9dAAe1349492457",
|
|
33
|
+
"smartAgentPaymaster": "0xf40792F5b4d56931B9f77b4ae356fA89eA526224",
|
|
34
|
+
"timestampEnforcer": "0x579e5cDDd94C27688CA5A0DDd2256995e7759280",
|
|
35
|
+
"universalSignatureValidator": "0x01EC03058e98D0E56509E63b20F8454Fc31681F2",
|
|
36
|
+
"valueEnforcer": "0x8cC88ac64F3A4C5784E7F8B41cAd8E17Ea05c34B",
|
|
37
|
+
"agentRegistryBase": "0x1f8609F11fcaf0666534579EABe8B39778DFEdaA",
|
|
38
|
+
"paymentEscrow": "0xF523F7a30b22F35B2Ee506392cfA16BD8FEEe411"
|
|
39
39
|
};
|
|
40
40
|
export default CONTRACTS;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agenticprimitives/contracts",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.16",
|
|
4
4
|
"description": "Solidity contracts + ABIs + flattened sources + per-network deployment addresses for the agenticprimitives stack.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
package/src/AgentAccount.sol
CHANGED
|
@@ -547,25 +547,39 @@ contract AgentAccount is
|
|
|
547
547
|
_upgradeAuthorizedCtx = false;
|
|
548
548
|
}
|
|
549
549
|
|
|
550
|
-
/// @notice Cancel a queued upgrade during the timelock window.
|
|
551
|
-
///
|
|
552
|
-
///
|
|
553
|
-
///
|
|
550
|
+
/// @notice Cancel a queued upgrade during the timelock window.
|
|
551
|
+
/// @dev NEW-CANCEL-UPGRADE-1: cancel is a governance op. On a CUSTODY-GOVERNED
|
|
552
|
+
/// account (mode>0 / org) it MUST go through the custody quorum — routed via
|
|
553
|
+
/// the CustodyPolicy executor (`_custodyGovCtx`), exactly like `scheduleUpgrade`
|
|
554
|
+
/// and the other governance mutators — so a single compromised custodian's
|
|
555
|
+
/// ECDSA signature cannot perpetually cancel quorum-scheduled upgrades
|
|
556
|
+
/// (upgrade-liveness DoS). The lightweight ECDSA cancel-grant fast-path remains
|
|
557
|
+
/// ONLY for non-governed (mode-0) accounts, where the sole custodian IS the owner.
|
|
554
558
|
/// @param ownerSig Owner ECDSA signature over `keccak256(abi.encode(
|
|
555
559
|
/// "UPGRADE_CANCEL", _pendingUpgrade.newImplementation,
|
|
556
|
-
/// address(this), block.chainid))`.
|
|
560
|
+
/// address(this), block.chainid))`. Ignored on governed accounts
|
|
561
|
+
/// (the quorum context authorizes; no signature is consulted).
|
|
557
562
|
function cancelPendingUpgrade(bytes calldata ownerSig) external {
|
|
563
|
+
bool governed = _hasCustodyGovernance();
|
|
564
|
+
// Governed: authorize FIRST (fail-closed before revealing pending state). Only the custody quorum
|
|
565
|
+
// (executor self-call with the gov context set) may cancel — `_custodyGovCtx` is set solely by
|
|
566
|
+
// `executeFromModule` when the caller is the CustodyPolicy module, so this reverts
|
|
567
|
+
// AdminRequiresCustodyQuorum for any single-custodian / external attempt.
|
|
568
|
+
if (governed) _requireCustodyGoverned();
|
|
558
569
|
PendingUpgrade memory p = _pendingUpgrade;
|
|
559
570
|
if (p.readyAt == 0) revert NoPendingUpgrade();
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
571
|
+
if (!governed) {
|
|
572
|
+
// Non-governed (mode-0): the sole custodian's ECDSA cancel-grant authorizes.
|
|
573
|
+
bytes32 digest = keccak256(
|
|
574
|
+
abi.encode(
|
|
575
|
+
bytes32("UPGRADE_CANCEL"),
|
|
576
|
+
p.newImplementation,
|
|
577
|
+
address(this),
|
|
578
|
+
block.chainid
|
|
579
|
+
)
|
|
580
|
+
);
|
|
581
|
+
if (!_verifyEcdsa(digest, ownerSig)) revert NotOwnerSig();
|
|
582
|
+
}
|
|
569
583
|
delete _pendingUpgrade;
|
|
570
584
|
emit UpgradeCancelled(p.newImplementation);
|
|
571
585
|
}
|
|
@@ -1028,18 +1042,30 @@ contract AgentAccount is
|
|
|
1028
1042
|
revert NotInstalledExecutor(msg.sender);
|
|
1029
1043
|
}
|
|
1030
1044
|
emit ModuleExecuted(msg.sender, target, value);
|
|
1031
|
-
// CA-1 + Wave-1/ACCT-C1 (spec 300): a module action is a
|
|
1032
|
-
// context (
|
|
1033
|
-
//
|
|
1034
|
-
//
|
|
1035
|
-
//
|
|
1036
|
-
//
|
|
1037
|
-
//
|
|
1038
|
-
|
|
1039
|
-
|
|
1045
|
+
// CA-1 + Wave-1/ACCT-C1 (spec 300): a module action from the CANONICAL CustodyPolicy is a
|
|
1046
|
+
// custody-governed context (gated upstream by its own T5 quorum + timelock). `_custodyGovCtx`
|
|
1047
|
+
// authorizes every governance mutator this call dispatches (the ONLY way past
|
|
1048
|
+
// `_requireCustodyGoverned` on a `mode>0` account); `_upgradeAuthorizedCtx` additionally exempts a
|
|
1049
|
+
// dispatched upgrade from the per-account timelock (no double delay). Both transient.
|
|
1050
|
+
//
|
|
1051
|
+
// NEW-EXEC-MODULE-1 (2026-07-05 audit, internal + external): grant that context ONLY to the
|
|
1052
|
+
// canonical CustodyPolicy the factory installs — NOT to any installed executor. Otherwise a second
|
|
1053
|
+
// (utility / automation) executor a quorum installs believing it unprivileged would silently inherit
|
|
1054
|
+
// full authority to mutate custody / DM / upgrade / modules, bypassing quorum+timelock. Matching the
|
|
1055
|
+
// specific policy address is the same check `_hasCustodyGovernance` uses. A non-canonical executor
|
|
1056
|
+
// runs WITHOUT the context, so `_requireCustodyGoverned` rejects any governance mutator it dispatches
|
|
1057
|
+
// (defense-in-depth: not reachable at v1 since the factory installs only CustodyPolicy).
|
|
1058
|
+
address f = _factory;
|
|
1059
|
+
bool custodyGoverned = f != address(0) && msg.sender == IAgentAccountFactoryView(f).custodyPolicy();
|
|
1060
|
+
if (custodyGoverned) {
|
|
1061
|
+
_custodyGovCtx = true;
|
|
1062
|
+
_upgradeAuthorizedCtx = true;
|
|
1063
|
+
}
|
|
1040
1064
|
(bool ok, bytes memory ret) = target.call{value: value}(data);
|
|
1041
|
-
|
|
1042
|
-
|
|
1065
|
+
if (custodyGoverned) {
|
|
1066
|
+
_upgradeAuthorizedCtx = false;
|
|
1067
|
+
_custodyGovCtx = false;
|
|
1068
|
+
}
|
|
1043
1069
|
if (!ok) {
|
|
1044
1070
|
assembly { revert(add(ret, 32), mload(ret)) }
|
|
1045
1071
|
}
|
|
@@ -1465,6 +1491,19 @@ contract AgentAccount is
|
|
|
1465
1491
|
return _passkeyStorage().piaToCredentialId[account] != bytes32(0);
|
|
1466
1492
|
}
|
|
1467
1493
|
|
|
1494
|
+
/// @notice EXT-ISCUSTODIAN-1 (2026-07-05 audit): like `isCustodian` but EXCLUDES the account itself.
|
|
1495
|
+
/// @dev `isCustodian(address(this)) == true` is deliberate (account-actor compatibility), but that
|
|
1496
|
+
/// footgun can recreate the ACCT-C2 quorum-collapse class in a FUTURE consumer that reuses
|
|
1497
|
+
/// `isCustodian` as if it meant "external signer." Any quorum / authority consumer that must count
|
|
1498
|
+
/// only real external custodians / passkeys (never the account) should use THIS view. ACCT-C2 fixed
|
|
1499
|
+
/// the current CustodyPolicy quorum at the counting site (reject signer==account); this gives new
|
|
1500
|
+
/// consumers the safe primitive so the class can't reappear off-path.
|
|
1501
|
+
function isExternalCustodianOrPasskey(address account) external view returns (bool) {
|
|
1502
|
+
if (account == address(this)) return false;
|
|
1503
|
+
if (_externalCustodians[account]) return true;
|
|
1504
|
+
return _passkeyStorage().piaToCredentialId[account] != bytes32(0);
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1468
1507
|
/// @inheritdoc IAgentAccount
|
|
1469
1508
|
/// @dev Counts EOA/contract custodians PLUS registered passkeys —
|
|
1470
1509
|
/// each passkey contributes one PIA-custodian. Matches the
|
|
@@ -80,6 +80,10 @@ contract AgentAccountFactory is GovernanceManaged {
|
|
|
80
80
|
/// @notice ACCT-M1 (spec 300): a mode-3 (org) account needs ≥2 signers so its separation-of-duties
|
|
81
81
|
/// (disjoint propose + apply quorums) is satisfiable — a 1-signer org can never split duties.
|
|
82
82
|
error InfeasibleOrgConfig(uint8 nSigners);
|
|
83
|
+
/// @notice EXT-TL-FLOOR-1 (external audit P1-2): a mode>0 timelock override is below the on-chain product
|
|
84
|
+
/// floor. Overrides may RAISE a safety delay but never LOWER it below the marketed minimum
|
|
85
|
+
/// (spec 300 — the T5/recovery guarantee is a protocol invariant, not a UI convention).
|
|
86
|
+
error TimelockBelowFloor(uint8 tier, uint32 provided, uint32 floorSecs);
|
|
83
87
|
error ZeroAddress();
|
|
84
88
|
/// @notice R9.6 / ATL-SEC-05 -- thrown when `params.custodians.length`
|
|
85
89
|
/// exceeds `MAX_INITIAL_CUSTODIANS`. Without this cap,
|
|
@@ -329,6 +333,15 @@ contract AgentAccountFactory is GovernanceManaged {
|
|
|
329
333
|
timelocks[5] = timelockOverrides[5] == 0 ? uint32(24 hours) : timelockOverrides[5];
|
|
330
334
|
timelocks[6] = timelockOverrides[6] == 0 ? uint32(48 hours) : timelockOverrides[6];
|
|
331
335
|
|
|
336
|
+
// EXT-TL-FLOOR-1 (external audit P1-2): a timelock override may RAISE a safety delay but NEVER lower it
|
|
337
|
+
// below the product floor. A zero override inherits the floor default above; a non-zero override below
|
|
338
|
+
// the floor reverts, so a mode>0 (custody-governed) account can never deploy with sub-floor T4/T5/T6
|
|
339
|
+
// (recovery = T6) delays. The "T5=24h / recovery=48h" guarantee becomes a protocol invariant, not a UI
|
|
340
|
+
// convention (spec 300 — raise-only). Demo/testnet fast-timelock deploys use zero overrides (defaults).
|
|
341
|
+
if (timelocks[4] < 1 hours) revert TimelockBelowFloor(4, timelocks[4], uint32(1 hours));
|
|
342
|
+
if (timelocks[5] < 24 hours) revert TimelockBelowFloor(5, timelocks[5], uint32(24 hours));
|
|
343
|
+
if (timelocks[6] < 48 hours) revert TimelockBelowFloor(6, timelocks[6], uint32(48 hours));
|
|
344
|
+
|
|
332
345
|
uint8 recThr = uint8(params.trustees.length / 2 + 1);
|
|
333
346
|
|
|
334
347
|
return abi.encode(
|
|
@@ -109,6 +109,10 @@ contract DelegationManager is IDelegationManager, ReentrancyGuard {
|
|
|
109
109
|
// Phase A.5 errors.
|
|
110
110
|
error NotDelegatorOrDelegate();
|
|
111
111
|
error HashMismatch();
|
|
112
|
+
/// @dev EXT-NOCODE-HOOK-1: a caveat enforcer with no code — a call to it would
|
|
113
|
+
/// succeed vacuously (fail-OPEN), so the live before/after hook loops reject it,
|
|
114
|
+
/// matching the view path (`verifyAuthorizationForCall` → "no-code-enforcer").
|
|
115
|
+
error NoCodeEnforcer(address enforcer);
|
|
112
116
|
/// @dev Thrown by the deprecated permissionless `revokeDelegation(bytes32)`
|
|
113
117
|
/// path. Migrate callers to `revokeDelegationByOwner(Delegation)`.
|
|
114
118
|
error LegacyRevocationDisabled();
|
|
@@ -454,6 +458,9 @@ contract DelegationManager is IDelegationManager, ReentrancyGuard {
|
|
|
454
458
|
) internal {
|
|
455
459
|
bytes32 dHash = hashDelegation(d);
|
|
456
460
|
for (uint256 j = 0; j < d.caveats.length; j++) {
|
|
461
|
+
// EXT-NOCODE-HOOK-1: fail closed on a no-code enforcer (a call would succeed vacuously),
|
|
462
|
+
// symmetric with the view path's "no-code-enforcer" reject — never rely on call semantics.
|
|
463
|
+
if (d.caveats[j].enforcer.code.length == 0) revert NoCodeEnforcer(d.caveats[j].enforcer);
|
|
457
464
|
ICaveatEnforcer(d.caveats[j].enforcer).beforeHook(
|
|
458
465
|
d.caveats[j].terms,
|
|
459
466
|
d.caveats[j].args,
|
|
@@ -475,6 +482,8 @@ contract DelegationManager is IDelegationManager, ReentrancyGuard {
|
|
|
475
482
|
) internal {
|
|
476
483
|
bytes32 dHash = hashDelegation(d);
|
|
477
484
|
for (uint256 j = 0; j < d.caveats.length; j++) {
|
|
485
|
+
// EXT-NOCODE-HOOK-1: fail closed on a no-code enforcer, symmetric with the before-hook + view path.
|
|
486
|
+
if (d.caveats[j].enforcer.code.length == 0) revert NoCodeEnforcer(d.caveats[j].enforcer);
|
|
478
487
|
ICaveatEnforcer(d.caveats[j].enforcer).afterHook(
|
|
479
488
|
d.caveats[j].terms,
|
|
480
489
|
d.caveats[j].args,
|
|
@@ -318,6 +318,10 @@ contract CustodyPolicy {
|
|
|
318
318
|
error TrusteeDoesNotExist(address guardian);
|
|
319
319
|
error InvalidMode(uint8 mode_);
|
|
320
320
|
error InvalidThresholdValue(uint8 thr);
|
|
321
|
+
/// @dev EXT-CHANGEMODE-1: a runtime ChangeMode into org mode (3) with an infeasible signer
|
|
322
|
+
/// count (< 2, so separation-of-duties can't split proposers from appliers). Mirrors the
|
|
323
|
+
/// factory's install-time InfeasibleOrgConfig.
|
|
324
|
+
error InfeasibleOrgConfig(uint8 nSigners);
|
|
321
325
|
/// @dev CP-1: a tier that must be configured (T4/T5 at install, T6 at read)
|
|
322
326
|
/// was left unset — refuse rather than fall to the 1-of-n read fallback.
|
|
323
327
|
error UnconfiguredTier(uint8 tier);
|
|
@@ -884,6 +888,23 @@ contract CustodyPolicy {
|
|
|
884
888
|
if (newMode > 3) revert InvalidMode(newMode);
|
|
885
889
|
uint8 oldMode = c.mode;
|
|
886
890
|
if (newMode == 0 && c.trusteeCount > 0) revert CannotDowngradeWithTrustees();
|
|
891
|
+
// EXT-CHANGEMODE-1 (2026-07-05 audit): a runtime ChangeMode must re-run the factory's install-time
|
|
892
|
+
// mode-3 feasibility so the account can't enter an un-executable / liveness-hostile org mode.
|
|
893
|
+
// Org SoD needs ≥2 signers (distinct proposers + appliers) and T4/T5 thresholds within the
|
|
894
|
+
// floor(N/2) cap (else 2×threshold > N → no disjoint quorum → the tier silently locks). Require the
|
|
895
|
+
// signer floor; cap the SoD-constrained thresholds (mirrors the factory, avoids a locked mode).
|
|
896
|
+
if (newMode == 3) {
|
|
897
|
+
uint256 n = IAgentAccount(account).custodianCount();
|
|
898
|
+
if (n < 2) revert InfeasibleOrgConfig(uint8(n));
|
|
899
|
+
uint8 sodCap = uint8(n / 2); // ≥ 1 since n ≥ 2
|
|
900
|
+
for (uint8 tier = 4; tier <= 5; tier++) {
|
|
901
|
+
uint8 v = c.approvalsRequiredByTier[tier];
|
|
902
|
+
if (v > sodCap) {
|
|
903
|
+
c.approvalsRequiredByTier[tier] = sodCap;
|
|
904
|
+
emit ThresholdChanged(account, tier, v, sodCap);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
887
908
|
c.mode = newMode;
|
|
888
909
|
emit ModeChanged(account, oldMode, newMode);
|
|
889
910
|
}
|
|
@@ -968,6 +989,13 @@ contract CustodyPolicy {
|
|
|
968
989
|
if (newCount == 0) revert InvalidThresholdValue(newCount);
|
|
969
990
|
uint256 n = IAgentAccount(account).custodianCount();
|
|
970
991
|
if (uint256(newCount) > n) revert InvalidThresholdValue(newCount);
|
|
992
|
+
// acct-mode3-sod-cap-runtime (2026-07-05 audit): the factory caps mode-3 (org) T4/T5 thresholds at
|
|
993
|
+
// floor(N/2) at install so a DISJOINT propose+apply quorum always exists (2×threshold ≤ N). A later
|
|
994
|
+
// ChangeApprovalsRequired must not raise them past that cap and silently lock the tier — reject an
|
|
995
|
+
// explicit over-cap request loud (the org can lower N-constraints or use a lower threshold).
|
|
996
|
+
if (c.mode == 3 && (tier == 4 || tier == 5) && uint256(newCount) > n / 2) {
|
|
997
|
+
revert InvalidThresholdValue(newCount);
|
|
998
|
+
}
|
|
971
999
|
uint8 oldValue = c.approvalsRequiredByTier[tier];
|
|
972
1000
|
if (oldValue == 0) oldValue = 1; // mirror _approvalsValue fallback
|
|
973
1001
|
c.approvalsRequiredByTier[tier] = newCount;
|