@agenticprimitives/contracts 1.0.0-alpha.12 → 1.0.0-alpha.14
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 -32
- package/dist/abi/AgentAccount.json +10 -0
- package/dist/abi/AgentAccountFactory.json +11 -0
- package/dist/abi/AgentRegistryBase.json +588 -0
- package/dist/abi/CustodyPolicy.json +11 -0
- package/dist/abi/IAgentAccountFactoryView.json +13 -0
- package/dist/abi/IRegistryMembershipPolicy.json +70 -0
- package/dist/abi/PaymentEnforcer.json +11 -6
- package/dist/abi/index.d.ts +2 -0
- package/dist/abi/index.js +2 -0
- package/dist/deployments/base-sepolia.d.ts +5 -4
- package/dist/deployments/base-sepolia.js +33 -32
- package/package.json +1 -1
- package/src/AgentAccount.sol +146 -7
- package/src/AgentAccountFactory.sol +16 -0
- package/src/SmartAgentPaymaster.sol +11 -6
- package/src/custody/CustodyPolicy.sol +10 -0
- package/src/enforcers/PaymentEnforcer.sol +49 -8
- package/src/identity/AgentProfilePredicates.sol +3 -0
- package/src/naming/AgentNamePredicates.sol +21 -0
- package/src/naming/AgentNameRegistry.sol +13 -3
- package/src/registry/AgentRegistryBase.sol +281 -0
- package/src/registry/IRegistryMembershipPolicy.sol +30 -0
|
@@ -778,6 +778,17 @@
|
|
|
778
778
|
}
|
|
779
779
|
]
|
|
780
780
|
},
|
|
781
|
+
{
|
|
782
|
+
"type": "error",
|
|
783
|
+
"name": "AdminSelfSignerNotAllowed",
|
|
784
|
+
"inputs": [
|
|
785
|
+
{
|
|
786
|
+
"name": "account",
|
|
787
|
+
"type": "address",
|
|
788
|
+
"internalType": "address"
|
|
789
|
+
}
|
|
790
|
+
]
|
|
791
|
+
},
|
|
781
792
|
{
|
|
782
793
|
"type": "error",
|
|
783
794
|
"name": "AdminUnauthorizedSigner",
|
|
@@ -12,6 +12,19 @@
|
|
|
12
12
|
],
|
|
13
13
|
"stateMutability": "view"
|
|
14
14
|
},
|
|
15
|
+
{
|
|
16
|
+
"type": "function",
|
|
17
|
+
"name": "custodyPolicy",
|
|
18
|
+
"inputs": [],
|
|
19
|
+
"outputs": [
|
|
20
|
+
{
|
|
21
|
+
"name": "",
|
|
22
|
+
"type": "address",
|
|
23
|
+
"internalType": "address"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"stateMutability": "view"
|
|
27
|
+
},
|
|
15
28
|
{
|
|
16
29
|
"type": "function",
|
|
17
30
|
"name": "governance",
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"type": "function",
|
|
4
|
+
"name": "canAdminister",
|
|
5
|
+
"inputs": [
|
|
6
|
+
{
|
|
7
|
+
"name": "registryId",
|
|
8
|
+
"type": "bytes32",
|
|
9
|
+
"internalType": "bytes32"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"name": "entryId",
|
|
13
|
+
"type": "bytes32",
|
|
14
|
+
"internalType": "bytes32"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "actor",
|
|
18
|
+
"type": "address",
|
|
19
|
+
"internalType": "address"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"outputs": [
|
|
23
|
+
{
|
|
24
|
+
"name": "ok",
|
|
25
|
+
"type": "bool",
|
|
26
|
+
"internalType": "bool"
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"stateMutability": "view"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"type": "function",
|
|
33
|
+
"name": "canRegister",
|
|
34
|
+
"inputs": [
|
|
35
|
+
{
|
|
36
|
+
"name": "registryId",
|
|
37
|
+
"type": "bytes32",
|
|
38
|
+
"internalType": "bytes32"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "entryId",
|
|
42
|
+
"type": "bytes32",
|
|
43
|
+
"internalType": "bytes32"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "subjectAgent",
|
|
47
|
+
"type": "address",
|
|
48
|
+
"internalType": "address"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "cardHash",
|
|
52
|
+
"type": "bytes32",
|
|
53
|
+
"internalType": "bytes32"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "claimHashes",
|
|
57
|
+
"type": "bytes32[]",
|
|
58
|
+
"internalType": "bytes32[]"
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"outputs": [
|
|
62
|
+
{
|
|
63
|
+
"name": "ok",
|
|
64
|
+
"type": "bool",
|
|
65
|
+
"internalType": "bool"
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"stateMutability": "view"
|
|
69
|
+
}
|
|
70
|
+
]
|
|
@@ -20,22 +20,22 @@
|
|
|
20
20
|
"name": "afterHook",
|
|
21
21
|
"inputs": [
|
|
22
22
|
{
|
|
23
|
-
"name": "",
|
|
23
|
+
"name": "terms",
|
|
24
24
|
"type": "bytes",
|
|
25
25
|
"internalType": "bytes"
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
|
-
"name": "",
|
|
28
|
+
"name": "args",
|
|
29
29
|
"type": "bytes",
|
|
30
30
|
"internalType": "bytes"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
|
-
"name": "",
|
|
33
|
+
"name": "delegationHash",
|
|
34
34
|
"type": "bytes32",
|
|
35
35
|
"internalType": "bytes32"
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
|
-
"name": "",
|
|
38
|
+
"name": "delegator",
|
|
39
39
|
"type": "address",
|
|
40
40
|
"internalType": "address"
|
|
41
41
|
},
|
|
@@ -55,13 +55,13 @@
|
|
|
55
55
|
"internalType": "uint256"
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
|
-
"name": "",
|
|
58
|
+
"name": "callData",
|
|
59
59
|
"type": "bytes",
|
|
60
60
|
"internalType": "bytes"
|
|
61
61
|
}
|
|
62
62
|
],
|
|
63
63
|
"outputs": [],
|
|
64
|
-
"stateMutability": "
|
|
64
|
+
"stateMutability": "nonpayable"
|
|
65
65
|
},
|
|
66
66
|
{
|
|
67
67
|
"type": "function",
|
|
@@ -412,6 +412,11 @@
|
|
|
412
412
|
"name": "NotTransferCall",
|
|
413
413
|
"inputs": []
|
|
414
414
|
},
|
|
415
|
+
{
|
|
416
|
+
"type": "error",
|
|
417
|
+
"name": "SettlementNotObserved",
|
|
418
|
+
"inputs": []
|
|
419
|
+
},
|
|
415
420
|
{
|
|
416
421
|
"type": "error",
|
|
417
422
|
"name": "ValueNotZero",
|
package/dist/abi/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export declare const AgentNameRegistry: Abi;
|
|
|
10
10
|
export declare const AgentNameUniversalResolver: Abi;
|
|
11
11
|
export declare const AgentProfilePredicates: Abi;
|
|
12
12
|
export declare const AgentProfileResolver: Abi;
|
|
13
|
+
export declare const AgentRegistryBase: Abi;
|
|
13
14
|
export declare const AgentRelationship: Abi;
|
|
14
15
|
export declare const AgentRelationshipPredicates: Abi;
|
|
15
16
|
export declare const AgreementRegistry: Abi;
|
|
@@ -41,6 +42,7 @@ export declare const IERC7579ModuleLifecycle: Abi;
|
|
|
41
42
|
export declare const IERC7579ModuleLike: Abi;
|
|
42
43
|
export declare const IGovernanceView: Abi;
|
|
43
44
|
export declare const IPaymentReceiptRegistry: Abi;
|
|
45
|
+
export declare const IRegistryMembershipPolicy: Abi;
|
|
44
46
|
export declare const MockUSDC: Abi;
|
|
45
47
|
export declare const MultiSendCallOnly: Abi;
|
|
46
48
|
export declare const MultiSendCallOnlyHarness: Abi;
|
package/dist/abi/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export { default as AgentNameRegistry } from './AgentNameRegistry.json' with { t
|
|
|
10
10
|
export { default as AgentNameUniversalResolver } from './AgentNameUniversalResolver.json' with { type: 'json' };
|
|
11
11
|
export { default as AgentProfilePredicates } from './AgentProfilePredicates.json' with { type: 'json' };
|
|
12
12
|
export { default as AgentProfileResolver } from './AgentProfileResolver.json' with { type: 'json' };
|
|
13
|
+
export { default as AgentRegistryBase } from './AgentRegistryBase.json' with { type: 'json' };
|
|
13
14
|
export { default as AgentRelationship } from './AgentRelationship.json' with { type: 'json' };
|
|
14
15
|
export { default as AgentRelationshipPredicates } from './AgentRelationshipPredicates.json' with { type: 'json' };
|
|
15
16
|
export { default as AgreementRegistry } from './AgreementRegistry.json' with { type: 'json' };
|
|
@@ -41,6 +42,7 @@ export { default as IERC7579ModuleLifecycle } from './IERC7579ModuleLifecycle.js
|
|
|
41
42
|
export { default as IERC7579ModuleLike } from './IERC7579ModuleLike.json' with { type: 'json' };
|
|
42
43
|
export { default as IGovernanceView } from './IGovernanceView.json' with { type: 'json' };
|
|
43
44
|
export { default as IPaymentReceiptRegistry } from './IPaymentReceiptRegistry.json' with { type: 'json' };
|
|
45
|
+
export { default as IRegistryMembershipPolicy } from './IRegistryMembershipPolicy.json' with { type: 'json' };
|
|
44
46
|
export { default as MockUSDC } from './MockUSDC.json' with { type: 'json' };
|
|
45
47
|
export { default as MultiSendCallOnly } from './MultiSendCallOnly.json' with { type: 'json' };
|
|
46
48
|
export { default as MultiSendCallOnlyHarness } from './MultiSendCallOnlyHarness.json' with { type: 'json' };
|
|
@@ -8,6 +8,7 @@ export interface Deployments {
|
|
|
8
8
|
readonly "agentNameResolver": Address;
|
|
9
9
|
readonly "agentNameUniversalResolver": Address;
|
|
10
10
|
readonly "agentProfileResolver": Address;
|
|
11
|
+
readonly "agentRegistryBase": Address;
|
|
11
12
|
readonly "agentRelationship": Address;
|
|
12
13
|
readonly "agreementRegistry": Address;
|
|
13
14
|
readonly "allowedMethodsEnforcer": Address;
|
|
@@ -20,7 +21,11 @@ export interface Deployments {
|
|
|
20
21
|
readonly "deployer": Address;
|
|
21
22
|
readonly "entryPoint": Address;
|
|
22
23
|
readonly "geoFeatureRegistry": Address;
|
|
24
|
+
readonly "mockUsdc": Address;
|
|
23
25
|
readonly "ontologyTermRegistry": Address;
|
|
26
|
+
readonly "paymentEnforcer": Address;
|
|
27
|
+
readonly "paymentEscrow": Address;
|
|
28
|
+
readonly "paymentReceiptRegistry": Address;
|
|
24
29
|
readonly "permissionlessSubregistry": Address;
|
|
25
30
|
readonly "permissionlessSubregistryDemoAgent": Address;
|
|
26
31
|
readonly "quorumEnforcer": Address;
|
|
@@ -31,10 +36,6 @@ export interface Deployments {
|
|
|
31
36
|
readonly "timestampEnforcer": Address;
|
|
32
37
|
readonly "universalSignatureValidator": Address;
|
|
33
38
|
readonly "valueEnforcer": Address;
|
|
34
|
-
readonly "paymentEnforcer": Address;
|
|
35
|
-
readonly "paymentReceiptRegistry": Address;
|
|
36
|
-
readonly "mockUsdc": Address;
|
|
37
|
-
readonly "paymentEscrow": Address;
|
|
38
39
|
readonly "chainId": number;
|
|
39
40
|
}
|
|
40
41
|
export declare const CONTRACTS: Deployments;
|
|
@@ -1,39 +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
|
-
"
|
|
4
|
+
"agentAccountFactory": "0xfCFafCbA6D88351aAAA190a5E971F06CAb40437d",
|
|
5
|
+
"agentAccountImplementation": "0x28b7d8e4682EF36bE479330Ba6CFE78E9E724Bc4",
|
|
6
|
+
"agentNameRegistry": "0x419928546Be67ba83C2aEaFCb6AD3364D5659C8D",
|
|
7
|
+
"agentNameResolver": "0xf96A25DeBF92C514459DC904ec8b79CE52D265A5",
|
|
8
|
+
"agentNameUniversalResolver": "0x3aC8Cb8Df1A8F9fcA05a37cEC82426b4432A53D3",
|
|
9
|
+
"agentProfileResolver": "0xb988e75179e11E4d17665d61c6a9Ce0e737A808F",
|
|
10
|
+
"agentRegistryBase": "0x7fab087fc3d0e1793bdb1d4c5d253635131ee1d1",
|
|
11
|
+
"agentRelationship": "0xDc409D69aC002B4FC90D4B453cc6B6277B98CB46",
|
|
12
|
+
"agreementRegistry": "0x882371Dc898f4835335a01558aE5C2B306069FcF",
|
|
13
|
+
"allowedMethodsEnforcer": "0x1Df87222f53ad26F599C60364F7232a3c0393ad9",
|
|
14
|
+
"allowedTargetsEnforcer": "0x55A9fD6aF8688EE9c68D15CDAa84d9DBD027B80F",
|
|
15
|
+
"approvedHashRegistry": "0x878272cc4E0c5bA026CEc29C9722F41fC0515fE5",
|
|
16
|
+
"attestationRegistry": "0xC695939EA5fB1d7a88BCF536EAC3C13bfcc9E50d",
|
|
17
|
+
"callDataHashEnforcer": "0x4ab106b80488FE6A920D973cDb96052a933c7450",
|
|
17
18
|
"chainId": 84532,
|
|
18
|
-
"custodyPolicy": "
|
|
19
|
-
"delegationManager": "
|
|
19
|
+
"custodyPolicy": "0xfAFDc79bc03CC7cE27f7AA12A3180E4E4C0BC3F6",
|
|
20
|
+
"delegationManager": "0x10DB7c0C5887910722354ef37eF874fBD124026C",
|
|
20
21
|
"deployer": "0x31ed17fb99e82E02085Ab4B3cbdaB05489098b44",
|
|
21
|
-
"entryPoint": "
|
|
22
|
-
"geoFeatureRegistry": "
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
22
|
+
"entryPoint": "0x86Dc419feDD30F58250B314F5947aDd8cf379436",
|
|
23
|
+
"geoFeatureRegistry": "0x1C3b16aF3C2649f2b1ac78aFD6AB20dA0c379121",
|
|
24
|
+
"mockUsdc": "0x027de10c034f4055551C32491BCe65711BFE5f69",
|
|
25
|
+
"ontologyTermRegistry": "0x95C149Be91c925FB348Fa231aD28440FBaD562cF",
|
|
26
|
+
"paymentEnforcer": "0xB09b95E7BcB5d1b3C934facFBEd5bc474b15897E",
|
|
27
|
+
"paymentEscrow": "0x053dA1bdD4f0A75b82A75A46F189f137a5267928",
|
|
28
|
+
"paymentReceiptRegistry": "0x29645211A44714b06B8c4C55c109Ef285699f56c",
|
|
29
|
+
"permissionlessSubregistry": "0x542915A4118A28f49D40DAE53Ee0dc5721Aa4868",
|
|
30
|
+
"permissionlessSubregistryDemoAgent": "0x00EB165eA2fd33448bbBd5634a8ba92D616AEc1D",
|
|
31
|
+
"quorumEnforcer": "0x093ff9790601F712B3730C3cAa34f9353dC93739",
|
|
32
|
+
"relationshipTypeRegistry": "0x0250274222baBB42d44e72e9992DFEB701399a56",
|
|
33
|
+
"shapeRegistry": "0x7d0a4e9A981775a3807282bbf3499e77f5E2bA53",
|
|
34
|
+
"skillDefinitionRegistry": "0x7be2c5615d83Ca95e02b9BDe24879eb220cb1780",
|
|
35
|
+
"smartAgentPaymaster": "0xe93f4ea2cEA8CFF898948c54D6d6144A8F14ca72",
|
|
36
|
+
"timestampEnforcer": "0x118A74d6F59ecD9D19BA4b720157a007b6f39894",
|
|
37
|
+
"universalSignatureValidator": "0x3Bc1Debf2ac2a59548aC5Ad09404A56bA21b5803",
|
|
38
|
+
"valueEnforcer": "0xB7952Ca4a5E10efD24C03c069a0Ea7e262ebE959"
|
|
38
39
|
};
|
|
39
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.14",
|
|
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
|
@@ -28,6 +28,11 @@ interface IAgentAccountFactoryView {
|
|
|
28
28
|
/// this address to call `IGovernanceView.isPaused()` from
|
|
29
29
|
/// `whenNotPaused`-guarded entrypoints.
|
|
30
30
|
function governance() external view returns (address);
|
|
31
|
+
/// @dev Wave-1/ACCT-C1 — the canonical CustodyPolicy this factory installs
|
|
32
|
+
/// as the custody executor for `mode > 0` accounts. AgentAccount reads it
|
|
33
|
+
/// to decide whether IT is custody-governed (its CustodyPolicy is installed)
|
|
34
|
+
/// vs. merely hosting an unrelated utility executor.
|
|
35
|
+
function custodyPolicy() external view returns (address);
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
/// @dev R6.5 — minimal interface for the pause read. Mirrors the same
|
|
@@ -158,6 +163,27 @@ contract AgentAccount is
|
|
|
158
163
|
/// `_authorizeUpgrade` frame) AND absent from the storage layout.
|
|
159
164
|
bool private transient _upgradeAuthorizedCtx;
|
|
160
165
|
|
|
166
|
+
/// @dev Wave-1 / ACCT-C1 (spec 300) — transient "this call stack was entered
|
|
167
|
+
/// by the installed CustodyPolicy EXECUTOR via `executeFromModule`"
|
|
168
|
+
/// (custody-quorum authorized) flag. Set ONLY inside `executeFromModule`,
|
|
169
|
+
/// around the dispatched call, cleared after. Governance mutators require
|
|
170
|
+
/// it on a custody-governed account (`mode > 0`, a CustodyPolicy EXECUTOR
|
|
171
|
+
/// installed): a 1-of-N UserOp `execute(self, adminSelector)` self-call
|
|
172
|
+
/// leaves the flag unset and reverts, so the quorum+timelock can no longer
|
|
173
|
+
/// be bypassed by a single compromised key. Person accounts (`mode 0`, no
|
|
174
|
+
/// CustodyPolicy) self-govern and are exempt. Transient ⇒ tx-global +
|
|
175
|
+
/// absent from the storage layout.
|
|
176
|
+
bool private transient _custodyGovCtx;
|
|
177
|
+
|
|
178
|
+
/// @dev Wave-1 / DM-3 (spec 300) — transient "this execution stack originated
|
|
179
|
+
/// from the DelegationManager". Set at the outermost `execute`/`executeBatch`
|
|
180
|
+
/// frame whose `msg.sender == _delegationManager`, preserved across the
|
|
181
|
+
/// legitimate `DM → execute(self, executeBatch(...))` nest, cleared by the
|
|
182
|
+
/// frame that set it. While set, a self-targeted governance selector is
|
|
183
|
+
/// rejected — a delegation may never reach account governance (that is the
|
|
184
|
+
/// CustodyPolicy's job), regardless of custody mode.
|
|
185
|
+
bool private transient _delegationExecCtx;
|
|
186
|
+
|
|
161
187
|
/// @dev Spec 007 Phase A.5 — maximum permitted upgrade timelock to
|
|
162
188
|
/// protect against an owner accidentally setting an absurdly
|
|
163
189
|
/// large delay that bricks future migrations.
|
|
@@ -223,6 +249,15 @@ contract AgentAccount is
|
|
|
223
249
|
error LegacyUpgradePathDisabled();
|
|
224
250
|
error ModuleOperationNotAllowed();
|
|
225
251
|
|
|
252
|
+
// Wave 1 — account authorization boundary (spec 300 / ACCT-C1 + DM-3).
|
|
253
|
+
/// @notice A governance mutator was reached on a custody-governed account
|
|
254
|
+
/// (`mode > 0`) outside the CustodyPolicy `executeFromModule` path —
|
|
255
|
+
/// i.e. a single-signer UserOp `execute(self, adminSelector)` self-call.
|
|
256
|
+
error AdminRequiresCustodyQuorum();
|
|
257
|
+
/// @notice A delegation-originated execution stack tried to self-call an
|
|
258
|
+
/// account-governance selector. Delegations may never reach governance.
|
|
259
|
+
error DelegatedGovernanceForbidden();
|
|
260
|
+
|
|
226
261
|
/// @notice Emitted when `setDelegationManager` rotates the DM via a
|
|
227
262
|
/// self-call (the only authorized path post-Wave-2A).
|
|
228
263
|
event DelegationManagerRotated(address indexed newDelegationManager);
|
|
@@ -441,8 +476,14 @@ contract AgentAccount is
|
|
|
441
476
|
// matured owner queue — set `_upgradeAuthorizedCtx` and pass through, so the
|
|
442
477
|
// custody path is not double-delayed. A zero timelock keeps the
|
|
443
478
|
// immediate-upgrade default (backward-compatible).
|
|
444
|
-
|
|
445
|
-
|
|
479
|
+
// Wave-1/ACCT-C1 + M-4 (spec 300): outside an authorized context, a
|
|
480
|
+
// custody-governed account (`mode>0`) may upgrade ONLY through the
|
|
481
|
+
// CustodyPolicy quorum — reject even when the per-account timelock is 0 (M-4
|
|
482
|
+
// floors it non-zero at the factory, but a quorum-set 0 must not re-open the
|
|
483
|
+
// direct path). A person account keeps the CA-1 behavior (timelock if set).
|
|
484
|
+
if (!_upgradeAuthorizedCtx) {
|
|
485
|
+
if (_hasCustodyGovernance()) revert AdminRequiresCustodyQuorum();
|
|
486
|
+
if (_upgradeTimelock != 0) revert DirectUpgradeBlocked();
|
|
446
487
|
}
|
|
447
488
|
}
|
|
448
489
|
|
|
@@ -478,6 +519,7 @@ contract AgentAccount is
|
|
|
478
519
|
/// meaningful when a timelock is configured — with none set, upgrade
|
|
479
520
|
/// directly. Overwrites any existing pending upgrade.
|
|
480
521
|
function scheduleUpgrade(address newImplementation) external onlySelf {
|
|
522
|
+
_requireCustodyGoverned();
|
|
481
523
|
if (newImplementation == address(0)) revert ZeroAddress();
|
|
482
524
|
uint256 tl = _upgradeTimelock;
|
|
483
525
|
if (tl == 0) revert UpgradeTimelockNotSet();
|
|
@@ -533,6 +575,7 @@ contract AgentAccount is
|
|
|
533
575
|
/// (`onlySelf`). 0 == immediate upgrades (default,
|
|
534
576
|
/// backward-compat).
|
|
535
577
|
function setUpgradeTimelock(uint256 secs) external onlySelf {
|
|
578
|
+
_requireCustodyGoverned();
|
|
536
579
|
if (secs > MAX_UPGRADE_TIMELOCK) {
|
|
537
580
|
revert UpgradeTimelockTooLong(secs, MAX_UPGRADE_TIMELOCK);
|
|
538
581
|
}
|
|
@@ -576,6 +619,7 @@ contract AgentAccount is
|
|
|
576
619
|
* a self-call into this function.
|
|
577
620
|
*/
|
|
578
621
|
function setDelegationManager(address dm) external onlySelf {
|
|
622
|
+
_requireCustodyGoverned();
|
|
579
623
|
if (dm.code.length == 0) revert ValidatorRequired();
|
|
580
624
|
_delegationManager = dm;
|
|
581
625
|
emit DelegationManagerRotated(dm);
|
|
@@ -639,6 +683,7 @@ contract AgentAccount is
|
|
|
639
683
|
* delegation the owner has authorized.
|
|
640
684
|
*/
|
|
641
685
|
function acceptSessionDelegation(bytes32 sessionDelegationHash) external onlySelf {
|
|
686
|
+
_requireCustodyGoverned();
|
|
642
687
|
if (_acceptedSessionDelegations[sessionDelegationHash]) {
|
|
643
688
|
revert SessionDelegationAlreadyAccepted(sessionDelegationHash);
|
|
644
689
|
}
|
|
@@ -823,6 +868,10 @@ contract AgentAccount is
|
|
|
823
868
|
address module,
|
|
824
869
|
bytes calldata initData
|
|
825
870
|
) external onlySelfOrFactoryInit whenNotPaused {
|
|
871
|
+
// Wave-1/ACCT-C1: on a custody-governed account, module installs must route
|
|
872
|
+
// through the CustodyPolicy quorum. Exempt by construction at factory-init
|
|
873
|
+
// (no EXECUTOR installed yet ⇒ `_hasCustodyGovernance()` is false).
|
|
874
|
+
_requireCustodyGoverned();
|
|
826
875
|
if (module == address(0)) revert ZeroAddress();
|
|
827
876
|
if (!_isSupportedModuleType(moduleTypeId)) revert UnsupportedModuleType(moduleTypeId);
|
|
828
877
|
|
|
@@ -872,6 +921,7 @@ contract AgentAccount is
|
|
|
872
921
|
// at deploy time, and there's never a legitimate reason for
|
|
873
922
|
// the factory to do that.
|
|
874
923
|
if (msg.sender != address(this)) revert ModuleOperationNotAllowed();
|
|
924
|
+
_requireCustodyGoverned();
|
|
875
925
|
if (!_isSupportedModuleType(moduleTypeId)) revert UnsupportedModuleType(moduleTypeId);
|
|
876
926
|
|
|
877
927
|
ModulesStorage storage $ = _modulesStorage();
|
|
@@ -978,14 +1028,18 @@ contract AgentAccount is
|
|
|
978
1028
|
revert NotInstalledExecutor(msg.sender);
|
|
979
1029
|
}
|
|
980
1030
|
emit ModuleExecuted(msg.sender, target, value);
|
|
981
|
-
// CA-1: a module action is a custody-governed
|
|
982
|
-
// EXECUTOR — the CustodyPolicy — reaches here,
|
|
983
|
-
// T5 quorum + timelock).
|
|
984
|
-
//
|
|
985
|
-
//
|
|
1031
|
+
// CA-1 + Wave-1/ACCT-C1 (spec 300): a module action is a custody-governed
|
|
1032
|
+
// context (only an installed EXECUTOR — the CustodyPolicy — reaches here,
|
|
1033
|
+
// gated upstream by its own T5 quorum + timelock). `_custodyGovCtx` authorizes
|
|
1034
|
+
// every governance mutator this call dispatches (the ONLY way past
|
|
1035
|
+
// `_requireCustodyGoverned` on a `mode>0` account); `_upgradeAuthorizedCtx`
|
|
1036
|
+
// additionally exempts a dispatched upgrade from the per-account timelock (no
|
|
1037
|
+
// double delay). Both transient, cleared after the call.
|
|
1038
|
+
_custodyGovCtx = true;
|
|
986
1039
|
_upgradeAuthorizedCtx = true;
|
|
987
1040
|
(bool ok, bytes memory ret) = target.call{value: value}(data);
|
|
988
1041
|
_upgradeAuthorizedCtx = false;
|
|
1042
|
+
_custodyGovCtx = false;
|
|
989
1043
|
if (!ok) {
|
|
990
1044
|
assembly { revert(add(ret, 32), mload(ret)) }
|
|
991
1045
|
}
|
|
@@ -1035,6 +1089,13 @@ contract AgentAccount is
|
|
|
1035
1089
|
function execute(address target, uint256 value, bytes calldata data) external override nonReentrant whenNotPaused {
|
|
1036
1090
|
_requireForExecute();
|
|
1037
1091
|
|
|
1092
|
+
// DM-3 (spec 300): mark a delegation-originated stack (set once at the
|
|
1093
|
+
// outermost DM frame; preserved across the legitimate DM → execute(self,
|
|
1094
|
+
// executeBatch(...)) nest) and forbid it from self-calling governance.
|
|
1095
|
+
bool setDelCtx = (msg.sender == _delegationManager && !_delegationExecCtx);
|
|
1096
|
+
if (setDelCtx) _delegationExecCtx = true;
|
|
1097
|
+
_rejectDelegatedGovernance(target, data);
|
|
1098
|
+
|
|
1038
1099
|
ModulesStorage storage $ = _modulesStorage();
|
|
1039
1100
|
address[] memory hooks = $.installedList[MODULE_TYPE_HOOK];
|
|
1040
1101
|
bytes[] memory hookData = new bytes[](hooks.length);
|
|
@@ -1062,6 +1123,8 @@ contract AgentAccount is
|
|
|
1062
1123
|
for (uint256 i = 0; i < hooks.length; i++) {
|
|
1063
1124
|
IERC7579HookLike(hooks[i]).postCheck(hookData[i]);
|
|
1064
1125
|
}
|
|
1126
|
+
|
|
1127
|
+
if (setDelCtx) _delegationExecCtx = false;
|
|
1065
1128
|
}
|
|
1066
1129
|
|
|
1067
1130
|
/// @notice Atomically execute multiple calls from this account.
|
|
@@ -1088,6 +1151,13 @@ contract AgentAccount is
|
|
|
1088
1151
|
function executeBatch(Call[] calldata calls) external override whenNotPaused {
|
|
1089
1152
|
_requireForExecute();
|
|
1090
1153
|
|
|
1154
|
+
// DM-3 (spec 300): same delegation-origin marking as `execute`. Preserved
|
|
1155
|
+
// across the DM → execute(self, executeBatch(...)) nest so a governance
|
|
1156
|
+
// self-call in ANY inner call is caught even though this frame's
|
|
1157
|
+
// msg.sender is address(this).
|
|
1158
|
+
bool setDelCtx = (msg.sender == _delegationManager && !_delegationExecCtx);
|
|
1159
|
+
if (setDelCtx) _delegationExecCtx = true;
|
|
1160
|
+
|
|
1091
1161
|
ModulesStorage storage $ = _modulesStorage();
|
|
1092
1162
|
address[] memory hooks = $.installedList[MODULE_TYPE_HOOK];
|
|
1093
1163
|
bytes[] memory hookData = new bytes[](hooks.length);
|
|
@@ -1101,6 +1171,7 @@ contract AgentAccount is
|
|
|
1101
1171
|
}
|
|
1102
1172
|
|
|
1103
1173
|
for (uint256 i = 0; i < calls.length; i++) {
|
|
1174
|
+
_rejectDelegatedGovernance(calls[i].target, calls[i].data);
|
|
1104
1175
|
(bool ok, bytes memory ret) = calls[i].target.call{ value: calls[i].value }(calls[i].data);
|
|
1105
1176
|
if (!ok) {
|
|
1106
1177
|
assembly {
|
|
@@ -1113,6 +1184,8 @@ contract AgentAccount is
|
|
|
1113
1184
|
for (uint256 i = 0; i < hooks.length; i++) {
|
|
1114
1185
|
IERC7579HookLike(hooks[i]).postCheck(hookData[i]);
|
|
1115
1186
|
}
|
|
1187
|
+
|
|
1188
|
+
if (setDelCtx) _delegationExecCtx = false;
|
|
1116
1189
|
}
|
|
1117
1190
|
|
|
1118
1191
|
// ─── ERC-4337 ───────────────────────────────────────────────────
|
|
@@ -1146,6 +1219,68 @@ contract AgentAccount is
|
|
|
1146
1219
|
}
|
|
1147
1220
|
}
|
|
1148
1221
|
|
|
1222
|
+
// ─── Wave 1 — account authorization boundary (spec 300) ─────────
|
|
1223
|
+
|
|
1224
|
+
/// @dev True when this account is custody-governed — i.e. the canonical
|
|
1225
|
+
/// CustodyPolicy the factory installs for `mode > 0` accounts is installed
|
|
1226
|
+
/// as an EXECUTOR here. Governance mutators then require the
|
|
1227
|
+
/// `executeFromModule` (quorum+timelock) path. A `mode 0` person account
|
|
1228
|
+
/// (no CustodyPolicy) self-governs; installing an UNRELATED utility executor
|
|
1229
|
+
/// does NOT make it custody-governed (we check the specific policy address,
|
|
1230
|
+
/// not "any executor"). If the factory is unknown (legacy direct deploy),
|
|
1231
|
+
/// fall back to person semantics.
|
|
1232
|
+
function _hasCustodyGovernance() internal view returns (bool) {
|
|
1233
|
+
address f = _factory;
|
|
1234
|
+
if (f == address(0)) return false;
|
|
1235
|
+
address cp = IAgentAccountFactoryView(f).custodyPolicy();
|
|
1236
|
+
if (cp == address(0)) return false;
|
|
1237
|
+
return _modulesStorage().installed[MODULE_TYPE_EXECUTOR][cp];
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
/// @dev ACCT-C1 gate: on a custody-governed account, a governance mutator is
|
|
1241
|
+
/// reachable only through `executeFromModule` (which sets `_custodyGovCtx`).
|
|
1242
|
+
/// A single-signer UserOp `execute(self, adminSelector)` self-call leaves the
|
|
1243
|
+
/// flag unset and reverts here, so the custody quorum can no longer be bypassed.
|
|
1244
|
+
function _requireCustodyGoverned() internal view {
|
|
1245
|
+
if (_hasCustodyGovernance() && !_custodyGovCtx) revert AdminRequiresCustodyQuorum();
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
/// @dev DM-3 gate: a delegation-originated stack may never self-call an account
|
|
1249
|
+
/// governance selector. `_delegationExecCtx` is set at the outermost
|
|
1250
|
+
/// DM-driven `execute`/`executeBatch` and persists across the legitimate
|
|
1251
|
+
/// `DM → execute(self, executeBatch(...))` nest, so a nested governance
|
|
1252
|
+
/// self-call is caught regardless of mode.
|
|
1253
|
+
function _rejectDelegatedGovernance(address target, bytes calldata data) internal view {
|
|
1254
|
+
if (
|
|
1255
|
+
_delegationExecCtx &&
|
|
1256
|
+
target == address(this) &&
|
|
1257
|
+
data.length >= 4 &&
|
|
1258
|
+
_isGovernanceSelector(bytes4(data[0:4]))
|
|
1259
|
+
) {
|
|
1260
|
+
revert DelegatedGovernanceForbidden();
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
/// @dev The account-governance selector set — mutators that change custody,
|
|
1265
|
+
/// the DelegationManager, installed modules, or the upgrade path. Kept in
|
|
1266
|
+
/// sync with the `_requireCustodyGoverned`-gated functions above.
|
|
1267
|
+
function _isGovernanceSelector(bytes4 s) internal pure returns (bool) {
|
|
1268
|
+
return
|
|
1269
|
+
s == this.setDelegationManager.selector ||
|
|
1270
|
+
s == UUPSUpgradeable.upgradeToAndCall.selector ||
|
|
1271
|
+
s == this.setUpgradeTimelock.selector ||
|
|
1272
|
+
s == this.scheduleUpgrade.selector ||
|
|
1273
|
+
s == this.executePendingUpgrade.selector ||
|
|
1274
|
+
s == this.cancelPendingUpgrade.selector ||
|
|
1275
|
+
s == this.installModule.selector ||
|
|
1276
|
+
s == this.uninstallModule.selector ||
|
|
1277
|
+
s == IAgentAccount.addCustodian.selector ||
|
|
1278
|
+
s == IAgentAccount.removeCustodian.selector ||
|
|
1279
|
+
s == this.addPasskey.selector ||
|
|
1280
|
+
s == this.removePasskey.selector ||
|
|
1281
|
+
s == this.acceptSessionDelegation.selector;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1149
1284
|
// ─── ERC-1271 ───────────────────────────────────────────────────
|
|
1150
1285
|
|
|
1151
1286
|
/// @dev 32-byte ERC-6492 magic suffix — `0x6492…6492` repeated.
|
|
@@ -1359,6 +1494,7 @@ contract AgentAccount is
|
|
|
1359
1494
|
/// the ERC-165 marker. Passkey custodians are not added here;
|
|
1360
1495
|
/// use `addPasskey` instead.
|
|
1361
1496
|
function addCustodian(address owner) external override onlySelf whenNotPaused {
|
|
1497
|
+
_requireCustodyGoverned();
|
|
1362
1498
|
if (owner == address(0)) revert ZeroAddress();
|
|
1363
1499
|
if (_externalCustodians[owner]) revert CustodianAlreadyExists(owner);
|
|
1364
1500
|
if (_isAgenticPrimitivesAgent(owner)) {
|
|
@@ -1402,6 +1538,7 @@ contract AgentAccount is
|
|
|
1402
1538
|
/// owner if there are also no registered passkeys. A passkey-only
|
|
1403
1539
|
/// account is allowed, but a zero-signer account is not.
|
|
1404
1540
|
function removeCustodian(address owner) external override onlySelf {
|
|
1541
|
+
_requireCustodyGoverned();
|
|
1405
1542
|
if (!_externalCustodians[owner]) revert CustodianDoesNotExist(owner);
|
|
1406
1543
|
if (_externalCustodianCount == 1 && _passkeyStorage().count == 0) revert CannotRemoveLastCustodian();
|
|
1407
1544
|
_externalCustodians[owner] = false;
|
|
@@ -1466,6 +1603,7 @@ contract AgentAccount is
|
|
|
1466
1603
|
uint256 y,
|
|
1467
1604
|
bytes32 rpIdHash
|
|
1468
1605
|
) external onlySelf {
|
|
1606
|
+
_requireCustodyGoverned();
|
|
1469
1607
|
if (x == 0 || y == 0) revert InvalidPasskeyPublicKey();
|
|
1470
1608
|
// Audit C-6: zero digest poisons piaToCredentialId mapping.
|
|
1471
1609
|
if (credentialIdDigest == bytes32(0)) revert InvalidCredentialIdDigest();
|
|
@@ -1490,6 +1628,7 @@ contract AgentAccount is
|
|
|
1490
1628
|
/// AND passkeys together. Also clears the credential's PIA
|
|
1491
1629
|
/// entry so `isCustodian(pia)` flips back to false.
|
|
1492
1630
|
function removePasskey(bytes32 credentialIdDigest) external onlySelf {
|
|
1631
|
+
_requireCustodyGoverned();
|
|
1493
1632
|
PasskeyStorage storage $ = _passkeyStorage();
|
|
1494
1633
|
if (!$.registered[credentialIdDigest]) revert PasskeyNotRegistered(credentialIdDigest);
|
|
1495
1634
|
if (_externalCustodianCount + $.count == 1) revert CannotRemoveLastSigner();
|
|
@@ -77,6 +77,9 @@ contract AgentAccountFactory is GovernanceManaged {
|
|
|
77
77
|
error NoInitialSigner();
|
|
78
78
|
error InsufficientTrusteesForMode(uint8 mode, uint256 actual, uint256 required);
|
|
79
79
|
error TrusteesRequiredForRecoverableMode(uint8 mode);
|
|
80
|
+
/// @notice ACCT-M1 (spec 300): a mode-3 (org) account needs ≥2 signers so its separation-of-duties
|
|
81
|
+
/// (disjoint propose + apply quorums) is satisfiable — a 1-signer org can never split duties.
|
|
82
|
+
error InfeasibleOrgConfig(uint8 nSigners);
|
|
80
83
|
error ZeroAddress();
|
|
81
84
|
/// @notice R9.6 / ATL-SEC-05 -- thrown when `params.custodians.length`
|
|
82
85
|
/// exceeds `MAX_INITIAL_CUSTODIANS`. Without this cap,
|
|
@@ -308,6 +311,19 @@ contract AgentAccountFactory is GovernanceManaged {
|
|
|
308
311
|
thresholds[t] = CustodyPolicy(custodyPolicy).defaultApprovals(uint8(nSigners), t);
|
|
309
312
|
}
|
|
310
313
|
|
|
314
|
+
// ACCT-M1 (spec 300): mode-3 (org) separation-of-duties requires DISJOINT propose + apply quorums
|
|
315
|
+
// for the T4/T5 tiers, so a satisfiable config needs 2×threshold DISTINCT signers. The default
|
|
316
|
+
// matrix sets T4/T5 = N for small N (all custodians), which would demand 2N signers — making every
|
|
317
|
+
// such change permanently un-executable (the account silently locks). Cap the SoD-constrained
|
|
318
|
+
// thresholds at floor(N/2) so a disjoint quorum always exists, and require ≥2 signers (a 1-signer
|
|
319
|
+
// org can't split duties). Modes 0-2 have no SoD, so their thresholds are unchanged.
|
|
320
|
+
if (params.mode == 3) {
|
|
321
|
+
if (nSigners < 2) revert InfeasibleOrgConfig(uint8(nSigners));
|
|
322
|
+
uint8 sodCap = uint8(nSigners / 2); // ≥ 1 since nSigners ≥ 2
|
|
323
|
+
if (thresholds[4] > sodCap) thresholds[4] = sodCap;
|
|
324
|
+
if (thresholds[5] > sodCap) thresholds[5] = sodCap;
|
|
325
|
+
}
|
|
326
|
+
|
|
311
327
|
uint32[7] memory timelocks;
|
|
312
328
|
timelocks[4] = timelockOverrides[4] == 0 ? uint32(1 hours) : timelockOverrides[4];
|
|
313
329
|
timelocks[5] = timelockOverrides[5] == 0 ? uint32(24 hours) : timelockOverrides[5];
|