@uvrn/adapter 1.0.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/dist/index.d.ts +4 -0
- package/dist/index.js +7 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.js +36 -0
- package/dist/src/signer.d.ts +27 -0
- package/dist/src/signer.js +45 -0
- package/dist/src/types.d.ts +94 -0
- package/dist/src/types.js +8 -0
- package/dist/src/validator.d.ts +17 -0
- package/dist/src/validator.js +82 -0
- package/dist/src/wrapper.d.ts +41 -0
- package/dist/src/wrapper.js +92 -0
- package/dist/tests/integration.test.d.ts +5 -0
- package/dist/tests/integration.test.js +105 -0
- package/dist/tests/wrapper.test.d.ts +5 -0
- package/dist/tests/wrapper.test.js +96 -0
- package/jest.config.js +12 -0
- package/package.json +36 -0
- package/schemas/drvc3.schema.json +115 -0
- package/src/index.ts +16 -0
- package/src/signer.ts +47 -0
- package/src/types.ts +102 -0
- package/src/validator.ts +53 -0
- package/src/wrapper.ts +103 -0
- package/tests/integration.test.ts +123 -0
- package/tests/wrapper.test.ts +115 -0
- package/tsconfig.json +21 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loosechain UVRN Adapter
|
|
3
|
+
* Layer 2 - Wraps Delta Engine Core receipts in DRVC3 envelopes
|
|
4
|
+
*/
|
|
5
|
+
export * from './types';
|
|
6
|
+
export { wrapInDRVC3, extractDeltaReceipt } from './wrapper';
|
|
7
|
+
export { signHash, recoverSigner, verifySignature } from './signer';
|
|
8
|
+
export { validateDRVC3, isDRVC3Receipt } from './validator';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Loosechain UVRN Adapter
|
|
4
|
+
* Layer 2 - Wraps Delta Engine Core receipts in DRVC3 envelopes
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
18
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.isDRVC3Receipt = exports.validateDRVC3 = exports.verifySignature = exports.recoverSigner = exports.signHash = exports.extractDeltaReceipt = exports.wrapInDRVC3 = void 0;
|
|
22
|
+
// Types
|
|
23
|
+
__exportStar(require("./types"), exports);
|
|
24
|
+
// Core wrapper
|
|
25
|
+
var wrapper_1 = require("./wrapper");
|
|
26
|
+
Object.defineProperty(exports, "wrapInDRVC3", { enumerable: true, get: function () { return wrapper_1.wrapInDRVC3; } });
|
|
27
|
+
Object.defineProperty(exports, "extractDeltaReceipt", { enumerable: true, get: function () { return wrapper_1.extractDeltaReceipt; } });
|
|
28
|
+
// Signing utilities
|
|
29
|
+
var signer_1 = require("./signer");
|
|
30
|
+
Object.defineProperty(exports, "signHash", { enumerable: true, get: function () { return signer_1.signHash; } });
|
|
31
|
+
Object.defineProperty(exports, "recoverSigner", { enumerable: true, get: function () { return signer_1.recoverSigner; } });
|
|
32
|
+
Object.defineProperty(exports, "verifySignature", { enumerable: true, get: function () { return signer_1.verifySignature; } });
|
|
33
|
+
// Validation
|
|
34
|
+
var validator_1 = require("./validator");
|
|
35
|
+
Object.defineProperty(exports, "validateDRVC3", { enumerable: true, get: function () { return validator_1.validateDRVC3; } });
|
|
36
|
+
Object.defineProperty(exports, "isDRVC3Receipt", { enumerable: true, get: function () { return validator_1.isDRVC3Receipt; } });
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EIP-191 Signing Utilities
|
|
3
|
+
* Provides Ethereum personal message signing for DRVC3 receipts
|
|
4
|
+
*/
|
|
5
|
+
import { Wallet, HDNodeWallet } from 'ethers';
|
|
6
|
+
/**
|
|
7
|
+
* Signs a hash using EIP-191 (Ethereum Signed Message)
|
|
8
|
+
* @param hash - The hex string hash to sign
|
|
9
|
+
* @param wallet - ethers Wallet instance with private key
|
|
10
|
+
* @returns Promise resolving to the signature hex string
|
|
11
|
+
*/
|
|
12
|
+
export declare function signHash(hash: string, wallet: Wallet | HDNodeWallet): Promise<string>;
|
|
13
|
+
/**
|
|
14
|
+
* Recovers the signer address from a hash and signature
|
|
15
|
+
* @param hash - The original hash that was signed
|
|
16
|
+
* @param signature - The EIP-191 signature
|
|
17
|
+
* @returns The signer's Ethereum address
|
|
18
|
+
*/
|
|
19
|
+
export declare function recoverSigner(hash: string, signature: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Verifies that a signature was created by the expected signer
|
|
22
|
+
* @param hash - The original hash that was signed
|
|
23
|
+
* @param signature - The EIP-191 signature
|
|
24
|
+
* @param expectedAddress - The expected signer address
|
|
25
|
+
* @returns True if the signature is valid and matches the expected address
|
|
26
|
+
*/
|
|
27
|
+
export declare function verifySignature(hash: string, signature: string, expectedAddress: string): boolean;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* EIP-191 Signing Utilities
|
|
4
|
+
* Provides Ethereum personal message signing for DRVC3 receipts
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.signHash = signHash;
|
|
8
|
+
exports.recoverSigner = recoverSigner;
|
|
9
|
+
exports.verifySignature = verifySignature;
|
|
10
|
+
const ethers_1 = require("ethers");
|
|
11
|
+
/**
|
|
12
|
+
* Signs a hash using EIP-191 (Ethereum Signed Message)
|
|
13
|
+
* @param hash - The hex string hash to sign
|
|
14
|
+
* @param wallet - ethers Wallet instance with private key
|
|
15
|
+
* @returns Promise resolving to the signature hex string
|
|
16
|
+
*/
|
|
17
|
+
async function signHash(hash, wallet) {
|
|
18
|
+
// signMessage automatically prefixes with "\x19Ethereum Signed Message:\n" + message length
|
|
19
|
+
return wallet.signMessage(hash);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Recovers the signer address from a hash and signature
|
|
23
|
+
* @param hash - The original hash that was signed
|
|
24
|
+
* @param signature - The EIP-191 signature
|
|
25
|
+
* @returns The signer's Ethereum address
|
|
26
|
+
*/
|
|
27
|
+
function recoverSigner(hash, signature) {
|
|
28
|
+
return (0, ethers_1.verifyMessage)(hash, signature);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Verifies that a signature was created by the expected signer
|
|
32
|
+
* @param hash - The original hash that was signed
|
|
33
|
+
* @param signature - The EIP-191 signature
|
|
34
|
+
* @param expectedAddress - The expected signer address
|
|
35
|
+
* @returns True if the signature is valid and matches the expected address
|
|
36
|
+
*/
|
|
37
|
+
function verifySignature(hash, signature, expectedAddress) {
|
|
38
|
+
try {
|
|
39
|
+
const recoveredAddress = recoverSigner(hash, signature);
|
|
40
|
+
return recoveredAddress.toLowerCase() === expectedAddress.toLowerCase();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DRVC3 Types for UVRN Adapter (v1.01)
|
|
3
|
+
* Layer 2 envelope types that wrap Layer 1 DeltaReceipt
|
|
4
|
+
*
|
|
5
|
+
* v1.01 adds the `extensions` field for Layer 2 provenance data.
|
|
6
|
+
*/
|
|
7
|
+
import { DeltaReceipt } from '@uvrn/core';
|
|
8
|
+
/**
|
|
9
|
+
* DRVC3 Integrity block - contains hash and signature data
|
|
10
|
+
*/
|
|
11
|
+
export interface DRVC3Integrity {
|
|
12
|
+
hash_algorithm: 'sha256';
|
|
13
|
+
hash: string;
|
|
14
|
+
signature_method: 'eip191';
|
|
15
|
+
signature: string;
|
|
16
|
+
signer_address: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* DRVC3 Validation block - contains score and embedded checks
|
|
20
|
+
*/
|
|
21
|
+
export interface DRVC3Validation {
|
|
22
|
+
v_score: number;
|
|
23
|
+
checks: {
|
|
24
|
+
delta_receipt: DeltaReceipt;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* DRVC3 Resource block (optional) - describes the verified resource
|
|
30
|
+
*/
|
|
31
|
+
export interface DRVC3Resource {
|
|
32
|
+
type?: string;
|
|
33
|
+
url?: string;
|
|
34
|
+
branch?: string;
|
|
35
|
+
commit_hash?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Block state - "loose" means mutable/portable, "blocked" means canonized/permanent
|
|
39
|
+
*/
|
|
40
|
+
export type BlockState = 'loose' | 'blocked';
|
|
41
|
+
/**
|
|
42
|
+
* Full DRVC3 Receipt Envelope
|
|
43
|
+
* Wraps Layer 1 DeltaReceipt with protocol metadata and signatures
|
|
44
|
+
*/
|
|
45
|
+
export interface DRVC3Receipt {
|
|
46
|
+
receipt_id: string;
|
|
47
|
+
issuer: string;
|
|
48
|
+
event: string;
|
|
49
|
+
timestamp: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
resource?: DRVC3Resource;
|
|
52
|
+
integrity: DRVC3Integrity;
|
|
53
|
+
validation: DRVC3Validation;
|
|
54
|
+
block_state: BlockState;
|
|
55
|
+
certificate: string;
|
|
56
|
+
replay_instructions?: Record<string, unknown>;
|
|
57
|
+
tags?: string[];
|
|
58
|
+
/**
|
|
59
|
+
* Layer 2 extension data — provenance, evidence, domain-specific metadata.
|
|
60
|
+
* This field is NOT covered by the L1 integrity hash. It is envelope metadata
|
|
61
|
+
* owned by the consumer chain (e.g., MarketChain source URLs, evidence links).
|
|
62
|
+
*/
|
|
63
|
+
extensions?: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Options for wrapping a DeltaReceipt in DRVC3 envelope
|
|
67
|
+
*/
|
|
68
|
+
export interface WrapOptions {
|
|
69
|
+
/** Issuer identifier (e.g., "uvrn", "app.example.com") */
|
|
70
|
+
issuer: string;
|
|
71
|
+
/** Event type (e.g., "delta-reconciliation") */
|
|
72
|
+
event: string;
|
|
73
|
+
/** Block state - defaults to "loose" */
|
|
74
|
+
blockState?: BlockState;
|
|
75
|
+
/** DRVC3 certificate version - defaults to "DRVC3 v1.0" */
|
|
76
|
+
certificate?: string;
|
|
77
|
+
/** Optional description */
|
|
78
|
+
description?: string;
|
|
79
|
+
/** Optional resource metadata */
|
|
80
|
+
resource?: DRVC3Resource;
|
|
81
|
+
/** Optional replay instructions */
|
|
82
|
+
replayInstructions?: Record<string, unknown>;
|
|
83
|
+
/** Optional tags (e.g., ["#uvrn", "#receipt"]) */
|
|
84
|
+
tags?: string[];
|
|
85
|
+
/** Optional Layer 2 extension data (provenance, evidence, domain metadata) */
|
|
86
|
+
extensions?: Record<string, unknown>;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Validation result from schema validation
|
|
90
|
+
*/
|
|
91
|
+
export interface DRVC3ValidationResult {
|
|
92
|
+
valid: boolean;
|
|
93
|
+
errors?: string[];
|
|
94
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DRVC3 Schema Validator
|
|
3
|
+
* Uses ajv to validate DRVC3 receipts against the official schema
|
|
4
|
+
*/
|
|
5
|
+
import { DRVC3ValidationResult } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Validates a DRVC3 receipt against the official schema
|
|
8
|
+
* @param receipt - The receipt object to validate
|
|
9
|
+
* @returns Validation result with errors if invalid
|
|
10
|
+
*/
|
|
11
|
+
export declare function validateDRVC3(receipt: unknown): DRVC3ValidationResult;
|
|
12
|
+
/**
|
|
13
|
+
* Type guard to check if an object is a valid DRVC3 receipt
|
|
14
|
+
* @param obj - Object to check
|
|
15
|
+
* @returns True if the object is a valid DRVC3 receipt
|
|
16
|
+
*/
|
|
17
|
+
export declare function isDRVC3Receipt(obj: unknown): boolean;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DRVC3 Schema Validator
|
|
4
|
+
* Uses ajv to validate DRVC3 receipts against the official schema
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
40
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
41
|
+
};
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.validateDRVC3 = validateDRVC3;
|
|
44
|
+
exports.isDRVC3Receipt = isDRVC3Receipt;
|
|
45
|
+
const ajv_1 = __importDefault(require("ajv"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const fs = __importStar(require("fs"));
|
|
48
|
+
// Load schema from file
|
|
49
|
+
const schemaPath = path.join(__dirname, '../schemas/drvc3.schema.json');
|
|
50
|
+
const drvc3Schema = JSON.parse(fs.readFileSync(schemaPath, 'utf-8'));
|
|
51
|
+
// Initialize Ajv with JSON Schema 2020-12 support
|
|
52
|
+
const ajv = new ajv_1.default({ strict: false });
|
|
53
|
+
// Add formats support (date-time, etc.)
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
55
|
+
const addFormats = require('ajv-formats');
|
|
56
|
+
addFormats(ajv);
|
|
57
|
+
// Compile the schema once
|
|
58
|
+
const validateSchema = ajv.compile(drvc3Schema);
|
|
59
|
+
/**
|
|
60
|
+
* Validates a DRVC3 receipt against the official schema
|
|
61
|
+
* @param receipt - The receipt object to validate
|
|
62
|
+
* @returns Validation result with errors if invalid
|
|
63
|
+
*/
|
|
64
|
+
function validateDRVC3(receipt) {
|
|
65
|
+
const valid = validateSchema(receipt);
|
|
66
|
+
if (valid) {
|
|
67
|
+
return { valid: true };
|
|
68
|
+
}
|
|
69
|
+
const errors = validateSchema.errors?.map(err => {
|
|
70
|
+
const path = err.instancePath || '/';
|
|
71
|
+
return `${path}: ${err.message}`;
|
|
72
|
+
}) || ['Unknown validation error'];
|
|
73
|
+
return { valid: false, errors };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Type guard to check if an object is a valid DRVC3 receipt
|
|
77
|
+
* @param obj - Object to check
|
|
78
|
+
* @returns True if the object is a valid DRVC3 receipt
|
|
79
|
+
*/
|
|
80
|
+
function isDRVC3Receipt(obj) {
|
|
81
|
+
return validateDRVC3(obj).valid;
|
|
82
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DRVC3 Wrapper
|
|
3
|
+
* Wraps Layer 1 DeltaReceipt in a DRVC3 envelope with EIP-191 signatures
|
|
4
|
+
*
|
|
5
|
+
* Key Principle: The DeltaReceipt hash is READ-ONLY from Layer 1.
|
|
6
|
+
* DRVC3 envelope fields (receipt_id, timestamp, signature) are envelope metadata
|
|
7
|
+
* and do NOT affect determinism or replay.
|
|
8
|
+
*/
|
|
9
|
+
import { DeltaReceipt } from '@uvrn/core';
|
|
10
|
+
import { Wallet, HDNodeWallet } from 'ethers';
|
|
11
|
+
import { DRVC3Receipt, WrapOptions } from './types';
|
|
12
|
+
/**
|
|
13
|
+
* Wraps a DeltaReceipt in a DRVC3 envelope
|
|
14
|
+
*
|
|
15
|
+
* @param deltaReceipt - Layer 1 DeltaReceipt (deterministic, hash-covered)
|
|
16
|
+
* @param signer - ethers Wallet for EIP-191 signing
|
|
17
|
+
* @param options - Envelope options (issuer, event, etc.)
|
|
18
|
+
* @returns Promise resolving to complete DRVC3 receipt
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import { runDeltaEngine } from '@uvrn/core';
|
|
23
|
+
* import { wrapInDRVC3 } from '@uvrn/adapter';
|
|
24
|
+
* import { Wallet } from 'ethers';
|
|
25
|
+
*
|
|
26
|
+
* const deltaReceipt = runDeltaEngine(bundle);
|
|
27
|
+
* const wallet = new Wallet(privateKey);
|
|
28
|
+
* const drvc3 = await wrapInDRVC3(deltaReceipt, wallet, {
|
|
29
|
+
* issuer: 'uvrn',
|
|
30
|
+
* event: 'delta-reconciliation'
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function wrapInDRVC3(deltaReceipt: DeltaReceipt, signer: Wallet | HDNodeWallet, options: WrapOptions): Promise<DRVC3Receipt>;
|
|
35
|
+
/**
|
|
36
|
+
* Extracts the original DeltaReceipt from a DRVC3 envelope
|
|
37
|
+
*
|
|
38
|
+
* @param drvc3 - DRVC3 receipt envelope
|
|
39
|
+
* @returns The embedded DeltaReceipt
|
|
40
|
+
*/
|
|
41
|
+
export declare function extractDeltaReceipt(drvc3: DRVC3Receipt): DeltaReceipt;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DRVC3 Wrapper
|
|
4
|
+
* Wraps Layer 1 DeltaReceipt in a DRVC3 envelope with EIP-191 signatures
|
|
5
|
+
*
|
|
6
|
+
* Key Principle: The DeltaReceipt hash is READ-ONLY from Layer 1.
|
|
7
|
+
* DRVC3 envelope fields (receipt_id, timestamp, signature) are envelope metadata
|
|
8
|
+
* and do NOT affect determinism or replay.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.wrapInDRVC3 = wrapInDRVC3;
|
|
12
|
+
exports.extractDeltaReceipt = extractDeltaReceipt;
|
|
13
|
+
const signer_1 = require("./signer");
|
|
14
|
+
/**
|
|
15
|
+
* Wraps a DeltaReceipt in a DRVC3 envelope
|
|
16
|
+
*
|
|
17
|
+
* @param deltaReceipt - Layer 1 DeltaReceipt (deterministic, hash-covered)
|
|
18
|
+
* @param signer - ethers Wallet for EIP-191 signing
|
|
19
|
+
* @param options - Envelope options (issuer, event, etc.)
|
|
20
|
+
* @returns Promise resolving to complete DRVC3 receipt
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import { runDeltaEngine } from '@uvrn/core';
|
|
25
|
+
* import { wrapInDRVC3 } from '@uvrn/adapter';
|
|
26
|
+
* import { Wallet } from 'ethers';
|
|
27
|
+
*
|
|
28
|
+
* const deltaReceipt = runDeltaEngine(bundle);
|
|
29
|
+
* const wallet = new Wallet(privateKey);
|
|
30
|
+
* const drvc3 = await wrapInDRVC3(deltaReceipt, wallet, {
|
|
31
|
+
* issuer: 'uvrn',
|
|
32
|
+
* event: 'delta-reconciliation'
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
async function wrapInDRVC3(deltaReceipt, signer, options) {
|
|
37
|
+
// 1. Generate receipt_id (ENVELOPE METADATA - non-deterministic, intentional)
|
|
38
|
+
const timestamp = new Date().toISOString();
|
|
39
|
+
const receipt_id = `drvc3-${deltaReceipt.bundleId}-${Date.now()}`;
|
|
40
|
+
// 2. Read hash from DeltaReceipt (HASH DOMAIN - read-only from Layer 1)
|
|
41
|
+
const hash = deltaReceipt.hash;
|
|
42
|
+
// 3. Sign hash with EIP-191 (ENVELOPE METADATA - certifies "who" and "when")
|
|
43
|
+
const signature = await (0, signer_1.signHash)(hash, signer);
|
|
44
|
+
// 4. Construct DRVC3 envelope
|
|
45
|
+
const drvc3 = {
|
|
46
|
+
receipt_id,
|
|
47
|
+
issuer: options.issuer,
|
|
48
|
+
event: options.event,
|
|
49
|
+
timestamp,
|
|
50
|
+
integrity: {
|
|
51
|
+
hash_algorithm: 'sha256',
|
|
52
|
+
hash,
|
|
53
|
+
signature_method: 'eip191',
|
|
54
|
+
signature,
|
|
55
|
+
signer_address: signer.address
|
|
56
|
+
},
|
|
57
|
+
validation: {
|
|
58
|
+
v_score: deltaReceipt.deltaFinal,
|
|
59
|
+
checks: {
|
|
60
|
+
delta_receipt: deltaReceipt
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
block_state: options.blockState || 'loose',
|
|
64
|
+
certificate: options.certificate || 'DRVC3 v1.01'
|
|
65
|
+
};
|
|
66
|
+
// Add optional fields if provided
|
|
67
|
+
if (options.description) {
|
|
68
|
+
drvc3.description = options.description;
|
|
69
|
+
}
|
|
70
|
+
if (options.resource) {
|
|
71
|
+
drvc3.resource = options.resource;
|
|
72
|
+
}
|
|
73
|
+
if (options.replayInstructions) {
|
|
74
|
+
drvc3.replay_instructions = options.replayInstructions;
|
|
75
|
+
}
|
|
76
|
+
if (options.extensions) {
|
|
77
|
+
drvc3.extensions = options.extensions;
|
|
78
|
+
}
|
|
79
|
+
if (options.tags) {
|
|
80
|
+
drvc3.tags = options.tags;
|
|
81
|
+
}
|
|
82
|
+
return drvc3;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Extracts the original DeltaReceipt from a DRVC3 envelope
|
|
86
|
+
*
|
|
87
|
+
* @param drvc3 - DRVC3 receipt envelope
|
|
88
|
+
* @returns The embedded DeltaReceipt
|
|
89
|
+
*/
|
|
90
|
+
function extractDeltaReceipt(drvc3) {
|
|
91
|
+
return drvc3.validation.checks.delta_receipt;
|
|
92
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Integration Tests
|
|
4
|
+
* Tests the full flow from DeltaBundle → DeltaReceipt → DRVC3Receipt
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const ethers_1 = require("ethers");
|
|
8
|
+
const core_1 = require("@uvrn/core");
|
|
9
|
+
const src_1 = require("../src");
|
|
10
|
+
describe('Integration: Layer 1 → Layer 2', () => {
|
|
11
|
+
let testWallet;
|
|
12
|
+
beforeAll(() => {
|
|
13
|
+
testWallet = ethers_1.Wallet.createRandom();
|
|
14
|
+
});
|
|
15
|
+
it('should complete full flow: bundle → receipt → DRVC3', async () => {
|
|
16
|
+
// 1. Create a DeltaBundle (input to Layer 1)
|
|
17
|
+
const bundle = {
|
|
18
|
+
bundleId: 'integration-test-001',
|
|
19
|
+
claim: 'Integration Test',
|
|
20
|
+
thresholdPct: 0.1,
|
|
21
|
+
dataSpecs: [
|
|
22
|
+
{
|
|
23
|
+
id: 'source-1',
|
|
24
|
+
label: 'Source 1',
|
|
25
|
+
sourceKind: 'metric',
|
|
26
|
+
originDocIds: ['doc-1'],
|
|
27
|
+
metrics: [
|
|
28
|
+
{ key: 'revenue', value: 1000 },
|
|
29
|
+
{ key: 'users', value: 500 }
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'source-2',
|
|
34
|
+
label: 'Source 2',
|
|
35
|
+
sourceKind: 'metric',
|
|
36
|
+
originDocIds: ['doc-2'],
|
|
37
|
+
metrics: [
|
|
38
|
+
{ key: 'revenue', value: 1050 },
|
|
39
|
+
{ key: 'users', value: 510 }
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
};
|
|
44
|
+
// 2. Run Layer 1 Engine
|
|
45
|
+
const deltaReceipt = (0, core_1.runDeltaEngine)(bundle);
|
|
46
|
+
// Verify Layer 1 receipt
|
|
47
|
+
const verifyResult = (0, core_1.verifyReceipt)(deltaReceipt);
|
|
48
|
+
expect(verifyResult.verified).toBe(true);
|
|
49
|
+
// 3. Wrap in DRVC3 (Layer 2)
|
|
50
|
+
const drvc3 = await (0, src_1.wrapInDRVC3)(deltaReceipt, testWallet, {
|
|
51
|
+
issuer: 'uvrn-integration',
|
|
52
|
+
event: 'delta-reconciliation',
|
|
53
|
+
tags: ['#uvrn', '#integration-test']
|
|
54
|
+
});
|
|
55
|
+
// 4. Validate DRVC3 schema
|
|
56
|
+
const schemaResult = (0, src_1.validateDRVC3)(drvc3);
|
|
57
|
+
expect(schemaResult.valid).toBe(true);
|
|
58
|
+
// 5. Verify hash chain integrity
|
|
59
|
+
expect(drvc3.integrity.hash).toBe(deltaReceipt.hash);
|
|
60
|
+
// 6. Extract and verify embedded receipt
|
|
61
|
+
const extracted = (0, src_1.extractDeltaReceipt)(drvc3);
|
|
62
|
+
expect(extracted.hash).toBe(deltaReceipt.hash);
|
|
63
|
+
expect((0, core_1.verifyReceipt)(extracted).verified).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
it('should maintain hash integrity through Layer 2 wrapping', async () => {
|
|
66
|
+
const bundle = {
|
|
67
|
+
bundleId: 'hash-integrity-test',
|
|
68
|
+
claim: 'Hash Test',
|
|
69
|
+
thresholdPct: 0.05,
|
|
70
|
+
dataSpecs: [
|
|
71
|
+
{
|
|
72
|
+
id: 'a',
|
|
73
|
+
label: 'A',
|
|
74
|
+
sourceKind: 'metric',
|
|
75
|
+
originDocIds: [],
|
|
76
|
+
metrics: [{ key: 'val', value: 100 }]
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'b',
|
|
80
|
+
label: 'B',
|
|
81
|
+
sourceKind: 'metric',
|
|
82
|
+
originDocIds: [],
|
|
83
|
+
metrics: [{ key: 'val', value: 100 }]
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
};
|
|
87
|
+
const receipt = (0, core_1.runDeltaEngine)(bundle);
|
|
88
|
+
const originalHash = receipt.hash;
|
|
89
|
+
// Wrap multiple times - hash should always match
|
|
90
|
+
const drvc3_1 = await (0, src_1.wrapInDRVC3)(receipt, testWallet, {
|
|
91
|
+
issuer: 'test',
|
|
92
|
+
event: 'test'
|
|
93
|
+
});
|
|
94
|
+
const drvc3_2 = await (0, src_1.wrapInDRVC3)(receipt, testWallet, {
|
|
95
|
+
issuer: 'test',
|
|
96
|
+
event: 'test'
|
|
97
|
+
});
|
|
98
|
+
// Envelope metadata differs (receipt_id, timestamp)
|
|
99
|
+
expect(drvc3_1.receipt_id).not.toBe(drvc3_2.receipt_id);
|
|
100
|
+
expect(drvc3_1.timestamp).not.toBe(drvc3_2.timestamp);
|
|
101
|
+
// But hash domain remains identical
|
|
102
|
+
expect(drvc3_1.integrity.hash).toBe(originalHash);
|
|
103
|
+
expect(drvc3_2.integrity.hash).toBe(originalHash);
|
|
104
|
+
});
|
|
105
|
+
});
|