@meantjs/profile 0.2.0 → 0.4.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/CHANGELOG.md CHANGED
@@ -2,6 +2,30 @@
2
2
 
3
3
  The five Candid Profile library packages (`@meantjs/profile`, `/format`, `/consent`, `/tools`, `/reconcile`) release together under one version and pin each other exactly; a version appears here even when this package did not change. Release steps: `docs/releasing.md` in the repository.
4
4
 
5
+ ## 0.4.0 — 2026-10-30
6
+
7
+ - What a call grants (spec §5.3, D-056): an `effect` of kind `transfer` or `approve` may carry `grant`, the positions of
8
+ who may take the tokens (`spender` or `to`), the `amount` and the `ends`. The validator checks them (new code
9
+ `E_GRANT`); a pack whose grant does not hold where it applies keeps its effect and loses the grant
10
+ (`I_PACK_ANNOTATION_SKIPPED`). The resolved form carries `grant` inside `effect`.
11
+ - The packs carry grants: `icrc1`, `icrc2`, `erc20` and `erc2612`, and the contract profiles `permit2` and
12
+ `dai-permit`. Their profile ids changed with them.
13
+
14
+ ## 0.3.0 — 2026-10-29
15
+
16
+ - EIP-712 typed messages, experimental (spec §15.9, D-055). A contract profile or EVM pack may carry
17
+ `binds.eip712: { domain?, types }`, and a contract profile may have it instead of `binds.abi`. A message is a type
18
+ the same document tags with `intent`, addressed like a function (`PermitSingle(0).details.amount`); the resolved form
19
+ lists messages under a new `messages` map (`encode_type`, `type_hash`, `tags`, `args`) and the bound domain as
20
+ `profiles[].eip712_domain`. Without types, the resolved form and the interface id are unchanged.
21
+ - `amount` takes `token`, a relative path to the `address` field that names its token (EVM only); `timestamp` takes
22
+ `threshold` with `message`, and `labels` (display only). New errors `E_EIP712` and `E_TOKEN_PATH`.
23
+ - `@meantjs/profile/evm` exports `encodeType`, `eip712TypeHash` and `parseEip712Types`; `abiInterfaceId` takes the
24
+ struct types as a second argument.
25
+ - New standard files: the `erc2612` pack (in `STANDARD_PACKS` and `loadPacks()`), and the `permit2` and `dai-permit`
26
+ contract profiles, shipped beside the packs (`@meantjs/profile/packs/permit2.profile.json`); `loadPacks()` returns
27
+ packs only, as before.
28
+
5
29
  ## 0.2.0 — 2026-10-28
6
30
 
7
31
  - `intent` and `effect` may sit on a case of a variant in a method's arguments, such as `propose(0).Transfer`
