opacity-issuer-core 0.2.1
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 +21 -0
- package/README.md +44 -0
- package/dist/chunk-2STMWRIV.js +164 -0
- package/dist/chunk-2STMWRIV.js.map +1 -0
- package/dist/chunk-3L7NNVUV.cjs +184 -0
- package/dist/chunk-3L7NNVUV.cjs.map +1 -0
- package/dist/chunk-54Q3MU62.js +29 -0
- package/dist/chunk-54Q3MU62.js.map +1 -0
- package/dist/chunk-7ODYBEZH.js +889 -0
- package/dist/chunk-7ODYBEZH.js.map +1 -0
- package/dist/chunk-GMPQFX25.cjs +923 -0
- package/dist/chunk-GMPQFX25.cjs.map +1 -0
- package/dist/chunk-HJQZWNZJ.cjs +33 -0
- package/dist/chunk-HJQZWNZJ.cjs.map +1 -0
- package/dist/documents/index.cjs +170 -0
- package/dist/documents/index.cjs.map +1 -0
- package/dist/documents/index.d.cts +1370 -0
- package/dist/documents/index.d.ts +1370 -0
- package/dist/documents/index.js +5 -0
- package/dist/documents/index.js.map +1 -0
- package/dist/documents/validate.cjs +53 -0
- package/dist/documents/validate.cjs.map +1 -0
- package/dist/documents/validate.d.cts +70 -0
- package/dist/documents/validate.d.ts +70 -0
- package/dist/documents/validate.js +4 -0
- package/dist/documents/validate.js.map +1 -0
- package/dist/index.cjs +8917 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +11088 -0
- package/dist/index.d.ts +11088 -0
- package/dist/index.js +8647 -0
- package/dist/index.js.map +1 -0
- package/dist/subgraph.cjs +891 -0
- package/dist/subgraph.cjs.map +1 -0
- package/dist/subgraph.d.cts +456 -0
- package/dist/subgraph.d.ts +456 -0
- package/dist/subgraph.js +882 -0
- package/dist/subgraph.js.map +1 -0
- package/dist/transport-0_X4HTI6.d.ts +39 -0
- package/dist/transport-uaC5Yl3p.d.cts +39 -0
- package/dist/types-B4Yi7WA4.d.cts +108 -0
- package/dist/types-B4Yi7WA4.d.ts +108 -0
- package/package.json +75 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Opacity Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# opacity-issuer-core
|
|
2
|
+
|
|
3
|
+
Backend-independent Opacity protocol helpers, contract ABIs, policy builders, issuer lifecycle, purchases, and document signing primitives. This package does not require mobile-api configuration or authentication.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { createIssuersNamespace } from 'opacity-issuer-core';
|
|
7
|
+
import { createSubgraphClient, createIndexerNamespace } from 'opacity-issuer-core/subgraph';
|
|
8
|
+
|
|
9
|
+
const issuers = createIssuersNamespace({ chainId, publicClient, walletClient });
|
|
10
|
+
const subgraph = createSubgraphClient({ url: process.env.SUBGRAPH_URL! });
|
|
11
|
+
const data = await subgraph.query<{ tokens: { id: string }[] }>('{ tokens { id } }');
|
|
12
|
+
const indexer = createIndexerNamespace({ url: process.env.SUBGRAPH_URL! });
|
|
13
|
+
const balances = await indexer.listBalances({ wallet });
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Keep authenticated subgraph URLs and headers in your application's server configuration. The direct clients share one HTTP transport, default to global `fetch` with a 30-second deadline, and accept cancellation and timeout overrides; the generic client also accepts headers and an injected fetch implementation so the application controls caching. HTTP failures, GraphQL errors (including partial responses), and absent data objects reject.
|
|
17
|
+
|
|
18
|
+
`opacity-issuer-core/subgraph` also exports the fixed hosted API operation list, lossless bigint wire helpers, and the shared operation argument and response validators used by the SDK and mobile-api. The same argument contract validates direct reads and decoded hosted requests, including unknown keys, uint256 quantities, snapshot bounds and cursor shapes. API adapters can apply tighter request budgets. These helpers do not choose an upstream endpoint.
|
|
19
|
+
|
|
20
|
+
Use `opacity-issuer-sdk` for external frontend integrations that route reads, user status, document sessions and relay through mobile-api. Core supplies protocol capabilities; application authentication, organization authorization, private signing keys, offchain document records and relayer infrastructure remain application/backend responsibilities.
|
|
21
|
+
|
|
22
|
+
For sandbox fixtures, `prepareSandboxUser(publicClient, { chainId, registryAddress, wallet,
|
|
23
|
+
traits: { accredited: true, jurisdictions: { US: true } } })` prepares only needed onboarding and
|
|
24
|
+
global trait writes from live state. Send the returned steps with the test wallet through
|
|
25
|
+
`createIssuersNamespace`. `resolveSandboxUserTraits`, `sandboxTraitId`, and
|
|
26
|
+
`sandboxJurisdictionTraitId` also work offline. Profiles are patches; document traits bypass a
|
|
27
|
+
policy gate without creating signed-document history. See the
|
|
28
|
+
[sandbox user guide](https://github.com/OpacityLabs/opacity-issuer-sdk/blob/main/docs/sandbox-users.md).
|
|
29
|
+
|
|
30
|
+
To create a separate random test wallet, use `createSandboxUser(publicClient, { chainId,
|
|
31
|
+
registryAddress, transport, traits, funding: { walletClient: sponsor, amount }, persist })`.
|
|
32
|
+
The sponsor approves one exact native-currency transfer; the generated wallet automatically signs
|
|
33
|
+
onboarding and trait writes. Funding is optional, has no default amount, and never retries automatically.
|
|
34
|
+
Credentials are persisted before writes and returned with progress for recovery.
|
|
35
|
+
Supply a saved test `privateKey` to reuse it. The read client and write transport must agree on
|
|
36
|
+
chain. `waitForSandboxUserFunding` reconciles a saved funding transfer without resending it.
|
|
37
|
+
|
|
38
|
+
### Token transfers
|
|
39
|
+
|
|
40
|
+
`createTransfersNamespace({ chainId, publicClient, walletClient })` provides `prepareTransfer`,
|
|
41
|
+
`sendTransfer`, and `waitForTransfer` for normal ERC1155 SecurityToken transfers. It checks live
|
|
42
|
+
policies and gas and verifies the exact transfer receipt. `transferSandboxUser` adds optional
|
|
43
|
+
one-transfer gas sponsorship and persistent progress for a saved local demo signer.
|
|
44
|
+
See [transfer integration](../../docs/transfers.md).
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { OpacityAttestationError } from './chunk-54Q3MU62.js';
|
|
2
|
+
import { isAddress, getAddress, isHex, size } from 'viem';
|
|
3
|
+
|
|
4
|
+
// src/documents/constants.ts
|
|
5
|
+
var DOCUMENT_ATTESTOR_DOMAIN_NAME = "DocumentAttestor";
|
|
6
|
+
var DOCUMENT_ATTESTOR_DOMAIN_VERSION = "1";
|
|
7
|
+
var DOCUMENT_ACCEPTANCE_TYPES = {
|
|
8
|
+
DocumentAcceptance: [
|
|
9
|
+
{ name: "nonce", type: "bytes32" },
|
|
10
|
+
{ name: "docHash", type: "bytes32" },
|
|
11
|
+
{ name: "deadline", type: "uint256" }
|
|
12
|
+
]
|
|
13
|
+
};
|
|
14
|
+
var DOCUMENT_ACCEPTANCE_PRIMARY_TYPE = "DocumentAcceptance";
|
|
15
|
+
var EIP712_DOMAIN_TYPE = [
|
|
16
|
+
{ name: "name", type: "string" },
|
|
17
|
+
{ name: "version", type: "string" },
|
|
18
|
+
{ name: "chainId", type: "uint256" },
|
|
19
|
+
{ name: "verifyingContract", type: "address" }
|
|
20
|
+
];
|
|
21
|
+
var DOCUMENT_ACCEPTANCE_TYPEHASH = "0xcd87f8252156623d78fd52f8f4f1c63bcda5d0b21a8c7f56f63a1759103d6598";
|
|
22
|
+
var MAX_ATTESTATION_LIFETIME_SECONDS = 2592000n;
|
|
23
|
+
var ECDSA_SIGNATURE_BYTES = 65;
|
|
24
|
+
|
|
25
|
+
// src/documents/validate.ts
|
|
26
|
+
var ZERO_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
27
|
+
function assertAddress(value, field) {
|
|
28
|
+
if (typeof value !== "string" || !isAddress(value, { strict: false })) {
|
|
29
|
+
throw new OpacityAttestationError("MalformedInput", `\`${field}\` is not a valid address.`, {
|
|
30
|
+
field
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
const normalized = getAddress(value);
|
|
34
|
+
if (normalized === "0x0000000000000000000000000000000000000000") {
|
|
35
|
+
throw new OpacityAttestationError("ZeroAddress", `\`${field}\` must not be the zero address.`, {
|
|
36
|
+
field
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return normalized;
|
|
40
|
+
}
|
|
41
|
+
function assertBytes32(value, field) {
|
|
42
|
+
if (typeof value !== "string" || !isHex(value) || value.length !== 2 + 64) {
|
|
43
|
+
throw new OpacityAttestationError(
|
|
44
|
+
"MalformedInput",
|
|
45
|
+
`\`${field}\` must be a 32-byte hex string (0x + 64 hex chars).`,
|
|
46
|
+
{ field }
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
function assertTraitId(value) {
|
|
52
|
+
const traitId = assertBytes32(value, "traitId");
|
|
53
|
+
if (traitId.toLowerCase() === ZERO_BYTES32) {
|
|
54
|
+
throw new OpacityAttestationError("InvalidTraitId", "`traitId` must not be zero.", {
|
|
55
|
+
field: "traitId"
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return traitId;
|
|
59
|
+
}
|
|
60
|
+
function assertBoolean(value, field) {
|
|
61
|
+
if (typeof value !== "boolean") {
|
|
62
|
+
throw new OpacityAttestationError("MalformedInput", `\`${field}\` must be a boolean.`, {
|
|
63
|
+
field
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
function assertDocHash(value) {
|
|
69
|
+
const docHash = assertBytes32(value, "docHash");
|
|
70
|
+
if (docHash.toLowerCase() === ZERO_BYTES32) {
|
|
71
|
+
throw new OpacityAttestationError("InvalidDocHash", "`docHash` must not be zero.", {
|
|
72
|
+
field: "docHash"
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return docHash;
|
|
76
|
+
}
|
|
77
|
+
function assertNonce(value) {
|
|
78
|
+
return assertBytes32(value, "nonce");
|
|
79
|
+
}
|
|
80
|
+
function assertTimestamp(value, field) {
|
|
81
|
+
if (typeof value !== "bigint") {
|
|
82
|
+
throw new OpacityAttestationError(
|
|
83
|
+
"MalformedInput",
|
|
84
|
+
`\`${field}\` must be a bigint of unix seconds.`,
|
|
85
|
+
{ field }
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
if (value < 0n) {
|
|
89
|
+
throw new OpacityAttestationError("MalformedInput", `\`${field}\` must not be negative.`, {
|
|
90
|
+
field
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
function assertServerSignature(value) {
|
|
96
|
+
if (typeof value !== "string" || !isHex(value)) {
|
|
97
|
+
throw new OpacityAttestationError("MalformedInput", "`serverSignature` must be a hex string.", {
|
|
98
|
+
field: "serverSignature"
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (value.length !== 2 + ECDSA_SIGNATURE_BYTES * 2) {
|
|
102
|
+
const length = size(value);
|
|
103
|
+
throw new OpacityAttestationError(
|
|
104
|
+
"InvalidSignatureLength",
|
|
105
|
+
`\`serverSignature\` must be ${ECDSA_SIGNATURE_BYTES} bytes; received ${length}. The document server signs with ECDSA, which accepts no other length.`,
|
|
106
|
+
{ field: "serverSignature" }
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
return value;
|
|
110
|
+
}
|
|
111
|
+
function assertUserSignature(value) {
|
|
112
|
+
if (typeof value !== "string" || !isHex(value) || value.length % 2 !== 0) {
|
|
113
|
+
throw new OpacityAttestationError(
|
|
114
|
+
"MalformedInput",
|
|
115
|
+
"`userSignature` must be a hex string of whole bytes.",
|
|
116
|
+
{ field: "userSignature" }
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
function assertSessionWindow(session, options = {}) {
|
|
122
|
+
const { deadline } = session;
|
|
123
|
+
assertTimestamp(deadline, "deadline");
|
|
124
|
+
if (session.issuedAt !== void 0) {
|
|
125
|
+
const issuedAt = assertTimestamp(session.issuedAt, "issuedAt");
|
|
126
|
+
const maxAllowed = issuedAt + MAX_ATTESTATION_LIFETIME_SECONDS;
|
|
127
|
+
if (deadline > maxAllowed) {
|
|
128
|
+
throw new OpacityAttestationError(
|
|
129
|
+
"AttestationDeadlineTooFar",
|
|
130
|
+
`\`deadline\` (${deadline}) exceeds \`issuedAt\` + MAX_ATTESTATION_LIFETIME (${maxAllowed}).`,
|
|
131
|
+
{ field: "deadline" }
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const { now } = options;
|
|
136
|
+
if (now === void 0) return;
|
|
137
|
+
assertTimestamp(now, "now");
|
|
138
|
+
if (session.issuedAt !== void 0 && session.issuedAt > now) {
|
|
139
|
+
throw new OpacityAttestationError(
|
|
140
|
+
"AttestationIssuedInFuture",
|
|
141
|
+
`\`issuedAt\` (${session.issuedAt}) is in the future relative to \`now\` (${now}). A post-dated session is rejected permanently, not held until it matures.`,
|
|
142
|
+
{ field: "issuedAt" }
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
if (now > deadline) {
|
|
146
|
+
throw new OpacityAttestationError(
|
|
147
|
+
"AttestationExpired",
|
|
148
|
+
`The session expired at ${deadline}, before \`now\` (${now}).`,
|
|
149
|
+
{ field: "deadline" }
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function assertChainId(value) {
|
|
154
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
155
|
+
throw new OpacityAttestationError("MalformedInput", "`chainId` must be a positive integer.", {
|
|
156
|
+
field: "chainId"
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return value;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export { DOCUMENT_ACCEPTANCE_PRIMARY_TYPE, DOCUMENT_ACCEPTANCE_TYPEHASH, DOCUMENT_ACCEPTANCE_TYPES, DOCUMENT_ATTESTOR_DOMAIN_NAME, DOCUMENT_ATTESTOR_DOMAIN_VERSION, ECDSA_SIGNATURE_BYTES, EIP712_DOMAIN_TYPE, MAX_ATTESTATION_LIFETIME_SECONDS, assertAddress, assertBoolean, assertBytes32, assertChainId, assertDocHash, assertNonce, assertServerSignature, assertSessionWindow, assertTimestamp, assertTraitId, assertUserSignature };
|
|
163
|
+
//# sourceMappingURL=chunk-2STMWRIV.js.map
|
|
164
|
+
//# sourceMappingURL=chunk-2STMWRIV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/documents/constants.ts","../src/documents/validate.ts"],"names":[],"mappings":"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","file":"chunk-2STMWRIV.js","sourcesContent":["import type { Hex } from 'viem';\n\n/**\n * EIP-712 domain `name` and `version`, from `EIP712(\"DocumentAttestor\", \"1\")` in\n * `DocumentAttestor.sol`. The domain has no `salt` — OpenZeppelin's `EIP712` uses\n * `EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)`.\n */\nexport const DOCUMENT_ATTESTOR_DOMAIN_NAME = 'DocumentAttestor';\nexport const DOCUMENT_ATTESTOR_DOMAIN_VERSION = '1';\n\n/**\n * The payload the investor's wallet signs.\n *\n * It deliberately binds neither `wallet` nor `traitId`: the trait is an internal mapping and the\n * prompt should show only what the human is agreeing to, while the binding to a wallet comes from\n * ECDSA recovery (or, for ERC-1271, from the server's own signature). Cross-deployment and\n * cross-chain replay are stopped by the domain's `chainId` + `verifyingContract`.\n *\n * Field order is consensus-critical — it is part of the type hash.\n */\nexport const DOCUMENT_ACCEPTANCE_TYPES = {\n DocumentAcceptance: [\n { name: 'nonce', type: 'bytes32' },\n { name: 'docHash', type: 'bytes32' },\n { name: 'deadline', type: 'uint256' },\n ],\n} as const;\n\nexport const DOCUMENT_ACCEPTANCE_PRIMARY_TYPE = 'DocumentAcceptance';\n\n/**\n * The EIP-712 domain type, needed only by `toEip712JsonPayload`: raw `eth_signTypedData_v4`\n * requires `EIP712Domain` to be present in `types`, whereas viem derives it and ethers v6 throws\n * if you supply it.\n */\nexport const EIP712_DOMAIN_TYPE = [\n { name: 'name', type: 'string' },\n { name: 'version', type: 'string' },\n { name: 'chainId', type: 'uint256' },\n { name: 'verifyingContract', type: 'address' },\n] as const;\n\n/**\n * `keccak256(\"DocumentAcceptance(bytes32 nonce,bytes32 docHash,uint256 deadline)\")`.\n *\n * Not used to build the payload (viem derives it from {@link DOCUMENT_ACCEPTANCE_TYPES}); exported\n * so a consumer can assert it against the contract's `DOCUMENT_ACCEPTANCE_TYPEHASH()` getter.\n */\nexport const DOCUMENT_ACCEPTANCE_TYPEHASH: Hex =\n '0xcd87f8252156623d78fd52f8f4f1c63bcda5d0b21a8c7f56f63a1759103d6598';\n\n/**\n * Mirrors `DocumentAttestor.MAX_ATTESTATION_LIFETIME` (30 days).\n *\n * Duplicated off-chain so `deadline > issuedAt + MAX_ATTESTATION_LIFETIME` can be caught before the\n * investor is prompted, rather than at redemption. It is a `constant` on a non-upgradeable contract,\n * so it cannot drift for a given deployment — but a successor deployment could choose a different\n * value, which is why `MAX_ATTESTATION_LIFETIME` is kept in `documentAttestorAbi` for\n * consumers that want to read it back.\n */\nexport const MAX_ATTESTATION_LIFETIME_SECONDS = 2_592_000n;\n\n/** Length in bytes of the ECDSA signature `ECDSA.recover` accepts — it rejects every other length. */\nexport const ECDSA_SIGNATURE_BYTES = 65;\n","import { getAddress, isAddress, isHex, size } from 'viem';\nimport type { Address, Hex } from 'viem';\n\nimport { OpacityAttestationError } from '../errors.js';\nimport { ECDSA_SIGNATURE_BYTES, MAX_ATTESTATION_LIFETIME_SECONDS } from './constants.js';\nimport type { ClockOptions } from './types.js';\n\nconst ZERO_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000';\n\n/**\n * Normalises an address and rejects the zero address.\n *\n * Returns the checksummed form: `attestDocument` takes `wallet` as a plain `address`, so casing\n * does not affect the calldata, but returning the canonical form keeps the descriptor comparable.\n */\nexport function assertAddress(value: Address, field: string): Address {\n if (typeof value !== 'string' || !isAddress(value, { strict: false })) {\n throw new OpacityAttestationError('MalformedInput', `\\`${field}\\` is not a valid address.`, {\n field,\n });\n }\n const normalized = getAddress(value);\n if (normalized === '0x0000000000000000000000000000000000000000') {\n throw new OpacityAttestationError('ZeroAddress', `\\`${field}\\` must not be the zero address.`, {\n field,\n });\n }\n return normalized;\n}\n\n/**\n * Rejects anything that is not 32 bytes of hex. Zero-ness is checked separately, per field.\n *\n * Length is checked on the string, not via `size()`, which rounds a half-byte up — `0x` followed\n * by 63 hex chars has a `size()` of 32 but is not a valid `bytes32`.\n */\nexport function assertBytes32(value: Hex, field: string): Hex {\n if (typeof value !== 'string' || !isHex(value) || value.length !== 2 + 64) {\n throw new OpacityAttestationError(\n 'MalformedInput',\n `\\`${field}\\` must be a 32-byte hex string (0x + 64 hex chars).`,\n { field },\n );\n }\n return value;\n}\n\n/**\n * `traitId` must be non-zero — `InvalidTraitId`.\n *\n * A zero trait id is almost always an un-set config value rather than a real trait.\n */\nexport function assertTraitId(value: Hex): Hex {\n const traitId = assertBytes32(value, 'traitId');\n if (traitId.toLowerCase() === ZERO_BYTES32) {\n throw new OpacityAttestationError('InvalidTraitId', '`traitId` must not be zero.', {\n field: 'traitId',\n });\n }\n return traitId;\n}\n\n/** Strict runtime boolean validation for callers that bypass TypeScript declarations. */\nexport function assertBoolean(value: boolean, field: string): boolean {\n if (typeof value !== 'boolean') {\n throw new OpacityAttestationError('MalformedInput', `\\`${field}\\` must be a boolean.`, {\n field,\n });\n }\n return value;\n}\n\n/**\n * `docHash` must be non-zero — `InvalidDocHash`.\n *\n * No executed document hashes to zero, so a zero here is a server-side bug and must not be attested.\n */\nexport function assertDocHash(value: Hex): Hex {\n const docHash = assertBytes32(value, 'docHash');\n if (docHash.toLowerCase() === ZERO_BYTES32) {\n throw new OpacityAttestationError('InvalidDocHash', '`docHash` must not be zero.', {\n field: 'docHash',\n });\n }\n return docHash;\n}\n\n/**\n * `nonce` must be well-formed, but may be zero.\n *\n * The contract applies no zero-check to the nonce — slot zero is burnable like any other — so\n * rejecting it here would be stricter than the chain.\n */\nexport function assertNonce(value: Hex): Hex {\n return assertBytes32(value, 'nonce');\n}\n\n/** Rejects negative or non-`bigint` unix timestamps before they are encoded as `uint256`. */\nexport function assertTimestamp(value: bigint, field: string): bigint {\n if (typeof value !== 'bigint') {\n throw new OpacityAttestationError(\n 'MalformedInput',\n `\\`${field}\\` must be a bigint of unix seconds.`,\n { field },\n );\n }\n if (value < 0n) {\n throw new OpacityAttestationError('MalformedInput', `\\`${field}\\` must not be negative.`, {\n field,\n });\n }\n return value;\n}\n\n/**\n * The 65-byte rule for the SERVER signature only.\n *\n * `ECDSA.recover` accepts exactly one length and reverts `ECDSAInvalidSignatureLength` on any\n * other. The investor signature must NOT be length-checked: `SignatureChecker` routes a\n * code-bearing wallet (a Safe, or an EIP-7702-delegated EOA) to ERC-1271, where the signature is\n * whatever that wallet's own validation logic accepts.\n */\nexport function assertServerSignature(value: Hex): Hex {\n if (typeof value !== 'string' || !isHex(value)) {\n throw new OpacityAttestationError('MalformedInput', '`serverSignature` must be a hex string.', {\n field: 'serverSignature',\n });\n }\n if (value.length !== 2 + ECDSA_SIGNATURE_BYTES * 2) {\n const length = size(value);\n throw new OpacityAttestationError(\n 'InvalidSignatureLength',\n `\\`serverSignature\\` must be ${ECDSA_SIGNATURE_BYTES} bytes; received ${length}. ` +\n 'The document server signs with ECDSA, which accepts no other length.',\n { field: 'serverSignature' },\n );\n }\n return value;\n}\n\n/**\n * The investor signature: hex, any BYTE length — an ERC-1271 wallet is not 65 bytes.\n *\n * Only the half-byte case is rejected, since it cannot encode as `bytes`.\n */\nexport function assertUserSignature(value: Hex): Hex {\n if (typeof value !== 'string' || !isHex(value) || value.length % 2 !== 0) {\n throw new OpacityAttestationError(\n 'MalformedInput',\n '`userSignature` must be a hex string of whole bytes.',\n { field: 'userSignature' },\n );\n }\n return value;\n}\n\n/**\n * The session-lifetime rules, split by whether they need a clock.\n *\n * `deadline <= issuedAt + MAX_ATTESTATION_LIFETIME` is absolute and always checked. The two\n * clock-relative rules run only when `now` is supplied — see {@link ClockOptions} for why that is\n * opt-in.\n */\nexport function assertSessionWindow(\n session: { issuedAt?: bigint | undefined; deadline: bigint },\n options: ClockOptions = {},\n): void {\n const { deadline } = session;\n assertTimestamp(deadline, 'deadline');\n\n if (session.issuedAt !== undefined) {\n const issuedAt = assertTimestamp(session.issuedAt, 'issuedAt');\n const maxAllowed = issuedAt + MAX_ATTESTATION_LIFETIME_SECONDS;\n if (deadline > maxAllowed) {\n throw new OpacityAttestationError(\n 'AttestationDeadlineTooFar',\n `\\`deadline\\` (${deadline}) exceeds \\`issuedAt\\` + MAX_ATTESTATION_LIFETIME (${maxAllowed}).`,\n { field: 'deadline' },\n );\n }\n }\n\n const { now } = options;\n if (now === undefined) return;\n assertTimestamp(now, 'now');\n\n if (session.issuedAt !== undefined && session.issuedAt > now) {\n throw new OpacityAttestationError(\n 'AttestationIssuedInFuture',\n `\\`issuedAt\\` (${session.issuedAt}) is in the future relative to \\`now\\` (${now}). ` +\n 'A post-dated session is rejected permanently, not held until it matures.',\n { field: 'issuedAt' },\n );\n }\n\n if (now > deadline) {\n throw new OpacityAttestationError(\n 'AttestationExpired',\n `The session expired at ${deadline}, before \\`now\\` (${now}).`,\n { field: 'deadline' },\n );\n }\n}\n\n/** Rejects a non-integer / out-of-range chain id before it lands in a signed domain. */\nexport function assertChainId(value: number): number {\n if (!Number.isInteger(value) || value <= 0) {\n throw new OpacityAttestationError('MalformedInput', '`chainId` must be a positive integer.', {\n field: 'chainId',\n });\n }\n return value;\n}\n"]}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkHJQZWNZJ_cjs = require('./chunk-HJQZWNZJ.cjs');
|
|
4
|
+
var viem = require('viem');
|
|
5
|
+
|
|
6
|
+
// src/documents/constants.ts
|
|
7
|
+
var DOCUMENT_ATTESTOR_DOMAIN_NAME = "DocumentAttestor";
|
|
8
|
+
var DOCUMENT_ATTESTOR_DOMAIN_VERSION = "1";
|
|
9
|
+
var DOCUMENT_ACCEPTANCE_TYPES = {
|
|
10
|
+
DocumentAcceptance: [
|
|
11
|
+
{ name: "nonce", type: "bytes32" },
|
|
12
|
+
{ name: "docHash", type: "bytes32" },
|
|
13
|
+
{ name: "deadline", type: "uint256" }
|
|
14
|
+
]
|
|
15
|
+
};
|
|
16
|
+
var DOCUMENT_ACCEPTANCE_PRIMARY_TYPE = "DocumentAcceptance";
|
|
17
|
+
var EIP712_DOMAIN_TYPE = [
|
|
18
|
+
{ name: "name", type: "string" },
|
|
19
|
+
{ name: "version", type: "string" },
|
|
20
|
+
{ name: "chainId", type: "uint256" },
|
|
21
|
+
{ name: "verifyingContract", type: "address" }
|
|
22
|
+
];
|
|
23
|
+
var DOCUMENT_ACCEPTANCE_TYPEHASH = "0xcd87f8252156623d78fd52f8f4f1c63bcda5d0b21a8c7f56f63a1759103d6598";
|
|
24
|
+
var MAX_ATTESTATION_LIFETIME_SECONDS = 2592000n;
|
|
25
|
+
var ECDSA_SIGNATURE_BYTES = 65;
|
|
26
|
+
|
|
27
|
+
// src/documents/validate.ts
|
|
28
|
+
var ZERO_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
29
|
+
function assertAddress(value, field) {
|
|
30
|
+
if (typeof value !== "string" || !viem.isAddress(value, { strict: false })) {
|
|
31
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError("MalformedInput", `\`${field}\` is not a valid address.`, {
|
|
32
|
+
field
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const normalized = viem.getAddress(value);
|
|
36
|
+
if (normalized === "0x0000000000000000000000000000000000000000") {
|
|
37
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError("ZeroAddress", `\`${field}\` must not be the zero address.`, {
|
|
38
|
+
field
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return normalized;
|
|
42
|
+
}
|
|
43
|
+
function assertBytes32(value, field) {
|
|
44
|
+
if (typeof value !== "string" || !viem.isHex(value) || value.length !== 2 + 64) {
|
|
45
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError(
|
|
46
|
+
"MalformedInput",
|
|
47
|
+
`\`${field}\` must be a 32-byte hex string (0x + 64 hex chars).`,
|
|
48
|
+
{ field }
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
function assertTraitId(value) {
|
|
54
|
+
const traitId = assertBytes32(value, "traitId");
|
|
55
|
+
if (traitId.toLowerCase() === ZERO_BYTES32) {
|
|
56
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError("InvalidTraitId", "`traitId` must not be zero.", {
|
|
57
|
+
field: "traitId"
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return traitId;
|
|
61
|
+
}
|
|
62
|
+
function assertBoolean(value, field) {
|
|
63
|
+
if (typeof value !== "boolean") {
|
|
64
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError("MalformedInput", `\`${field}\` must be a boolean.`, {
|
|
65
|
+
field
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
function assertDocHash(value) {
|
|
71
|
+
const docHash = assertBytes32(value, "docHash");
|
|
72
|
+
if (docHash.toLowerCase() === ZERO_BYTES32) {
|
|
73
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError("InvalidDocHash", "`docHash` must not be zero.", {
|
|
74
|
+
field: "docHash"
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return docHash;
|
|
78
|
+
}
|
|
79
|
+
function assertNonce(value) {
|
|
80
|
+
return assertBytes32(value, "nonce");
|
|
81
|
+
}
|
|
82
|
+
function assertTimestamp(value, field) {
|
|
83
|
+
if (typeof value !== "bigint") {
|
|
84
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError(
|
|
85
|
+
"MalformedInput",
|
|
86
|
+
`\`${field}\` must be a bigint of unix seconds.`,
|
|
87
|
+
{ field }
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
if (value < 0n) {
|
|
91
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError("MalformedInput", `\`${field}\` must not be negative.`, {
|
|
92
|
+
field
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
function assertServerSignature(value) {
|
|
98
|
+
if (typeof value !== "string" || !viem.isHex(value)) {
|
|
99
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError("MalformedInput", "`serverSignature` must be a hex string.", {
|
|
100
|
+
field: "serverSignature"
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (value.length !== 2 + ECDSA_SIGNATURE_BYTES * 2) {
|
|
104
|
+
const length = viem.size(value);
|
|
105
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError(
|
|
106
|
+
"InvalidSignatureLength",
|
|
107
|
+
`\`serverSignature\` must be ${ECDSA_SIGNATURE_BYTES} bytes; received ${length}. The document server signs with ECDSA, which accepts no other length.`,
|
|
108
|
+
{ field: "serverSignature" }
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
function assertUserSignature(value) {
|
|
114
|
+
if (typeof value !== "string" || !viem.isHex(value) || value.length % 2 !== 0) {
|
|
115
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError(
|
|
116
|
+
"MalformedInput",
|
|
117
|
+
"`userSignature` must be a hex string of whole bytes.",
|
|
118
|
+
{ field: "userSignature" }
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return value;
|
|
122
|
+
}
|
|
123
|
+
function assertSessionWindow(session, options = {}) {
|
|
124
|
+
const { deadline } = session;
|
|
125
|
+
assertTimestamp(deadline, "deadline");
|
|
126
|
+
if (session.issuedAt !== void 0) {
|
|
127
|
+
const issuedAt = assertTimestamp(session.issuedAt, "issuedAt");
|
|
128
|
+
const maxAllowed = issuedAt + MAX_ATTESTATION_LIFETIME_SECONDS;
|
|
129
|
+
if (deadline > maxAllowed) {
|
|
130
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError(
|
|
131
|
+
"AttestationDeadlineTooFar",
|
|
132
|
+
`\`deadline\` (${deadline}) exceeds \`issuedAt\` + MAX_ATTESTATION_LIFETIME (${maxAllowed}).`,
|
|
133
|
+
{ field: "deadline" }
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const { now } = options;
|
|
138
|
+
if (now === void 0) return;
|
|
139
|
+
assertTimestamp(now, "now");
|
|
140
|
+
if (session.issuedAt !== void 0 && session.issuedAt > now) {
|
|
141
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError(
|
|
142
|
+
"AttestationIssuedInFuture",
|
|
143
|
+
`\`issuedAt\` (${session.issuedAt}) is in the future relative to \`now\` (${now}). A post-dated session is rejected permanently, not held until it matures.`,
|
|
144
|
+
{ field: "issuedAt" }
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
if (now > deadline) {
|
|
148
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError(
|
|
149
|
+
"AttestationExpired",
|
|
150
|
+
`The session expired at ${deadline}, before \`now\` (${now}).`,
|
|
151
|
+
{ field: "deadline" }
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function assertChainId(value) {
|
|
156
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
157
|
+
throw new chunkHJQZWNZJ_cjs.OpacityAttestationError("MalformedInput", "`chainId` must be a positive integer.", {
|
|
158
|
+
field: "chainId"
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return value;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
exports.DOCUMENT_ACCEPTANCE_PRIMARY_TYPE = DOCUMENT_ACCEPTANCE_PRIMARY_TYPE;
|
|
165
|
+
exports.DOCUMENT_ACCEPTANCE_TYPEHASH = DOCUMENT_ACCEPTANCE_TYPEHASH;
|
|
166
|
+
exports.DOCUMENT_ACCEPTANCE_TYPES = DOCUMENT_ACCEPTANCE_TYPES;
|
|
167
|
+
exports.DOCUMENT_ATTESTOR_DOMAIN_NAME = DOCUMENT_ATTESTOR_DOMAIN_NAME;
|
|
168
|
+
exports.DOCUMENT_ATTESTOR_DOMAIN_VERSION = DOCUMENT_ATTESTOR_DOMAIN_VERSION;
|
|
169
|
+
exports.ECDSA_SIGNATURE_BYTES = ECDSA_SIGNATURE_BYTES;
|
|
170
|
+
exports.EIP712_DOMAIN_TYPE = EIP712_DOMAIN_TYPE;
|
|
171
|
+
exports.MAX_ATTESTATION_LIFETIME_SECONDS = MAX_ATTESTATION_LIFETIME_SECONDS;
|
|
172
|
+
exports.assertAddress = assertAddress;
|
|
173
|
+
exports.assertBoolean = assertBoolean;
|
|
174
|
+
exports.assertBytes32 = assertBytes32;
|
|
175
|
+
exports.assertChainId = assertChainId;
|
|
176
|
+
exports.assertDocHash = assertDocHash;
|
|
177
|
+
exports.assertNonce = assertNonce;
|
|
178
|
+
exports.assertServerSignature = assertServerSignature;
|
|
179
|
+
exports.assertSessionWindow = assertSessionWindow;
|
|
180
|
+
exports.assertTimestamp = assertTimestamp;
|
|
181
|
+
exports.assertTraitId = assertTraitId;
|
|
182
|
+
exports.assertUserSignature = assertUserSignature;
|
|
183
|
+
//# sourceMappingURL=chunk-3L7NNVUV.cjs.map
|
|
184
|
+
//# sourceMappingURL=chunk-3L7NNVUV.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/documents/constants.ts","../src/documents/validate.ts"],"names":["isAddress","OpacityAttestationError","getAddress","isHex","size"],"mappings":"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","file":"chunk-3L7NNVUV.cjs","sourcesContent":["import type { Hex } from 'viem';\n\n/**\n * EIP-712 domain `name` and `version`, from `EIP712(\"DocumentAttestor\", \"1\")` in\n * `DocumentAttestor.sol`. The domain has no `salt` — OpenZeppelin's `EIP712` uses\n * `EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)`.\n */\nexport const DOCUMENT_ATTESTOR_DOMAIN_NAME = 'DocumentAttestor';\nexport const DOCUMENT_ATTESTOR_DOMAIN_VERSION = '1';\n\n/**\n * The payload the investor's wallet signs.\n *\n * It deliberately binds neither `wallet` nor `traitId`: the trait is an internal mapping and the\n * prompt should show only what the human is agreeing to, while the binding to a wallet comes from\n * ECDSA recovery (or, for ERC-1271, from the server's own signature). Cross-deployment and\n * cross-chain replay are stopped by the domain's `chainId` + `verifyingContract`.\n *\n * Field order is consensus-critical — it is part of the type hash.\n */\nexport const DOCUMENT_ACCEPTANCE_TYPES = {\n DocumentAcceptance: [\n { name: 'nonce', type: 'bytes32' },\n { name: 'docHash', type: 'bytes32' },\n { name: 'deadline', type: 'uint256' },\n ],\n} as const;\n\nexport const DOCUMENT_ACCEPTANCE_PRIMARY_TYPE = 'DocumentAcceptance';\n\n/**\n * The EIP-712 domain type, needed only by `toEip712JsonPayload`: raw `eth_signTypedData_v4`\n * requires `EIP712Domain` to be present in `types`, whereas viem derives it and ethers v6 throws\n * if you supply it.\n */\nexport const EIP712_DOMAIN_TYPE = [\n { name: 'name', type: 'string' },\n { name: 'version', type: 'string' },\n { name: 'chainId', type: 'uint256' },\n { name: 'verifyingContract', type: 'address' },\n] as const;\n\n/**\n * `keccak256(\"DocumentAcceptance(bytes32 nonce,bytes32 docHash,uint256 deadline)\")`.\n *\n * Not used to build the payload (viem derives it from {@link DOCUMENT_ACCEPTANCE_TYPES}); exported\n * so a consumer can assert it against the contract's `DOCUMENT_ACCEPTANCE_TYPEHASH()` getter.\n */\nexport const DOCUMENT_ACCEPTANCE_TYPEHASH: Hex =\n '0xcd87f8252156623d78fd52f8f4f1c63bcda5d0b21a8c7f56f63a1759103d6598';\n\n/**\n * Mirrors `DocumentAttestor.MAX_ATTESTATION_LIFETIME` (30 days).\n *\n * Duplicated off-chain so `deadline > issuedAt + MAX_ATTESTATION_LIFETIME` can be caught before the\n * investor is prompted, rather than at redemption. It is a `constant` on a non-upgradeable contract,\n * so it cannot drift for a given deployment — but a successor deployment could choose a different\n * value, which is why `MAX_ATTESTATION_LIFETIME` is kept in `documentAttestorAbi` for\n * consumers that want to read it back.\n */\nexport const MAX_ATTESTATION_LIFETIME_SECONDS = 2_592_000n;\n\n/** Length in bytes of the ECDSA signature `ECDSA.recover` accepts — it rejects every other length. */\nexport const ECDSA_SIGNATURE_BYTES = 65;\n","import { getAddress, isAddress, isHex, size } from 'viem';\nimport type { Address, Hex } from 'viem';\n\nimport { OpacityAttestationError } from '../errors.js';\nimport { ECDSA_SIGNATURE_BYTES, MAX_ATTESTATION_LIFETIME_SECONDS } from './constants.js';\nimport type { ClockOptions } from './types.js';\n\nconst ZERO_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000';\n\n/**\n * Normalises an address and rejects the zero address.\n *\n * Returns the checksummed form: `attestDocument` takes `wallet` as a plain `address`, so casing\n * does not affect the calldata, but returning the canonical form keeps the descriptor comparable.\n */\nexport function assertAddress(value: Address, field: string): Address {\n if (typeof value !== 'string' || !isAddress(value, { strict: false })) {\n throw new OpacityAttestationError('MalformedInput', `\\`${field}\\` is not a valid address.`, {\n field,\n });\n }\n const normalized = getAddress(value);\n if (normalized === '0x0000000000000000000000000000000000000000') {\n throw new OpacityAttestationError('ZeroAddress', `\\`${field}\\` must not be the zero address.`, {\n field,\n });\n }\n return normalized;\n}\n\n/**\n * Rejects anything that is not 32 bytes of hex. Zero-ness is checked separately, per field.\n *\n * Length is checked on the string, not via `size()`, which rounds a half-byte up — `0x` followed\n * by 63 hex chars has a `size()` of 32 but is not a valid `bytes32`.\n */\nexport function assertBytes32(value: Hex, field: string): Hex {\n if (typeof value !== 'string' || !isHex(value) || value.length !== 2 + 64) {\n throw new OpacityAttestationError(\n 'MalformedInput',\n `\\`${field}\\` must be a 32-byte hex string (0x + 64 hex chars).`,\n { field },\n );\n }\n return value;\n}\n\n/**\n * `traitId` must be non-zero — `InvalidTraitId`.\n *\n * A zero trait id is almost always an un-set config value rather than a real trait.\n */\nexport function assertTraitId(value: Hex): Hex {\n const traitId = assertBytes32(value, 'traitId');\n if (traitId.toLowerCase() === ZERO_BYTES32) {\n throw new OpacityAttestationError('InvalidTraitId', '`traitId` must not be zero.', {\n field: 'traitId',\n });\n }\n return traitId;\n}\n\n/** Strict runtime boolean validation for callers that bypass TypeScript declarations. */\nexport function assertBoolean(value: boolean, field: string): boolean {\n if (typeof value !== 'boolean') {\n throw new OpacityAttestationError('MalformedInput', `\\`${field}\\` must be a boolean.`, {\n field,\n });\n }\n return value;\n}\n\n/**\n * `docHash` must be non-zero — `InvalidDocHash`.\n *\n * No executed document hashes to zero, so a zero here is a server-side bug and must not be attested.\n */\nexport function assertDocHash(value: Hex): Hex {\n const docHash = assertBytes32(value, 'docHash');\n if (docHash.toLowerCase() === ZERO_BYTES32) {\n throw new OpacityAttestationError('InvalidDocHash', '`docHash` must not be zero.', {\n field: 'docHash',\n });\n }\n return docHash;\n}\n\n/**\n * `nonce` must be well-formed, but may be zero.\n *\n * The contract applies no zero-check to the nonce — slot zero is burnable like any other — so\n * rejecting it here would be stricter than the chain.\n */\nexport function assertNonce(value: Hex): Hex {\n return assertBytes32(value, 'nonce');\n}\n\n/** Rejects negative or non-`bigint` unix timestamps before they are encoded as `uint256`. */\nexport function assertTimestamp(value: bigint, field: string): bigint {\n if (typeof value !== 'bigint') {\n throw new OpacityAttestationError(\n 'MalformedInput',\n `\\`${field}\\` must be a bigint of unix seconds.`,\n { field },\n );\n }\n if (value < 0n) {\n throw new OpacityAttestationError('MalformedInput', `\\`${field}\\` must not be negative.`, {\n field,\n });\n }\n return value;\n}\n\n/**\n * The 65-byte rule for the SERVER signature only.\n *\n * `ECDSA.recover` accepts exactly one length and reverts `ECDSAInvalidSignatureLength` on any\n * other. The investor signature must NOT be length-checked: `SignatureChecker` routes a\n * code-bearing wallet (a Safe, or an EIP-7702-delegated EOA) to ERC-1271, where the signature is\n * whatever that wallet's own validation logic accepts.\n */\nexport function assertServerSignature(value: Hex): Hex {\n if (typeof value !== 'string' || !isHex(value)) {\n throw new OpacityAttestationError('MalformedInput', '`serverSignature` must be a hex string.', {\n field: 'serverSignature',\n });\n }\n if (value.length !== 2 + ECDSA_SIGNATURE_BYTES * 2) {\n const length = size(value);\n throw new OpacityAttestationError(\n 'InvalidSignatureLength',\n `\\`serverSignature\\` must be ${ECDSA_SIGNATURE_BYTES} bytes; received ${length}. ` +\n 'The document server signs with ECDSA, which accepts no other length.',\n { field: 'serverSignature' },\n );\n }\n return value;\n}\n\n/**\n * The investor signature: hex, any BYTE length — an ERC-1271 wallet is not 65 bytes.\n *\n * Only the half-byte case is rejected, since it cannot encode as `bytes`.\n */\nexport function assertUserSignature(value: Hex): Hex {\n if (typeof value !== 'string' || !isHex(value) || value.length % 2 !== 0) {\n throw new OpacityAttestationError(\n 'MalformedInput',\n '`userSignature` must be a hex string of whole bytes.',\n { field: 'userSignature' },\n );\n }\n return value;\n}\n\n/**\n * The session-lifetime rules, split by whether they need a clock.\n *\n * `deadline <= issuedAt + MAX_ATTESTATION_LIFETIME` is absolute and always checked. The two\n * clock-relative rules run only when `now` is supplied — see {@link ClockOptions} for why that is\n * opt-in.\n */\nexport function assertSessionWindow(\n session: { issuedAt?: bigint | undefined; deadline: bigint },\n options: ClockOptions = {},\n): void {\n const { deadline } = session;\n assertTimestamp(deadline, 'deadline');\n\n if (session.issuedAt !== undefined) {\n const issuedAt = assertTimestamp(session.issuedAt, 'issuedAt');\n const maxAllowed = issuedAt + MAX_ATTESTATION_LIFETIME_SECONDS;\n if (deadline > maxAllowed) {\n throw new OpacityAttestationError(\n 'AttestationDeadlineTooFar',\n `\\`deadline\\` (${deadline}) exceeds \\`issuedAt\\` + MAX_ATTESTATION_LIFETIME (${maxAllowed}).`,\n { field: 'deadline' },\n );\n }\n }\n\n const { now } = options;\n if (now === undefined) return;\n assertTimestamp(now, 'now');\n\n if (session.issuedAt !== undefined && session.issuedAt > now) {\n throw new OpacityAttestationError(\n 'AttestationIssuedInFuture',\n `\\`issuedAt\\` (${session.issuedAt}) is in the future relative to \\`now\\` (${now}). ` +\n 'A post-dated session is rejected permanently, not held until it matures.',\n { field: 'issuedAt' },\n );\n }\n\n if (now > deadline) {\n throw new OpacityAttestationError(\n 'AttestationExpired',\n `The session expired at ${deadline}, before \\`now\\` (${now}).`,\n { field: 'deadline' },\n );\n }\n}\n\n/** Rejects a non-integer / out-of-range chain id before it lands in a signed domain. */\nexport function assertChainId(value: number): number {\n if (!Number.isInteger(value) || value <= 0) {\n throw new OpacityAttestationError('MalformedInput', '`chainId` must be a positive integer.', {\n field: 'chainId',\n });\n }\n return value;\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var OpacityIssuerError = class extends Error {
|
|
3
|
+
constructor(message, options) {
|
|
4
|
+
super(message, options);
|
|
5
|
+
this.name = "OpacityIssuerError";
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
var OpacityConfigError = class extends OpacityIssuerError {
|
|
9
|
+
constructor(message, options) {
|
|
10
|
+
super(message, options);
|
|
11
|
+
this.name = "OpacityConfigError";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var OpacityAttestationError = class extends OpacityIssuerError {
|
|
15
|
+
/** Which check failed. Mirrors a contract error name where one exists. */
|
|
16
|
+
code;
|
|
17
|
+
/** The offending parameter, when the failure is attributable to a single one. */
|
|
18
|
+
field;
|
|
19
|
+
constructor(code, message, options) {
|
|
20
|
+
super(message, options?.cause === void 0 ? void 0 : { cause: options.cause });
|
|
21
|
+
this.name = "OpacityAttestationError";
|
|
22
|
+
this.code = code;
|
|
23
|
+
this.field = options?.field;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export { OpacityAttestationError, OpacityConfigError, OpacityIssuerError };
|
|
28
|
+
//# sourceMappingURL=chunk-54Q3MU62.js.map
|
|
29
|
+
//# sourceMappingURL=chunk-54Q3MU62.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts"],"names":[],"mappings":";AAmBO,IAAM,kBAAA,GAAN,cAAiC,KAAA,CAAM;AAAA,EAC5C,WAAA,CAAY,SAAiB,OAAA,EAA+B;AAC1D,IAAA,KAAA,CAAM,SAAS,OAAO,CAAA;AACtB,IAAA,IAAA,CAAK,IAAA,GAAO,oBAAA;AAAA,EACd;AACF;AAGO,IAAM,kBAAA,GAAN,cAAiC,kBAAA,CAAmB;AAAA,EACzD,WAAA,CAAY,SAAiB,OAAA,EAA+B;AAC1D,IAAA,KAAA,CAAM,SAAS,OAAO,CAAA;AACtB,IAAA,IAAA,CAAK,IAAA,GAAO,oBAAA;AAAA,EACd;AACF;AASO,IAAM,uBAAA,GAAN,cAAsC,kBAAA,CAAmB;AAAA;AAAA,EAErD,IAAA;AAAA;AAAA,EAEA,KAAA;AAAA,EAET,WAAA,CACE,IAAA,EACA,OAAA,EACA,OAAA,EACA;AACA,IAAA,KAAA,CAAM,OAAA,EAAS,SAAS,KAAA,KAAU,MAAA,GAAY,SAAY,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,CAAA;AAClF,IAAA,IAAA,CAAK,IAAA,GAAO,yBAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,QAAQ,OAAA,EAAS,KAAA;AAAA,EACxB;AACF","file":"chunk-54Q3MU62.js","sourcesContent":["import type { AttestationErrorCode } from './documents/types.js';\n\n// `OpacityDiscoveryError` is deliberately NOT re-exported from here, even though it belongs to\n// this hierarchy and is exported from the package root (via `documents/index.ts`).\n//\n// A value re-export — `export { OpacityDiscoveryError } from './documents/discovery.js'` — is a\n// RUNTIME edge, and `discovery.ts` already imports this module for `OpacityIssuerError`. The cycle\n// is fatal, not benign: `config.ts` imports `errors.js` first, so `errors.js` starts evaluating,\n// the re-export pulls in `discovery.js`, and `class OpacityDiscoveryError extends\n// OpacityIssuerError` runs while `OpacityIssuerError` is still in its temporal dead zone —\n// `TypeError: Class extends value undefined`. Verified, not theorised.\n//\n// The type-only imports above are safe for the opposite reason: `verbatimModuleSyntax` erases\n// them, so they create no runtime edge at all.\n\n/**\n * Base class for every error thrown by this SDK, so consumers can do a single\n * `instanceof OpacityIssuerError` check at their integration boundary.\n */\nexport class OpacityIssuerError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'OpacityIssuerError';\n }\n}\n\n/** Thrown when `createOpacityIssuerClient` is called with invalid configuration. */\nexport class OpacityConfigError extends OpacityIssuerError {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'OpacityConfigError';\n }\n}\n\n/**\n * Thrown by the document-attestation builders when a parameter would produce a transaction the\n * `DocumentAttestor` is guaranteed to reject, or is too malformed to encode.\n *\n * Branch on {@link code}, not on the message: each value names the on-chain error it stands in for,\n * so a pre-flight rejection is legible in the same terms as the revert it saved.\n */\nexport class OpacityAttestationError extends OpacityIssuerError {\n /** Which check failed. Mirrors a contract error name where one exists. */\n readonly code: AttestationErrorCode;\n /** The offending parameter, when the failure is attributable to a single one. */\n readonly field: string | undefined;\n\n constructor(\n code: AttestationErrorCode,\n message: string,\n options?: { field?: string; cause?: unknown },\n ) {\n super(message, options?.cause === undefined ? undefined : { cause: options.cause });\n this.name = 'OpacityAttestationError';\n this.code = code;\n this.field = options?.field;\n }\n}\n"]}
|