@keelcodes/policy 0.1.0
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/LICENSE +201 -0
- package/README.md +137 -0
- package/dist/bounded.d.ts +192 -0
- package/dist/bounded.d.ts.map +1 -0
- package/dist/bounded.js +341 -0
- package/dist/bounded.js.map +1 -0
- package/dist/commitment.d.ts +68 -0
- package/dist/commitment.d.ts.map +1 -0
- package/dist/commitment.js +80 -0
- package/dist/commitment.js.map +1 -0
- package/dist/erc20.d.ts +31 -0
- package/dist/erc20.d.ts.map +1 -0
- package/dist/erc20.js +36 -0
- package/dist/erc20.js.map +1 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +22 -0
- package/dist/errors.js.map +1 -0
- package/dist/evaluate.d.ts +32 -0
- package/dist/evaluate.d.ts.map +1 -0
- package/dist/evaluate.js +125 -0
- package/dist/evaluate.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/normalize.d.ts +10 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +92 -0
- package/dist/normalize.js.map +1 -0
- package/dist/session.d.ts +98 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +128 -0
- package/dist/session.js.map +1 -0
- package/dist/types.d.ts +108 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +21 -0
- package/dist/types.js.map +1 -0
- package/package.json +52 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export type Address = `0x${string}`;
|
|
2
|
+
export type Hex = `0x${string}`;
|
|
3
|
+
/**
|
|
4
|
+
* Schema version, mixed into the commitment hash so a future DSL change can
|
|
5
|
+
* never silently produce a hash collision with an older, semantically
|
|
6
|
+
* different policy.
|
|
7
|
+
*/
|
|
8
|
+
export declare const POLICY_VERSION = 1;
|
|
9
|
+
/**
|
|
10
|
+
* Per-token ERC-20 ceiling, as authored. Keyed by the token contract, which is
|
|
11
|
+
* also the call target: enforcing the cap requires reading the amount out of
|
|
12
|
+
* the token's own `transfer` / `approve` call data.
|
|
13
|
+
*/
|
|
14
|
+
export interface TokenLimitInput {
|
|
15
|
+
/** ERC-20 contract the cap applies to. */
|
|
16
|
+
token: Address;
|
|
17
|
+
/** Token amount ceiling for a single call; `0`/omitted means unlimited. */
|
|
18
|
+
maxPerTx?: bigint;
|
|
19
|
+
/** Token amount ceiling accumulated within a day; `0`/omitted means unlimited. */
|
|
20
|
+
maxDaily?: bigint;
|
|
21
|
+
}
|
|
22
|
+
/** A rule scoped to one target contract, as authored. */
|
|
23
|
+
export interface PolicyRuleInput {
|
|
24
|
+
/** Contract the agent may call. */
|
|
25
|
+
target: Address;
|
|
26
|
+
/** Allowed 4-byte selectors; omitted or empty means "any method on target". */
|
|
27
|
+
selectors?: readonly Hex[];
|
|
28
|
+
/** Native-value ceiling for a single call; `0`/omitted means unlimited. */
|
|
29
|
+
maxPerTx?: bigint;
|
|
30
|
+
/** Native-value ceiling accumulated within a day; `0`/omitted means unlimited. */
|
|
31
|
+
maxDaily?: bigint;
|
|
32
|
+
/** Maximum number of calls; `0`/omitted means unlimited. */
|
|
33
|
+
maxCalls?: number;
|
|
34
|
+
/** ERC-20 ceilings, one per token contract; each token may appear once. */
|
|
35
|
+
tokenLimits?: readonly TokenLimitInput[];
|
|
36
|
+
}
|
|
37
|
+
/** A policy as authored. */
|
|
38
|
+
export interface PolicyInput {
|
|
39
|
+
/** Unix seconds before which the policy is not valid; `0`/omitted = immediately. */
|
|
40
|
+
validAfter?: bigint;
|
|
41
|
+
/** Unix seconds after which the policy expires; `0`/omitted = never. */
|
|
42
|
+
validUntil?: bigint;
|
|
43
|
+
rules: readonly PolicyRuleInput[];
|
|
44
|
+
}
|
|
45
|
+
/** A per-token ERC-20 ceiling with every field populated (post-normalisation). */
|
|
46
|
+
export interface TokenLimit {
|
|
47
|
+
readonly token: Address;
|
|
48
|
+
readonly maxPerTx: bigint;
|
|
49
|
+
readonly maxDaily: bigint;
|
|
50
|
+
}
|
|
51
|
+
/** A rule with every field populated (post-normalisation). */
|
|
52
|
+
export interface PolicyRule {
|
|
53
|
+
readonly target: Address;
|
|
54
|
+
readonly selectors: readonly Hex[];
|
|
55
|
+
readonly maxPerTx: bigint;
|
|
56
|
+
readonly maxDaily: bigint;
|
|
57
|
+
readonly maxCalls: number;
|
|
58
|
+
readonly tokenLimits: readonly TokenLimit[];
|
|
59
|
+
}
|
|
60
|
+
/** A normalised, hash-stable policy. */
|
|
61
|
+
export interface Policy {
|
|
62
|
+
readonly version: number;
|
|
63
|
+
readonly validAfter: bigint;
|
|
64
|
+
readonly validUntil: bigint;
|
|
65
|
+
readonly rules: readonly PolicyRule[];
|
|
66
|
+
}
|
|
67
|
+
/** A call an agent wants to make. */
|
|
68
|
+
export interface Call {
|
|
69
|
+
readonly target: Address;
|
|
70
|
+
/** Native value sent with the call. */
|
|
71
|
+
readonly value: bigint;
|
|
72
|
+
/** Call data; `0x` for a plain value transfer. */
|
|
73
|
+
readonly data: Hex;
|
|
74
|
+
/** 4-byte selector (first 4 bytes of `data`), or `0x` when there is no data. */
|
|
75
|
+
readonly selector: Hex;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Accrued usage for one rule, kept by the caller (off-chain) or by the on-chain
|
|
79
|
+
* hook's accounting. `dailySpent` / `tokenSpent` must be reset by the caller
|
|
80
|
+
* when the day window rolls over.
|
|
81
|
+
*/
|
|
82
|
+
export interface RuleUsage {
|
|
83
|
+
readonly calls: number;
|
|
84
|
+
/** Native value spent in the current day window. */
|
|
85
|
+
readonly dailySpent: bigint;
|
|
86
|
+
/** Per-token amount spent in the current day window, keyed by lower-cased token address. */
|
|
87
|
+
readonly tokenSpent?: Readonly<Record<string, bigint>>;
|
|
88
|
+
}
|
|
89
|
+
/** Evaluation context: the current time plus per-rule usage, aligned to `policy.rules` by index. */
|
|
90
|
+
export interface PolicyState {
|
|
91
|
+
/** Current unix time in seconds. */
|
|
92
|
+
readonly now: bigint;
|
|
93
|
+
/** Usage aligned to `policy.rules`; absent entries are treated as zero. */
|
|
94
|
+
readonly usage: readonly RuleUsage[];
|
|
95
|
+
}
|
|
96
|
+
/** Why a call was denied. */
|
|
97
|
+
export type DenyReason = 'not-yet-valid' | 'expired' | 'no-matching-rule' | 'value-per-tx-exceeded' | 'daily-limit-exceeded' | 'call-count-exceeded' | 'token-per-tx-exceeded' | 'token-daily-limit-exceeded' | 'token-transfer-from-blocked' | 'token-amount-unparsable';
|
|
98
|
+
export interface Decision {
|
|
99
|
+
readonly allowed: boolean;
|
|
100
|
+
/** Set when `allowed` is false. */
|
|
101
|
+
readonly reason?: DenyReason;
|
|
102
|
+
/**
|
|
103
|
+
* Index of the rule that matched, when one did. On an allowed decision this
|
|
104
|
+
* is the rule whose usage the caller must advance.
|
|
105
|
+
*/
|
|
106
|
+
readonly ruleIndex?: number;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Keel policy model — account-agnostic authorization for agent accounts.
|
|
3
|
+
//
|
|
4
|
+
// A policy declares what an agent may do with an account: which targets it may
|
|
5
|
+
// call, which methods on them, and the value / frequency ceilings. The model
|
|
6
|
+
// deliberately contains **no account-specific encodings**: it is the same
|
|
7
|
+
// `Policy` whether it is later compiled to an ERC-7579 hook module, a 7710
|
|
8
|
+
// enforcer, or evaluated off-chain for a pre-check. That is what "account
|
|
9
|
+
// agnostic" means here (see docs/KEEL_PLAN.md §4.4 ②).
|
|
10
|
+
//
|
|
11
|
+
// Fields are authored optionally ({@link PolicyInput}) and normalised to a
|
|
12
|
+
// fully-populated {@link Policy} before hashing, so semantically identical
|
|
13
|
+
// policies always produce the same commitment hash.
|
|
14
|
+
// ============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* Schema version, mixed into the commitment hash so a future DSL change can
|
|
17
|
+
* never silently produce a hash collision with an older, semantically
|
|
18
|
+
* different policy.
|
|
19
|
+
*/
|
|
20
|
+
export const POLICY_VERSION = 1;
|
|
21
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,yEAAyE;AACzE,EAAE;AACF,+EAA+E;AAC/E,6EAA6E;AAC7E,0EAA0E;AAC1E,2EAA2E;AAC3E,0EAA0E;AAC1E,uDAAuD;AACvD,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,oDAAoD;AACpD,+EAA+E;AAK/E;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@keelcodes/policy",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Account-agnostic agent authorization policy: declarative DSL, canonical commitment hash and off-chain pre-check/simulation.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"homepage": "https://keel.codes",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/keelcodes/keel.git",
|
|
10
|
+
"directory": "packages/policy"
|
|
11
|
+
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"viem": "^2.21.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"vitest": "^2.1.4"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=20"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"erc-4337",
|
|
40
|
+
"erc-7579",
|
|
41
|
+
"policy",
|
|
42
|
+
"session-keys",
|
|
43
|
+
"agent",
|
|
44
|
+
"account-abstraction"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc -p tsconfig.json",
|
|
48
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"clean": "rm -rf dist"
|
|
51
|
+
}
|
|
52
|
+
}
|