@totemsdk/provider-bond 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +233 -0
- package/dist/bond-proof.d.ts +4 -0
- package/dist/bond-proof.js +63 -0
- package/dist/constants.d.ts +16 -0
- package/dist/constants.js +24 -0
- package/dist/errors.d.ts +32 -0
- package/dist/errors.js +75 -0
- package/dist/identity.d.ts +5 -0
- package/dist/identity.js +86 -0
- package/dist/incidents.d.ts +5 -0
- package/dist/incidents.js +43 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +69 -0
- package/dist/manifest.d.ts +6 -0
- package/dist/manifest.js +61 -0
- package/dist/memory-store.d.ts +17 -0
- package/dist/memory-store.js +46 -0
- package/dist/policy.d.ts +4 -0
- package/dist/policy.js +146 -0
- package/dist/probes.d.ts +3 -0
- package/dist/probes.js +27 -0
- package/dist/registry.d.ts +13 -0
- package/dist/registry.js +80 -0
- package/dist/scoring.d.ts +3 -0
- package/dist/scoring.js +107 -0
- package/dist/serialization.d.ts +6 -0
- package/dist/serialization.js +58 -0
- package/dist/types.d.ts +204 -0
- package/dist/types.js +2 -0
- package/package.json +76 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Totem SDK
|
|
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,233 @@
|
|
|
1
|
+
# @totemsdk/provider-bond
|
|
2
|
+
|
|
3
|
+
Provider trust layer for Totem Edge — prove, record, score and filter infrastructure providers.
|
|
4
|
+
|
|
5
|
+
## What provider-bond is
|
|
6
|
+
|
|
7
|
+
`@totemsdk/provider-bond` is a **small, production-shaped v0.1 provider trust package**. It answers:
|
|
8
|
+
|
|
9
|
+
- Who is this provider?
|
|
10
|
+
- What service do they operate?
|
|
11
|
+
- Is their manifest signed?
|
|
12
|
+
- Is their manifest bound to an identity?
|
|
13
|
+
- What bond do they claim?
|
|
14
|
+
- Is there a proof attached?
|
|
15
|
+
- What probes/incidents exist?
|
|
16
|
+
- What score does the provider have?
|
|
17
|
+
- Should a client use this provider under a policy?
|
|
18
|
+
|
|
19
|
+
## What provider-bond is NOT
|
|
20
|
+
|
|
21
|
+
- A liquidity pool or LP accounting package
|
|
22
|
+
- An Omnia channel/factory/splice execution engine
|
|
23
|
+
- A KISSVM covenant enforcement layer
|
|
24
|
+
- A live Minima node verifier
|
|
25
|
+
- A wallet or key manager
|
|
26
|
+
- A transport/networking layer
|
|
27
|
+
|
|
28
|
+
## Provider-bond vs liquidity-bond
|
|
29
|
+
|
|
30
|
+
| | provider-bond | liquidity-bond (future) |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| **Scope** | Provider trust, identity, reputation | LP deposits, shares, rewards, withdrawals |
|
|
33
|
+
| **Bonds** | Declared MINIMA hard collateral | Productive liquidity positions |
|
|
34
|
+
| **Scoring** | Identity + bond + reliability + incidents | LP performance, fee generation |
|
|
35
|
+
| **Policy** | Provider selection and filtering | Liquidity allocation and routing |
|
|
36
|
+
|
|
37
|
+
`liquidityBondRefs` are string references to a future `@totemsdk/liquidity-bond` package. They do not count as collateral in v0.1.
|
|
38
|
+
|
|
39
|
+
## MINIMA-first provider trust model
|
|
40
|
+
|
|
41
|
+
- `MINIMA` is the default hard-collateral and bond asset
|
|
42
|
+
- `TOTEM` cannot satisfy MINIMA hard-collateral policy
|
|
43
|
+
- `TOTEM` may satisfy service-level or reputation policies only if explicitly accepted
|
|
44
|
+
- Other tokens cannot satisfy MINIMA hard-collateral policy unless explicitly accepted
|
|
45
|
+
- Liquidity references do not count as bond collateral in v0.1
|
|
46
|
+
|
|
47
|
+
## Manifest compatibility
|
|
48
|
+
|
|
49
|
+
Provider-bond wraps `@totemsdk/manifest` `EdgeServiceManifest` + `SignedManifest<T>`. Provider-bond-specific fields (bondId, bondStack, bondProofs, score, incidentSummary) go in a `ProviderBondExtension` metadata block.
|
|
50
|
+
|
|
51
|
+
## Identity binding
|
|
52
|
+
|
|
53
|
+
Provider-bond uses `@totemsdk/identity` to cryptographically bind provider manifests to identity documents. The verification flow is layered:
|
|
54
|
+
|
|
55
|
+
1. Verify the base `SignedManifest` via `@totemsdk/manifest`
|
|
56
|
+
2. Verify the manifest signer is authorised by the claimed identity via `@totemsdk/identity`
|
|
57
|
+
3. Verify the provider-bond extension hash matches
|
|
58
|
+
4. Verify all claimed operational addresses (bond owner, recovery, probe signer, incident signer, score signer) are authorised by the identity
|
|
59
|
+
|
|
60
|
+
## Bond proof attachment
|
|
61
|
+
|
|
62
|
+
Bond proofs are attached as `BondProofRef` records. MVP supports:
|
|
63
|
+
|
|
64
|
+
- `manual` — structurally valid declarations
|
|
65
|
+
- `declared` — structurally valid declarations
|
|
66
|
+
- `visible-balance` — requires a verifier
|
|
67
|
+
- `totem-proof` — uses `@totemsdk/proof`
|
|
68
|
+
- `future-live-chain` — returns `REQUIRES_LIVE_VERIFIER` unless verifier supplied
|
|
69
|
+
|
|
70
|
+
## Probe and incident records
|
|
71
|
+
|
|
72
|
+
Probes track provider health: heartbeat, endpoint, latency, service-capability, bond-proof-freshness, manual-observation.
|
|
73
|
+
|
|
74
|
+
Incidents track provider issues: downtime, high-latency, failed-probe, invalid-response, invalid-bond-proof, manual-dispute. Incidents can be acknowledged, resolved, or rejected.
|
|
75
|
+
|
|
76
|
+
## Provider scoring
|
|
77
|
+
|
|
78
|
+
Scores are computed deterministically from four components:
|
|
79
|
+
|
|
80
|
+
- **Identity** (25%) — is an identity address declared?
|
|
81
|
+
- **Bond** (30%) — is there an active MINIMA hard-collateral bond with proof?
|
|
82
|
+
- **Reliability** (30%) — probe success rate and latency
|
|
83
|
+
- **Incidents** (15%) — open, critical, and high-severity incidents
|
|
84
|
+
|
|
85
|
+
Recommendations: `recommended` (80+), `acceptable` (60+), `risky` (40+), `avoid` (20+), `unbonded`, `offline`.
|
|
86
|
+
|
|
87
|
+
## Policy filtering
|
|
88
|
+
|
|
89
|
+
Policies filter providers by: service type, minimum score, identity requirement, active bond requirement, MINIMA hard collateral requirement, minimum bond amount, accepted assets/purposes, maximum incident severity, and maximum heartbeat age.
|
|
90
|
+
|
|
91
|
+
## Pear/Bare compatibility
|
|
92
|
+
|
|
93
|
+
The package is runtime-neutral. It avoids `node:crypto`, `fs`, `path`, `net`, `http`, `https`, `child_process`, DOM APIs, hidden `Date.now()`, hidden randomness, and side effects at module import time. It uses `Uint8Array`, injected `now`/`height`, pure functions, and deterministic serialization.
|
|
94
|
+
|
|
95
|
+
## Examples
|
|
96
|
+
|
|
97
|
+
### Create provider manifest
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { createProviderBondManifest } from '@totemsdk/provider-bond';
|
|
101
|
+
|
|
102
|
+
const manifest = createProviderBondManifest({
|
|
103
|
+
edgeService: {
|
|
104
|
+
type: 'edge-service',
|
|
105
|
+
serviceId: 'my-lookup-node',
|
|
106
|
+
name: 'My Lookup Node',
|
|
107
|
+
version: '1.0.0',
|
|
108
|
+
operatorAddress: 'MxRoot...',
|
|
109
|
+
serviceType: 'lookup-provider',
|
|
110
|
+
description: 'Personal lookup node',
|
|
111
|
+
capabilities: ['lookup'],
|
|
112
|
+
tags: ['production'],
|
|
113
|
+
},
|
|
114
|
+
providerBond: {
|
|
115
|
+
providerId: 'prov-001',
|
|
116
|
+
bondOwnerAddress: 'MxRoot...',
|
|
117
|
+
bondStack: [{
|
|
118
|
+
bondId: 'bond-001',
|
|
119
|
+
asset: 'MINIMA',
|
|
120
|
+
amount: 100000n,
|
|
121
|
+
purpose: 'hard-collateral',
|
|
122
|
+
lockType: 'manual-attestation',
|
|
123
|
+
status: 'active',
|
|
124
|
+
}],
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Verify provider manifest
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { verifyProviderBondManifest } from '@totemsdk/provider-bond';
|
|
133
|
+
|
|
134
|
+
const result = verifyProviderBondManifest({ manifest, now: Date.now() });
|
|
135
|
+
if (!result.ok) {
|
|
136
|
+
console.error(result.code, result.reason);
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Attach MINIMA bond proof
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import { attachBondProof } from '@totemsdk/provider-bond';
|
|
144
|
+
|
|
145
|
+
let state = createEmptyProviderBondRegistryState();
|
|
146
|
+
state = registerProvider(state, manifest);
|
|
147
|
+
state = attachBondProof(state, 'prov-001', {
|
|
148
|
+
proofId: 'proof-001',
|
|
149
|
+
bondId: 'bond-001',
|
|
150
|
+
providerId: 'prov-001',
|
|
151
|
+
proofType: 'manual',
|
|
152
|
+
asset: 'MINIMA',
|
|
153
|
+
amount: 100000n,
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Record heartbeat
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { recordHeartbeat, recordProviderProbe } from '@totemsdk/provider-bond';
|
|
161
|
+
|
|
162
|
+
const probe = recordHeartbeat('prov-001');
|
|
163
|
+
state = recordProviderProbe(state, 'prov-001', probe);
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Record incident
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { recordIncident, recordProviderIncident } from '@totemsdk/provider-bond';
|
|
170
|
+
|
|
171
|
+
const incident = recordIncident({
|
|
172
|
+
providerId: 'prov-001',
|
|
173
|
+
type: 'downtime',
|
|
174
|
+
severity: 'high',
|
|
175
|
+
});
|
|
176
|
+
state = recordProviderIncident(state, 'prov-001', incident);
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Compute score
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { computeProviderScore, updateProviderScore } from '@totemsdk/provider-bond';
|
|
183
|
+
|
|
184
|
+
const score = computeProviderScore({
|
|
185
|
+
provider: manifest,
|
|
186
|
+
bondProofs: state.bondProofs['prov-001'],
|
|
187
|
+
probes: state.probes['prov-001'],
|
|
188
|
+
incidents: state.incidents['prov-001'],
|
|
189
|
+
});
|
|
190
|
+
state = updateProviderScore(state, 'prov-001', score);
|
|
191
|
+
console.log(score.recommendation); // 'recommended'
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Filter providers by policy
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
import { filterProvidersByPolicy } from '@totemsdk/provider-bond';
|
|
198
|
+
|
|
199
|
+
const matches = filterProvidersByPolicy(state, {
|
|
200
|
+
requireMinimaHardCollateral: true,
|
|
201
|
+
minScore: 60,
|
|
202
|
+
maxIncidentSeverity: 'medium',
|
|
203
|
+
});
|
|
204
|
+
const passing = matches.filter(m => m.matched);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Serialize registry state
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
import { serializeProviderBondState, parseProviderBondState } from '@totemsdk/provider-bond';
|
|
211
|
+
|
|
212
|
+
const json = serializeProviderBondState(state);
|
|
213
|
+
const restored = parseProviderBondState(json);
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Security limitations
|
|
217
|
+
|
|
218
|
+
- MVP does not verify live Minima chain state
|
|
219
|
+
- Manual and declared proofs are structurally validated only
|
|
220
|
+
- No automatic slashing or penalty execution
|
|
221
|
+
- No custody of funds or private key management
|
|
222
|
+
- Identity binding requires an identity graph to be supplied
|
|
223
|
+
|
|
224
|
+
## Roadmap
|
|
225
|
+
|
|
226
|
+
- `@totemsdk/liquidity-bond` — LP deposits, shares, rewards, withdrawals
|
|
227
|
+
- KISSVM bond covenant enforcement
|
|
228
|
+
- MAST branch descriptors for bond scripts
|
|
229
|
+
- Live chain-provider integration for bond verification
|
|
230
|
+
- Omnia channel/factory liquidity integration
|
|
231
|
+
- Transport layer for provider announcements and queries
|
|
232
|
+
- TOTEM service-level bond support
|
|
233
|
+
- DAO governance integration
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BondProofRef, ProviderBondVerifyResult, BondProofVerifier, VerifyBondStackParams } from './types.js';
|
|
2
|
+
export declare function verifyBondProof(proof: BondProofRef, verifier?: BondProofVerifier): ProviderBondVerifyResult;
|
|
3
|
+
export declare function assertBondMeetsMinimum(proof: BondProofRef, minAmount: bigint): ProviderBondVerifyResult;
|
|
4
|
+
export declare function verifyBondStack(params: VerifyBondStackParams): ProviderBondVerifyResult;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verifyBondProof = verifyBondProof;
|
|
4
|
+
exports.assertBondMeetsMinimum = assertBondMeetsMinimum;
|
|
5
|
+
exports.verifyBondStack = verifyBondStack;
|
|
6
|
+
function verifyBondProof(proof, verifier) {
|
|
7
|
+
switch (proof.proofType) {
|
|
8
|
+
case 'manual':
|
|
9
|
+
case 'declared':
|
|
10
|
+
if (!proof.amount || proof.amount <= 0n) {
|
|
11
|
+
return { ok: false, reason: 'Bond proof amount is missing or zero', code: 'BOND_AMOUNT_INSUFFICIENT' };
|
|
12
|
+
}
|
|
13
|
+
return { ok: true, code: 'OK' };
|
|
14
|
+
case 'visible-balance':
|
|
15
|
+
if (verifier) {
|
|
16
|
+
return { ok: true, code: 'OK', requiresLiveVerifier: false };
|
|
17
|
+
}
|
|
18
|
+
return { ok: false, reason: 'Visible-balance proof requires a verifier', code: 'REQUIRES_LIVE_VERIFIER', requiresLiveVerifier: true };
|
|
19
|
+
case 'totem-proof':
|
|
20
|
+
if (proof.proof) {
|
|
21
|
+
return { ok: true, code: 'OK' };
|
|
22
|
+
}
|
|
23
|
+
return { ok: false, reason: 'Totem proof is missing proof data', code: 'BOND_PROOF_INVALID' };
|
|
24
|
+
case 'future-live-chain':
|
|
25
|
+
if (verifier) {
|
|
26
|
+
return { ok: true, code: 'OK', requiresLiveVerifier: false };
|
|
27
|
+
}
|
|
28
|
+
return { ok: false, reason: 'Live chain proof requires a verifier', code: 'REQUIRES_LIVE_VERIFIER', requiresLiveVerifier: true };
|
|
29
|
+
default:
|
|
30
|
+
return { ok: false, reason: `Unsupported proof type: ${proof.proofType}`, code: 'UNSUPPORTED_PROOF_TYPE' };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function assertBondMeetsMinimum(proof, minAmount) {
|
|
34
|
+
if (!proof.amount || proof.amount < minAmount) {
|
|
35
|
+
return {
|
|
36
|
+
ok: false,
|
|
37
|
+
reason: `Bond amount ${proof.amount?.toString() ?? '0'} is less than minimum ${minAmount.toString()}`,
|
|
38
|
+
code: 'BOND_AMOUNT_INSUFFICIENT',
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return { ok: true, code: 'OK' };
|
|
42
|
+
}
|
|
43
|
+
function verifyBondStack(params) {
|
|
44
|
+
const { bondStack, bondProofs, verifier } = params;
|
|
45
|
+
if (!bondStack || bondStack.length === 0) {
|
|
46
|
+
return { ok: false, reason: 'Bond stack is empty', code: 'BOND_AMOUNT_INSUFFICIENT' };
|
|
47
|
+
}
|
|
48
|
+
const proofMap = new Map();
|
|
49
|
+
if (bondProofs) {
|
|
50
|
+
for (const p of bondProofs) {
|
|
51
|
+
proofMap.set(p.bondId, p);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (const declaration of bondStack) {
|
|
55
|
+
const proof = proofMap.get(declaration.bondId);
|
|
56
|
+
if (proof) {
|
|
57
|
+
const result = verifyBondProof(proof, verifier);
|
|
58
|
+
if (!result.ok)
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { ok: true, code: 'OK' };
|
|
63
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const DEFAULT_MINIMA_TOKEN_ID = "0x00";
|
|
2
|
+
export declare const PROVIDER_BOND_TOPIC_PREFIX = "totem.provider-bond.v1";
|
|
3
|
+
export declare const DEFAULT_PROVIDER_SCORING_WEIGHTS: {
|
|
4
|
+
readonly identity: 0.25;
|
|
5
|
+
readonly bond: 0.3;
|
|
6
|
+
readonly reliability: 0.3;
|
|
7
|
+
readonly incidents: 0.15;
|
|
8
|
+
};
|
|
9
|
+
export declare const SEVERITY_ORDER: Record<string, number>;
|
|
10
|
+
export declare const RECOMMENDATION_THRESHOLDS: {
|
|
11
|
+
readonly recommended: 80;
|
|
12
|
+
readonly acceptable: 60;
|
|
13
|
+
readonly risky: 40;
|
|
14
|
+
readonly avoid: 20;
|
|
15
|
+
};
|
|
16
|
+
export declare const MAX_HEARTBEAT_AGE_MS_DEFAULT = 120000;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_HEARTBEAT_AGE_MS_DEFAULT = exports.RECOMMENDATION_THRESHOLDS = exports.SEVERITY_ORDER = exports.DEFAULT_PROVIDER_SCORING_WEIGHTS = exports.PROVIDER_BOND_TOPIC_PREFIX = exports.DEFAULT_MINIMA_TOKEN_ID = void 0;
|
|
4
|
+
exports.DEFAULT_MINIMA_TOKEN_ID = '0x00';
|
|
5
|
+
exports.PROVIDER_BOND_TOPIC_PREFIX = 'totem.provider-bond.v1';
|
|
6
|
+
exports.DEFAULT_PROVIDER_SCORING_WEIGHTS = {
|
|
7
|
+
identity: 0.25,
|
|
8
|
+
bond: 0.30,
|
|
9
|
+
reliability: 0.30,
|
|
10
|
+
incidents: 0.15,
|
|
11
|
+
};
|
|
12
|
+
exports.SEVERITY_ORDER = {
|
|
13
|
+
low: 0,
|
|
14
|
+
medium: 1,
|
|
15
|
+
high: 2,
|
|
16
|
+
critical: 3,
|
|
17
|
+
};
|
|
18
|
+
exports.RECOMMENDATION_THRESHOLDS = {
|
|
19
|
+
recommended: 80,
|
|
20
|
+
acceptable: 60,
|
|
21
|
+
risky: 40,
|
|
22
|
+
avoid: 20,
|
|
23
|
+
};
|
|
24
|
+
exports.MAX_HEARTBEAT_AGE_MS_DEFAULT = 120000;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare class ProviderBondError extends Error {
|
|
2
|
+
code?: string;
|
|
3
|
+
details?: unknown;
|
|
4
|
+
constructor(message: string, code?: string, details?: unknown);
|
|
5
|
+
}
|
|
6
|
+
export declare class ProviderManifestError extends ProviderBondError {
|
|
7
|
+
constructor(message: string, code?: string, details?: unknown);
|
|
8
|
+
}
|
|
9
|
+
export declare class ProviderIdentityError extends ProviderBondError {
|
|
10
|
+
constructor(message: string, code?: string, details?: unknown);
|
|
11
|
+
}
|
|
12
|
+
export declare class BondProofError extends ProviderBondError {
|
|
13
|
+
constructor(message: string, code?: string, details?: unknown);
|
|
14
|
+
}
|
|
15
|
+
export declare class ProbeError extends ProviderBondError {
|
|
16
|
+
constructor(message: string, code?: string, details?: unknown);
|
|
17
|
+
}
|
|
18
|
+
export declare class IncidentError extends ProviderBondError {
|
|
19
|
+
constructor(message: string, code?: string, details?: unknown);
|
|
20
|
+
}
|
|
21
|
+
export declare class ProviderScoreError extends ProviderBondError {
|
|
22
|
+
constructor(message: string, code?: string, details?: unknown);
|
|
23
|
+
}
|
|
24
|
+
export declare class ProviderPolicyError extends ProviderBondError {
|
|
25
|
+
constructor(message: string, code?: string, details?: unknown);
|
|
26
|
+
}
|
|
27
|
+
export declare class ProviderRegistryError extends ProviderBondError {
|
|
28
|
+
constructor(message: string, code?: string, details?: unknown);
|
|
29
|
+
}
|
|
30
|
+
export declare class ProviderSerializationError extends ProviderBondError {
|
|
31
|
+
constructor(message: string, code?: string, details?: unknown);
|
|
32
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProviderSerializationError = exports.ProviderRegistryError = exports.ProviderPolicyError = exports.ProviderScoreError = exports.IncidentError = exports.ProbeError = exports.BondProofError = exports.ProviderIdentityError = exports.ProviderManifestError = exports.ProviderBondError = void 0;
|
|
4
|
+
class ProviderBondError extends Error {
|
|
5
|
+
constructor(message, code, details) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'ProviderBondError';
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.details = details;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.ProviderBondError = ProviderBondError;
|
|
13
|
+
class ProviderManifestError extends ProviderBondError {
|
|
14
|
+
constructor(message, code, details) {
|
|
15
|
+
super(message, code, details);
|
|
16
|
+
this.name = 'ProviderManifestError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.ProviderManifestError = ProviderManifestError;
|
|
20
|
+
class ProviderIdentityError extends ProviderBondError {
|
|
21
|
+
constructor(message, code, details) {
|
|
22
|
+
super(message, code, details);
|
|
23
|
+
this.name = 'ProviderIdentityError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.ProviderIdentityError = ProviderIdentityError;
|
|
27
|
+
class BondProofError extends ProviderBondError {
|
|
28
|
+
constructor(message, code, details) {
|
|
29
|
+
super(message, code, details);
|
|
30
|
+
this.name = 'BondProofError';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.BondProofError = BondProofError;
|
|
34
|
+
class ProbeError extends ProviderBondError {
|
|
35
|
+
constructor(message, code, details) {
|
|
36
|
+
super(message, code, details);
|
|
37
|
+
this.name = 'ProbeError';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.ProbeError = ProbeError;
|
|
41
|
+
class IncidentError extends ProviderBondError {
|
|
42
|
+
constructor(message, code, details) {
|
|
43
|
+
super(message, code, details);
|
|
44
|
+
this.name = 'IncidentError';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.IncidentError = IncidentError;
|
|
48
|
+
class ProviderScoreError extends ProviderBondError {
|
|
49
|
+
constructor(message, code, details) {
|
|
50
|
+
super(message, code, details);
|
|
51
|
+
this.name = 'ProviderScoreError';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.ProviderScoreError = ProviderScoreError;
|
|
55
|
+
class ProviderPolicyError extends ProviderBondError {
|
|
56
|
+
constructor(message, code, details) {
|
|
57
|
+
super(message, code, details);
|
|
58
|
+
this.name = 'ProviderPolicyError';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.ProviderPolicyError = ProviderPolicyError;
|
|
62
|
+
class ProviderRegistryError extends ProviderBondError {
|
|
63
|
+
constructor(message, code, details) {
|
|
64
|
+
super(message, code, details);
|
|
65
|
+
this.name = 'ProviderRegistryError';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.ProviderRegistryError = ProviderRegistryError;
|
|
69
|
+
class ProviderSerializationError extends ProviderBondError {
|
|
70
|
+
constructor(message, code, details) {
|
|
71
|
+
super(message, code, details);
|
|
72
|
+
this.name = 'ProviderSerializationError';
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.ProviderSerializationError = ProviderSerializationError;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ProviderBondVerifyResult, BindProviderManifestToIdentityParams, VerifyProviderManifestIdentityParams, VerifyProviderBondAddressesParams, AssertProviderControlsAddressParams } from './types.js';
|
|
2
|
+
export declare function bindProviderManifestToIdentity(params: BindProviderManifestToIdentityParams): unknown;
|
|
3
|
+
export declare function verifyProviderManifestIdentity(params: VerifyProviderManifestIdentityParams): ProviderBondVerifyResult;
|
|
4
|
+
export declare function verifyProviderBondAddresses(params: VerifyProviderBondAddressesParams): ProviderBondVerifyResult;
|
|
5
|
+
export declare function assertProviderControlsAddress(params: AssertProviderControlsAddressParams): ProviderBondVerifyResult;
|
package/dist/identity.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bindProviderManifestToIdentity = bindProviderManifestToIdentity;
|
|
4
|
+
exports.verifyProviderManifestIdentity = verifyProviderManifestIdentity;
|
|
5
|
+
exports.verifyProviderBondAddresses = verifyProviderBondAddresses;
|
|
6
|
+
exports.assertProviderControlsAddress = assertProviderControlsAddress;
|
|
7
|
+
function isIdentityGraph(value) {
|
|
8
|
+
if (!value || typeof value !== 'object')
|
|
9
|
+
return false;
|
|
10
|
+
const g = value;
|
|
11
|
+
return typeof g.document === 'object' && g.document !== null && Array.isArray(g.claims);
|
|
12
|
+
}
|
|
13
|
+
function getAuthorisedAddresses(identityGraph) {
|
|
14
|
+
if (!isIdentityGraph(identityGraph))
|
|
15
|
+
return [];
|
|
16
|
+
const addresses = new Set();
|
|
17
|
+
const doc = identityGraph.document;
|
|
18
|
+
if (doc.rootAddress)
|
|
19
|
+
addresses.add(doc.rootAddress);
|
|
20
|
+
if (doc.controllerAddress)
|
|
21
|
+
addresses.add(doc.controllerAddress);
|
|
22
|
+
for (const c of identityGraph.claims) {
|
|
23
|
+
if (c.claim.type === 'delegates_to' && c.proof?.address) {
|
|
24
|
+
addresses.add(c.proof.address);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return Array.from(addresses);
|
|
28
|
+
}
|
|
29
|
+
function bindProviderManifestToIdentity(params) {
|
|
30
|
+
return {
|
|
31
|
+
manifestId: params.manifest.edgeServiceManifestId,
|
|
32
|
+
identityGraph: params.identityGraph,
|
|
33
|
+
bound: true,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function verifyProviderManifestIdentity(params) {
|
|
37
|
+
const { manifest, identityGraph } = params;
|
|
38
|
+
if (!isIdentityGraph(identityGraph)) {
|
|
39
|
+
return { ok: false, reason: 'Invalid identity graph', code: 'IDENTITY_NOT_AUTHORISED' };
|
|
40
|
+
}
|
|
41
|
+
const signerAddress = manifest.signedEdgeService?.authorAddress;
|
|
42
|
+
if (!signerAddress) {
|
|
43
|
+
return { ok: false, reason: 'No signer address in manifest', code: 'IDENTITY_NOT_AUTHORISED' };
|
|
44
|
+
}
|
|
45
|
+
const authorised = getAuthorisedAddresses(identityGraph);
|
|
46
|
+
if (!authorised.includes(signerAddress)) {
|
|
47
|
+
return { ok: false, reason: 'Manifest signer is not authorised by identity', code: 'IDENTITY_NOT_AUTHORISED' };
|
|
48
|
+
}
|
|
49
|
+
return { ok: true, code: 'OK' };
|
|
50
|
+
}
|
|
51
|
+
function verifyProviderBondAddresses(params) {
|
|
52
|
+
const { manifest, identityGraph } = params;
|
|
53
|
+
if (!isIdentityGraph(identityGraph)) {
|
|
54
|
+
return { ok: false, reason: 'Invalid identity graph', code: 'IDENTITY_NOT_AUTHORISED' };
|
|
55
|
+
}
|
|
56
|
+
const authorised = getAuthorisedAddresses(identityGraph);
|
|
57
|
+
const pb = manifest.providerBond;
|
|
58
|
+
const checks = [
|
|
59
|
+
{ address: pb.bondOwnerAddress, code: 'BOND_OWNER_NOT_AUTHORISED', label: 'bond owner' },
|
|
60
|
+
{ address: pb.bondRecoveryAddress, code: 'BOND_RECOVERY_NOT_AUTHORISED', label: 'bond recovery' },
|
|
61
|
+
{ address: pb.probeSignerAddress, code: 'PROBE_SIGNER_NOT_AUTHORISED', label: 'probe signer' },
|
|
62
|
+
{ address: pb.incidentSignerAddress, code: 'INCIDENT_SIGNER_NOT_AUTHORISED', label: 'incident signer' },
|
|
63
|
+
{ address: pb.scoreSignerAddress, code: 'SCORE_SIGNER_NOT_AUTHORISED', label: 'score signer' },
|
|
64
|
+
];
|
|
65
|
+
for (const check of checks) {
|
|
66
|
+
if (check.address && !authorised.includes(check.address)) {
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
reason: `${check.label} address is not authorised by identity`,
|
|
70
|
+
code: check.code,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { ok: true, code: 'OK' };
|
|
75
|
+
}
|
|
76
|
+
function assertProviderControlsAddress(params) {
|
|
77
|
+
const { manifest, address, identityGraph } = params;
|
|
78
|
+
if (!isIdentityGraph(identityGraph)) {
|
|
79
|
+
return { ok: false, reason: 'Invalid identity graph', code: 'IDENTITY_NOT_AUTHORISED' };
|
|
80
|
+
}
|
|
81
|
+
const authorised = getAuthorisedAddresses(identityGraph);
|
|
82
|
+
if (!authorised.includes(address)) {
|
|
83
|
+
return { ok: false, reason: 'Address is not authorised by identity', code: 'IDENTITY_NOT_AUTHORISED' };
|
|
84
|
+
}
|
|
85
|
+
return { ok: true, code: 'OK' };
|
|
86
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IncidentRecord, RecordIncidentParams } from './types.js';
|
|
2
|
+
export declare function recordIncident(params: RecordIncidentParams): IncidentRecord;
|
|
3
|
+
export declare function acknowledgeIncident(incident: IncidentRecord, now?: number): IncidentRecord;
|
|
4
|
+
export declare function resolveIncident(incident: IncidentRecord, now?: number): IncidentRecord;
|
|
5
|
+
export declare function rejectIncident(incident: IncidentRecord, reason: string, now?: number): IncidentRecord;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.recordIncident = recordIncident;
|
|
4
|
+
exports.acknowledgeIncident = acknowledgeIncident;
|
|
5
|
+
exports.resolveIncident = resolveIncident;
|
|
6
|
+
exports.rejectIncident = rejectIncident;
|
|
7
|
+
let incidentCounter = 0;
|
|
8
|
+
function recordIncident(params) {
|
|
9
|
+
const now = params.now ?? Date.now();
|
|
10
|
+
incidentCounter++;
|
|
11
|
+
return {
|
|
12
|
+
incidentId: `incident-${now}-${incidentCounter}`,
|
|
13
|
+
providerId: params.providerId,
|
|
14
|
+
type: params.type,
|
|
15
|
+
severity: params.severity,
|
|
16
|
+
status: 'open',
|
|
17
|
+
createdAt: now,
|
|
18
|
+
message: params.message,
|
|
19
|
+
metadata: params.metadata,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function acknowledgeIncident(incident, now) {
|
|
23
|
+
return {
|
|
24
|
+
...incident,
|
|
25
|
+
status: 'acknowledged',
|
|
26
|
+
resolvedAt: now ?? Date.now(),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function resolveIncident(incident, now) {
|
|
30
|
+
return {
|
|
31
|
+
...incident,
|
|
32
|
+
status: 'resolved',
|
|
33
|
+
resolvedAt: now ?? Date.now(),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function rejectIncident(incident, reason, now) {
|
|
37
|
+
return {
|
|
38
|
+
...incident,
|
|
39
|
+
status: 'rejected',
|
|
40
|
+
resolvedAt: now ?? Date.now(),
|
|
41
|
+
message: incident.message ? `${incident.message} (rejected: ${reason})` : `Rejected: ${reason}`,
|
|
42
|
+
};
|
|
43
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type { BondAsset, BondPurpose, BondStatus, BondLockType, ProviderBondVerifyCode, ProviderRecommendation, ProbeType, IncidentType, IncidentSeverity, IncidentStatus, BondProofType, ProviderBondVerifyResult, BondStatusContext, ProviderBondAssetDeclaration, BondProofRef, ProviderBondExtension, ProviderBondManifest, ProviderScore, IncidentSummary, ProbeResult, IncidentRecord, ProviderPolicy, PolicyMatch, ProviderBondRegistryState, ProviderScoringWeights, ComputeProviderScoreParams, CreateProviderBondManifestParams, VerifyProviderBondManifestParams, BindProviderManifestToIdentityParams, VerifyProviderManifestIdentityParams, VerifyProviderBondAddressesParams, AssertProviderControlsAddressParams, BondProofVerifier, VerifyBondStackParams, RecordProbeParams, RecordIncidentParams, } from './types.js';
|
|
2
|
+
export { ProviderBondError, ProviderManifestError, ProviderIdentityError, BondProofError, ProbeError, IncidentError, ProviderScoreError, ProviderPolicyError, ProviderRegistryError, ProviderSerializationError, } from './errors.js';
|
|
3
|
+
export { DEFAULT_MINIMA_TOKEN_ID, PROVIDER_BOND_TOPIC_PREFIX, DEFAULT_PROVIDER_SCORING_WEIGHTS, } from './constants.js';
|
|
4
|
+
export { serializeProviderBondState, parseProviderBondState, serializeProviderBondRecord, parseProviderBondRecord, } from './serialization.js';
|
|
5
|
+
export { createProviderBondManifest, computeProviderBondExtensionHash, computeProviderBondManifestHash, verifyProviderBondManifest, assertManifestNotExpired, } from './manifest.js';
|
|
6
|
+
export { bindProviderManifestToIdentity, verifyProviderManifestIdentity, verifyProviderBondAddresses, assertProviderControlsAddress, } from './identity.js';
|
|
7
|
+
export { verifyBondProof, assertBondMeetsMinimum, verifyBondStack, } from './bond-proof.js';
|
|
8
|
+
export { recordProbe, recordHeartbeat, } from './probes.js';
|
|
9
|
+
export { recordIncident, acknowledgeIncident, resolveIncident, rejectIncident, } from './incidents.js';
|
|
10
|
+
export { computeProviderScore, computeProviderRecommendation, } from './scoring.js';
|
|
11
|
+
export { filterProvidersByPolicy, rankProvidersByPolicy, explainProviderPolicyMatch, } from './policy.js';
|
|
12
|
+
export { createEmptyProviderBondRegistryState, registerProvider, updateProviderManifest, attachBondProof, recordProviderProbe, recordProviderIncident, updateProviderScore, listProviders, getProvider, listProvidersByServiceType, listRiskyProviders, listOfflineProviders, } from './registry.js';
|
|
13
|
+
export { MemoryProviderBondStore } from './memory-store.js';
|