@meantjs/profile 0.3.0 → 0.5.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,35 @@
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.5.0 — 2026-10-30
6
+
7
+ - Pins, experimental (spec §15.4, D-058): the new tag `fixed`, with `value` one address, says that a profile describes
8
+ a call or an EIP-712 message only with that address at an `address` position of its arguments. Elsewhere it is
9
+ `E_TAG_TARGET` or `E_TAG_NOT_APPLICABLE`, a value with a bad checksum `E_ADDRESS_CHECKSUM`, and two profiles that pin
10
+ one position to different addresses conflict in any layers (`E_CONFLICT`, at the lower one). A profile with a pin
11
+ that does not hold supplies only its effects, without grants, and its pins that hold; a pin's error is never an
12
+ `I_PACK_ANNOTATION_SKIPPED`. The resolved form carries the tag.
13
+ - New standard contract profiles, shipped beside the packs: `usdc` and `usdc-base-sepolia` (USDC's EIP-3009
14
+ messages `TransferWithAuthorization`, `ReceiveWithAuthorization` and `CancelAuthorization` on Ethereum, Base and
15
+ Arbitrum, and on Base Sepolia, whose USDC signs under another domain name), and `x402-exact-permit2` (x402's
16
+ `exact` payment through Permit2, its spender pinned to x402's proxy). The `permit2` profile also lists Base and Base
17
+ Sepolia (chains 8453 and 84532), so its profile id changed.
18
+ - A contract profile resolved against another ABI (`resolveService({ abi })`, `candid-profile resolve --abi`) reports
19
+ `W_REBOUND` and `E_STALE` at `binds.abi`, naming the identity of its ABI (spec §15.3, D-057). They were reported at
20
+ `binds.interface_id`, which a contract profile does not have, and `W_REBOUND` read "profile is bound to undefined".
21
+ Canister profiles are unchanged.
22
+ - Docs: the spec now lists `named` among the tags a stale profile does not supply, as the resolver has done since D-045;
23
+ the README and `served.mjs` no longer point at the kit, which is not public yet.
24
+
25
+ ## 0.4.0 — 2026-10-30
26
+
27
+ - What a call grants (spec §5.3, D-056): an `effect` of kind `transfer` or `approve` may carry `grant`, the positions of
28
+ who may take the tokens (`spender` or `to`), the `amount` and the `ends`. The validator checks them (new code
29
+ `E_GRANT`); a pack whose grant does not hold where it applies keeps its effect and loses the grant
30
+ (`I_PACK_ANNOTATION_SKIPPED`). The resolved form carries `grant` inside `effect`.
31
+ - The packs carry grants: `icrc1`, `icrc2`, `erc20` and `erc2612`, and the contract profiles `permit2` and
32
+ `dai-permit`. Their profile ids changed with them.
33
+
5
34
  ## 0.3.0 — 2026-10-29
6
35
 
7
36
  - EIP-712 typed messages, experimental (spec §15.9, D-055). A contract profile or EVM pack may carry
package/README.md CHANGED
@@ -146,7 +146,7 @@ const r = await resolveService({ did, validateSchema, profiles: doc ? [{ doc }]
146
146
 
147
147
  A canister serves its profile as the public custom section `icp:public candid:profile`. Reading the bytes is the
148
148
  consumer's job (one certified `read_state` of `/canister/<id>/metadata/candid:service` and `.../candid:profile`;
149
- `packages/kit` `fetch` does it with `@icp-sdk/core`); this package checks what came back:
149
+ the project's kit, not public yet, does it with `@icp-sdk/core`); this package checks what came back:
150
150
 
151
151
  ```js
152
152
  import { readServedProfile, resolveService } from "@meantjs/profile";
@@ -162,7 +162,7 @@ const r = await resolveService({ did: serviceText, profiles: served.ok ? [{ doc:
162
162
  installed yet (a module does not know the id it will run as); any other non-string throws.
163
163
  - Binding is the resolver's usual rule (spec section 7): resolve against the `candid:service` the same canister
164
164
  serves, so a profile for another interface is `rebound` or `stale` as any other.
165
- - Tests: `test/served.test.mjs`; end to end on PocketIC in `packages/kit/pocketic/`.
165
+ - Tests: `test/served.test.mjs`; end to end on PocketIC in the kit's tests, which are not public yet.
166
166
 
167
167
  ## EVM contracts (experimental, spec section 15, D-054 and D-055)
168
168
 
@@ -186,8 +186,12 @@ r.resolved.methods.transfer.tags.intent.args.template; // "Send {wad} to {dst}":
186
186
  (`PermitSingle(0).details.amount`) and listed under the resolved form's `messages` with its `encode_type` and
187
187
  `type_hash`. `amount.token` names an amount's token by an `address` field (`E_TOKEN_PATH` otherwise). Bad types, a
188
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.
189
+ pack, and the contract profiles `permit2`, `dai-permit`, `usdc`, `usdc-base-sepolia` and `x402-exact-permit2`
190
+ shipped beside the packs (`@meantjs/profile/packs/permit2.profile.json`); `loadPacks()` returns the packs only.
191
+ - **Pins** (`fixed`, spec §15.4, D-058): an `address` in the arguments of a function or a message that the profile
192
+ describes only with one value, as x402's Permit2 payment holds x402's proxy as its spender. A pin that does not hold
193
+ (another place or type, a bad checksum, an address that does not resolve, another value pinned by any profile) is
194
+ an error, and its profile then supplies only its effects, without grants, and its pins that hold.
191
195
  - **Refused for now:** overloaded function names and unreadable fragments (`E_ABI`); `idempotency`, `outcome`, `list`,
192
196
  `names` and `named` on a contract (`E_TAG_TARGET`); `account` and `subaccount` (`E_TAG_NOT_APPLICABLE`); `[ ]`
193
197
  template segments (`E_TEMPLATE`).
@@ -58,7 +58,11 @@
58
58
  "tag": "effect",
59
59
  "args": {
60
60
  "kind": "approve",
61
- "irreversible": false
61
+ "irreversible": false,
62
+ "grant": {
63
+ "spender": "spender",
64
+ "amount": "allowed"
65
+ }
62
66
  }
63
67
  },
64
68
  {
@@ -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
  {
@@ -57,7 +57,11 @@
57
57
  "tag": "effect",
58
58
  "args": {
59
59
  "kind": "approve",
60
- "irreversible": false
60
+ "irreversible": false,
61
+ "grant": {
62
+ "spender": "spender",
63
+ "amount": "value"
64
+ }
61
65
  }
62
66
  },
63
67
  {
@@ -131,7 +135,11 @@
131
135
  "tag": "effect",
132
136
  "args": {
133
137
  "kind": "approve",
134
- "irreversible": false
138
+ "irreversible": false,
139
+ "grant": {
140
+ "spender": "spender",
141
+ "amount": "value"
142
+ }
135
143
  }
136
144
  },
137
145
  {
@@ -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
  {
@@ -5,7 +5,7 @@
5
5
  "name": "permit2",
6
6
  "origin": "third_party",
7
7
  "language": "en",
8
- "description": "Uniswap's Permit2 (spec section 15.9, experimental): its AllowanceTransfer messages (PermitSingle, PermitBatch), which set allowances, and its SignatureTransfer messages (PermitTransferFrom, PermitBatchTransferFrom), which authorize one transfer. Witness messages (PermitWitnessTransferFrom) are left out: each protocol adds its own witness type (O1). Bound to the deployments ERC-7730's own Permit2 example lists, so a look-alike contract named \"Permit2\" gets none of these words. Amounts are in the token the message names: a consumer supplies that token's decimals() and symbol(), and shows its address beside the symbol.",
8
+ "description": "Uniswap's Permit2 (spec section 15.9, experimental): its AllowanceTransfer messages (PermitSingle, PermitBatch), which set allowances, and its SignatureTransfer messages (PermitTransferFrom, PermitBatchTransferFrom), which authorize one transfer. Witness messages (PermitWitnessTransferFrom) are left out: each protocol adds its own witness type, in a profile of its own (O9; x402's is x402-exact-permit2). Bound to the deployments ERC-7730's own Permit2 example lists (chains 1 and 42161) and to Base and Base Sepolia (8453 and 84532), whose Permit2 code and domain were read on chain on 2026-10-30, so a look-alike contract named \"Permit2\" gets none of these words. Amounts are in the token the message names: a consumer supplies that token's decimals() and symbol(), and shows its address beside the symbol.",
9
9
  "binds": {
10
10
  "eip712": {
11
11
  "domain": {
@@ -111,9 +111,17 @@
111
111
  "chain_id": 1,
112
112
  "address": "0x000000000022D473030F116dDEE9F6B43aC78BA3"
113
113
  },
114
+ {
115
+ "chain_id": 8453,
116
+ "address": "0x000000000022D473030F116dDEE9F6B43aC78BA3"
117
+ },
114
118
  {
115
119
  "chain_id": 42161,
116
120
  "address": "0x000000000022D473030F116dDEE9F6B43aC78BA3"
121
+ },
122
+ {
123
+ "chain_id": 84532,
124
+ "address": "0x000000000022D473030F116dDEE9F6B43aC78BA3"
117
125
  }
118
126
  ]
119
127
  },
@@ -131,7 +139,15 @@
131
139
  "tag": "effect",
132
140
  "args": {
133
141
  "kind": "approve",
134
- "irreversible": false
142
+ "irreversible": false,
143
+ "grant": {
144
+ "spender": "spender",
145
+ "amount": "details.amount",
146
+ "ends": [
147
+ "details.expiration",
148
+ "sigDeadline"
149
+ ]
150
+ }
135
151
  }
136
152
  },
137
153
  {
@@ -309,7 +325,14 @@
309
325
  "tag": "effect",
310
326
  "args": {
311
327
  "kind": "transfer",
312
- "irreversible": true
328
+ "irreversible": true,
329
+ "grant": {
330
+ "spender": "spender",
331
+ "amount": "permitted.amount",
332
+ "ends": [
333
+ "deadline"
334
+ ]
335
+ }
313
336
  }
314
337
  },
315
338
  {
@@ -0,0 +1,301 @@
1
+ {
2
+ "format": "candid-profile",
3
+ "format_version": 0,
4
+ "kind": "contract",
5
+ "name": "usdc-base-sepolia",
6
+ "origin": "third_party",
7
+ "language": "en",
8
+ "description": "USDC's EIP-3009 messages on Base Sepolia, a test network (spec section 15.9, experimental), with the usdc profile's words. TransferWithAuthorization and ReceiveWithAuthorization pay `to` once, by a signature that someone else submits (only the payee, for ReceiveWithAuthorization), and CancelAuthorization cancels one that is unused (EIP-3009; Circle stablecoin-evm, FiatTokenV2.sol). x402's `exact` scheme pays by TransferWithAuthorization by default (coinbase/x402, specs/schemes/exact/scheme_exact_evm.md). Only the messages are described: USDC's ABI names transferWithAuthorization, receiveWithAuthorization, cancelAuthorization and permit twice each, which the resolver refuses (O1). Base Sepolia's USDC signs under the domain name `USDC`, not the mainnets' `USD Coin`, and a profile binds one domain, so it has a profile of its own. Read on chain on 2026-10-30 (DOMAIN_SEPARATOR, decimals 6, the three type hashes); x402's own examples use it.",
9
+ "binds": {
10
+ "eip712": {
11
+ "domain": {
12
+ "name": "USDC",
13
+ "version": "2"
14
+ },
15
+ "types": {
16
+ "CancelAuthorization": [
17
+ {
18
+ "name": "authorizer",
19
+ "type": "address"
20
+ },
21
+ {
22
+ "name": "nonce",
23
+ "type": "bytes32"
24
+ }
25
+ ],
26
+ "ReceiveWithAuthorization": [
27
+ {
28
+ "name": "from",
29
+ "type": "address"
30
+ },
31
+ {
32
+ "name": "to",
33
+ "type": "address"
34
+ },
35
+ {
36
+ "name": "value",
37
+ "type": "uint256"
38
+ },
39
+ {
40
+ "name": "validAfter",
41
+ "type": "uint256"
42
+ },
43
+ {
44
+ "name": "validBefore",
45
+ "type": "uint256"
46
+ },
47
+ {
48
+ "name": "nonce",
49
+ "type": "bytes32"
50
+ }
51
+ ],
52
+ "TransferWithAuthorization": [
53
+ {
54
+ "name": "from",
55
+ "type": "address"
56
+ },
57
+ {
58
+ "name": "to",
59
+ "type": "address"
60
+ },
61
+ {
62
+ "name": "value",
63
+ "type": "uint256"
64
+ },
65
+ {
66
+ "name": "validAfter",
67
+ "type": "uint256"
68
+ },
69
+ {
70
+ "name": "validBefore",
71
+ "type": "uint256"
72
+ },
73
+ {
74
+ "name": "nonce",
75
+ "type": "bytes32"
76
+ }
77
+ ]
78
+ }
79
+ },
80
+ "deployments": [
81
+ {
82
+ "chain_id": 84532,
83
+ "address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
84
+ }
85
+ ]
86
+ },
87
+ "annotations": [
88
+ {
89
+ "at": "TransferWithAuthorization",
90
+ "tag": "intent",
91
+ "args": {
92
+ "title": "Pay USDC by signature",
93
+ "template": "Send {value} from {from} to {to}, once. Valid after {validAfter}. Expires: {validBefore}."
94
+ }
95
+ },
96
+ {
97
+ "at": "TransferWithAuthorization",
98
+ "tag": "effect",
99
+ "args": {
100
+ "kind": "transfer",
101
+ "irreversible": true,
102
+ "grant": {
103
+ "to": "to",
104
+ "amount": "value",
105
+ "ends": [
106
+ "validBefore"
107
+ ]
108
+ }
109
+ }
110
+ },
111
+ {
112
+ "at": "TransferWithAuthorization(0).from",
113
+ "tag": "describe",
114
+ "args": {
115
+ "label": "From"
116
+ }
117
+ },
118
+ {
119
+ "at": "TransferWithAuthorization(0).to",
120
+ "tag": "describe",
121
+ "args": {
122
+ "label": "To"
123
+ }
124
+ },
125
+ {
126
+ "at": "TransferWithAuthorization(0).value",
127
+ "tag": "amount",
128
+ "args": {
129
+ "decimals": 6,
130
+ "symbol": "USDC"
131
+ }
132
+ },
133
+ {
134
+ "at": "TransferWithAuthorization(0).value",
135
+ "tag": "describe",
136
+ "args": {
137
+ "label": "Amount"
138
+ }
139
+ },
140
+ {
141
+ "at": "TransferWithAuthorization(0).validAfter",
142
+ "tag": "timestamp",
143
+ "args": {
144
+ "unit": "s",
145
+ "epoch": "unix"
146
+ }
147
+ },
148
+ {
149
+ "at": "TransferWithAuthorization(0).validAfter",
150
+ "tag": "describe",
151
+ "args": {
152
+ "label": "Valid after"
153
+ }
154
+ },
155
+ {
156
+ "at": "TransferWithAuthorization(0).validBefore",
157
+ "tag": "timestamp",
158
+ "args": {
159
+ "unit": "s",
160
+ "epoch": "unix",
161
+ "threshold": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
162
+ "message": "Never"
163
+ }
164
+ },
165
+ {
166
+ "at": "TransferWithAuthorization(0).validBefore",
167
+ "tag": "describe",
168
+ "args": {
169
+ "label": "Expires"
170
+ }
171
+ },
172
+ {
173
+ "at": "TransferWithAuthorization(0).nonce",
174
+ "tag": "describe",
175
+ "args": {
176
+ "label": "Nonce"
177
+ }
178
+ },
179
+ {
180
+ "at": "ReceiveWithAuthorization",
181
+ "tag": "intent",
182
+ "args": {
183
+ "title": "Pay USDC by signature, collected by the payee",
184
+ "template": "Send {value} from {from} to {to}, once; only {to} can submit it. Valid after {validAfter}. Expires: {validBefore}."
185
+ }
186
+ },
187
+ {
188
+ "at": "ReceiveWithAuthorization",
189
+ "tag": "effect",
190
+ "args": {
191
+ "kind": "transfer",
192
+ "irreversible": true,
193
+ "grant": {
194
+ "to": "to",
195
+ "amount": "value",
196
+ "ends": [
197
+ "validBefore"
198
+ ]
199
+ }
200
+ }
201
+ },
202
+ {
203
+ "at": "ReceiveWithAuthorization(0).from",
204
+ "tag": "describe",
205
+ "args": {
206
+ "label": "From"
207
+ }
208
+ },
209
+ {
210
+ "at": "ReceiveWithAuthorization(0).to",
211
+ "tag": "describe",
212
+ "args": {
213
+ "label": "To"
214
+ }
215
+ },
216
+ {
217
+ "at": "ReceiveWithAuthorization(0).value",
218
+ "tag": "amount",
219
+ "args": {
220
+ "decimals": 6,
221
+ "symbol": "USDC"
222
+ }
223
+ },
224
+ {
225
+ "at": "ReceiveWithAuthorization(0).value",
226
+ "tag": "describe",
227
+ "args": {
228
+ "label": "Amount"
229
+ }
230
+ },
231
+ {
232
+ "at": "ReceiveWithAuthorization(0).validAfter",
233
+ "tag": "timestamp",
234
+ "args": {
235
+ "unit": "s",
236
+ "epoch": "unix"
237
+ }
238
+ },
239
+ {
240
+ "at": "ReceiveWithAuthorization(0).validAfter",
241
+ "tag": "describe",
242
+ "args": {
243
+ "label": "Valid after"
244
+ }
245
+ },
246
+ {
247
+ "at": "ReceiveWithAuthorization(0).validBefore",
248
+ "tag": "timestamp",
249
+ "args": {
250
+ "unit": "s",
251
+ "epoch": "unix",
252
+ "threshold": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
253
+ "message": "Never"
254
+ }
255
+ },
256
+ {
257
+ "at": "ReceiveWithAuthorization(0).validBefore",
258
+ "tag": "describe",
259
+ "args": {
260
+ "label": "Expires"
261
+ }
262
+ },
263
+ {
264
+ "at": "ReceiveWithAuthorization(0).nonce",
265
+ "tag": "describe",
266
+ "args": {
267
+ "label": "Nonce"
268
+ }
269
+ },
270
+ {
271
+ "at": "CancelAuthorization",
272
+ "tag": "intent",
273
+ "args": {
274
+ "title": "Cancel a USDC payment signature",
275
+ "template": "Cancel the unused USDC payment signature of {authorizer} with nonce {nonce}."
276
+ }
277
+ },
278
+ {
279
+ "at": "CancelAuthorization",
280
+ "tag": "effect",
281
+ "args": {
282
+ "kind": "write",
283
+ "irreversible": true
284
+ }
285
+ },
286
+ {
287
+ "at": "CancelAuthorization(0).authorizer",
288
+ "tag": "describe",
289
+ "args": {
290
+ "label": "Signer of the payment"
291
+ }
292
+ },
293
+ {
294
+ "at": "CancelAuthorization(0).nonce",
295
+ "tag": "describe",
296
+ "args": {
297
+ "label": "Nonce"
298
+ }
299
+ }
300
+ ]
301
+ }