@sip-protocol/sdk 0.7.3 → 0.8.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/README.md +267 -0
- package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
- package/dist/browser.d.mts +10 -4
- package/dist/browser.d.ts +10 -4
- package/dist/browser.js +47556 -19603
- package/dist/browser.mjs +628 -48
- package/dist/chunk-4GRJ5MAW.mjs +152 -0
- package/dist/chunk-5D7A3L3W.mjs +717 -0
- package/dist/chunk-64AYA5F5.mjs +7834 -0
- package/dist/chunk-GMDGB22A.mjs +379 -0
- package/dist/chunk-I534WKN7.mjs +328 -0
- package/dist/chunk-IBZVA5Y7.mjs +1003 -0
- package/dist/chunk-PRRZAWJE.mjs +223 -0
- package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
- package/dist/{chunk-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
- package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
- package/dist/constants-LHAAUC2T.mjs +51 -0
- package/dist/dist-2OGQ7FED.mjs +3957 -0
- package/dist/dist-IFHPYLDX.mjs +254 -0
- package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
- package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
- package/dist/{index-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
- package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +48396 -19623
- package/dist/index.mjs +537 -19
- package/dist/interface-Bf7w1PLW.d.mts +679 -0
- package/dist/interface-Bf7w1PLW.d.ts +679 -0
- package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
- package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
- package/dist/proofs/halo2.d.mts +151 -0
- package/dist/proofs/halo2.d.ts +151 -0
- package/dist/proofs/halo2.js +350 -0
- package/dist/proofs/halo2.mjs +11 -0
- package/dist/proofs/kimchi.d.mts +160 -0
- package/dist/proofs/kimchi.d.ts +160 -0
- package/dist/proofs/kimchi.js +431 -0
- package/dist/proofs/kimchi.mjs +13 -0
- package/dist/proofs/noir.d.mts +1 -1
- package/dist/proofs/noir.d.ts +1 -1
- package/dist/proofs/noir.js +74 -18
- package/dist/proofs/noir.mjs +84 -24
- package/dist/solana-U3MEGU7W.mjs +280 -0
- package/dist/validity_proof-3POXLPNY.mjs +21 -0
- package/package.json +44 -11
- package/src/adapters/index.ts +41 -0
- package/src/adapters/jupiter.ts +571 -0
- package/src/adapters/near-intents.ts +135 -0
- package/src/advisor/advisor.ts +653 -0
- package/src/advisor/index.ts +54 -0
- package/src/advisor/tools.ts +303 -0
- package/src/advisor/types.ts +164 -0
- package/src/chains/ethereum/announcement.ts +536 -0
- package/src/chains/ethereum/bnb-optimizations.ts +474 -0
- package/src/chains/ethereum/commitment.ts +522 -0
- package/src/chains/ethereum/constants.ts +462 -0
- package/src/chains/ethereum/deployment.ts +596 -0
- package/src/chains/ethereum/gas-estimation.ts +538 -0
- package/src/chains/ethereum/index.ts +268 -0
- package/src/chains/ethereum/optimizations.ts +614 -0
- package/src/chains/ethereum/privacy-adapter.ts +855 -0
- package/src/chains/ethereum/registry.ts +584 -0
- package/src/chains/ethereum/rpc.ts +905 -0
- package/src/chains/ethereum/stealth.ts +491 -0
- package/src/chains/ethereum/token.ts +790 -0
- package/src/chains/ethereum/transfer.ts +637 -0
- package/src/chains/ethereum/types.ts +456 -0
- package/src/chains/ethereum/viewing-key.ts +455 -0
- package/src/chains/near/commitment.ts +608 -0
- package/src/chains/near/constants.ts +284 -0
- package/src/chains/near/function-call.ts +871 -0
- package/src/chains/near/history.ts +654 -0
- package/src/chains/near/implicit-account.ts +840 -0
- package/src/chains/near/index.ts +393 -0
- package/src/chains/near/native-transfer.ts +658 -0
- package/src/chains/near/nep141.ts +775 -0
- package/src/chains/near/privacy-adapter.ts +889 -0
- package/src/chains/near/resolver.ts +971 -0
- package/src/chains/near/rpc.ts +1016 -0
- package/src/chains/near/stealth.ts +419 -0
- package/src/chains/near/types.ts +317 -0
- package/src/chains/near/viewing-key.ts +876 -0
- package/src/chains/solana/anchor-transfer.ts +386 -0
- package/src/chains/solana/commitment.ts +577 -0
- package/src/chains/solana/constants.ts +126 -12
- package/src/chains/solana/ephemeral-keys.ts +543 -0
- package/src/chains/solana/index.ts +252 -1
- package/src/chains/solana/key-derivation.ts +418 -0
- package/src/chains/solana/kit-compat.ts +334 -0
- package/src/chains/solana/optimizations.ts +560 -0
- package/src/chains/solana/privacy-adapter.ts +605 -0
- package/src/chains/solana/providers/generic.ts +47 -6
- package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
- package/src/chains/solana/providers/helius-enhanced.ts +623 -0
- package/src/chains/solana/providers/helius.ts +186 -33
- package/src/chains/solana/providers/index.ts +31 -0
- package/src/chains/solana/providers/interface.ts +61 -18
- package/src/chains/solana/providers/quicknode.ts +409 -0
- package/src/chains/solana/providers/triton.ts +426 -0
- package/src/chains/solana/providers/webhook.ts +338 -67
- package/src/chains/solana/rpc-client.ts +1150 -0
- package/src/chains/solana/scan.ts +83 -66
- package/src/chains/solana/sol-transfer.ts +732 -0
- package/src/chains/solana/spl-transfer.ts +886 -0
- package/src/chains/solana/stealth-scanner.ts +703 -0
- package/src/chains/solana/sunspot-verifier.ts +453 -0
- package/src/chains/solana/transaction-builder.ts +755 -0
- package/src/chains/solana/transfer.ts +74 -5
- package/src/chains/solana/types.ts +57 -6
- package/src/chains/solana/utils.ts +110 -0
- package/src/chains/solana/viewing-key.ts +807 -0
- package/src/compliance/fireblocks.ts +921 -0
- package/src/compliance/index.ts +23 -0
- package/src/compliance/range-sas.ts +398 -33
- package/src/config/endpoints.ts +100 -0
- package/src/crypto.ts +11 -8
- package/src/errors.ts +82 -0
- package/src/evm/erc4337-relayer.ts +830 -0
- package/src/evm/index.ts +47 -0
- package/src/fees/calculator.ts +396 -0
- package/src/fees/index.ts +87 -0
- package/src/fees/near-contract.ts +429 -0
- package/src/fees/types.ts +268 -0
- package/src/index.ts +686 -1
- package/src/intent.ts +6 -3
- package/src/logger.ts +324 -0
- package/src/network/index.ts +80 -0
- package/src/network/proxy.ts +691 -0
- package/src/optimizations/index.ts +541 -0
- package/src/oracle/types.ts +1 -0
- package/src/privacy-backends/arcium-types.ts +727 -0
- package/src/privacy-backends/arcium.ts +719 -0
- package/src/privacy-backends/combined-privacy.ts +866 -0
- package/src/privacy-backends/cspl-token.ts +595 -0
- package/src/privacy-backends/cspl-types.ts +512 -0
- package/src/privacy-backends/cspl.ts +907 -0
- package/src/privacy-backends/health.ts +488 -0
- package/src/privacy-backends/inco-types.ts +323 -0
- package/src/privacy-backends/inco.ts +616 -0
- package/src/privacy-backends/index.ts +254 -4
- package/src/privacy-backends/interface.ts +649 -6
- package/src/privacy-backends/lru-cache.ts +343 -0
- package/src/privacy-backends/magicblock.ts +458 -0
- package/src/privacy-backends/mock.ts +258 -0
- package/src/privacy-backends/privacycash.ts +13 -17
- package/src/privacy-backends/private-swap.ts +570 -0
- package/src/privacy-backends/rate-limiter.ts +683 -0
- package/src/privacy-backends/registry.ts +414 -2
- package/src/privacy-backends/router.ts +283 -3
- package/src/privacy-backends/shadowwire.ts +449 -0
- package/src/privacy-backends/sip-native.ts +3 -0
- package/src/privacy-logger.ts +191 -0
- package/src/production-safety.ts +373 -0
- package/src/proofs/aggregator.ts +1029 -0
- package/src/proofs/browser-composer.ts +1150 -0
- package/src/proofs/browser.ts +113 -25
- package/src/proofs/cache/index.ts +127 -0
- package/src/proofs/cache/interface.ts +545 -0
- package/src/proofs/cache/key-generator.ts +188 -0
- package/src/proofs/cache/lru-cache.ts +481 -0
- package/src/proofs/cache/multi-tier-cache.ts +575 -0
- package/src/proofs/cache/persistent-cache.ts +788 -0
- package/src/proofs/compliance-proof.ts +872 -0
- package/src/proofs/composer/base.ts +923 -0
- package/src/proofs/composer/index.ts +25 -0
- package/src/proofs/composer/interface.ts +518 -0
- package/src/proofs/composer/types.ts +383 -0
- package/src/proofs/converters/halo2.ts +452 -0
- package/src/proofs/converters/index.ts +208 -0
- package/src/proofs/converters/interface.ts +363 -0
- package/src/proofs/converters/kimchi.ts +462 -0
- package/src/proofs/converters/noir.ts +451 -0
- package/src/proofs/fallback.ts +888 -0
- package/src/proofs/halo2.ts +42 -0
- package/src/proofs/index.ts +471 -0
- package/src/proofs/interface.ts +13 -0
- package/src/proofs/kimchi.ts +42 -0
- package/src/proofs/lazy.ts +1004 -0
- package/src/proofs/mock.ts +25 -1
- package/src/proofs/noir.ts +110 -29
- package/src/proofs/orchestrator.ts +960 -0
- package/src/proofs/parallel/concurrency.ts +297 -0
- package/src/proofs/parallel/dependency-graph.ts +602 -0
- package/src/proofs/parallel/executor.ts +420 -0
- package/src/proofs/parallel/index.ts +131 -0
- package/src/proofs/parallel/interface.ts +685 -0
- package/src/proofs/parallel/worker-pool.ts +644 -0
- package/src/proofs/providers/halo2.ts +560 -0
- package/src/proofs/providers/index.ts +34 -0
- package/src/proofs/providers/kimchi.ts +641 -0
- package/src/proofs/validator.ts +881 -0
- package/src/proofs/verifier.ts +867 -0
- package/src/quantum/index.ts +112 -0
- package/src/quantum/winternitz-vault.ts +639 -0
- package/src/quantum/wots.ts +611 -0
- package/src/settlement/backends/direct-chain.ts +1 -0
- package/src/settlement/index.ts +9 -0
- package/src/settlement/router.ts +732 -46
- package/src/solana/index.ts +72 -0
- package/src/solana/jito-relayer.ts +687 -0
- package/src/solana/noir-verifier-types.ts +430 -0
- package/src/solana/noir-verifier.ts +816 -0
- package/src/stealth/address-derivation.ts +193 -0
- package/src/stealth/ed25519.ts +431 -0
- package/src/stealth/index.ts +233 -0
- package/src/stealth/meta-address.ts +221 -0
- package/src/stealth/secp256k1.ts +368 -0
- package/src/stealth/utils.ts +194 -0
- package/src/stealth.ts +50 -1504
- package/src/sync/index.ts +106 -0
- package/src/sync/manager.ts +504 -0
- package/src/sync/mock-provider.ts +318 -0
- package/src/sync/oblivious.ts +625 -0
- package/src/tokens/index.ts +15 -0
- package/src/tokens/registry.ts +301 -0
- package/src/utils/deprecation.ts +94 -0
- package/src/utils/index.ts +9 -0
- package/src/wallet/ethereum/index.ts +68 -0
- package/src/wallet/ethereum/metamask-privacy.ts +420 -0
- package/src/wallet/ethereum/multi-wallet.ts +646 -0
- package/src/wallet/ethereum/privacy-adapter.ts +700 -0
- package/src/wallet/ethereum/types.ts +3 -1
- package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
- package/src/wallet/hardware/index.ts +10 -0
- package/src/wallet/hardware/ledger-privacy.ts +414 -0
- package/src/wallet/index.ts +71 -0
- package/src/wallet/near/adapter.ts +626 -0
- package/src/wallet/near/index.ts +86 -0
- package/src/wallet/near/meteor-wallet.ts +1153 -0
- package/src/wallet/near/my-near-wallet.ts +790 -0
- package/src/wallet/near/wallet-selector.ts +702 -0
- package/src/wallet/solana/adapter.ts +6 -4
- package/src/wallet/solana/index.ts +13 -0
- package/src/wallet/solana/privacy-adapter.ts +567 -0
- package/src/wallet/sui/types.ts +6 -4
- package/src/zcash/rpc-client.ts +13 -6
- package/dist/chunk-2XIVXWHA.mjs +0 -1930
- package/dist/chunk-3INS3PR5.mjs +0 -884
- package/dist/chunk-3OVABDRH.mjs +0 -17096
- package/dist/chunk-7RFRWDCW.mjs +0 -1504
- package/dist/chunk-DLDWZFYC.mjs +0 -1495
- package/dist/chunk-E6SZWREQ.mjs +0 -57
- package/dist/chunk-F6F73W35.mjs +0 -16166
- package/dist/chunk-G33LB27A.mjs +0 -16166
- package/dist/chunk-HGU6HZRC.mjs +0 -231
- package/dist/chunk-L2K34JCU.mjs +0 -1496
- package/dist/chunk-OFDBEIEK.mjs +0 -16166
- package/dist/chunk-SF7YSLF5.mjs +0 -1515
- package/dist/chunk-SN4ZDTVW.mjs +0 -16166
- package/dist/chunk-WWUSGOXE.mjs +0 -17129
- package/dist/constants-VOI7BSLK.mjs +0 -27
- package/dist/index-B71aXVzk.d.ts +0 -13264
- package/dist/index-BYZbDjal.d.ts +0 -11390
- package/dist/index-CHB3KuOB.d.mts +0 -11859
- package/dist/index-CzWPI6Le.d.ts +0 -11859
- package/dist/index-pOIIuwfV.d.mts +0 -13264
- package/dist/index-xbWjohNq.d.mts +0 -11390
- package/dist/solana-4O4K45VU.mjs +0 -46
- package/dist/solana-5EMCTPTS.mjs +0 -46
- package/dist/solana-NDABAZ6P.mjs +0 -56
- package/dist/solana-Q4NAVBTS.mjs +0 -46
- package/dist/solana-ZYO63LY5.mjs +0 -46
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/proofs/kimchi.ts
|
|
21
|
+
var kimchi_exports = {};
|
|
22
|
+
__export(kimchi_exports, {
|
|
23
|
+
KimchiProvider: () => KimchiProvider,
|
|
24
|
+
createKimchiProvider: () => createKimchiProvider,
|
|
25
|
+
createMinaMainnetProvider: () => createMinaMainnetProvider,
|
|
26
|
+
createZkAppProvider: () => createZkAppProvider
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(kimchi_exports);
|
|
29
|
+
|
|
30
|
+
// src/proofs/providers/halo2.ts
|
|
31
|
+
var import_utils = require("@noble/hashes/utils");
|
|
32
|
+
var import_types = require("@sip-protocol/types");
|
|
33
|
+
|
|
34
|
+
// src/proofs/providers/kimchi.ts
|
|
35
|
+
var import_utils2 = require("@noble/hashes/utils");
|
|
36
|
+
var import_types2 = require("@sip-protocol/types");
|
|
37
|
+
var DEFAULT_KIMCHI_CONFIG = {
|
|
38
|
+
circuits: [],
|
|
39
|
+
verbose: false,
|
|
40
|
+
network: "testnet",
|
|
41
|
+
enablePickles: true,
|
|
42
|
+
cacheDir: "",
|
|
43
|
+
compileWorkers: 2
|
|
44
|
+
};
|
|
45
|
+
var KIMCHI_PROOF_SIZE = 22 * 1024;
|
|
46
|
+
var KIMCHI_VERSION = "1.0.0";
|
|
47
|
+
var KimchiProvider = class {
|
|
48
|
+
system = "kimchi";
|
|
49
|
+
_config;
|
|
50
|
+
_status;
|
|
51
|
+
_capabilities;
|
|
52
|
+
_metrics;
|
|
53
|
+
_circuits = /* @__PURE__ */ new Map();
|
|
54
|
+
_compiledCircuits = /* @__PURE__ */ new Map();
|
|
55
|
+
_initPromise = null;
|
|
56
|
+
_initError = null;
|
|
57
|
+
constructor(config = {}) {
|
|
58
|
+
this._config = { ...DEFAULT_KIMCHI_CONFIG, ...config };
|
|
59
|
+
this._metrics = {
|
|
60
|
+
proofsGenerated: 0,
|
|
61
|
+
proofsVerified: 0,
|
|
62
|
+
avgGenerationTimeMs: 0,
|
|
63
|
+
avgVerificationTimeMs: 0,
|
|
64
|
+
successRate: 1,
|
|
65
|
+
memoryUsageBytes: 0
|
|
66
|
+
};
|
|
67
|
+
this._status = {
|
|
68
|
+
isReady: false,
|
|
69
|
+
isBusy: false,
|
|
70
|
+
queueLength: 0,
|
|
71
|
+
metrics: this._metrics
|
|
72
|
+
};
|
|
73
|
+
this._capabilities = {
|
|
74
|
+
system: "kimchi",
|
|
75
|
+
supportsRecursion: this._config.enablePickles,
|
|
76
|
+
supportsBatchVerification: true,
|
|
77
|
+
supportsBrowser: true,
|
|
78
|
+
supportsNode: true,
|
|
79
|
+
maxProofSize: KIMCHI_PROOF_SIZE * 10,
|
|
80
|
+
// Allow some overhead
|
|
81
|
+
supportedStrategies: [
|
|
82
|
+
import_types2.ProofAggregationStrategy.SEQUENTIAL,
|
|
83
|
+
import_types2.ProofAggregationStrategy.PARALLEL,
|
|
84
|
+
import_types2.ProofAggregationStrategy.BATCH,
|
|
85
|
+
...this._config.enablePickles ? [import_types2.ProofAggregationStrategy.RECURSIVE] : []
|
|
86
|
+
],
|
|
87
|
+
availableCircuits: []
|
|
88
|
+
};
|
|
89
|
+
for (const circuit of this._config.circuits) {
|
|
90
|
+
this._circuits.set(circuit.id, circuit);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// ─── Properties ───────────────────────────────────────────────────────────
|
|
94
|
+
get capabilities() {
|
|
95
|
+
return {
|
|
96
|
+
...this._capabilities,
|
|
97
|
+
availableCircuits: Array.from(this._circuits.keys())
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
get status() {
|
|
101
|
+
return { ...this._status };
|
|
102
|
+
}
|
|
103
|
+
// ─── Lifecycle ────────────────────────────────────────────────────────────
|
|
104
|
+
async initialize() {
|
|
105
|
+
if (this._status.isReady) return;
|
|
106
|
+
if (this._initPromise) {
|
|
107
|
+
return this._initPromise;
|
|
108
|
+
}
|
|
109
|
+
this._initPromise = this.doInitialize();
|
|
110
|
+
return this._initPromise;
|
|
111
|
+
}
|
|
112
|
+
async doInitialize() {
|
|
113
|
+
try {
|
|
114
|
+
if (this._config.verbose) {
|
|
115
|
+
console.log("[KimchiProvider] Initializing...");
|
|
116
|
+
console.log(`[KimchiProvider] Network: ${this._config.network}`);
|
|
117
|
+
console.log(`[KimchiProvider] Pickles enabled: ${this._config.enablePickles}`);
|
|
118
|
+
}
|
|
119
|
+
await this.simulateAsyncLoad();
|
|
120
|
+
this._status.isReady = true;
|
|
121
|
+
if (this._config.verbose) {
|
|
122
|
+
console.log("[KimchiProvider] Initialization complete");
|
|
123
|
+
console.log(`[KimchiProvider] Available circuits: ${Array.from(this._circuits.keys()).join(", ") || "none"}`);
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
this._initError = error instanceof Error ? error : new Error(String(error));
|
|
127
|
+
this._status.lastError = this._initError.message;
|
|
128
|
+
throw this._initError;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async waitUntilReady(timeoutMs = 3e4) {
|
|
132
|
+
if (this._status.isReady) return;
|
|
133
|
+
if (this._initError) {
|
|
134
|
+
throw this._initError;
|
|
135
|
+
}
|
|
136
|
+
if (!this._initPromise) {
|
|
137
|
+
this._initPromise = this.doInitialize();
|
|
138
|
+
}
|
|
139
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
140
|
+
setTimeout(() => reject(new Error(`KimchiProvider initialization timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
141
|
+
});
|
|
142
|
+
await Promise.race([this._initPromise, timeoutPromise]);
|
|
143
|
+
}
|
|
144
|
+
async dispose() {
|
|
145
|
+
this._compiledCircuits.clear();
|
|
146
|
+
this._status.isReady = false;
|
|
147
|
+
this._initPromise = null;
|
|
148
|
+
this._initError = null;
|
|
149
|
+
if (this._config.verbose) {
|
|
150
|
+
console.log("[KimchiProvider] Disposed");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// ─── Circuit Management ───────────────────────────────────────────────────
|
|
154
|
+
getAvailableCircuits() {
|
|
155
|
+
return Array.from(this._circuits.keys());
|
|
156
|
+
}
|
|
157
|
+
hasCircuit(circuitId) {
|
|
158
|
+
return this._circuits.has(circuitId);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Register a circuit configuration
|
|
162
|
+
*/
|
|
163
|
+
registerCircuit(config) {
|
|
164
|
+
this._circuits.set(config.id, config);
|
|
165
|
+
if (this._config.verbose) {
|
|
166
|
+
console.log(`[KimchiProvider] Registered circuit: ${config.id} (${config.gateCount} gates)`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Compile a circuit for proof generation
|
|
171
|
+
*
|
|
172
|
+
* Compiling in Kimchi/o1js creates the verification key and prepares
|
|
173
|
+
* the circuit for proving.
|
|
174
|
+
*/
|
|
175
|
+
async compileCircuit(circuitId) {
|
|
176
|
+
const circuit = this._circuits.get(circuitId);
|
|
177
|
+
if (!circuit) {
|
|
178
|
+
throw new Error(`Circuit not found: ${circuitId}`);
|
|
179
|
+
}
|
|
180
|
+
if (this._config.verbose) {
|
|
181
|
+
console.log(`[KimchiProvider] Compiling circuit: ${circuitId}`);
|
|
182
|
+
}
|
|
183
|
+
await this.delay(100 + circuit.gateCount * 0.1);
|
|
184
|
+
const vkHash = `0x${(0, import_utils2.bytesToHex)((0, import_utils2.randomBytes)(32))}`;
|
|
185
|
+
this._compiledCircuits.set(circuitId, {
|
|
186
|
+
compiled: true,
|
|
187
|
+
vkHash
|
|
188
|
+
});
|
|
189
|
+
if (this._config.verbose) {
|
|
190
|
+
console.log(`[KimchiProvider] Circuit compiled: ${circuitId}, vkHash: ${vkHash.slice(0, 18)}...`);
|
|
191
|
+
}
|
|
192
|
+
return vkHash;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Check if a circuit is compiled
|
|
196
|
+
*/
|
|
197
|
+
isCircuitCompiled(circuitId) {
|
|
198
|
+
return this._compiledCircuits.get(circuitId)?.compiled === true;
|
|
199
|
+
}
|
|
200
|
+
// ─── Proof Generation ─────────────────────────────────────────────────────
|
|
201
|
+
async generateProof(request) {
|
|
202
|
+
const startTime = Date.now();
|
|
203
|
+
if (!this._status.isReady) {
|
|
204
|
+
return {
|
|
205
|
+
success: false,
|
|
206
|
+
error: "Provider not initialized",
|
|
207
|
+
timeMs: Date.now() - startTime,
|
|
208
|
+
providerId: `kimchi-${this.generateProviderId()}`
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
const circuit = this._circuits.get(request.circuitId);
|
|
212
|
+
if (!circuit) {
|
|
213
|
+
return {
|
|
214
|
+
success: false,
|
|
215
|
+
error: `Circuit not found: ${request.circuitId}`,
|
|
216
|
+
timeMs: Date.now() - startTime,
|
|
217
|
+
providerId: `kimchi-${this.generateProviderId()}`
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
this._status.isBusy = true;
|
|
222
|
+
if (!this.isCircuitCompiled(request.circuitId)) {
|
|
223
|
+
await this.compileCircuit(request.circuitId);
|
|
224
|
+
}
|
|
225
|
+
const proof = await this.generateMockProof(request, circuit);
|
|
226
|
+
const timeMs = Date.now() - startTime;
|
|
227
|
+
this._metrics.proofsGenerated++;
|
|
228
|
+
this._metrics.avgGenerationTimeMs = (this._metrics.avgGenerationTimeMs * (this._metrics.proofsGenerated - 1) + timeMs) / this._metrics.proofsGenerated;
|
|
229
|
+
return {
|
|
230
|
+
success: true,
|
|
231
|
+
proof,
|
|
232
|
+
timeMs,
|
|
233
|
+
providerId: `kimchi-${this.generateProviderId()}`
|
|
234
|
+
};
|
|
235
|
+
} catch (error) {
|
|
236
|
+
this._metrics.successRate = this._metrics.proofsGenerated > 0 ? (this._metrics.proofsGenerated - 1) / this._metrics.proofsGenerated : 0;
|
|
237
|
+
return {
|
|
238
|
+
success: false,
|
|
239
|
+
error: error instanceof Error ? error.message : "Unknown error during proof generation",
|
|
240
|
+
timeMs: Date.now() - startTime,
|
|
241
|
+
providerId: `kimchi-${this.generateProviderId()}`
|
|
242
|
+
};
|
|
243
|
+
} finally {
|
|
244
|
+
this._status.isBusy = false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
async generateMockProof(request, circuit) {
|
|
248
|
+
const simulatedTimeMs = Math.min(200 + circuit.gateCount * 0.5, 5e3);
|
|
249
|
+
await this.delay(simulatedTimeMs);
|
|
250
|
+
const proofBytes = (0, import_utils2.randomBytes)(KIMCHI_PROOF_SIZE);
|
|
251
|
+
const proofHex = `0x${(0, import_utils2.bytesToHex)(proofBytes)}`;
|
|
252
|
+
const publicInputs = Object.values(request.publicInputs).map((v) => {
|
|
253
|
+
if (typeof v === "string" && v.startsWith("0x")) {
|
|
254
|
+
return v;
|
|
255
|
+
}
|
|
256
|
+
if (typeof v === "bigint" || typeof v === "number") {
|
|
257
|
+
return `0x${v.toString(16).padStart(64, "0")}`;
|
|
258
|
+
}
|
|
259
|
+
return `0x${Buffer.from(String(v)).toString("hex")}`;
|
|
260
|
+
});
|
|
261
|
+
const vkHash = this._compiledCircuits.get(request.circuitId)?.vkHash;
|
|
262
|
+
return {
|
|
263
|
+
id: `kimchi-proof-${Date.now()}-${(0, import_utils2.randomBytes)(4).reduce((a, b) => a + b.toString(16), "")}`,
|
|
264
|
+
proof: proofHex,
|
|
265
|
+
publicInputs,
|
|
266
|
+
verificationKey: vkHash,
|
|
267
|
+
metadata: {
|
|
268
|
+
system: "kimchi",
|
|
269
|
+
systemVersion: KIMCHI_VERSION,
|
|
270
|
+
circuitId: circuit.id,
|
|
271
|
+
circuitVersion: "1.0.0",
|
|
272
|
+
generatedAt: Date.now(),
|
|
273
|
+
proofSizeBytes: KIMCHI_PROOF_SIZE,
|
|
274
|
+
verificationCost: BigInt(Math.ceil(circuit.gateCount / 10)),
|
|
275
|
+
targetChainId: this._config.network === "mainnet" ? "mina:mainnet" : "mina:testnet"
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
// ─── Verification ─────────────────────────────────────────────────────────
|
|
280
|
+
async verifyProof(proof) {
|
|
281
|
+
if (!this._status.isReady) {
|
|
282
|
+
throw new Error("Provider not initialized");
|
|
283
|
+
}
|
|
284
|
+
const startTime = Date.now();
|
|
285
|
+
try {
|
|
286
|
+
const isValid = this.validateProofFormat(proof);
|
|
287
|
+
const timeMs = Date.now() - startTime;
|
|
288
|
+
this._metrics.proofsVerified++;
|
|
289
|
+
this._metrics.avgVerificationTimeMs = (this._metrics.avgVerificationTimeMs * (this._metrics.proofsVerified - 1) + timeMs) / this._metrics.proofsVerified;
|
|
290
|
+
return isValid;
|
|
291
|
+
} catch {
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async verifyBatch(proofs) {
|
|
296
|
+
if (!this._status.isReady) {
|
|
297
|
+
throw new Error("Provider not initialized");
|
|
298
|
+
}
|
|
299
|
+
const results = [];
|
|
300
|
+
for (const proof of proofs) {
|
|
301
|
+
results.push(await this.verifyProof(proof));
|
|
302
|
+
}
|
|
303
|
+
return results;
|
|
304
|
+
}
|
|
305
|
+
validateProofFormat(proof) {
|
|
306
|
+
if (!proof.id || !proof.proof || !proof.metadata) {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
if (proof.metadata.system !== "kimchi") {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
if (!proof.proof.startsWith("0x")) {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
const proofBytes = (proof.proof.length - 2) / 2;
|
|
316
|
+
if (proofBytes < KIMCHI_PROOF_SIZE * 0.5 || proofBytes > KIMCHI_PROOF_SIZE * 2) {
|
|
317
|
+
if (this._config.verbose) {
|
|
318
|
+
console.warn(`[KimchiProvider] Unusual proof size: ${proofBytes} bytes (expected ~${KIMCHI_PROOF_SIZE})`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (proof.metadata.expiresAt && proof.metadata.expiresAt < Date.now()) {
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
// ─── Recursive Proving (Pickles) ──────────────────────────────────────────
|
|
327
|
+
/**
|
|
328
|
+
* Check if Pickles recursive proving is available
|
|
329
|
+
*/
|
|
330
|
+
supportsRecursion() {
|
|
331
|
+
return this._config.enablePickles;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Merge multiple proofs recursively using Pickles
|
|
335
|
+
*
|
|
336
|
+
* This enables constant-size proofs regardless of how many
|
|
337
|
+
* proofs are combined.
|
|
338
|
+
*/
|
|
339
|
+
async mergeProofsRecursively(proofs) {
|
|
340
|
+
if (!this._config.enablePickles) {
|
|
341
|
+
if (this._config.verbose) {
|
|
342
|
+
console.warn("[KimchiProvider] Pickles not enabled for recursive merging");
|
|
343
|
+
}
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
if (proofs.length === 0) {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
if (proofs.length === 1) {
|
|
350
|
+
return proofs[0];
|
|
351
|
+
}
|
|
352
|
+
if (this._config.verbose) {
|
|
353
|
+
console.log(`[KimchiProvider] Merging ${proofs.length} proofs recursively`);
|
|
354
|
+
}
|
|
355
|
+
await this.delay(proofs.length * 100);
|
|
356
|
+
const mergedProofBytes = (0, import_utils2.randomBytes)(KIMCHI_PROOF_SIZE);
|
|
357
|
+
const combinedInputs = proofs.flatMap((p) => p.publicInputs);
|
|
358
|
+
return {
|
|
359
|
+
id: `kimchi-merged-${Date.now()}`,
|
|
360
|
+
proof: `0x${(0, import_utils2.bytesToHex)(mergedProofBytes)}`,
|
|
361
|
+
publicInputs: combinedInputs.slice(0, 10),
|
|
362
|
+
// Limit public inputs
|
|
363
|
+
metadata: {
|
|
364
|
+
system: "kimchi",
|
|
365
|
+
systemVersion: KIMCHI_VERSION,
|
|
366
|
+
circuitId: "pickles_merge",
|
|
367
|
+
circuitVersion: "1.0.0",
|
|
368
|
+
generatedAt: Date.now(),
|
|
369
|
+
proofSizeBytes: KIMCHI_PROOF_SIZE
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────
|
|
374
|
+
async simulateAsyncLoad() {
|
|
375
|
+
await this.delay(50);
|
|
376
|
+
}
|
|
377
|
+
delay(ms) {
|
|
378
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
379
|
+
}
|
|
380
|
+
generateProviderId() {
|
|
381
|
+
return (0, import_utils2.bytesToHex)((0, import_utils2.randomBytes)(4));
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
function createKimchiProvider(config) {
|
|
385
|
+
return new KimchiProvider(config);
|
|
386
|
+
}
|
|
387
|
+
function createMinaMainnetProvider() {
|
|
388
|
+
return new KimchiProvider({
|
|
389
|
+
network: "mainnet",
|
|
390
|
+
enablePickles: true,
|
|
391
|
+
circuits: [
|
|
392
|
+
{
|
|
393
|
+
id: "token_transfer",
|
|
394
|
+
name: "Token Transfer Circuit",
|
|
395
|
+
gateCount: 5e3,
|
|
396
|
+
publicInputCount: 4,
|
|
397
|
+
usesRecursion: false
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
id: "state_update",
|
|
401
|
+
name: "State Update Circuit",
|
|
402
|
+
gateCount: 8e3,
|
|
403
|
+
publicInputCount: 6,
|
|
404
|
+
usesRecursion: true
|
|
405
|
+
}
|
|
406
|
+
]
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
function createZkAppProvider(network = "testnet") {
|
|
410
|
+
return new KimchiProvider({
|
|
411
|
+
network,
|
|
412
|
+
enablePickles: true,
|
|
413
|
+
verbose: network === "local",
|
|
414
|
+
circuits: [
|
|
415
|
+
{
|
|
416
|
+
id: "zkapp_method",
|
|
417
|
+
name: "zkApp Method Circuit",
|
|
418
|
+
gateCount: 3e3,
|
|
419
|
+
publicInputCount: 3,
|
|
420
|
+
usesRecursion: false
|
|
421
|
+
}
|
|
422
|
+
]
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
426
|
+
0 && (module.exports = {
|
|
427
|
+
KimchiProvider,
|
|
428
|
+
createKimchiProvider,
|
|
429
|
+
createMinaMainnetProvider,
|
|
430
|
+
createZkAppProvider
|
|
431
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
KimchiProvider,
|
|
3
|
+
createKimchiProvider,
|
|
4
|
+
createMinaMainnetProvider,
|
|
5
|
+
createZkAppProvider
|
|
6
|
+
} from "../chunk-5D7A3L3W.mjs";
|
|
7
|
+
import "../chunk-XGB3TDIC.mjs";
|
|
8
|
+
export {
|
|
9
|
+
KimchiProvider,
|
|
10
|
+
createKimchiProvider,
|
|
11
|
+
createMinaMainnetProvider,
|
|
12
|
+
createZkAppProvider
|
|
13
|
+
};
|
package/dist/proofs/noir.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import '@sip-protocol/types';
|
|
2
|
-
export { f as NoirProofProvider, N as NoirProviderConfig, e as PublicKeyCoordinates } from '../noir-
|
|
2
|
+
export { f as NoirProofProvider, N as NoirProviderConfig, e as PublicKeyCoordinates } from '../noir-kzbLVTei.mjs';
|
package/dist/proofs/noir.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import '@sip-protocol/types';
|
|
2
|
-
export { f as NoirProofProvider, N as NoirProviderConfig, e as PublicKeyCoordinates } from '../noir-
|
|
2
|
+
export { f as NoirProofProvider, N as NoirProviderConfig, e as PublicKeyCoordinates } from '../noir-kzbLVTei.js';
|
package/dist/proofs/noir.js
CHANGED
|
@@ -985,10 +985,18 @@ fn test_time_constraint_edge_case() {
|
|
|
985
985
|
`, path: "/Users/rz/local-dev/sip-protocol/packages/circuits/fulfillment_proof/src/main.nr" } }, expression_width: { Bounded: { width: 4 } } };
|
|
986
986
|
|
|
987
987
|
// src/proofs/noir.ts
|
|
988
|
+
var fundingCircuit = funding_proof_default;
|
|
989
|
+
var validityCircuit = validity_proof_default;
|
|
990
|
+
var fulfillmentCircuit = fulfillment_proof_default;
|
|
991
|
+
var DEFAULT_INIT_TIMEOUT_MS = 3e4;
|
|
988
992
|
var NoirProofProvider = class {
|
|
989
993
|
framework = "noir";
|
|
990
994
|
_isReady = false;
|
|
995
|
+
_initPromise = null;
|
|
996
|
+
_initError = null;
|
|
991
997
|
config;
|
|
998
|
+
// Barretenberg instance (shared by all backends)
|
|
999
|
+
barretenberg = null;
|
|
992
1000
|
// Circuit instances
|
|
993
1001
|
fundingNoir = null;
|
|
994
1002
|
fundingBackend = null;
|
|
@@ -1051,26 +1059,79 @@ var NoirProofProvider = class {
|
|
|
1051
1059
|
if (this._isReady) {
|
|
1052
1060
|
return;
|
|
1053
1061
|
}
|
|
1062
|
+
if (this._initPromise) {
|
|
1063
|
+
return this._initPromise;
|
|
1064
|
+
}
|
|
1065
|
+
if (this._initError) {
|
|
1066
|
+
throw this._initError;
|
|
1067
|
+
}
|
|
1068
|
+
this._initPromise = this._doInitialize();
|
|
1069
|
+
try {
|
|
1070
|
+
await this._initPromise;
|
|
1071
|
+
} catch (error) {
|
|
1072
|
+
this._initError = error instanceof Error ? error : new Error(String(error));
|
|
1073
|
+
this._initPromise = null;
|
|
1074
|
+
throw error;
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Wait for the provider to be ready, with optional timeout
|
|
1079
|
+
*
|
|
1080
|
+
* This method blocks until initialization is complete or the timeout is reached.
|
|
1081
|
+
* If initialization is already complete, resolves immediately.
|
|
1082
|
+
* If initialization hasn't started, this method will start it.
|
|
1083
|
+
*
|
|
1084
|
+
* @param timeoutMs - Maximum time to wait in milliseconds (default: 30000)
|
|
1085
|
+
* @throws ProofError if timeout is reached before ready
|
|
1086
|
+
* @throws ProofError if initialization fails
|
|
1087
|
+
*/
|
|
1088
|
+
async waitUntilReady(timeoutMs = DEFAULT_INIT_TIMEOUT_MS) {
|
|
1089
|
+
if (this._isReady) {
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
if (this._initError) {
|
|
1093
|
+
throw new ProofError(
|
|
1094
|
+
`NoirProofProvider initialization failed: ${this._initError.message}`,
|
|
1095
|
+
"SIP_4004" /* PROOF_PROVIDER_NOT_READY */,
|
|
1096
|
+
{ context: { error: this._initError } }
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
const initPromise = this._initPromise ?? this.initialize();
|
|
1100
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1101
|
+
setTimeout(() => {
|
|
1102
|
+
reject(new ProofError(
|
|
1103
|
+
`NoirProofProvider initialization timed out after ${timeoutMs}ms`,
|
|
1104
|
+
"SIP_4004" /* PROOF_PROVIDER_NOT_READY */
|
|
1105
|
+
));
|
|
1106
|
+
}, timeoutMs);
|
|
1107
|
+
});
|
|
1108
|
+
await Promise.race([initPromise, timeoutPromise]);
|
|
1109
|
+
}
|
|
1110
|
+
/**
|
|
1111
|
+
* Internal initialization logic
|
|
1112
|
+
*/
|
|
1113
|
+
async _doInitialize() {
|
|
1054
1114
|
try {
|
|
1055
1115
|
if (this.config.verbose) {
|
|
1056
1116
|
console.log("[NoirProofProvider] Initializing...");
|
|
1057
1117
|
}
|
|
1058
|
-
|
|
1059
|
-
this.
|
|
1118
|
+
this.barretenberg = await import_bb.Barretenberg.new();
|
|
1119
|
+
if (this.config.verbose) {
|
|
1120
|
+
console.log("[NoirProofProvider] Barretenberg initialized");
|
|
1121
|
+
}
|
|
1122
|
+
this.fundingBackend = new import_bb.UltraHonkBackend(fundingCircuit.bytecode, this.barretenberg);
|
|
1060
1123
|
this.fundingNoir = new import_noir_js.Noir(fundingCircuit);
|
|
1061
1124
|
if (this.config.verbose) {
|
|
1062
1125
|
console.log("[NoirProofProvider] Funding circuit loaded");
|
|
1063
1126
|
const artifactVersion = funding_proof_default.noir_version;
|
|
1064
1127
|
console.log(`[NoirProofProvider] Noir version: ${artifactVersion ?? "unknown"}`);
|
|
1065
1128
|
}
|
|
1066
|
-
|
|
1067
|
-
this.validityBackend = new import_bb.UltraHonkBackend(validityCircuit.bytecode);
|
|
1129
|
+
this.validityBackend = new import_bb.UltraHonkBackend(validityCircuit.bytecode, this.barretenberg);
|
|
1068
1130
|
this.validityNoir = new import_noir_js.Noir(validityCircuit);
|
|
1069
1131
|
if (this.config.verbose) {
|
|
1070
1132
|
console.log("[NoirProofProvider] Validity circuit loaded");
|
|
1071
1133
|
}
|
|
1072
|
-
|
|
1073
|
-
this.fulfillmentBackend = new import_bb.UltraHonkBackend(fulfillmentCircuit.bytecode);
|
|
1134
|
+
this.fulfillmentBackend = new import_bb.UltraHonkBackend(fulfillmentCircuit.bytecode, this.barretenberg);
|
|
1074
1135
|
this.fulfillmentNoir = new import_noir_js.Noir(fulfillmentCircuit);
|
|
1075
1136
|
if (this.config.verbose) {
|
|
1076
1137
|
console.log("[NoirProofProvider] Fulfillment circuit loaded");
|
|
@@ -1528,21 +1589,16 @@ var NoirProofProvider = class {
|
|
|
1528
1589
|
* Destroy the provider and free resources
|
|
1529
1590
|
*/
|
|
1530
1591
|
async destroy() {
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
}
|
|
1535
|
-
if (this.validityBackend) {
|
|
1536
|
-
await this.validityBackend.destroy();
|
|
1537
|
-
this.validityBackend = null;
|
|
1538
|
-
}
|
|
1539
|
-
if (this.fulfillmentBackend) {
|
|
1540
|
-
await this.fulfillmentBackend.destroy();
|
|
1541
|
-
this.fulfillmentBackend = null;
|
|
1542
|
-
}
|
|
1592
|
+
this.fundingBackend = null;
|
|
1593
|
+
this.validityBackend = null;
|
|
1594
|
+
this.fulfillmentBackend = null;
|
|
1543
1595
|
this.fundingNoir = null;
|
|
1544
1596
|
this.validityNoir = null;
|
|
1545
1597
|
this.fulfillmentNoir = null;
|
|
1598
|
+
if (this.barretenberg) {
|
|
1599
|
+
await this.barretenberg.destroy();
|
|
1600
|
+
this.barretenberg = null;
|
|
1601
|
+
}
|
|
1546
1602
|
this._isReady = false;
|
|
1547
1603
|
}
|
|
1548
1604
|
// ─── Private Methods ───────────────────────────────────────────────────────
|