@sip-protocol/cli 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 +175 -0
- package/bin/sip.js +4 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +538 -0
- package/dist/index.mjs +520 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 RECTOR Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# @sip-protocol/cli
|
|
2
|
+
|
|
3
|
+
Command-line tool for Shielded Intents Protocol (SIP) operations.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @sip-protocol/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or use directly with npx:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx @sip-protocol/cli --help
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Commands
|
|
18
|
+
|
|
19
|
+
### Initialize Configuration
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
sip init [options]
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
-n, --network <network> Network (mainnet|testnet) (default: "testnet")
|
|
26
|
+
-p, --privacy <level> Default privacy level (default: "transparent")
|
|
27
|
+
--reset Reset configuration to defaults
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Generate Stealth Meta-Address
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
sip keygen [options]
|
|
34
|
+
|
|
35
|
+
Options:
|
|
36
|
+
-c, --chain <chain> Target chain (ethereum, solana, near) (default: "ethereum")
|
|
37
|
+
--spending-key <key> Spending private key (hex)
|
|
38
|
+
--viewing-key <key> Viewing private key (hex)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Create Pedersen Commitment
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
sip commit <amount> [options]
|
|
45
|
+
|
|
46
|
+
Arguments:
|
|
47
|
+
amount Amount to commit
|
|
48
|
+
|
|
49
|
+
Options:
|
|
50
|
+
-b, --blinding <factor> Blinding factor (hex, optional)
|
|
51
|
+
--verify Verify the commitment after creation
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Generate ZK Proof
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Funding proof
|
|
58
|
+
sip prove funding [options]
|
|
59
|
+
|
|
60
|
+
Options:
|
|
61
|
+
-b, --balance <amount> Current balance (required)
|
|
62
|
+
-m, --minimum <amount> Minimum required (required)
|
|
63
|
+
-c, --commitment <hex> Balance commitment
|
|
64
|
+
|
|
65
|
+
# Validity proof
|
|
66
|
+
sip prove validity [options]
|
|
67
|
+
|
|
68
|
+
Options:
|
|
69
|
+
-i, --intent <hash> Intent hash (required)
|
|
70
|
+
-s, --sender <address> Sender address (required)
|
|
71
|
+
-c, --commitment <hex> Amount commitment
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Verify ZK Proof
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
sip verify <proof> [options]
|
|
78
|
+
|
|
79
|
+
Arguments:
|
|
80
|
+
proof Proof to verify (hex string)
|
|
81
|
+
|
|
82
|
+
Options:
|
|
83
|
+
-t, --type <type> Proof type (funding|validity|fulfillment) (default: "funding")
|
|
84
|
+
-p, --public-inputs <json> Public inputs (JSON array)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Get Swap Quote
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
sip quote <from-chain> <to-chain> <amount> [options]
|
|
91
|
+
|
|
92
|
+
Arguments:
|
|
93
|
+
from-chain Source chain (e.g., ethereum, solana)
|
|
94
|
+
to-chain Destination chain
|
|
95
|
+
amount Amount to swap
|
|
96
|
+
|
|
97
|
+
Options:
|
|
98
|
+
-t, --token <symbol> Token symbol (default: native token)
|
|
99
|
+
-p, --privacy <level> Privacy level (transparent|shielded|compliant)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Execute Swap
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
sip swap <from-chain> <to-chain> <amount> [options]
|
|
106
|
+
|
|
107
|
+
Arguments:
|
|
108
|
+
from-chain Source chain (e.g., ethereum, solana)
|
|
109
|
+
to-chain Destination chain
|
|
110
|
+
amount Amount to swap
|
|
111
|
+
|
|
112
|
+
Options:
|
|
113
|
+
-t, --token <symbol> Token symbol (default: native token)
|
|
114
|
+
-p, --privacy <level> Privacy level (transparent|shielded|compliant)
|
|
115
|
+
-r, --recipient <address> Recipient address (optional)
|
|
116
|
+
--solver <id> Specific solver to use
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Scan for Stealth Payments
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
sip scan [options]
|
|
123
|
+
|
|
124
|
+
Options:
|
|
125
|
+
-c, --chain <chain> Chain to scan (ethereum, solana, near) (required)
|
|
126
|
+
-s, --spending-key <key> Your spending private key (hex) (required)
|
|
127
|
+
-v, --viewing-key <key> Your viewing private key (hex) (required)
|
|
128
|
+
-a, --addresses <addresses...> Specific addresses to check
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Examples
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Initialize with testnet
|
|
135
|
+
sip init --network testnet --privacy shielded
|
|
136
|
+
|
|
137
|
+
# Generate stealth keys for Ethereum
|
|
138
|
+
sip keygen --chain ethereum
|
|
139
|
+
|
|
140
|
+
# Create commitment
|
|
141
|
+
sip commit 1000000000000000000 --verify
|
|
142
|
+
|
|
143
|
+
# Generate funding proof
|
|
144
|
+
sip prove funding --balance 5000000 --minimum 1000000
|
|
145
|
+
|
|
146
|
+
# Get quote for ETH to SOL swap
|
|
147
|
+
sip quote ethereum solana 1000000000000000000 --privacy shielded
|
|
148
|
+
|
|
149
|
+
# Execute swap
|
|
150
|
+
sip swap ethereum solana 1000000000000000000 --privacy shielded
|
|
151
|
+
|
|
152
|
+
# Scan for stealth payments
|
|
153
|
+
sip scan --chain ethereum -s 0xYOUR_SPENDING_KEY -v 0xYOUR_VIEWING_KEY -a 0xADDRESS1 0xADDRESS2
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Development
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Install dependencies
|
|
160
|
+
pnpm install
|
|
161
|
+
|
|
162
|
+
# Build
|
|
163
|
+
pnpm build
|
|
164
|
+
|
|
165
|
+
# Test locally
|
|
166
|
+
node bin/sip.js --help
|
|
167
|
+
|
|
168
|
+
# Link globally for testing
|
|
169
|
+
npm link
|
|
170
|
+
sip --help
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
MIT
|
package/bin/sip.js
ADDED
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/index.ts
|
|
27
|
+
var import_commander9 = require("commander");
|
|
28
|
+
|
|
29
|
+
// src/commands/init.ts
|
|
30
|
+
var import_commander = require("commander");
|
|
31
|
+
var import_types = require("@sip-protocol/types");
|
|
32
|
+
|
|
33
|
+
// src/utils/config.ts
|
|
34
|
+
var import_conf = __toESM(require("conf"));
|
|
35
|
+
var schema = {
|
|
36
|
+
network: {
|
|
37
|
+
type: "string",
|
|
38
|
+
default: "testnet"
|
|
39
|
+
},
|
|
40
|
+
defaultPrivacy: {
|
|
41
|
+
type: "string",
|
|
42
|
+
default: "transparent"
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var store = new import_conf.default({
|
|
46
|
+
projectName: "sip-protocol",
|
|
47
|
+
schema
|
|
48
|
+
});
|
|
49
|
+
function getConfig() {
|
|
50
|
+
return {
|
|
51
|
+
network: store.get("network"),
|
|
52
|
+
defaultPrivacy: store.get("defaultPrivacy"),
|
|
53
|
+
defaultChain: store.get("defaultChain"),
|
|
54
|
+
rpcEndpoints: store.get("rpcEndpoints")
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function setConfig(key, value) {
|
|
58
|
+
store.set(key, value);
|
|
59
|
+
}
|
|
60
|
+
function resetConfig() {
|
|
61
|
+
store.clear();
|
|
62
|
+
}
|
|
63
|
+
function getConfigPath() {
|
|
64
|
+
return store.path;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/utils/output.ts
|
|
68
|
+
var import_chalk = __toESM(require("chalk"));
|
|
69
|
+
var import_ora = __toESM(require("ora"));
|
|
70
|
+
function success(message) {
|
|
71
|
+
console.log(import_chalk.default.green("\u2713"), message);
|
|
72
|
+
}
|
|
73
|
+
function error(message) {
|
|
74
|
+
console.error(import_chalk.default.red("\u2717"), message);
|
|
75
|
+
}
|
|
76
|
+
function warning(message) {
|
|
77
|
+
console.warn(import_chalk.default.yellow("\u26A0"), message);
|
|
78
|
+
}
|
|
79
|
+
function info(message) {
|
|
80
|
+
console.log(import_chalk.default.blue("\u2139"), message);
|
|
81
|
+
}
|
|
82
|
+
function heading(message) {
|
|
83
|
+
console.log(import_chalk.default.bold.cyan(`
|
|
84
|
+
${message}
|
|
85
|
+
`));
|
|
86
|
+
}
|
|
87
|
+
function keyValue(key, value) {
|
|
88
|
+
console.log(import_chalk.default.gray(` ${key}:`), import_chalk.default.white(String(value)));
|
|
89
|
+
}
|
|
90
|
+
function spinner(text) {
|
|
91
|
+
return (0, import_ora.default)(text).start();
|
|
92
|
+
}
|
|
93
|
+
function table(headers, rows) {
|
|
94
|
+
const colWidths = headers.map(
|
|
95
|
+
(h, i) => Math.max(h.length, ...rows.map((r) => String(r[i] || "").length))
|
|
96
|
+
);
|
|
97
|
+
console.log(
|
|
98
|
+
headers.map((h, i) => import_chalk.default.bold(h.padEnd(colWidths[i]))).join(" ")
|
|
99
|
+
);
|
|
100
|
+
console.log(colWidths.map((w) => "\u2500".repeat(w)).join(" "));
|
|
101
|
+
rows.forEach((row) => {
|
|
102
|
+
console.log(
|
|
103
|
+
row.map((cell, i) => String(cell).padEnd(colWidths[i])).join(" ")
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function formatAmount(amount, decimals = 18) {
|
|
108
|
+
const divisor = 10n ** BigInt(decimals);
|
|
109
|
+
const integer = amount / divisor;
|
|
110
|
+
const fraction = amount % divisor;
|
|
111
|
+
const fractionStr = fraction.toString().padStart(decimals, "0").slice(0, 6);
|
|
112
|
+
return `${integer}.${fractionStr}`;
|
|
113
|
+
}
|
|
114
|
+
function formatHash(hash, length = 8) {
|
|
115
|
+
if (hash.length <= length * 2) return hash;
|
|
116
|
+
return `${hash.slice(0, length)}...${hash.slice(-length)}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/commands/init.ts
|
|
120
|
+
function createInitCommand() {
|
|
121
|
+
return new import_commander.Command("init").description("Initialize SIP configuration").option("-n, --network <network>", "Network (mainnet|testnet)", "testnet").option("-p, --privacy <level>", "Default privacy level", "transparent").option("--reset", "Reset configuration to defaults").action(async (options) => {
|
|
122
|
+
try {
|
|
123
|
+
heading("Initialize SIP Protocol");
|
|
124
|
+
if (options.reset) {
|
|
125
|
+
resetConfig();
|
|
126
|
+
success("Configuration reset to defaults");
|
|
127
|
+
}
|
|
128
|
+
const privacy = options.privacy;
|
|
129
|
+
if (!Object.values(import_types.PrivacyLevel).includes(privacy)) {
|
|
130
|
+
throw new Error(`Invalid privacy level: ${privacy}`);
|
|
131
|
+
}
|
|
132
|
+
setConfig("network", options.network);
|
|
133
|
+
setConfig("defaultPrivacy", privacy);
|
|
134
|
+
success("SIP initialized successfully");
|
|
135
|
+
info(`Network: ${options.network}`);
|
|
136
|
+
info(`Default Privacy: ${privacy}`);
|
|
137
|
+
info(`Config file: ${getConfigPath()}`);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
console.error("Failed to initialize:", err);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/commands/keygen.ts
|
|
146
|
+
var import_commander2 = require("commander");
|
|
147
|
+
var import_sdk = require("@sip-protocol/sdk");
|
|
148
|
+
function createKeygenCommand() {
|
|
149
|
+
return new import_commander2.Command("keygen").description("Generate stealth meta-address").option("-c, --chain <chain>", "Target chain (ethereum, solana, near)", "ethereum").option("--spending-key <key>", "Spending private key (hex)").option("--viewing-key <key>", "Viewing private key (hex)").action(async (options) => {
|
|
150
|
+
try {
|
|
151
|
+
heading("Generate Stealth Meta-Address");
|
|
152
|
+
const chain = options.chain;
|
|
153
|
+
const useEd25519 = (0, import_sdk.isEd25519Chain)(chain);
|
|
154
|
+
let metaAddress;
|
|
155
|
+
if (useEd25519) {
|
|
156
|
+
if (options.spendingKey || options.viewingKey) {
|
|
157
|
+
warning("Ed25519 chains do not support custom keys in CLI yet");
|
|
158
|
+
}
|
|
159
|
+
metaAddress = (0, import_sdk.generateEd25519StealthMetaAddress)(chain);
|
|
160
|
+
} else {
|
|
161
|
+
metaAddress = (0, import_sdk.generateStealthMetaAddress)(chain);
|
|
162
|
+
}
|
|
163
|
+
success("Stealth meta-address generated");
|
|
164
|
+
keyValue("Chain", chain);
|
|
165
|
+
const spendingPubKey = metaAddress.metaAddress.spendingKey;
|
|
166
|
+
const viewingPubKey = metaAddress.metaAddress.viewingKey;
|
|
167
|
+
const spendingPrivKey = metaAddress.spendingPrivateKey;
|
|
168
|
+
const viewingPrivKey = metaAddress.viewingPrivateKey;
|
|
169
|
+
keyValue("Spending Public Key", spendingPubKey);
|
|
170
|
+
keyValue("Viewing Public Key", viewingPubKey);
|
|
171
|
+
const encoded = (0, import_sdk.encodeStealthMetaAddress)(metaAddress.metaAddress);
|
|
172
|
+
keyValue("Encoded Address", encoded);
|
|
173
|
+
console.log();
|
|
174
|
+
warning("PRIVATE KEYS - Keep these secure!");
|
|
175
|
+
keyValue("Spending Private Key", spendingPrivKey);
|
|
176
|
+
keyValue("Viewing Private Key", viewingPrivKey);
|
|
177
|
+
} catch (err) {
|
|
178
|
+
console.error("Failed to generate keys:", err);
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/commands/commit.ts
|
|
185
|
+
var import_commander3 = require("commander");
|
|
186
|
+
var import_sdk2 = require("@sip-protocol/sdk");
|
|
187
|
+
function createCommitCommand() {
|
|
188
|
+
return new import_commander3.Command("commit").description("Create Pedersen commitment").argument("<amount>", "Amount to commit").option("-b, --blinding <factor>", "Blinding factor (hex, optional)").option("--verify", "Verify the commitment after creation").action(async (amountStr, options) => {
|
|
189
|
+
try {
|
|
190
|
+
heading("Create Pedersen Commitment");
|
|
191
|
+
const amount = BigInt(amountStr);
|
|
192
|
+
info(`Committing amount: ${amount}`);
|
|
193
|
+
const commitment = options.blinding ? (0, import_sdk2.commit)(amount, options.blinding) : (0, import_sdk2.commit)(amount);
|
|
194
|
+
success("Commitment created");
|
|
195
|
+
keyValue("Commitment", commitment.commitment);
|
|
196
|
+
keyValue("Blinding Factor", commitment.blinding);
|
|
197
|
+
keyValue("Amount", amount.toString());
|
|
198
|
+
if (options.verify) {
|
|
199
|
+
console.log();
|
|
200
|
+
info("Verifying commitment...");
|
|
201
|
+
const isValid = (0, import_sdk2.verifyOpening)(commitment.commitment, amount, commitment.blinding);
|
|
202
|
+
if (isValid) {
|
|
203
|
+
success("Commitment verified successfully");
|
|
204
|
+
} else {
|
|
205
|
+
console.error("Commitment verification failed");
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
} catch (err) {
|
|
210
|
+
console.error("Failed to create commitment:", err);
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/commands/prove.ts
|
|
217
|
+
var import_commander4 = require("commander");
|
|
218
|
+
var import_sdk3 = require("@sip-protocol/sdk");
|
|
219
|
+
function createProveCommand() {
|
|
220
|
+
const prove = new import_commander4.Command("prove").description("Generate ZK proof");
|
|
221
|
+
prove.command("funding").description("Generate funding proof").requiredOption("-b, --balance <amount>", "Current balance").requiredOption("-m, --minimum <amount>", "Minimum required").option("-a, --asset <id>", "Asset identifier", "ETH").option("-u, --user <address>", "User address", "0x0000000000000000000000000000000000000000").action(async (options) => {
|
|
222
|
+
try {
|
|
223
|
+
heading("Generate Funding Proof");
|
|
224
|
+
const blindingFactor = new Uint8Array(32);
|
|
225
|
+
const ownershipSignature = new Uint8Array(64);
|
|
226
|
+
const params = {
|
|
227
|
+
balance: BigInt(options.balance),
|
|
228
|
+
minimumRequired: BigInt(options.minimum),
|
|
229
|
+
blindingFactor,
|
|
230
|
+
assetId: options.asset,
|
|
231
|
+
userAddress: options.user,
|
|
232
|
+
ownershipSignature
|
|
233
|
+
};
|
|
234
|
+
const spin = spinner("Generating proof...");
|
|
235
|
+
const provider = new import_sdk3.MockProofProvider({ silent: true });
|
|
236
|
+
await provider.initialize();
|
|
237
|
+
const result = await provider.generateFundingProof(params);
|
|
238
|
+
spin.succeed("Proof generated");
|
|
239
|
+
success("Funding proof created");
|
|
240
|
+
keyValue("Proof", result.proof.proof);
|
|
241
|
+
keyValue("Public Inputs", JSON.stringify(result.publicInputs));
|
|
242
|
+
keyValue("Type", result.proof.type);
|
|
243
|
+
} catch (err) {
|
|
244
|
+
console.error("Failed to generate proof:", err);
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
prove.command("validity").description("Generate validity proof").requiredOption("-i, --intent <hash>", "Intent hash").requiredOption("-s, --sender <address>", "Sender address").action(async (options) => {
|
|
249
|
+
try {
|
|
250
|
+
heading("Generate Validity Proof");
|
|
251
|
+
const senderBlinding = new Uint8Array(32);
|
|
252
|
+
const senderSecret = new Uint8Array(32);
|
|
253
|
+
const authorizationSignature = new Uint8Array(64);
|
|
254
|
+
const nonce = new Uint8Array(32);
|
|
255
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
256
|
+
const params = {
|
|
257
|
+
intentHash: options.intent,
|
|
258
|
+
senderAddress: options.sender,
|
|
259
|
+
senderBlinding,
|
|
260
|
+
senderSecret,
|
|
261
|
+
authorizationSignature,
|
|
262
|
+
nonce,
|
|
263
|
+
timestamp: now,
|
|
264
|
+
expiry: now + 300
|
|
265
|
+
// 5 minutes from now
|
|
266
|
+
};
|
|
267
|
+
const spin = spinner("Generating proof...");
|
|
268
|
+
const provider = new import_sdk3.MockProofProvider({ silent: true });
|
|
269
|
+
await provider.initialize();
|
|
270
|
+
const result = await provider.generateValidityProof(params);
|
|
271
|
+
spin.succeed("Proof generated");
|
|
272
|
+
success("Validity proof created");
|
|
273
|
+
keyValue("Proof", result.proof.proof);
|
|
274
|
+
keyValue("Public Inputs", JSON.stringify(result.publicInputs));
|
|
275
|
+
keyValue("Type", result.proof.type);
|
|
276
|
+
} catch (err) {
|
|
277
|
+
console.error("Failed to generate proof:", err);
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
return prove;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// src/commands/verify.ts
|
|
285
|
+
var import_commander5 = require("commander");
|
|
286
|
+
var import_sdk4 = require("@sip-protocol/sdk");
|
|
287
|
+
function createVerifyCommand() {
|
|
288
|
+
return new import_commander5.Command("verify").description("Verify ZK proof").argument("<proof>", "Proof to verify (hex string)").option("-t, --type <type>", "Proof type (funding|validity|fulfillment)", "funding").option("-p, --public-inputs <json>", "Public inputs (JSON array)").action(async (proofHex, options) => {
|
|
289
|
+
try {
|
|
290
|
+
heading("Verify ZK Proof");
|
|
291
|
+
info(`Proof type: ${options.type}`);
|
|
292
|
+
info(`Proof: ${proofHex.slice(0, 20)}...`);
|
|
293
|
+
const publicInputs = options.publicInputs ? JSON.parse(options.publicInputs) : [];
|
|
294
|
+
const proofHexStr = proofHex.startsWith("0x") ? proofHex : `0x${proofHex}`;
|
|
295
|
+
const zkProof = {
|
|
296
|
+
type: options.type,
|
|
297
|
+
proof: proofHexStr,
|
|
298
|
+
publicInputs
|
|
299
|
+
};
|
|
300
|
+
const spin = spinner("Verifying proof...");
|
|
301
|
+
const provider = new import_sdk4.MockProofProvider({ silent: true });
|
|
302
|
+
await provider.initialize();
|
|
303
|
+
const isValid = await provider.verifyProof(zkProof);
|
|
304
|
+
spin.stop();
|
|
305
|
+
if (isValid) {
|
|
306
|
+
success(`Proof is valid (type: ${options.type})`);
|
|
307
|
+
} else {
|
|
308
|
+
error("Proof is invalid");
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
} catch (err) {
|
|
312
|
+
console.error("Failed to verify proof:", err);
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// src/commands/quote.ts
|
|
319
|
+
var import_commander6 = require("commander");
|
|
320
|
+
var import_sdk5 = require("@sip-protocol/sdk");
|
|
321
|
+
function createQuoteCommand() {
|
|
322
|
+
return new import_commander6.Command("quote").description("Get swap quote").argument("<from-chain>", "Source chain (e.g., ethereum, solana)").argument("<to-chain>", "Destination chain").argument("<amount>", "Amount to swap").option("-t, --token <symbol>", "Token symbol (default: native token)").option("-p, --privacy <level>", "Privacy level (transparent|shielded|compliant)").action(async (fromChain, toChain, amountStr, options) => {
|
|
323
|
+
try {
|
|
324
|
+
heading("Get Swap Quote");
|
|
325
|
+
const config = getConfig();
|
|
326
|
+
const amount = BigInt(amountStr);
|
|
327
|
+
const privacy = options.privacy || config.defaultPrivacy;
|
|
328
|
+
const sip = (0, import_sdk5.createSIP)(config.network);
|
|
329
|
+
const spin = spinner("Fetching quotes...");
|
|
330
|
+
const inputAsset = import_sdk5.NATIVE_TOKENS[fromChain] || {
|
|
331
|
+
chain: fromChain,
|
|
332
|
+
symbol: options.token || "native",
|
|
333
|
+
address: null,
|
|
334
|
+
decimals: 18
|
|
335
|
+
};
|
|
336
|
+
const outputAsset = import_sdk5.NATIVE_TOKENS[toChain] || {
|
|
337
|
+
chain: toChain,
|
|
338
|
+
symbol: options.token || "native",
|
|
339
|
+
address: null,
|
|
340
|
+
decimals: 18
|
|
341
|
+
};
|
|
342
|
+
const intent = await sip.createIntent({
|
|
343
|
+
input: {
|
|
344
|
+
asset: inputAsset,
|
|
345
|
+
amount
|
|
346
|
+
},
|
|
347
|
+
output: {
|
|
348
|
+
asset: outputAsset,
|
|
349
|
+
minAmount: 0n,
|
|
350
|
+
// Accept any amount for quote discovery
|
|
351
|
+
maxSlippage: 0.05
|
|
352
|
+
// 5% slippage tolerance
|
|
353
|
+
},
|
|
354
|
+
privacy
|
|
355
|
+
});
|
|
356
|
+
const quotes = await sip.getQuotes(intent);
|
|
357
|
+
spin.succeed(`Found ${quotes.length} quote(s)`);
|
|
358
|
+
if (quotes.length === 0) {
|
|
359
|
+
console.log("\nNo quotes available");
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
console.log();
|
|
363
|
+
const headers = ["Solver", "Output Amount", "Fee", "Time (s)"];
|
|
364
|
+
const rows = quotes.map((q) => [
|
|
365
|
+
q.solverId,
|
|
366
|
+
formatAmount(q.outputAmount),
|
|
367
|
+
formatAmount(q.fee),
|
|
368
|
+
q.estimatedTime.toString()
|
|
369
|
+
]);
|
|
370
|
+
table(headers, rows);
|
|
371
|
+
const best = quotes[0];
|
|
372
|
+
console.log();
|
|
373
|
+
success("Best quote:");
|
|
374
|
+
keyValue("Solver", best.solverId);
|
|
375
|
+
keyValue("Output Amount", formatAmount(best.outputAmount));
|
|
376
|
+
keyValue("Estimated Time", `${best.estimatedTime}s`);
|
|
377
|
+
} catch (err) {
|
|
378
|
+
console.error("Failed to get quote:", err);
|
|
379
|
+
process.exit(1);
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// src/commands/swap.ts
|
|
385
|
+
var import_commander7 = require("commander");
|
|
386
|
+
var import_sdk6 = require("@sip-protocol/sdk");
|
|
387
|
+
function createSwapCommand() {
|
|
388
|
+
return new import_commander7.Command("swap").description("Execute swap").argument("<from-chain>", "Source chain (e.g., ethereum, solana)").argument("<to-chain>", "Destination chain").argument("<amount>", "Amount to swap").option("-t, --token <symbol>", "Token symbol (default: native token)").option("-p, --privacy <level>", "Privacy level (transparent|shielded|compliant)").option("-r, --recipient <address>", "Recipient address (optional)").option("--solver <id>", "Specific solver to use").action(async (fromChain, toChain, amountStr, options) => {
|
|
389
|
+
try {
|
|
390
|
+
heading("Execute Swap");
|
|
391
|
+
const config = getConfig();
|
|
392
|
+
const amount = BigInt(amountStr);
|
|
393
|
+
const privacy = options.privacy || config.defaultPrivacy;
|
|
394
|
+
const sip = (0, import_sdk6.createSIP)(config.network);
|
|
395
|
+
const inputAsset = import_sdk6.NATIVE_TOKENS[fromChain] || {
|
|
396
|
+
chain: fromChain,
|
|
397
|
+
symbol: options.token || "native",
|
|
398
|
+
address: null,
|
|
399
|
+
decimals: 18
|
|
400
|
+
};
|
|
401
|
+
const outputAsset = import_sdk6.NATIVE_TOKENS[toChain] || {
|
|
402
|
+
chain: toChain,
|
|
403
|
+
symbol: options.token || "native",
|
|
404
|
+
address: null,
|
|
405
|
+
decimals: 18
|
|
406
|
+
};
|
|
407
|
+
info("Creating shielded intent...");
|
|
408
|
+
const intent = await sip.createIntent({
|
|
409
|
+
input: {
|
|
410
|
+
asset: inputAsset,
|
|
411
|
+
amount
|
|
412
|
+
},
|
|
413
|
+
output: {
|
|
414
|
+
asset: outputAsset,
|
|
415
|
+
minAmount: 0n,
|
|
416
|
+
// Accept any amount
|
|
417
|
+
maxSlippage: 0.05
|
|
418
|
+
// 5% slippage tolerance
|
|
419
|
+
},
|
|
420
|
+
privacy,
|
|
421
|
+
recipientMetaAddress: options.recipient
|
|
422
|
+
});
|
|
423
|
+
success("Intent created");
|
|
424
|
+
keyValue("Intent ID", formatHash(intent.intentId));
|
|
425
|
+
const spin = spinner("Fetching quotes...");
|
|
426
|
+
const quotes = await sip.getQuotes(intent);
|
|
427
|
+
spin.succeed(`Found ${quotes.length} quote(s)`);
|
|
428
|
+
if (quotes.length === 0) {
|
|
429
|
+
console.error("\nNo quotes available");
|
|
430
|
+
process.exit(1);
|
|
431
|
+
}
|
|
432
|
+
const selectedQuote = options.solver ? quotes.find((q) => q.solverId === options.solver) : quotes[0];
|
|
433
|
+
if (!selectedQuote) {
|
|
434
|
+
console.error(`
|
|
435
|
+
Solver not found: ${options.solver}`);
|
|
436
|
+
process.exit(1);
|
|
437
|
+
}
|
|
438
|
+
info(`Using solver: ${selectedQuote.solverId}`);
|
|
439
|
+
keyValue("Output Amount", formatAmount(selectedQuote.outputAmount));
|
|
440
|
+
const executeSpin = spinner("Executing swap...");
|
|
441
|
+
const result = await sip.execute(intent, selectedQuote);
|
|
442
|
+
executeSpin.succeed("Swap executed");
|
|
443
|
+
success("Swap completed successfully");
|
|
444
|
+
if (result.txHash) {
|
|
445
|
+
keyValue("Transaction Hash", formatHash(result.txHash));
|
|
446
|
+
}
|
|
447
|
+
if (result.outputAmount) {
|
|
448
|
+
keyValue("Output Amount", formatAmount(result.outputAmount));
|
|
449
|
+
}
|
|
450
|
+
keyValue("Status", result.status);
|
|
451
|
+
} catch (err) {
|
|
452
|
+
console.error("Failed to execute swap:", err);
|
|
453
|
+
process.exit(1);
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// src/commands/scan.ts
|
|
459
|
+
var import_commander8 = require("commander");
|
|
460
|
+
var import_sdk7 = require("@sip-protocol/sdk");
|
|
461
|
+
function createScanCommand() {
|
|
462
|
+
return new import_commander8.Command("scan").description("Scan for stealth payments").requiredOption("-c, --chain <chain>", "Chain to scan (ethereum, solana, near)").requiredOption("-s, --spending-key <key>", "Your spending private key (hex)").requiredOption("-v, --viewing-key <key>", "Your viewing private key (hex)").option("-a, --addresses <addresses...>", "Specific addresses to check").action(async (options) => {
|
|
463
|
+
try {
|
|
464
|
+
heading("Scan for Stealth Payments");
|
|
465
|
+
const chain = options.chain;
|
|
466
|
+
const useEd25519 = (0, import_sdk7.isEd25519Chain)(chain);
|
|
467
|
+
info(`Scanning ${chain} for stealth payments...`);
|
|
468
|
+
info(`Using ${useEd25519 ? "ed25519" : "secp256k1"} curve`);
|
|
469
|
+
if (!options.addresses || options.addresses.length === 0) {
|
|
470
|
+
warning("No addresses provided. Specify addresses with -a flag.");
|
|
471
|
+
info("Example: sip scan -c ethereum -s 0x... -v 0x... -a 0xabc... 0xdef...");
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const results = [];
|
|
475
|
+
for (const address of options.addresses) {
|
|
476
|
+
try {
|
|
477
|
+
let result;
|
|
478
|
+
if (useEd25519) {
|
|
479
|
+
result = (0, import_sdk7.checkEd25519StealthAddress)(
|
|
480
|
+
address,
|
|
481
|
+
options.spendingKey,
|
|
482
|
+
options.viewingKey
|
|
483
|
+
);
|
|
484
|
+
} else {
|
|
485
|
+
result = (0, import_sdk7.checkStealthAddress)(
|
|
486
|
+
address,
|
|
487
|
+
options.spendingKey,
|
|
488
|
+
options.viewingKey
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
results.push({
|
|
492
|
+
address,
|
|
493
|
+
isMine: result.isMine,
|
|
494
|
+
privateKey: result.isMine ? result.stealthPrivateKey : void 0
|
|
495
|
+
});
|
|
496
|
+
} catch (err) {
|
|
497
|
+
results.push({
|
|
498
|
+
address,
|
|
499
|
+
isMine: false
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
console.log();
|
|
504
|
+
const foundCount = results.filter((r) => r.isMine).length;
|
|
505
|
+
success(`Scanned ${results.length} address(es), found ${foundCount} stealth payment(s)`);
|
|
506
|
+
if (foundCount > 0) {
|
|
507
|
+
console.log();
|
|
508
|
+
const headers = ["Address", "Match", "Private Key"];
|
|
509
|
+
const rows = results.filter((r) => r.isMine).map((r) => [
|
|
510
|
+
r.address.slice(0, 10) + "...",
|
|
511
|
+
"Yes",
|
|
512
|
+
r.privateKey ? r.privateKey.slice(0, 10) + "..." : "N/A"
|
|
513
|
+
]);
|
|
514
|
+
table(headers, rows);
|
|
515
|
+
console.log();
|
|
516
|
+
warning("Store the private keys securely to access these funds");
|
|
517
|
+
} else {
|
|
518
|
+
info("No stealth payments found");
|
|
519
|
+
}
|
|
520
|
+
} catch (err) {
|
|
521
|
+
console.error("Failed to scan:", err);
|
|
522
|
+
process.exit(1);
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// src/index.ts
|
|
528
|
+
var program = new import_commander9.Command();
|
|
529
|
+
program.name("sip").description("Shielded Intents Protocol (SIP) - Privacy layer for cross-chain transactions").version("0.1.0");
|
|
530
|
+
program.addCommand(createInitCommand());
|
|
531
|
+
program.addCommand(createKeygenCommand());
|
|
532
|
+
program.addCommand(createCommitCommand());
|
|
533
|
+
program.addCommand(createProveCommand());
|
|
534
|
+
program.addCommand(createVerifyCommand());
|
|
535
|
+
program.addCommand(createQuoteCommand());
|
|
536
|
+
program.addCommand(createSwapCommand());
|
|
537
|
+
program.addCommand(createScanCommand());
|
|
538
|
+
program.parse();
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command as Command9 } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/commands/init.ts
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
import { PrivacyLevel } from "@sip-protocol/types";
|
|
9
|
+
|
|
10
|
+
// src/utils/config.ts
|
|
11
|
+
import Conf from "conf";
|
|
12
|
+
var schema = {
|
|
13
|
+
network: {
|
|
14
|
+
type: "string",
|
|
15
|
+
default: "testnet"
|
|
16
|
+
},
|
|
17
|
+
defaultPrivacy: {
|
|
18
|
+
type: "string",
|
|
19
|
+
default: "transparent"
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var store = new Conf({
|
|
23
|
+
projectName: "sip-protocol",
|
|
24
|
+
schema
|
|
25
|
+
});
|
|
26
|
+
function getConfig() {
|
|
27
|
+
return {
|
|
28
|
+
network: store.get("network"),
|
|
29
|
+
defaultPrivacy: store.get("defaultPrivacy"),
|
|
30
|
+
defaultChain: store.get("defaultChain"),
|
|
31
|
+
rpcEndpoints: store.get("rpcEndpoints")
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function setConfig(key, value) {
|
|
35
|
+
store.set(key, value);
|
|
36
|
+
}
|
|
37
|
+
function resetConfig() {
|
|
38
|
+
store.clear();
|
|
39
|
+
}
|
|
40
|
+
function getConfigPath() {
|
|
41
|
+
return store.path;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/utils/output.ts
|
|
45
|
+
import chalk from "chalk";
|
|
46
|
+
import ora from "ora";
|
|
47
|
+
function success(message) {
|
|
48
|
+
console.log(chalk.green("\u2713"), message);
|
|
49
|
+
}
|
|
50
|
+
function error(message) {
|
|
51
|
+
console.error(chalk.red("\u2717"), message);
|
|
52
|
+
}
|
|
53
|
+
function warning(message) {
|
|
54
|
+
console.warn(chalk.yellow("\u26A0"), message);
|
|
55
|
+
}
|
|
56
|
+
function info(message) {
|
|
57
|
+
console.log(chalk.blue("\u2139"), message);
|
|
58
|
+
}
|
|
59
|
+
function heading(message) {
|
|
60
|
+
console.log(chalk.bold.cyan(`
|
|
61
|
+
${message}
|
|
62
|
+
`));
|
|
63
|
+
}
|
|
64
|
+
function keyValue(key, value) {
|
|
65
|
+
console.log(chalk.gray(` ${key}:`), chalk.white(String(value)));
|
|
66
|
+
}
|
|
67
|
+
function spinner(text) {
|
|
68
|
+
return ora(text).start();
|
|
69
|
+
}
|
|
70
|
+
function table(headers, rows) {
|
|
71
|
+
const colWidths = headers.map(
|
|
72
|
+
(h, i) => Math.max(h.length, ...rows.map((r) => String(r[i] || "").length))
|
|
73
|
+
);
|
|
74
|
+
console.log(
|
|
75
|
+
headers.map((h, i) => chalk.bold(h.padEnd(colWidths[i]))).join(" ")
|
|
76
|
+
);
|
|
77
|
+
console.log(colWidths.map((w) => "\u2500".repeat(w)).join(" "));
|
|
78
|
+
rows.forEach((row) => {
|
|
79
|
+
console.log(
|
|
80
|
+
row.map((cell, i) => String(cell).padEnd(colWidths[i])).join(" ")
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function formatAmount(amount, decimals = 18) {
|
|
85
|
+
const divisor = 10n ** BigInt(decimals);
|
|
86
|
+
const integer = amount / divisor;
|
|
87
|
+
const fraction = amount % divisor;
|
|
88
|
+
const fractionStr = fraction.toString().padStart(decimals, "0").slice(0, 6);
|
|
89
|
+
return `${integer}.${fractionStr}`;
|
|
90
|
+
}
|
|
91
|
+
function formatHash(hash, length = 8) {
|
|
92
|
+
if (hash.length <= length * 2) return hash;
|
|
93
|
+
return `${hash.slice(0, length)}...${hash.slice(-length)}`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/commands/init.ts
|
|
97
|
+
function createInitCommand() {
|
|
98
|
+
return new Command("init").description("Initialize SIP configuration").option("-n, --network <network>", "Network (mainnet|testnet)", "testnet").option("-p, --privacy <level>", "Default privacy level", "transparent").option("--reset", "Reset configuration to defaults").action(async (options) => {
|
|
99
|
+
try {
|
|
100
|
+
heading("Initialize SIP Protocol");
|
|
101
|
+
if (options.reset) {
|
|
102
|
+
resetConfig();
|
|
103
|
+
success("Configuration reset to defaults");
|
|
104
|
+
}
|
|
105
|
+
const privacy = options.privacy;
|
|
106
|
+
if (!Object.values(PrivacyLevel).includes(privacy)) {
|
|
107
|
+
throw new Error(`Invalid privacy level: ${privacy}`);
|
|
108
|
+
}
|
|
109
|
+
setConfig("network", options.network);
|
|
110
|
+
setConfig("defaultPrivacy", privacy);
|
|
111
|
+
success("SIP initialized successfully");
|
|
112
|
+
info(`Network: ${options.network}`);
|
|
113
|
+
info(`Default Privacy: ${privacy}`);
|
|
114
|
+
info(`Config file: ${getConfigPath()}`);
|
|
115
|
+
} catch (err) {
|
|
116
|
+
console.error("Failed to initialize:", err);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/commands/keygen.ts
|
|
123
|
+
import { Command as Command2 } from "commander";
|
|
124
|
+
import {
|
|
125
|
+
generateStealthMetaAddress,
|
|
126
|
+
generateEd25519StealthMetaAddress,
|
|
127
|
+
isEd25519Chain,
|
|
128
|
+
encodeStealthMetaAddress
|
|
129
|
+
} from "@sip-protocol/sdk";
|
|
130
|
+
function createKeygenCommand() {
|
|
131
|
+
return new Command2("keygen").description("Generate stealth meta-address").option("-c, --chain <chain>", "Target chain (ethereum, solana, near)", "ethereum").option("--spending-key <key>", "Spending private key (hex)").option("--viewing-key <key>", "Viewing private key (hex)").action(async (options) => {
|
|
132
|
+
try {
|
|
133
|
+
heading("Generate Stealth Meta-Address");
|
|
134
|
+
const chain = options.chain;
|
|
135
|
+
const useEd25519 = isEd25519Chain(chain);
|
|
136
|
+
let metaAddress;
|
|
137
|
+
if (useEd25519) {
|
|
138
|
+
if (options.spendingKey || options.viewingKey) {
|
|
139
|
+
warning("Ed25519 chains do not support custom keys in CLI yet");
|
|
140
|
+
}
|
|
141
|
+
metaAddress = generateEd25519StealthMetaAddress(chain);
|
|
142
|
+
} else {
|
|
143
|
+
metaAddress = generateStealthMetaAddress(chain);
|
|
144
|
+
}
|
|
145
|
+
success("Stealth meta-address generated");
|
|
146
|
+
keyValue("Chain", chain);
|
|
147
|
+
const spendingPubKey = metaAddress.metaAddress.spendingKey;
|
|
148
|
+
const viewingPubKey = metaAddress.metaAddress.viewingKey;
|
|
149
|
+
const spendingPrivKey = metaAddress.spendingPrivateKey;
|
|
150
|
+
const viewingPrivKey = metaAddress.viewingPrivateKey;
|
|
151
|
+
keyValue("Spending Public Key", spendingPubKey);
|
|
152
|
+
keyValue("Viewing Public Key", viewingPubKey);
|
|
153
|
+
const encoded = encodeStealthMetaAddress(metaAddress.metaAddress);
|
|
154
|
+
keyValue("Encoded Address", encoded);
|
|
155
|
+
console.log();
|
|
156
|
+
warning("PRIVATE KEYS - Keep these secure!");
|
|
157
|
+
keyValue("Spending Private Key", spendingPrivKey);
|
|
158
|
+
keyValue("Viewing Private Key", viewingPrivKey);
|
|
159
|
+
} catch (err) {
|
|
160
|
+
console.error("Failed to generate keys:", err);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/commands/commit.ts
|
|
167
|
+
import { Command as Command3 } from "commander";
|
|
168
|
+
import { commit, verifyOpening } from "@sip-protocol/sdk";
|
|
169
|
+
function createCommitCommand() {
|
|
170
|
+
return new Command3("commit").description("Create Pedersen commitment").argument("<amount>", "Amount to commit").option("-b, --blinding <factor>", "Blinding factor (hex, optional)").option("--verify", "Verify the commitment after creation").action(async (amountStr, options) => {
|
|
171
|
+
try {
|
|
172
|
+
heading("Create Pedersen Commitment");
|
|
173
|
+
const amount = BigInt(amountStr);
|
|
174
|
+
info(`Committing amount: ${amount}`);
|
|
175
|
+
const commitment = options.blinding ? commit(amount, options.blinding) : commit(amount);
|
|
176
|
+
success("Commitment created");
|
|
177
|
+
keyValue("Commitment", commitment.commitment);
|
|
178
|
+
keyValue("Blinding Factor", commitment.blinding);
|
|
179
|
+
keyValue("Amount", amount.toString());
|
|
180
|
+
if (options.verify) {
|
|
181
|
+
console.log();
|
|
182
|
+
info("Verifying commitment...");
|
|
183
|
+
const isValid = verifyOpening(commitment.commitment, amount, commitment.blinding);
|
|
184
|
+
if (isValid) {
|
|
185
|
+
success("Commitment verified successfully");
|
|
186
|
+
} else {
|
|
187
|
+
console.error("Commitment verification failed");
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} catch (err) {
|
|
192
|
+
console.error("Failed to create commitment:", err);
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// src/commands/prove.ts
|
|
199
|
+
import { Command as Command4 } from "commander";
|
|
200
|
+
import { MockProofProvider } from "@sip-protocol/sdk";
|
|
201
|
+
function createProveCommand() {
|
|
202
|
+
const prove = new Command4("prove").description("Generate ZK proof");
|
|
203
|
+
prove.command("funding").description("Generate funding proof").requiredOption("-b, --balance <amount>", "Current balance").requiredOption("-m, --minimum <amount>", "Minimum required").option("-a, --asset <id>", "Asset identifier", "ETH").option("-u, --user <address>", "User address", "0x0000000000000000000000000000000000000000").action(async (options) => {
|
|
204
|
+
try {
|
|
205
|
+
heading("Generate Funding Proof");
|
|
206
|
+
const blindingFactor = new Uint8Array(32);
|
|
207
|
+
const ownershipSignature = new Uint8Array(64);
|
|
208
|
+
const params = {
|
|
209
|
+
balance: BigInt(options.balance),
|
|
210
|
+
minimumRequired: BigInt(options.minimum),
|
|
211
|
+
blindingFactor,
|
|
212
|
+
assetId: options.asset,
|
|
213
|
+
userAddress: options.user,
|
|
214
|
+
ownershipSignature
|
|
215
|
+
};
|
|
216
|
+
const spin = spinner("Generating proof...");
|
|
217
|
+
const provider = new MockProofProvider({ silent: true });
|
|
218
|
+
await provider.initialize();
|
|
219
|
+
const result = await provider.generateFundingProof(params);
|
|
220
|
+
spin.succeed("Proof generated");
|
|
221
|
+
success("Funding proof created");
|
|
222
|
+
keyValue("Proof", result.proof.proof);
|
|
223
|
+
keyValue("Public Inputs", JSON.stringify(result.publicInputs));
|
|
224
|
+
keyValue("Type", result.proof.type);
|
|
225
|
+
} catch (err) {
|
|
226
|
+
console.error("Failed to generate proof:", err);
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
prove.command("validity").description("Generate validity proof").requiredOption("-i, --intent <hash>", "Intent hash").requiredOption("-s, --sender <address>", "Sender address").action(async (options) => {
|
|
231
|
+
try {
|
|
232
|
+
heading("Generate Validity Proof");
|
|
233
|
+
const senderBlinding = new Uint8Array(32);
|
|
234
|
+
const senderSecret = new Uint8Array(32);
|
|
235
|
+
const authorizationSignature = new Uint8Array(64);
|
|
236
|
+
const nonce = new Uint8Array(32);
|
|
237
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
238
|
+
const params = {
|
|
239
|
+
intentHash: options.intent,
|
|
240
|
+
senderAddress: options.sender,
|
|
241
|
+
senderBlinding,
|
|
242
|
+
senderSecret,
|
|
243
|
+
authorizationSignature,
|
|
244
|
+
nonce,
|
|
245
|
+
timestamp: now,
|
|
246
|
+
expiry: now + 300
|
|
247
|
+
// 5 minutes from now
|
|
248
|
+
};
|
|
249
|
+
const spin = spinner("Generating proof...");
|
|
250
|
+
const provider = new MockProofProvider({ silent: true });
|
|
251
|
+
await provider.initialize();
|
|
252
|
+
const result = await provider.generateValidityProof(params);
|
|
253
|
+
spin.succeed("Proof generated");
|
|
254
|
+
success("Validity proof created");
|
|
255
|
+
keyValue("Proof", result.proof.proof);
|
|
256
|
+
keyValue("Public Inputs", JSON.stringify(result.publicInputs));
|
|
257
|
+
keyValue("Type", result.proof.type);
|
|
258
|
+
} catch (err) {
|
|
259
|
+
console.error("Failed to generate proof:", err);
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
return prove;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// src/commands/verify.ts
|
|
267
|
+
import { Command as Command5 } from "commander";
|
|
268
|
+
import { MockProofProvider as MockProofProvider2 } from "@sip-protocol/sdk";
|
|
269
|
+
function createVerifyCommand() {
|
|
270
|
+
return new Command5("verify").description("Verify ZK proof").argument("<proof>", "Proof to verify (hex string)").option("-t, --type <type>", "Proof type (funding|validity|fulfillment)", "funding").option("-p, --public-inputs <json>", "Public inputs (JSON array)").action(async (proofHex, options) => {
|
|
271
|
+
try {
|
|
272
|
+
heading("Verify ZK Proof");
|
|
273
|
+
info(`Proof type: ${options.type}`);
|
|
274
|
+
info(`Proof: ${proofHex.slice(0, 20)}...`);
|
|
275
|
+
const publicInputs = options.publicInputs ? JSON.parse(options.publicInputs) : [];
|
|
276
|
+
const proofHexStr = proofHex.startsWith("0x") ? proofHex : `0x${proofHex}`;
|
|
277
|
+
const zkProof = {
|
|
278
|
+
type: options.type,
|
|
279
|
+
proof: proofHexStr,
|
|
280
|
+
publicInputs
|
|
281
|
+
};
|
|
282
|
+
const spin = spinner("Verifying proof...");
|
|
283
|
+
const provider = new MockProofProvider2({ silent: true });
|
|
284
|
+
await provider.initialize();
|
|
285
|
+
const isValid = await provider.verifyProof(zkProof);
|
|
286
|
+
spin.stop();
|
|
287
|
+
if (isValid) {
|
|
288
|
+
success(`Proof is valid (type: ${options.type})`);
|
|
289
|
+
} else {
|
|
290
|
+
error("Proof is invalid");
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
} catch (err) {
|
|
294
|
+
console.error("Failed to verify proof:", err);
|
|
295
|
+
process.exit(1);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// src/commands/quote.ts
|
|
301
|
+
import { Command as Command6 } from "commander";
|
|
302
|
+
import { createSIP, NATIVE_TOKENS } from "@sip-protocol/sdk";
|
|
303
|
+
function createQuoteCommand() {
|
|
304
|
+
return new Command6("quote").description("Get swap quote").argument("<from-chain>", "Source chain (e.g., ethereum, solana)").argument("<to-chain>", "Destination chain").argument("<amount>", "Amount to swap").option("-t, --token <symbol>", "Token symbol (default: native token)").option("-p, --privacy <level>", "Privacy level (transparent|shielded|compliant)").action(async (fromChain, toChain, amountStr, options) => {
|
|
305
|
+
try {
|
|
306
|
+
heading("Get Swap Quote");
|
|
307
|
+
const config = getConfig();
|
|
308
|
+
const amount = BigInt(amountStr);
|
|
309
|
+
const privacy = options.privacy || config.defaultPrivacy;
|
|
310
|
+
const sip = createSIP(config.network);
|
|
311
|
+
const spin = spinner("Fetching quotes...");
|
|
312
|
+
const inputAsset = NATIVE_TOKENS[fromChain] || {
|
|
313
|
+
chain: fromChain,
|
|
314
|
+
symbol: options.token || "native",
|
|
315
|
+
address: null,
|
|
316
|
+
decimals: 18
|
|
317
|
+
};
|
|
318
|
+
const outputAsset = NATIVE_TOKENS[toChain] || {
|
|
319
|
+
chain: toChain,
|
|
320
|
+
symbol: options.token || "native",
|
|
321
|
+
address: null,
|
|
322
|
+
decimals: 18
|
|
323
|
+
};
|
|
324
|
+
const intent = await sip.createIntent({
|
|
325
|
+
input: {
|
|
326
|
+
asset: inputAsset,
|
|
327
|
+
amount
|
|
328
|
+
},
|
|
329
|
+
output: {
|
|
330
|
+
asset: outputAsset,
|
|
331
|
+
minAmount: 0n,
|
|
332
|
+
// Accept any amount for quote discovery
|
|
333
|
+
maxSlippage: 0.05
|
|
334
|
+
// 5% slippage tolerance
|
|
335
|
+
},
|
|
336
|
+
privacy
|
|
337
|
+
});
|
|
338
|
+
const quotes = await sip.getQuotes(intent);
|
|
339
|
+
spin.succeed(`Found ${quotes.length} quote(s)`);
|
|
340
|
+
if (quotes.length === 0) {
|
|
341
|
+
console.log("\nNo quotes available");
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
console.log();
|
|
345
|
+
const headers = ["Solver", "Output Amount", "Fee", "Time (s)"];
|
|
346
|
+
const rows = quotes.map((q) => [
|
|
347
|
+
q.solverId,
|
|
348
|
+
formatAmount(q.outputAmount),
|
|
349
|
+
formatAmount(q.fee),
|
|
350
|
+
q.estimatedTime.toString()
|
|
351
|
+
]);
|
|
352
|
+
table(headers, rows);
|
|
353
|
+
const best = quotes[0];
|
|
354
|
+
console.log();
|
|
355
|
+
success("Best quote:");
|
|
356
|
+
keyValue("Solver", best.solverId);
|
|
357
|
+
keyValue("Output Amount", formatAmount(best.outputAmount));
|
|
358
|
+
keyValue("Estimated Time", `${best.estimatedTime}s`);
|
|
359
|
+
} catch (err) {
|
|
360
|
+
console.error("Failed to get quote:", err);
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// src/commands/swap.ts
|
|
367
|
+
import { Command as Command7 } from "commander";
|
|
368
|
+
import { createSIP as createSIP2, NATIVE_TOKENS as NATIVE_TOKENS2 } from "@sip-protocol/sdk";
|
|
369
|
+
function createSwapCommand() {
|
|
370
|
+
return new Command7("swap").description("Execute swap").argument("<from-chain>", "Source chain (e.g., ethereum, solana)").argument("<to-chain>", "Destination chain").argument("<amount>", "Amount to swap").option("-t, --token <symbol>", "Token symbol (default: native token)").option("-p, --privacy <level>", "Privacy level (transparent|shielded|compliant)").option("-r, --recipient <address>", "Recipient address (optional)").option("--solver <id>", "Specific solver to use").action(async (fromChain, toChain, amountStr, options) => {
|
|
371
|
+
try {
|
|
372
|
+
heading("Execute Swap");
|
|
373
|
+
const config = getConfig();
|
|
374
|
+
const amount = BigInt(amountStr);
|
|
375
|
+
const privacy = options.privacy || config.defaultPrivacy;
|
|
376
|
+
const sip = createSIP2(config.network);
|
|
377
|
+
const inputAsset = NATIVE_TOKENS2[fromChain] || {
|
|
378
|
+
chain: fromChain,
|
|
379
|
+
symbol: options.token || "native",
|
|
380
|
+
address: null,
|
|
381
|
+
decimals: 18
|
|
382
|
+
};
|
|
383
|
+
const outputAsset = NATIVE_TOKENS2[toChain] || {
|
|
384
|
+
chain: toChain,
|
|
385
|
+
symbol: options.token || "native",
|
|
386
|
+
address: null,
|
|
387
|
+
decimals: 18
|
|
388
|
+
};
|
|
389
|
+
info("Creating shielded intent...");
|
|
390
|
+
const intent = await sip.createIntent({
|
|
391
|
+
input: {
|
|
392
|
+
asset: inputAsset,
|
|
393
|
+
amount
|
|
394
|
+
},
|
|
395
|
+
output: {
|
|
396
|
+
asset: outputAsset,
|
|
397
|
+
minAmount: 0n,
|
|
398
|
+
// Accept any amount
|
|
399
|
+
maxSlippage: 0.05
|
|
400
|
+
// 5% slippage tolerance
|
|
401
|
+
},
|
|
402
|
+
privacy,
|
|
403
|
+
recipientMetaAddress: options.recipient
|
|
404
|
+
});
|
|
405
|
+
success("Intent created");
|
|
406
|
+
keyValue("Intent ID", formatHash(intent.intentId));
|
|
407
|
+
const spin = spinner("Fetching quotes...");
|
|
408
|
+
const quotes = await sip.getQuotes(intent);
|
|
409
|
+
spin.succeed(`Found ${quotes.length} quote(s)`);
|
|
410
|
+
if (quotes.length === 0) {
|
|
411
|
+
console.error("\nNo quotes available");
|
|
412
|
+
process.exit(1);
|
|
413
|
+
}
|
|
414
|
+
const selectedQuote = options.solver ? quotes.find((q) => q.solverId === options.solver) : quotes[0];
|
|
415
|
+
if (!selectedQuote) {
|
|
416
|
+
console.error(`
|
|
417
|
+
Solver not found: ${options.solver}`);
|
|
418
|
+
process.exit(1);
|
|
419
|
+
}
|
|
420
|
+
info(`Using solver: ${selectedQuote.solverId}`);
|
|
421
|
+
keyValue("Output Amount", formatAmount(selectedQuote.outputAmount));
|
|
422
|
+
const executeSpin = spinner("Executing swap...");
|
|
423
|
+
const result = await sip.execute(intent, selectedQuote);
|
|
424
|
+
executeSpin.succeed("Swap executed");
|
|
425
|
+
success("Swap completed successfully");
|
|
426
|
+
if (result.txHash) {
|
|
427
|
+
keyValue("Transaction Hash", formatHash(result.txHash));
|
|
428
|
+
}
|
|
429
|
+
if (result.outputAmount) {
|
|
430
|
+
keyValue("Output Amount", formatAmount(result.outputAmount));
|
|
431
|
+
}
|
|
432
|
+
keyValue("Status", result.status);
|
|
433
|
+
} catch (err) {
|
|
434
|
+
console.error("Failed to execute swap:", err);
|
|
435
|
+
process.exit(1);
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// src/commands/scan.ts
|
|
441
|
+
import { Command as Command8 } from "commander";
|
|
442
|
+
import { checkStealthAddress, checkEd25519StealthAddress, isEd25519Chain as isEd25519Chain2 } from "@sip-protocol/sdk";
|
|
443
|
+
function createScanCommand() {
|
|
444
|
+
return new Command8("scan").description("Scan for stealth payments").requiredOption("-c, --chain <chain>", "Chain to scan (ethereum, solana, near)").requiredOption("-s, --spending-key <key>", "Your spending private key (hex)").requiredOption("-v, --viewing-key <key>", "Your viewing private key (hex)").option("-a, --addresses <addresses...>", "Specific addresses to check").action(async (options) => {
|
|
445
|
+
try {
|
|
446
|
+
heading("Scan for Stealth Payments");
|
|
447
|
+
const chain = options.chain;
|
|
448
|
+
const useEd25519 = isEd25519Chain2(chain);
|
|
449
|
+
info(`Scanning ${chain} for stealth payments...`);
|
|
450
|
+
info(`Using ${useEd25519 ? "ed25519" : "secp256k1"} curve`);
|
|
451
|
+
if (!options.addresses || options.addresses.length === 0) {
|
|
452
|
+
warning("No addresses provided. Specify addresses with -a flag.");
|
|
453
|
+
info("Example: sip scan -c ethereum -s 0x... -v 0x... -a 0xabc... 0xdef...");
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
const results = [];
|
|
457
|
+
for (const address of options.addresses) {
|
|
458
|
+
try {
|
|
459
|
+
let result;
|
|
460
|
+
if (useEd25519) {
|
|
461
|
+
result = checkEd25519StealthAddress(
|
|
462
|
+
address,
|
|
463
|
+
options.spendingKey,
|
|
464
|
+
options.viewingKey
|
|
465
|
+
);
|
|
466
|
+
} else {
|
|
467
|
+
result = checkStealthAddress(
|
|
468
|
+
address,
|
|
469
|
+
options.spendingKey,
|
|
470
|
+
options.viewingKey
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
results.push({
|
|
474
|
+
address,
|
|
475
|
+
isMine: result.isMine,
|
|
476
|
+
privateKey: result.isMine ? result.stealthPrivateKey : void 0
|
|
477
|
+
});
|
|
478
|
+
} catch (err) {
|
|
479
|
+
results.push({
|
|
480
|
+
address,
|
|
481
|
+
isMine: false
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
console.log();
|
|
486
|
+
const foundCount = results.filter((r) => r.isMine).length;
|
|
487
|
+
success(`Scanned ${results.length} address(es), found ${foundCount} stealth payment(s)`);
|
|
488
|
+
if (foundCount > 0) {
|
|
489
|
+
console.log();
|
|
490
|
+
const headers = ["Address", "Match", "Private Key"];
|
|
491
|
+
const rows = results.filter((r) => r.isMine).map((r) => [
|
|
492
|
+
r.address.slice(0, 10) + "...",
|
|
493
|
+
"Yes",
|
|
494
|
+
r.privateKey ? r.privateKey.slice(0, 10) + "..." : "N/A"
|
|
495
|
+
]);
|
|
496
|
+
table(headers, rows);
|
|
497
|
+
console.log();
|
|
498
|
+
warning("Store the private keys securely to access these funds");
|
|
499
|
+
} else {
|
|
500
|
+
info("No stealth payments found");
|
|
501
|
+
}
|
|
502
|
+
} catch (err) {
|
|
503
|
+
console.error("Failed to scan:", err);
|
|
504
|
+
process.exit(1);
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// src/index.ts
|
|
510
|
+
var program = new Command9();
|
|
511
|
+
program.name("sip").description("Shielded Intents Protocol (SIP) - Privacy layer for cross-chain transactions").version("0.1.0");
|
|
512
|
+
program.addCommand(createInitCommand());
|
|
513
|
+
program.addCommand(createKeygenCommand());
|
|
514
|
+
program.addCommand(createCommitCommand());
|
|
515
|
+
program.addCommand(createProveCommand());
|
|
516
|
+
program.addCommand(createVerifyCommand());
|
|
517
|
+
program.addCommand(createQuoteCommand());
|
|
518
|
+
program.addCommand(createSwapCommand());
|
|
519
|
+
program.addCommand(createScanCommand());
|
|
520
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sip-protocol/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Command-line tool for Shielded Intents Protocol (SIP) operations",
|
|
5
|
+
"author": "SIP Protocol <hello@sip-protocol.org>",
|
|
6
|
+
"homepage": "https://sip-protocol.org",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/sip-protocol/sip-protocol.git",
|
|
10
|
+
"directory": "packages/cli"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/sip-protocol/sip-protocol/issues"
|
|
14
|
+
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"sip": "./bin/sip.js"
|
|
17
|
+
},
|
|
18
|
+
"main": "./dist/index.js",
|
|
19
|
+
"module": "./dist/index.mjs",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"files": [
|
|
22
|
+
"bin",
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@sip-protocol/sdk": "^0.6.0",
|
|
27
|
+
"@sip-protocol/types": "^0.2.0",
|
|
28
|
+
"commander": "^12.0.0",
|
|
29
|
+
"chalk": "^4.1.2",
|
|
30
|
+
"ora": "^5.4.1",
|
|
31
|
+
"conf": "^10.2.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^20.10.0",
|
|
35
|
+
"tsup": "^8.0.0",
|
|
36
|
+
"typescript": "^5.3.0",
|
|
37
|
+
"vitest": "^1.1.0"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"sip",
|
|
41
|
+
"cli",
|
|
42
|
+
"privacy",
|
|
43
|
+
"intents",
|
|
44
|
+
"cross-chain",
|
|
45
|
+
"stealth-addresses",
|
|
46
|
+
"zcash"
|
|
47
|
+
],
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsup src/index.ts --format cjs,esm --dts && chmod +x bin/sip.js",
|
|
51
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
52
|
+
"lint": "eslint --ext .ts src/",
|
|
53
|
+
"typecheck": "tsc --noEmit",
|
|
54
|
+
"clean": "rm -rf dist",
|
|
55
|
+
"test": "vitest --passWithNoTests"
|
|
56
|
+
}
|
|
57
|
+
}
|