package/README.md CHANGED
@@ -164,7 +164,7 @@ const r = await resolveService({ did: serviceText, profiles: served.ok ? [{ doc:
164
164
  serves, so a profile for another interface is `rebound` or `stale` as any other.
165
165
  - Tests: `test/served.test.mjs`; end to end on PocketIC in `packages/kit/pocketic/`.
166
166
 
167
- ## EVM contracts (experimental, spec section 15, D-054)
167
+ ## EVM contracts (experimental, spec section 15, D-054 and D-055)
168
168
 
169
169
  A third input, `abi`: an EVM contract's ABI as human-readable fragments or JSON ABI entries. The resolver reads it as
170
170
  the graph a `.did` compiles to (a function is a method, its parameters one record at argument 0, a tuple a record in
@@ -181,15 +181,23 @@ r.resolved.methods.transfer.tags.intent.args.template; // "Send {wad} to {dst}":
181
181
  that has every one of their functions, by selector, output types and kind of call (no subtyping); their addresses
182
182
  and placeholders are rewritten to the contract's parameter names by position. A pack or profile for the other kind
183
183
  of interface is `E_CHAIN` when given, and skipped in a pack search, so `loadPacks()` serves both kinds.
184
+ - **EIP-712 messages** (spec §15.9, D-055): `binds.eip712: { domain?, types }` in a contract profile (with or without
185
+ `binds.abi`) or an EVM pack. A type the same document tags with `intent` is a message, addressed like a function
186
+ (`PermitSingle(0).details.amount`) and listed under the resolved form's `messages` with its `encode_type` and
187
+ `type_hash`. `amount.token` names an amount's token by an `address` field (`E_TOKEN_PATH` otherwise). Bad types, a
188
+ message named like a function and two meanings for one type name are `E_EIP712`. Standard files: the `erc2612`
189
+ pack, and the `permit2` and `dai-permit` contract profiles shipped beside the packs
190
+ (`@meantjs/profile/packs/permit2.profile.json`); `loadPacks()` returns the packs only.
184
191
  - **Refused for now:** overloaded function names and unreadable fragments (`E_ABI`); `idempotency`, `outcome`, `list`,
185
192
  `names` and `named` on a contract (`E_TAG_TARGET`); `account` and `subaccount` (`E_TAG_NOT_APPLICABLE`); `[ ]`
186
193
  template segments (`E_TEMPLATE`).
187
194
  - **`@meantjs/profile/evm`** is the toolkit underneath, browser-safe and without dependencies: `keccak256`, `parseAbi`,
188
195
  `parseSignature`, `canonicalFragment`, `selectorOf`, `abiInterfaceId`, a strict codec (`encodeParams`, `encodeCall`,
189
196
  `decodeParams`: a value read from anything but its canonical encoding is refused), `toChecksumAddress`,
190
- `readAddress` and `typedDataDigest` (EIP-712). `test/evm.test.mjs` checks Keccak against an independent
191
- implementation (and the block boundary), the ERC-20 selectors, the ERC-8176 schema UID, EIP-55's examples and
192
- EIP-712's Mail example.
197
+ `readAddress`, `typedDataDigest` (EIP-712), `encodeType`, `eip712TypeHash` and `parseEip712Types`.
198
+ `test/evm.test.mjs` checks Keccak against an independent implementation (and the block boundary), the ERC-20
199
+ selectors, the ERC-8176 schema UID, EIP-55's examples and EIP-712's Mail example; `test/eip712.test.mjs` the type
200
+ hashes of the standard messages (DAI's equals `dai.sol`'s constant).
193
201
 
194
202
  ## CLI
195
203
 
@@ -0,0 +1,117 @@
1
+ {
2
+ "format": "candid-profile",
3
+ "format_version": 0,
4
+ "kind": "contract",
5
+ "name": "dai-permit",
6
+ "origin": "third_party",
7
+ "language": "en",
8
+ "description": "DAI's permit on Ethereum mainnet (spec section 15.9, experimental), older than EIP-2612 and different from it: `allowed` sets the allowance to all of the holder's DAI (true, uint256 max) or to none (false), and `expiry` 0 means the signature never expires (MakerDAO dss, src/dai.sol). Only the message is described; DAI's functions are ERC-20's and the erc20 pack covers them.",
9
+ "binds": {
10
+ "eip712": {
11
+ "domain": {
12
+ "name": "Dai Stablecoin",
13
+ "version": "1"
14
+ },
15
+ "types": {
16
+ "Permit": [
17
+ {
18
+ "name": "holder",
19
+ "type": "address"
20
+ },
21
+ {
22
+ "name": "spender",
23
+ "type": "address"
24
+ },
25
+ {
26
+ "name": "nonce",
27
+ "type": "uint256"
28
+ },
29
+ {
30
+ "name": "expiry",
31
+ "type": "uint256"
32
+ },
33
+ {
34
+ "name": "allowed",
35
+ "type": "bool"
36
+ }
37
+ ]
38
+ }
39
+ },
40
+ "deployments": [
41
+ {
42
+ "chain_id": 1,
43
+ "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F"
44
+ }
45
+ ]
46
+ },
47
+ "annotations": [
48
+ {
49
+ "at": "Permit",
50
+ "tag": "intent",
51
+ "args": {
52
+ "title": "Permit DAI spending",
53
+ "template": "Set the DAI allowance {holder} gives {spender} to all of it if allowed is true, to none if false (allowed: {allowed}). Signature expires: {expiry}."
54
+ }
55
+ },
56
+ {
57
+ "at": "Permit",
58
+ "tag": "effect",
59
+ "args": {
60
+ "kind": "approve",
61
+ "irreversible": false,
62
+ "grant": {
63
+ "spender": "spender",
64
+ "amount": "allowed"
65
+ }
66
+ }
67
+ },
68
+ {
69
+ "at": "Permit(0).holder",
70
+ "tag": "describe",
71
+ "args": {
72
+ "label": "Holder"
73
+ }
74
+ },
75
+ {
76
+ "at": "Permit(0).spender",
77
+ "tag": "describe",
78
+ "args": {
79
+ "label": "Spender"
80
+ }
81
+ },
82
+ {
83
+ "at": "Permit(0).allowed",
84
+ "tag": "describe",
85
+ "args": {
86
+ "label": "Allowed (true: all, false: none)"
87
+ }
88
+ },
89
+ {
90
+ "at": "Permit(0).expiry",
91
+ "tag": "timestamp",
92
+ "args": {
93
+ "unit": "s",
94
+ "epoch": "unix",
95
+ "threshold": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
96
+ "message": "Never",
97
+ "labels": {
98
+ "0": "Never"
99
+ }
100
+ }
101
+ },
102
+ {
103
+ "at": "Permit(0).expiry",
104
+ "tag": "describe",
105
+ "args": {
106
+ "label": "Signature expires"
107
+ }
108
+ },
109
+ {
110
+ "at": "Permit(0).nonce",
111
+ "tag": "describe",
112
+ "args": {
113
+ "label": "Nonce"
114
+ }
115
+ }
116
+ ]
117
+ }
@@ -33,7 +33,11 @@
33
33
  "tag": "effect",
34
34
  "args": {
35
35
  "kind": "transfer",
36
- "irreversible": true
36
+ "irreversible": true,
37
+ "grant": {
38
+ "to": "to",
39
+ "amount": "value"
40
+ }
37
41
  }
38
42
  },
39
43
  {
@@ -75,7 +79,11 @@
75
79
  "tag": "effect",
76
80
  "args": {
77
81
  "kind": "approve",
78
- "irreversible": false
82
+ "irreversible": false,
83
+ "grant": {
84
+ "spender": "spender",
85
+ "amount": "value"
86
+ }
79
87
  }
80
88
  },
81
89
  {
@@ -0,0 +1,204 @@
1
+ {
2
+ "format": "candid-profile",
3
+ "format_version": 0,
4
+ "kind": "pack",
5
+ "name": "erc2612",
6
+ "origin": "pack",
7
+ "language": "en",
8
+ "description": "Standard pack for EIP-2612 permits on EVM chains (spec section 15.9, experimental): the signed `Permit` message that sets an ERC-20 allowance, and the `permit` function that submits one. Applies to a contract that has every function of `binds.abi` with the same selector, outputs and kind of call, `decimals()` and `symbol()` included, since the amounts read them. A signing request matches the `Permit` message by its EIP-712 type hash, and its verifying contract is the token, so `query:` refs are calls to that token. The domain's name and version are each token's own, so the pack names neither.",
9
+ "binds": {
10
+ "standard": "ERC-2612",
11
+ "spec_url": "https://eips.ethereum.org/EIPS/eip-2612",
12
+ "abi": [
13
+ "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
14
+ "function nonces(address owner) view returns (uint256)",
15
+ "function DOMAIN_SEPARATOR() view returns (bytes32)",
16
+ "function decimals() view returns (uint8)",
17
+ "function symbol() view returns (string)"
18
+ ],
19
+ "eip712": {
20
+ "types": {
21
+ "Permit": [
22
+ {
23
+ "name": "owner",
24
+ "type": "address"
25
+ },
26
+ {
27
+ "name": "spender",
28
+ "type": "address"
29
+ },
30
+ {
31
+ "name": "value",
32
+ "type": "uint256"
33
+ },
34
+ {
35
+ "name": "nonce",
36
+ "type": "uint256"
37
+ },
38
+ {
39
+ "name": "deadline",
40
+ "type": "uint256"
41
+ }
42
+ ]
43
+ }
44
+ }
45
+ },
46
+ "annotations": [
47
+ {
48
+ "at": "Permit",
49
+ "tag": "intent",
50
+ "args": {
51
+ "title": "Permit token spending",
52
+ "template": "Allow {spender} to spend up to {value} from {owner}. Signature expires: {deadline}."
53
+ }
54
+ },
55
+ {
56
+ "at": "Permit",
57
+ "tag": "effect",
58
+ "args": {
59
+ "kind": "approve",
60
+ "irreversible": false,
61
+ "grant": {
62
+ "spender": "spender",
63
+ "amount": "value"
64
+ }
65
+ }
66
+ },
67
+ {
68
+ "at": "Permit(0).value",
69
+ "tag": "amount",
70
+ "args": {
71
+ "decimals": {
72
+ "from": "query:decimals"
73
+ },
74
+ "symbol": {
75
+ "from": "query:symbol"
76
+ },
77
+ "threshold": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
78
+ }
79
+ },
80
+ {
81
+ "at": "Permit(0).value",
82
+ "tag": "describe",
83
+ "args": {
84
+ "label": "Amount"
85
+ }
86
+ },
87
+ {
88
+ "at": "Permit(0).deadline",
89
+ "tag": "timestamp",
90
+ "args": {
91
+ "unit": "s",
92
+ "epoch": "unix",
93
+ "threshold": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
94
+ "message": "Never"
95
+ }
96
+ },
97
+ {
98
+ "at": "Permit(0).deadline",
99
+ "tag": "describe",
100
+ "args": {
101
+ "label": "Signature expires"
102
+ }
103
+ },
104
+ {
105
+ "at": "Permit(0).owner",
106
+ "tag": "describe",
107
+ "args": {
108
+ "label": "Owner"
109
+ }
110
+ },
111
+ {
112
+ "at": "Permit(0).spender",
113
+ "tag": "describe",
114
+ "args": {
115
+ "label": "Spender"
116
+ }
117
+ },
118
+ {
119
+ "at": "Permit(0).nonce",
120
+ "tag": "describe",
121
+ "args": {
122
+ "label": "Nonce"
123
+ }
124
+ },
125
+ {
126
+ "at": "permit",
127
+ "tag": "intent",
128
+ "args": {
129
+ "title": "Submit a token permit",
130
+ "template": "Set {spender}'s allowance from {owner} to {value} with {owner}'s signature. Signature expires: {deadline}."
131
+ }
132
+ },
133
+ {
134
+ "at": "permit",
135
+ "tag": "effect",
136
+ "args": {
137
+ "kind": "approve",
138
+ "irreversible": false,
139
+ "grant": {
140
+ "spender": "spender",
141
+ "amount": "value"
142
+ }
143
+ }
144
+ },
145
+ {
146
+ "at": "permit(0).value",
147
+ "tag": "amount",
148
+ "args": {
149
+ "decimals": {
150
+ "from": "query:decimals"
151
+ },
152
+ "symbol": {
153
+ "from": "query:symbol"
154
+ },
155
+ "threshold": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
156
+ }
157
+ },
158
+ {
159
+ "at": "permit(0).value",
160
+ "tag": "describe",
161
+ "args": {
162
+ "label": "Amount"
163
+ }
164
+ },
165
+ {
166
+ "at": "permit(0).deadline",
167
+ "tag": "timestamp",
168
+ "args": {
169
+ "unit": "s",
170
+ "epoch": "unix",
171
+ "threshold": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
172
+ "message": "Never"
173
+ }
174
+ },
175
+ {
176
+ "at": "permit(0).deadline",
177
+ "tag": "describe",
178
+ "args": {
179
+ "label": "Signature expires"
180
+ }
181
+ },
182
+ {
183
+ "at": "permit(0).owner",
184
+ "tag": "describe",
185
+ "args": {
186
+ "label": "Owner"
187
+ }
188
+ },
189
+ {
190
+ "at": "permit(0).spender",
191
+ "tag": "describe",
192
+ "args": {
193
+ "label": "Spender"
194
+ }
195
+ },
196
+ {
197
+ "at": "permit(0).v",
198
+ "tag": "describe",
199
+ "args": {
200
+ "label": "Signature v"
201
+ }
202
+ }
203
+ ]
204
+ }
@@ -25,7 +25,11 @@
25
25
  "tag": "effect",
26
26
  "args": {
27
27
  "kind": "transfer",
28
- "irreversible": true
28
+ "irreversible": true,
29
+ "grant": {
30
+ "to": "to",
31
+ "amount": "amount"
32
+ }
29
33
  }
30
34
  },
31
35
  {
@@ -25,7 +25,14 @@
25
25
  "tag": "effect",
26
26
  "args": {
27
27
  "kind": "approve",
28
- "irreversible": false
28
+ "irreversible": false,
29
+ "grant": {
30
+ "spender": "spender",
31
+ "amount": "amount",
32
+ "ends": [
33
+ "expires_at"
34
+ ]
35
+ }
29
36
  }
30
37
  },
31
38
  {