@bsv/dpp-core 0.3.0-beta.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 +58 -0
- package/README.md +95 -0
- package/dist/acceptance.d.ts +100 -0
- package/dist/acceptance.d.ts.map +1 -0
- package/dist/acceptance.js +202 -0
- package/dist/acceptance.js.map +1 -0
- package/dist/anchor.d.ts +66 -0
- package/dist/anchor.d.ts.map +1 -0
- package/dist/anchor.js +145 -0
- package/dist/anchor.js.map +1 -0
- package/dist/attestation.d.ts +40 -0
- package/dist/attestation.d.ts.map +1 -0
- package/dist/attestation.js +111 -0
- package/dist/attestation.js.map +1 -0
- package/dist/blob.d.ts +11 -0
- package/dist/blob.d.ts.map +1 -0
- package/dist/blob.js +16 -0
- package/dist/blob.js.map +1 -0
- package/dist/canonical.d.ts +32 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +54 -0
- package/dist/canonical.js.map +1 -0
- package/dist/canonicalJson.d.ts +22 -0
- package/dist/canonicalJson.d.ts.map +1 -0
- package/dist/canonicalJson.js +60 -0
- package/dist/canonicalJson.js.map +1 -0
- package/dist/codec.d.ts +45 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +459 -0
- package/dist/codec.js.map +1 -0
- package/dist/constants.d.ts +150 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +179 -0
- package/dist/constants.js.map +1 -0
- package/dist/did.d.ts +37 -0
- package/dist/did.d.ts.map +1 -0
- package/dist/did.js +129 -0
- package/dist/did.js.map +1 -0
- package/dist/evidence.d.ts +224 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +716 -0
- package/dist/evidence.js.map +1 -0
- package/dist/evidencePackage.d.ts +114 -0
- package/dist/evidencePackage.d.ts.map +1 -0
- package/dist/evidencePackage.js +164 -0
- package/dist/evidencePackage.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/owner.d.ts +135 -0
- package/dist/owner.d.ts.map +1 -0
- package/dist/owner.js +181 -0
- package/dist/owner.js.map +1 -0
- package/dist/publisherPolicy.d.ts +70 -0
- package/dist/publisherPolicy.d.ts.map +1 -0
- package/dist/publisherPolicy.js +186 -0
- package/dist/publisherPolicy.js.map +1 -0
- package/dist/signatures.d.ts +84 -0
- package/dist/signatures.d.ts.map +1 -0
- package/dist/signatures.js +137 -0
- package/dist/signatures.js.map +1 -0
- package/dist/transition.d.ts +29 -0
- package/dist/transition.d.ts.map +1 -0
- package/dist/transition.js +117 -0
- package/dist/transition.js.map +1 -0
- package/dist/types.d.ts +135 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/verifyChain.d.ts +152 -0
- package/dist/verifyChain.d.ts.map +1 -0
- package/dist/verifyChain.js +314 -0
- package/dist/verifyChain.js.map +1 -0
- package/package.json +46 -0
- package/schemas/capabilities.schema.json +129 -0
- package/schemas/epcis-import.schema.json +212 -0
- package/schemas/evidence-export.schema.json +67 -0
- package/schemas/evidence-package.schema.json +307 -0
- package/schemas/native-evidence-extension.schema.json +66 -0
- package/schemas/paginated-history.schema.json +32 -0
- package/schemas/passport-projection.schema.json +151 -0
- package/schemas/passport-source.schema.json +370 -0
- package/schemas/profile-evidence.schema.json +706 -0
- package/schemas/publisher-policy.schema.json +173 -0
- package/schemas/verification-report.schema.json +397 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Open BSV License Version 6 – granted by BSV Association, Alpenstrasse 15, 6300
|
|
2
|
+
Zug, Switzerland (CHE-427.008.338) ("Licensor"), to you as a user (henceforth
|
|
3
|
+
"You", "User" or "Licensee").
|
|
4
|
+
|
|
5
|
+
For the purposes of this license, the definitions below have the following
|
|
6
|
+
meanings:
|
|
7
|
+
|
|
8
|
+
"Bitcoin Protocol" means the protocol implementation, cryptographic rules,
|
|
9
|
+
network protocols, and consensus mechanisms in the Bitcoin White Paper as
|
|
10
|
+
described here https://protocol.bsvblockchain.org.
|
|
11
|
+
|
|
12
|
+
"Bitcoin White Paper" means the paper entitled 'Bitcoin: A Peer-to-Peer
|
|
13
|
+
Electronic Cash System' published by 'Satoshi Nakamoto' in October 2008.
|
|
14
|
+
|
|
15
|
+
"BSV Blockchain" means:
|
|
16
|
+
|
|
17
|
+
(a) the Bitcoin blockchain containing block height #556767 with the hash
|
|
18
|
+
"000000000000000001d956714215d96ffc00e0afda4cd0a96c96f8d802b1662b" and
|
|
19
|
+
that contains the longest honest persistent chain of blocks which has been
|
|
20
|
+
produced in a manner which is consistent with the rules set forth in the
|
|
21
|
+
Network Access Rules; and
|
|
22
|
+
(b) the test blockchains that contain the longest honest persistent chains of
|
|
23
|
+
blocks which has been produced in a manner which is consistent with the
|
|
24
|
+
rules set forth in the Network Access Rules.
|
|
25
|
+
|
|
26
|
+
"Network Access Rules" or "Rules" means the set of rules regulating the
|
|
27
|
+
relationship between BSV Association and the nodes on BSV based on the Bitcoin
|
|
28
|
+
Protocol rules and those set out in the Bitcoin White Paper, and available here
|
|
29
|
+
https://bsvblockchain.org/network-access-rules.
|
|
30
|
+
|
|
31
|
+
"Software" means the software the subject of this license, including any/all
|
|
32
|
+
intellectual property rights therein and associated documentation files.
|
|
33
|
+
|
|
34
|
+
BSV Association grants permission, free of charge and on a non-exclusive basis
|
|
35
|
+
to any person obtaining a copy of the Software to deal in the Software, including
|
|
36
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute,
|
|
37
|
+
sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
|
38
|
+
Software is furnished to do so, subject to and conditioned upon the following
|
|
39
|
+
conditions:
|
|
40
|
+
|
|
41
|
+
1 - The text "© BSV Association", and this license shall be included in all
|
|
42
|
+
copies or substantial portions of the Software.
|
|
43
|
+
|
|
44
|
+
2 - The Software, and any software that is derived from the Software or parts
|
|
45
|
+
thereof, may only be used exclusively on the BSV Blockchain.
|
|
46
|
+
|
|
47
|
+
For the avoidance of doubt, this license is granted subject to and conditioned
|
|
48
|
+
upon your compliance with these terms only and is limited to uses on the BSV
|
|
49
|
+
Blockchain. Any exercise of rights not compliant with these terms including
|
|
50
|
+
use not for the BSV Blockchain is deemed outside the scope of the license.
|
|
51
|
+
|
|
52
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
53
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES REGARDING ENTITLEMENT,
|
|
54
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
55
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS THEREOF BE LIABLE FOR ANY CLAIM,
|
|
56
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
57
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
58
|
+
DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# @bsv/dpp-core
|
|
2
|
+
|
|
3
|
+
**Experimental prerelease:** For implementation and interoperability testing. APIs may change significantly before a stable release. Pin exact package versions and retain your lockfile. This package is not declared production-ready. Package versions are separate from the specification, wire-format and frozen profile versions they implement.
|
|
4
|
+
|
|
5
|
+
The DPP standard's reference implementation for record versions 1 and 2, the
|
|
6
|
+
attestation rail and the verification report, and the only place in this
|
|
7
|
+
repository the standard's rules are implemented. Everything else in the
|
|
8
|
+
reference implementation imports it: the overlay topic manager admits outputs
|
|
9
|
+
by asking this package whether a state is valid, and the consuming
|
|
10
|
+
applications build and verify every record through it. An independent
|
|
11
|
+
implementation does not import it; it reproduces the same rules from `spec/`
|
|
12
|
+
and holds itself to the same `fixtures/`.
|
|
13
|
+
|
|
14
|
+
Standard v1 is v0 plus the JSON field conventions (`spec/record-model.md` §3,
|
|
15
|
+
fields 9 and 10). The 14-field layout and the
|
|
16
|
+
chain invariants are untouched from v0, which is why the suite here was ported
|
|
17
|
+
rather than rewritten.
|
|
18
|
+
|
|
19
|
+
## Install and consume
|
|
20
|
+
|
|
21
|
+
This is a pre-1.0 candidate. Once the release is published, install exact versions from npm:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm install --save-exact @bsv/dpp-core@0.3.0-beta.1 @bsv/sdk@2.4.2
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Node >=22 and ECMAScript modules are supported. Browser use of the runtime is untested. No source checkout or build of this package is needed after installation.
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
import { PrivateKey, ProtoWallet } from '@bsv/sdk'
|
|
31
|
+
import { didKeyFromIdentityKey, signLifecycleClaim, verifyLifecycleClaim } from '@bsv/dpp-core'
|
|
32
|
+
|
|
33
|
+
const key = PrivateKey.fromRandom()
|
|
34
|
+
const claim = await signLifecycleClaim({
|
|
35
|
+
claimFormat: 'dpp-lifecycle-v1',
|
|
36
|
+
passportId: 'https://example.com/01/09521000000018/21/EXAMPLE',
|
|
37
|
+
recordId: '0'.repeat(64), // Synthetic record identifier for this offline example.
|
|
38
|
+
eventType: 'Origin',
|
|
39
|
+
timestamp: new Date().toISOString(),
|
|
40
|
+
issuer: didKeyFromIdentityKey(key.toPublicKey().toString()),
|
|
41
|
+
issuerKeyId: 'example',
|
|
42
|
+
profile: 'general',
|
|
43
|
+
profile_version: 2,
|
|
44
|
+
}, new ProtoWallet(key))
|
|
45
|
+
console.log(verifyLifecycleClaim(claim))
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This offline example creates a temporary key and signs a claim. Production callers supply their authorised signing capability. Signature verification alone does not establish authority, current status or blockchain inclusion.
|
|
49
|
+
|
|
50
|
+
The `@bsv/dpp-core/schemas/*` export carries the standard's JSON schemas. For example, load `@bsv/dpp-core/schemas/verification-report.schema.json` using a JSON import or Node's `createRequire`. The evidence export schema and its referenced evidence package schema are shipped together. They are data files and may also be used by other runtimes.
|
|
51
|
+
|
|
52
|
+
## Public API
|
|
53
|
+
|
|
54
|
+
`src/index.ts` re-exports the whole surface, so `@bsv/dpp-core` is the only
|
|
55
|
+
specifier anything needs:
|
|
56
|
+
|
|
57
|
+
| Module | What it owns |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `codec.ts` | The 14-field version 1 layout and the 17-field version 2 layout, selected by field count: encode and decode per `spec/record-model.md` §3 and `spec/record-model-v2.md` §3 |
|
|
60
|
+
| `signatures.ts` | The canonical signature preimages: unframed for version 1 (§5), framed and domain-tagged for version 2 (`record-model-v2.md` §5) |
|
|
61
|
+
| `transition.ts` | Which operation may change what, state by state, for both versions: the version 2 control proof, the terminal `RETIRE` and the single upgrade transition |
|
|
62
|
+
| `owner.ts` | The owner and controller key, the linkage scalar, the owner-signed transfer of version 1 and the control proof of version 2 |
|
|
63
|
+
| `acceptance.ts` | The managed acceptance record `dpp-managed-acceptance@1` (`spec/managed-custody.md` §3): inspect, sign, commit and bind to the `TRANSFER` |
|
|
64
|
+
| `verifyChain.ts` | Chain verification from genesis, including SPV inclusion; `inspectChain` is the same loop reported finding by finding |
|
|
65
|
+
| `evidence.ts` | `verifyPassportEvidence`, the one verification contract of `spec/verification.md`: sixteen named checks, four answers each, an expected subject and a latest-state observation, across the token, attestation, anchor and credential rails |
|
|
66
|
+
| `anchor.ts` | The generic complete-representation anchor `bsv-attestation-anchor-v1` (`spec/rules.md` §5): build, strict decode and check-by-check inspection |
|
|
67
|
+
| `attestation.ts` | Native lifecycle claims `dpp-lifecycle-v1` (`spec/rules.md` §3): validate, sign, verify and digest |
|
|
68
|
+
| `blob.ts` | Owner-tier blob hash binding (§7) |
|
|
69
|
+
| `canonical.ts` | The canonical bytes an attestation is signed and hashed over: a refusing subset of JCS (`spec/rules.md` §4) |
|
|
70
|
+
| `constants.ts`, `types.ts` | The shared vocabulary both of the above are written against |
|
|
71
|
+
|
|
72
|
+
## Working on it
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
npm run build # tsc to dist/, which is what the exports map points at
|
|
76
|
+
npm run typecheck # the same compile, emitting nothing
|
|
77
|
+
npm test # the whole suite runs offline
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The build matters. `main`, `types` and the `exports` map all point into
|
|
81
|
+
`dist/`, and nothing aliases the specifier back to `src/`, so a consumer that
|
|
82
|
+
has not built this package fails to resolve it rather than falling back to
|
|
83
|
+
source. A fresh clone should run `npm run build --workspaces` before anything
|
|
84
|
+
that imports `@bsv/dpp-core`.
|
|
85
|
+
|
|
86
|
+
## The rule that governs it
|
|
87
|
+
|
|
88
|
+
Within the reference implementation this package is the single place the
|
|
89
|
+
standard's rules are coded, and no reference consumer reimplements any of it:
|
|
90
|
+
if a consumer needs behaviour that is not here, the change belongs here, with a
|
|
91
|
+
test. The normative text is the specification, not this package: `spec/`
|
|
92
|
+
defines the rules, `fixtures/` pins the bytes, and an independent
|
|
93
|
+
implementation reproduces both without this code. Where this package and the
|
|
94
|
+
specification disagree before version 1.0, `GOVERNANCE.md` names the
|
|
95
|
+
tiebreaker.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { MANAGED_CUSTODY_PROFILE } from './constants.js';
|
|
2
|
+
import type { DppStateV2, Outpoint } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The managed acceptance record (`spec/managed-custody.md` §3): the evidence a
|
|
5
|
+
* custodian retains that the current holder offered a transfer and the
|
|
6
|
+
* intended recipient accepted it through the application, before the
|
|
7
|
+
* custodian spent the tip. A version 2 TRANSFER under the profile carries
|
|
8
|
+
* `authorisation_commitment` equal to the SHA-256 of this record's canonical
|
|
9
|
+
* JSON, signature included, so the on-chain state binds the acceptance and the
|
|
10
|
+
* record binds the exact predecessor, destination key, terms and expiry.
|
|
11
|
+
*
|
|
12
|
+
* What it is: custody-dependent evidence. The custodian signs it; the
|
|
13
|
+
* recipient's key never does. A reader learns that the custodian observed an
|
|
14
|
+
* acceptance under these terms and that the transfer it executed matches them.
|
|
15
|
+
* It is not a signature made with a key the recipient controls, and the record
|
|
16
|
+
* says so in `acceptance.evidenceKind`. A profile that needs recipient-signed
|
|
17
|
+
* acceptance is a later profile with its own record format.
|
|
18
|
+
*
|
|
19
|
+
* What stays out: application account identifiers, claim codes, names and
|
|
20
|
+
* contact details. The recipient is named by the identity key the destination
|
|
21
|
+
* derives from, and a claim code by its SHA-256, so the record can be exported
|
|
22
|
+
* with the passport's public evidence.
|
|
23
|
+
*/
|
|
24
|
+
export declare const MANAGED_ACCEPTANCE_FORMAT: "dpp-managed-acceptance@1";
|
|
25
|
+
export { MANAGED_CUSTODY_PROFILE };
|
|
26
|
+
export type OfferMechanism = 'claim-code' | 'named-recipient';
|
|
27
|
+
export interface ManagedAcceptanceClaim {
|
|
28
|
+
acceptanceFormat: typeof MANAGED_ACCEPTANCE_FORMAT;
|
|
29
|
+
/** Unique per offer; a retry names the same request and never a second one. */
|
|
30
|
+
requestId: string;
|
|
31
|
+
passportId: string;
|
|
32
|
+
lineageGenesis: Outpoint;
|
|
33
|
+
/** The tip the offer was made against; the TRANSFER must spend exactly this. */
|
|
34
|
+
expectedPredecessor: Outpoint;
|
|
35
|
+
/** SHA-256, hex, of the terms as the application presented them to the recipient (the story word, a note, revised restricted values), in the application's own canonical form. */
|
|
36
|
+
termsDigest: string;
|
|
37
|
+
offer: {
|
|
38
|
+
/** The current holder's actor identity key, the key field 7 of the TRANSFER carries. */
|
|
39
|
+
holderIdentityKey: string;
|
|
40
|
+
createdAt: string;
|
|
41
|
+
expiresAt: string;
|
|
42
|
+
mechanism: OfferMechanism;
|
|
43
|
+
/** claim-code: SHA-256 of the code, hex; named-recipient: the recipient's identity key. Absent when the mechanism carries nothing to reference. */
|
|
44
|
+
recipientRef?: string;
|
|
45
|
+
};
|
|
46
|
+
acceptance: {
|
|
47
|
+
/** The recipient's actor identity key, from which the destination derives. */
|
|
48
|
+
recipientIdentityKey: string;
|
|
49
|
+
/** The controller key the TRANSFER moves control to: field 6 of the TRANSFER. */
|
|
50
|
+
destinationKey: string;
|
|
51
|
+
acceptedAt: string;
|
|
52
|
+
/** Always custodian-attested under this format; named so a reader never mistakes it for a recipient signature. */
|
|
53
|
+
evidenceKind: 'custodian-attested';
|
|
54
|
+
};
|
|
55
|
+
/** The custodian's identity key, compressed hex, which signs the record. */
|
|
56
|
+
custodian: string;
|
|
57
|
+
}
|
|
58
|
+
export interface ManagedAcceptanceRecord extends ManagedAcceptanceClaim {
|
|
59
|
+
/** DER ECDSA, lowercase hex, over SHA-256 of the canonical JSON of the record without this property. */
|
|
60
|
+
signature: string;
|
|
61
|
+
}
|
|
62
|
+
export interface AcceptanceSigner {
|
|
63
|
+
sign(preimage: number[]): Promise<number[]> | number[];
|
|
64
|
+
}
|
|
65
|
+
export type AcceptanceFailureReason = 'format' | 'time-order' | 'signature-invalid' | 'custodian-unexpected' | 'state-mismatch';
|
|
66
|
+
export interface AcceptanceFailure {
|
|
67
|
+
reason: AcceptanceFailureReason;
|
|
68
|
+
detail: string;
|
|
69
|
+
}
|
|
70
|
+
export interface AcceptanceInspection {
|
|
71
|
+
/** The record has the declared shape and its own declarations agree. */
|
|
72
|
+
structureValid: boolean;
|
|
73
|
+
/** The custodian's signature over the canonical record, or null when the record could not be canonicalised. */
|
|
74
|
+
signatureValid: boolean | null;
|
|
75
|
+
/** SHA-256 of the complete signed record in canonical JSON: what a TRANSFER commits to. Present when the record canonicalises. */
|
|
76
|
+
commitment?: string;
|
|
77
|
+
failures: AcceptanceFailure[];
|
|
78
|
+
}
|
|
79
|
+
/** The bytes the custodian signs: the record without `signature`, in canonical JSON, UTF-8. */
|
|
80
|
+
export declare function acceptanceSigningPreimage(claim: ManagedAcceptanceClaim | ManagedAcceptanceRecord): number[];
|
|
81
|
+
/** The commitment a TRANSFER carries in field 15: SHA-256 of the complete signed record, canonical JSON. */
|
|
82
|
+
export declare function acceptanceCommitment(record: ManagedAcceptanceRecord): string;
|
|
83
|
+
/**
|
|
84
|
+
* Inspect a record on its own: structure, the custodian's signature and, when
|
|
85
|
+
* the caller names the custodians it trusts, whether the signer is one of
|
|
86
|
+
* them. Binding to the TRANSFER that commits to it is `bindAcceptanceToState`.
|
|
87
|
+
*/
|
|
88
|
+
export declare function inspectManagedAcceptance(value: unknown, options?: {
|
|
89
|
+
custodians?: readonly string[];
|
|
90
|
+
}): AcceptanceInspection;
|
|
91
|
+
/**
|
|
92
|
+
* Whether a version 2 TRANSFER executed exactly the acceptance the record
|
|
93
|
+
* evidences: same passport and lineage, the tip the offer named, the
|
|
94
|
+
* destination the recipient accepted, the holder who offered as the actor,
|
|
95
|
+
* and the record's own commitment in field 15. Every mismatch is named.
|
|
96
|
+
*/
|
|
97
|
+
export declare function bindAcceptanceToState(record: ManagedAcceptanceRecord, state: DppStateV2): AcceptanceFailure[];
|
|
98
|
+
/** Sign a claim as the custodian. The signer's key must be `claim.custodian`; the result is checked before it is returned. */
|
|
99
|
+
export declare function signManagedAcceptance(claim: ManagedAcceptanceClaim, signer: AcceptanceSigner): Promise<ManagedAcceptanceRecord>;
|
|
100
|
+
//# sourceMappingURL=acceptance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acceptance.d.ts","sourceRoot":"","sources":["../src/acceptance.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAEtD;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,eAAO,MAAM,yBAAyB,EAAG,0BAAmC,CAAA;AAC5E,OAAO,EAAE,uBAAuB,EAAE,CAAA;AAElC,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,iBAAiB,CAAA;AAE7D,MAAM,WAAW,sBAAsB;IACrC,gBAAgB,EAAE,OAAO,yBAAyB,CAAA;IAClD,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,QAAQ,CAAA;IACxB,gFAAgF;IAChF,mBAAmB,EAAE,QAAQ,CAAA;IAC7B,kLAAkL;IAClL,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE;QACL,wFAAwF;QACxF,iBAAiB,EAAE,MAAM,CAAA;QACzB,SAAS,EAAE,MAAM,CAAA;QACjB,SAAS,EAAE,MAAM,CAAA;QACjB,SAAS,EAAE,cAAc,CAAA;QACzB,mJAAmJ;QACnJ,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,CAAA;IACD,UAAU,EAAE;QACV,8EAA8E;QAC9E,oBAAoB,EAAE,MAAM,CAAA;QAC5B,iFAAiF;QACjF,cAAc,EAAE,MAAM,CAAA;QACtB,UAAU,EAAE,MAAM,CAAA;QAClB,kHAAkH;QAClH,YAAY,EAAE,oBAAoB,CAAA;KACnC,CAAA;IACD,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,uBAAwB,SAAQ,sBAAsB;IACrE,wGAAwG;IACxG,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAA;CACvD;AAQD,MAAM,MAAM,uBAAuB,GAC/B,QAAQ,GACR,YAAY,GACZ,mBAAmB,GACnB,sBAAsB,GACtB,gBAAgB,CAAA;AAEpB,MAAM,WAAW,iBAAiB;IAAG,MAAM,EAAE,uBAAuB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAEtF,MAAM,WAAW,oBAAoB;IACnC,wEAAwE;IACxE,cAAc,EAAE,OAAO,CAAA;IACvB,+GAA+G;IAC/G,cAAc,EAAE,OAAO,GAAG,IAAI,CAAA;IAC9B,kIAAkI;IAClI,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,iBAAiB,EAAE,CAAA;CAC9B;AAUD,+FAA+F;AAC/F,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,sBAAsB,GAAG,uBAAuB,GAAG,MAAM,EAAE,CAG3G;AAED,4GAA4G;AAC5G,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,uBAAuB,GAAG,MAAM,CAE5E;AA6DD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAO,GAAG,oBAAoB,CAoB/H;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,uBAAuB,EAAE,KAAK,EAAE,UAAU,GAAG,iBAAiB,EAAE,CAY7G;AAED,8HAA8H;AAC9H,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,sBAAsB,EAAE,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAWrI"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { Hash, PublicKey, Signature, Utils } from '@bsv/sdk';
|
|
2
|
+
import { canonicalJson, CanonicalJsonError } from './canonicalJson.js';
|
|
3
|
+
import { MANAGED_CUSTODY_PROFILE } from './constants.js';
|
|
4
|
+
/**
|
|
5
|
+
* The managed acceptance record (`spec/managed-custody.md` §3): the evidence a
|
|
6
|
+
* custodian retains that the current holder offered a transfer and the
|
|
7
|
+
* intended recipient accepted it through the application, before the
|
|
8
|
+
* custodian spent the tip. A version 2 TRANSFER under the profile carries
|
|
9
|
+
* `authorisation_commitment` equal to the SHA-256 of this record's canonical
|
|
10
|
+
* JSON, signature included, so the on-chain state binds the acceptance and the
|
|
11
|
+
* record binds the exact predecessor, destination key, terms and expiry.
|
|
12
|
+
*
|
|
13
|
+
* What it is: custody-dependent evidence. The custodian signs it; the
|
|
14
|
+
* recipient's key never does. A reader learns that the custodian observed an
|
|
15
|
+
* acceptance under these terms and that the transfer it executed matches them.
|
|
16
|
+
* It is not a signature made with a key the recipient controls, and the record
|
|
17
|
+
* says so in `acceptance.evidenceKind`. A profile that needs recipient-signed
|
|
18
|
+
* acceptance is a later profile with its own record format.
|
|
19
|
+
*
|
|
20
|
+
* What stays out: application account identifiers, claim codes, names and
|
|
21
|
+
* contact details. The recipient is named by the identity key the destination
|
|
22
|
+
* derives from, and a claim code by its SHA-256, so the record can be exported
|
|
23
|
+
* with the passport's public evidence.
|
|
24
|
+
*/
|
|
25
|
+
export const MANAGED_ACCEPTANCE_FORMAT = 'dpp-managed-acceptance@1';
|
|
26
|
+
export { MANAGED_CUSTODY_PROFILE };
|
|
27
|
+
const KEY = /^0[23][0-9a-f]{64}$/;
|
|
28
|
+
const HEX64 = /^[0-9a-f]{64}$/;
|
|
29
|
+
const TIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
|
|
30
|
+
const CONTROL = /[\u0000-\u001f\u007f-\u009f]/u;
|
|
31
|
+
const MAX_REQUEST_ID = 128;
|
|
32
|
+
const text = (value, maximum) => typeof value === 'string' && value.length > 0 && Utils.toArray(value, 'utf8').length <= maximum && !CONTROL.test(value);
|
|
33
|
+
const outpointOk = (value) => typeof value === 'object' && value !== null && HEX64.test(value.txid ?? '') && Number.isInteger(value.outputIndex) && value.outputIndex >= 0;
|
|
34
|
+
const instant = (value) => Date.parse(value);
|
|
35
|
+
/** The bytes the custodian signs: the record without `signature`, in canonical JSON, UTF-8. */
|
|
36
|
+
export function acceptanceSigningPreimage(claim) {
|
|
37
|
+
const { signature: _signature, ...unsigned } = claim;
|
|
38
|
+
return Utils.toArray(canonicalJson(unsigned), 'utf8');
|
|
39
|
+
}
|
|
40
|
+
/** The commitment a TRANSFER carries in field 15: SHA-256 of the complete signed record, canonical JSON. */
|
|
41
|
+
export function acceptanceCommitment(record) {
|
|
42
|
+
return Utils.toHex(Hash.sha256(Utils.toArray(canonicalJson(record), 'utf8')));
|
|
43
|
+
}
|
|
44
|
+
function structure(value, failures) {
|
|
45
|
+
const fail = (reason, detail) => { failures.push({ reason, detail }); };
|
|
46
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
47
|
+
fail('format', 'the record must be an object');
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const r = value;
|
|
51
|
+
const allowed = new Set(['acceptanceFormat', 'requestId', 'passportId', 'lineageGenesis', 'expectedPredecessor', 'termsDigest', 'offer', 'acceptance', 'custodian', 'signature']);
|
|
52
|
+
for (const key of Object.keys(r))
|
|
53
|
+
if (!allowed.has(key))
|
|
54
|
+
fail('format', `unsupported property ${key}`);
|
|
55
|
+
if (r.acceptanceFormat !== MANAGED_ACCEPTANCE_FORMAT)
|
|
56
|
+
fail('format', `acceptanceFormat is not ${MANAGED_ACCEPTANCE_FORMAT}`);
|
|
57
|
+
if (!text(r.requestId, MAX_REQUEST_ID))
|
|
58
|
+
fail('format', `requestId must be printable text of at most ${MAX_REQUEST_ID} bytes`);
|
|
59
|
+
if (!text(r.passportId, 512))
|
|
60
|
+
fail('format', 'passportId must be printable text of at most 512 bytes');
|
|
61
|
+
if (!outpointOk(r.lineageGenesis))
|
|
62
|
+
fail('format', 'lineageGenesis must be an outpoint');
|
|
63
|
+
if (!outpointOk(r.expectedPredecessor))
|
|
64
|
+
fail('format', 'expectedPredecessor must be an outpoint');
|
|
65
|
+
if (!HEX64.test(String(r.termsDigest ?? '')))
|
|
66
|
+
fail('format', 'termsDigest must be 64 lowercase hex characters');
|
|
67
|
+
const offer = r.offer;
|
|
68
|
+
if (offer == null || typeof offer !== 'object' || Array.isArray(offer))
|
|
69
|
+
fail('format', 'offer must be an object');
|
|
70
|
+
else {
|
|
71
|
+
for (const key of Object.keys(offer))
|
|
72
|
+
if (!['holderIdentityKey', 'createdAt', 'expiresAt', 'mechanism', 'recipientRef'].includes(key))
|
|
73
|
+
fail('format', `unsupported offer property ${key}`);
|
|
74
|
+
if (!KEY.test(String(offer.holderIdentityKey ?? '')))
|
|
75
|
+
fail('format', 'offer.holderIdentityKey must be a compressed public key');
|
|
76
|
+
if (!TIME.test(String(offer.createdAt ?? '')) || !Number.isFinite(instant(String(offer.createdAt))))
|
|
77
|
+
fail('format', 'offer.createdAt must be an ISO date-time with a timezone');
|
|
78
|
+
if (!TIME.test(String(offer.expiresAt ?? '')) || !Number.isFinite(instant(String(offer.expiresAt))))
|
|
79
|
+
fail('format', 'offer.expiresAt must be an ISO date-time with a timezone');
|
|
80
|
+
if (offer.mechanism !== 'claim-code' && offer.mechanism !== 'named-recipient')
|
|
81
|
+
fail('format', 'offer.mechanism must be claim-code or named-recipient');
|
|
82
|
+
if (offer.recipientRef !== undefined && !(offer.mechanism === 'claim-code' ? HEX64.test(String(offer.recipientRef)) : KEY.test(String(offer.recipientRef)))) {
|
|
83
|
+
fail('format', 'offer.recipientRef must be a SHA-256 for a claim code or a compressed key for a named recipient');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const acceptance = r.acceptance;
|
|
87
|
+
if (acceptance == null || typeof acceptance !== 'object' || Array.isArray(acceptance))
|
|
88
|
+
fail('format', 'acceptance must be an object');
|
|
89
|
+
else {
|
|
90
|
+
for (const key of Object.keys(acceptance))
|
|
91
|
+
if (!['recipientIdentityKey', 'destinationKey', 'acceptedAt', 'evidenceKind'].includes(key))
|
|
92
|
+
fail('format', `unsupported acceptance property ${key}`);
|
|
93
|
+
if (!KEY.test(String(acceptance.recipientIdentityKey ?? '')))
|
|
94
|
+
fail('format', 'acceptance.recipientIdentityKey must be a compressed public key');
|
|
95
|
+
if (!KEY.test(String(acceptance.destinationKey ?? '')))
|
|
96
|
+
fail('format', 'acceptance.destinationKey must be a compressed public key');
|
|
97
|
+
if (!TIME.test(String(acceptance.acceptedAt ?? '')) || !Number.isFinite(instant(String(acceptance.acceptedAt))))
|
|
98
|
+
fail('format', 'acceptance.acceptedAt must be an ISO date-time with a timezone');
|
|
99
|
+
if (acceptance.evidenceKind !== 'custodian-attested')
|
|
100
|
+
fail('format', 'acceptance.evidenceKind must be custodian-attested');
|
|
101
|
+
}
|
|
102
|
+
if (!KEY.test(String(r.custodian ?? '')))
|
|
103
|
+
fail('format', 'custodian must be a compressed public key');
|
|
104
|
+
if (typeof r.signature !== 'string' || !/^(?:[0-9a-f]{2}){8,72}$/.test(r.signature))
|
|
105
|
+
fail('format', 'signature must be lowercase DER hex');
|
|
106
|
+
else {
|
|
107
|
+
try {
|
|
108
|
+
const der = Signature.fromDER(r.signature, 'hex');
|
|
109
|
+
if (Utils.toHex(der.toDER()) !== r.signature)
|
|
110
|
+
fail('format', 'signature must use canonical DER');
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
fail('format', 'signature is not DER');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (failures.length > 0)
|
|
117
|
+
return false;
|
|
118
|
+
const record = value;
|
|
119
|
+
const created = instant(record.offer.createdAt);
|
|
120
|
+
const accepted = instant(record.acceptance.acceptedAt);
|
|
121
|
+
const expires = instant(record.offer.expiresAt);
|
|
122
|
+
if (!(created <= accepted))
|
|
123
|
+
fail('time-order', 'acceptedAt precedes createdAt');
|
|
124
|
+
if (!(accepted <= expires))
|
|
125
|
+
fail('time-order', 'acceptedAt is after expiresAt: the offer had expired');
|
|
126
|
+
if (record.offer.mechanism === 'named-recipient' && record.offer.recipientRef != null && record.offer.recipientRef !== record.acceptance.recipientIdentityKey) {
|
|
127
|
+
fail('state-mismatch', 'the named recipient is not the accepting identity');
|
|
128
|
+
}
|
|
129
|
+
return failures.length === 0;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Inspect a record on its own: structure, the custodian's signature and, when
|
|
133
|
+
* the caller names the custodians it trusts, whether the signer is one of
|
|
134
|
+
* them. Binding to the TRANSFER that commits to it is `bindAcceptanceToState`.
|
|
135
|
+
*/
|
|
136
|
+
export function inspectManagedAcceptance(value, options = {}) {
|
|
137
|
+
const failures = [];
|
|
138
|
+
const structureValid = structure(value, failures);
|
|
139
|
+
if (!structureValid)
|
|
140
|
+
return { structureValid, signatureValid: null, failures };
|
|
141
|
+
const record = value;
|
|
142
|
+
let signatureValid = null;
|
|
143
|
+
let commitment;
|
|
144
|
+
try {
|
|
145
|
+
const preimage = acceptanceSigningPreimage(record);
|
|
146
|
+
signatureValid = PublicKey.fromString(record.custodian).verify(preimage, Signature.fromDER(Utils.toArray(record.signature, 'hex')));
|
|
147
|
+
commitment = acceptanceCommitment(record);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
signatureValid = error instanceof CanonicalJsonError ? null : false;
|
|
151
|
+
if (signatureValid === null)
|
|
152
|
+
failures.push({ reason: 'format', detail: error instanceof Error ? error.message : 'the record has no canonical form' });
|
|
153
|
+
}
|
|
154
|
+
if (signatureValid === false)
|
|
155
|
+
failures.push({ reason: 'signature-invalid', detail: `the signature does not verify under custodian ${record.custodian}` });
|
|
156
|
+
if (options.custodians != null && !options.custodians.includes(record.custodian)) {
|
|
157
|
+
failures.push({ reason: 'custodian-unexpected', detail: `signed by ${record.custodian}, not a custodian the policy names` });
|
|
158
|
+
}
|
|
159
|
+
return { structureValid, signatureValid, ...(commitment == null ? {} : { commitment }), failures };
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Whether a version 2 TRANSFER executed exactly the acceptance the record
|
|
163
|
+
* evidences: same passport and lineage, the tip the offer named, the
|
|
164
|
+
* destination the recipient accepted, the holder who offered as the actor,
|
|
165
|
+
* and the record's own commitment in field 15. Every mismatch is named.
|
|
166
|
+
*/
|
|
167
|
+
export function bindAcceptanceToState(record, state) {
|
|
168
|
+
const failures = [];
|
|
169
|
+
const fail = (detail) => { failures.push({ reason: 'state-mismatch', detail }); };
|
|
170
|
+
if (state.op !== 'TRANSFER')
|
|
171
|
+
fail(`the state is a ${state.op}, not a TRANSFER`);
|
|
172
|
+
if (state.passportId !== record.passportId)
|
|
173
|
+
fail('the state names another passport');
|
|
174
|
+
if (state.lineageGenesis == null || state.lineageGenesis.txid !== record.lineageGenesis.txid || state.lineageGenesis.outputIndex !== record.lineageGenesis.outputIndex)
|
|
175
|
+
fail('the state names another lineage');
|
|
176
|
+
if (state.previousTxid !== record.expectedPredecessor.txid || state.previousOutputIndex !== record.expectedPredecessor.outputIndex)
|
|
177
|
+
fail('the state spends a tip other than the one the offer named');
|
|
178
|
+
if (state.ownerIdentityKey !== record.acceptance.destinationKey)
|
|
179
|
+
fail('the state moves control to a key other than the accepted destination');
|
|
180
|
+
if (state.actorIdentityKey !== record.offer.holderIdentityKey)
|
|
181
|
+
fail('the state was made by an actor other than the holder who offered');
|
|
182
|
+
if (state.authorisationCommitment !== acceptanceCommitment(record))
|
|
183
|
+
fail('the state does not commit to this record');
|
|
184
|
+
if (instant(record.acceptance.acceptedAt) > instant(state.timestamp))
|
|
185
|
+
fail('the state is timestamped before the acceptance it executes');
|
|
186
|
+
return failures;
|
|
187
|
+
}
|
|
188
|
+
/** Sign a claim as the custodian. The signer's key must be `claim.custodian`; the result is checked before it is returned. */
|
|
189
|
+
export async function signManagedAcceptance(claim, signer) {
|
|
190
|
+
const failures = [];
|
|
191
|
+
// A well-formed placeholder (r = 1, s = 1) stands in for the signature while the claim's own shape is checked.
|
|
192
|
+
if (!structure({ ...claim, signature: '3006020101020101' }, failures)) {
|
|
193
|
+
throw new Error(`acceptance record is not well formed: ${failures.map((f) => f.detail).join('; ')}`);
|
|
194
|
+
}
|
|
195
|
+
const der = await signer.sign(acceptanceSigningPreimage(claim));
|
|
196
|
+
const record = { ...claim, signature: Utils.toHex(der) };
|
|
197
|
+
const inspection = inspectManagedAcceptance(record);
|
|
198
|
+
if (inspection.signatureValid !== true)
|
|
199
|
+
throw new Error('the signer does not hold the custodian key the record names');
|
|
200
|
+
return record;
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=acceptance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acceptance.js","sourceRoot":"","sources":["../src/acceptance.ts"],"names":[],"mappings":"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"}
|
package/dist/anchor.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { LockingScript, PublicKey, type WalletProtocol } from '@bsv/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* The generic complete-representation anchor, `bsv-attestation-anchor-v1`
|
|
4
|
+
* (`spec/rules.md` §5 and §6). It lives in the core rather than in the overlay
|
|
5
|
+
* package because a reader in a browser verifies anchors without a database or
|
|
6
|
+
* an overlay engine, and `verifyPassportEvidence` (evidence.ts) reports the
|
|
7
|
+
* anchor rail beside the token rail from one package. `@bsv/dpp-overlay-topics`
|
|
8
|
+
* re-exports every name below unchanged.
|
|
9
|
+
*/
|
|
10
|
+
export declare const ATTESTATION_ANCHOR_PREFIX = "bsv-attestation-anchor-v1";
|
|
11
|
+
export declare const ATTESTATION_ANCHOR_PROTOCOL: WalletProtocol;
|
|
12
|
+
export declare const ATTESTATION_ANCHOR_BASKET = "attestation-anchor";
|
|
13
|
+
export declare const ATTESTATION_ANCHOR_FIELD_COUNT = 9;
|
|
14
|
+
/** Metadata is authenticated as the anchor service's statement, not as credential authority. */
|
|
15
|
+
export interface AnchorMetadata {
|
|
16
|
+
digest: string;
|
|
17
|
+
attestationId: string;
|
|
18
|
+
issuer: string;
|
|
19
|
+
subject: string;
|
|
20
|
+
attestationType: string;
|
|
21
|
+
representation: string;
|
|
22
|
+
mediaType: string;
|
|
23
|
+
anchoredBy: string;
|
|
24
|
+
}
|
|
25
|
+
export interface AttestationAnchor extends AnchorMetadata {
|
|
26
|
+
lockingKey: string;
|
|
27
|
+
signature: number[];
|
|
28
|
+
}
|
|
29
|
+
export interface AnchorSigner {
|
|
30
|
+
createSignature(args: {
|
|
31
|
+
data: number[];
|
|
32
|
+
protocolID: WalletProtocol;
|
|
33
|
+
keyID: string;
|
|
34
|
+
counterparty: string;
|
|
35
|
+
}): Promise<{
|
|
36
|
+
signature: number[];
|
|
37
|
+
}>;
|
|
38
|
+
}
|
|
39
|
+
export declare function expectedAttestationLockingKey(anchoredBy: string, attestationId: string): PublicKey;
|
|
40
|
+
export declare function attestationAnchorFields(anchor: AnchorMetadata): number[][];
|
|
41
|
+
export declare function attestationAnchorSigningPreimage(fields: number[][]): number[];
|
|
42
|
+
export declare function buildAttestationAnchor(anchor: AnchorMetadata, signer: AnchorSigner): Promise<LockingScript>;
|
|
43
|
+
/**
|
|
44
|
+
* What a reader learnt from one output, check by check, so a report can say
|
|
45
|
+
* which rule failed rather than only that one did. `metadata` is present once
|
|
46
|
+
* the layout and every field bound held; the two Booleans are `null` until the
|
|
47
|
+
* material they need was decoded. `decodeAttestationAnchor` collapses this to
|
|
48
|
+
* the total strict parser the topic manager and the fixtures use.
|
|
49
|
+
*/
|
|
50
|
+
export interface AttestationAnchorInspection {
|
|
51
|
+
metadata?: AnchorMetadata;
|
|
52
|
+
/** Canonical hex of the key in the first push, when it is a canonical compressed key. */
|
|
53
|
+
lockingKey?: string;
|
|
54
|
+
/** The child the metadata says the locking key must be, when metadata decoded. */
|
|
55
|
+
derivedKey?: string;
|
|
56
|
+
keyDerivationValid: boolean | null;
|
|
57
|
+
/** Verified against the derived key, never against whatever key the script happened to carry. */
|
|
58
|
+
signatureValid: boolean | null;
|
|
59
|
+
signature?: number[];
|
|
60
|
+
/** The first structural refusal, present when `metadata` is absent or a key did not parse. */
|
|
61
|
+
failure?: string;
|
|
62
|
+
}
|
|
63
|
+
export declare function inspectAttestationAnchor(script: LockingScript): AttestationAnchorInspection;
|
|
64
|
+
/** A total strict parser: invalid or legacy outputs return null. No credential proof is implied. */
|
|
65
|
+
export declare function decodeAttestationAnchor(script: LockingScript): AttestationAnchor | null;
|
|
66
|
+
//# sourceMappingURL=anchor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor.d.ts","sourceRoot":"","sources":["../src/anchor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,aAAa,EAAE,SAAS,EAAoB,KAAK,cAAc,EAAE,MAAM,UAAU,CAAA;AAE5G;;;;;;;GAOG;AAEH,eAAO,MAAM,yBAAyB,8BAA8B,CAAA;AACpE,eAAO,MAAM,2BAA2B,EAAE,cAAiD,CAAA;AAC3F,eAAO,MAAM,yBAAyB,uBAAuB,CAAA;AAC7D,eAAO,MAAM,8BAA8B,IAAI,CAAA;AAE/C,gGAAgG;AAChG,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,EAAE,MAAM,CAAA;IACvB,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AACD,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACvD,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,EAAE,CAAA;CACpB;AACD,MAAM,WAAW,YAAY;IAC3B,eAAe,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,EAAE,cAAc,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;CAC7I;AAoBD,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,SAAS,CAIlG;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,EAAE,EAAE,CAW1E;AAED,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,CAK7E;AAED,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAajH;AAED;;;;;;GAMG;AACH,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,yFAAyF;IACzF,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kBAAkB,EAAE,OAAO,GAAG,IAAI,CAAA;IAClC,iGAAiG;IACjG,cAAc,EAAE,OAAO,GAAG,IAAI,CAAA;IAC9B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,8FAA8F;IAC9F,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,GAAG,2BAA2B,CA6C3F;AAED,oGAAoG;AACpG,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,GAAG,iBAAiB,GAAG,IAAI,CAOvF"}
|