Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d829c0a
add scanner commands (nonce/cluster/operator) and improve help UX
martinssvlabs Mar 30, 2026
f05de6f
integrate scanner commands into ssv-keys and improve help UX
martinssvlabs Mar 30, 2026
0baa9e6
centralize operator-id parsing and validation
martinssvlabs Apr 1, 2026
312e4d0
make operator argument validation stateless and stricter
martinssvlabs Apr 1, 2026
6342784
await file writes and improve sdk cache keying
martinssvlabs Apr 1, 2026
52d98ae
regenerate cli bundles
martinssvlabs Apr 1, 2026
9e7ac51
add adaptive binary entrypoint with scanner command support
martinssvlabs Apr 1, 2026
1bf6415
regenerate bundles for cli-binary packaging
martinssvlabs Apr 1, 2026
93dd663
run fresh build before packaging binaries on all platforms
martinssvlabs Apr 1, 2026
5d8ed05
remove explicit any types and prune unused command/action logic
martinssvlabs Apr 2, 2026
94046cf
refactor(scanner): align cluster and operator scans with latest sdk
martinssvlabs May 12, 2026
5767098
refactor(shares): use sdk keyshares helpers in offline flow
martinssvlabs May 13, 2026
cc47a31
chore(deps): use published @ssv-labs/ssv-sdk@1.0.2
martinssvlabs May 22, 2026
a9136fe
chore(release): refresh dist
martinssvlabs May 22, 2026
60fa97a
chore(ci): rerun workflows
martinssvlabs May 26, 2026
572556a
chore(pnpm): move build approvals to pnpm-workspace
martinssvlabs May 26, 2026
e37c9d1
chore(pnpm): switch build approvals to allowBuilds
martinssvlabs May 26, 2026
f135ff9
fix(cli): improve scanner validation and command error handling
martinssvlabs May 28, 2026
1d9eb55
fix(cli): improve scanner validation and refresh dist
martinssvlabs May 28, 2026
16dbf07
chore(package): avoid redundant rebuilds in packaging scripts
martinssvlabs May 28, 2026
b9c43ba
test(cluster): increase ClusterAction test timeout
martinssvlabs May 28, 2026
6ea65c9
fix(cli): improve scanner error handling and refresh dist
martinssvlabs May 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,22 @@ If you want to run a compiled version (easier option than the CLI)
```bash
./ssv-keys-mac
```
The executable supports both interactive and command modes:
* Interactive mode (choose action from prompt):
```bash
./ssv-keys-mac
```
* Command mode (explicit action):
```bash
./ssv-keys-mac shares --help
./ssv-keys-mac nonce --help
./ssv-keys-mac cluster --help
./ssv-keys-mac operator --help
```
* Legacy shares mode is still supported for backward compatibility:
```bash
./ssv-keys-mac --keystore=./validator_keys --password=... --operator-ids=... --operator-keys=... --owner-address=... --owner-nonce=...
```
7. If your operating system prevents you from running the executable, you can open it from the file manager (Finder in case of macOS), right-click on it, and click the `Open` menu. Once open click the `Open` or `allow` button when you are asked to do so. After this, go back to the console and try to run it again.

## Option 2: Running from the CLI
Expand Down
161 changes: 161 additions & 0 deletions dist/ccip-B6NEIIlP.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const cliShared = require("./cli-shared-Bd3M9dlh.js");
class OffchainLookupError extends cliShared.BaseError {
constructor({ callbackSelector, cause, data, extraData, sender, urls }) {
super(cause.shortMessage || "An error occurred while fetching for an offchain result.", {
cause,
metaMessages: [
...cause.metaMessages || [],
cause.metaMessages?.length ? "" : [],
"Offchain Gateway Call:",
urls && [
" Gateway URL(s):",
...urls.map((url) => ` ${cliShared.getUrl(url)}`)
],
` Sender: ${sender}`,
` Data: ${data}`,
` Callback selector: ${callbackSelector}`,
` Extra data: ${extraData}`
].flat(),
name: "OffchainLookupError"
});
}
}
class OffchainLookupResponseMalformedError extends cliShared.BaseError {
constructor({ result, url }) {
super("Offchain gateway response is malformed. Response data must be a hex value.", {
metaMessages: [
`Gateway URL: ${cliShared.getUrl(url)}`,
`Response: ${cliShared.stringify(result)}`
],
name: "OffchainLookupResponseMalformedError"
});
}
}
class OffchainLookupSenderMismatchError extends cliShared.BaseError {
constructor({ sender, to }) {
super("Reverted sender address does not match target contract address (`to`).", {
metaMessages: [
`Contract address: ${to}`,
`OffchainLookup sender address: ${sender}`
],
name: "OffchainLookupSenderMismatchError"
});
}
}
const offchainLookupSignature = "0x556f1830";
const offchainLookupAbiItem = {
name: "OffchainLookup",
type: "error",
inputs: [
{
name: "sender",
type: "address"
},
{
name: "urls",
type: "string[]"
},
{
name: "callData",
type: "bytes"
},
{
name: "callbackFunction",
type: "bytes4"
},
{
name: "extraData",
type: "bytes"
}
]
};
async function offchainLookup(client, { blockNumber, blockTag, data, to }) {
const { args } = cliShared.decodeErrorResult({
data,
abi: [offchainLookupAbiItem]
});
const [sender, urls, callData, callbackSelector, extraData] = args;
const { ccipRead } = client;
const ccipRequest_ = ccipRead && typeof ccipRead?.request === "function" ? ccipRead.request : ccipRequest;
try {
if (!cliShared.isAddressEqual(to, sender))
throw new OffchainLookupSenderMismatchError({ sender, to });
const result = urls.includes(cliShared.localBatchGatewayUrl) ? await cliShared.localBatchGatewayRequest({
data: callData,
ccipRequest: ccipRequest_
}) : await ccipRequest_({ data: callData, sender, urls });
const { data: data_ } = await cliShared.call(client, {
blockNumber,
blockTag,
data: cliShared.concat([
callbackSelector,
cliShared.encodeAbiParameters([{ type: "bytes" }, { type: "bytes" }], [result, extraData])
]),
to
});
return data_;
} catch (err) {
throw new OffchainLookupError({
callbackSelector,
cause: err,
data,
extraData,
sender,
urls
});
}
}
async function ccipRequest({ data, sender, urls }) {
let error = new Error("An unknown error occurred.");
for (let i = 0; i < urls.length; i++) {
const url = urls[i];
const method = url.includes("{data}") ? "GET" : "POST";
const body = method === "POST" ? { data, sender } : void 0;
const headers = method === "POST" ? { "Content-Type": "application/json" } : {};
try {
const response = await fetch(url.replace("{sender}", sender.toLowerCase()).replace("{data}", data), {
body: JSON.stringify(body),
headers,
method
});
let result;
if (response.headers.get("Content-Type")?.startsWith("application/json")) {
result = (await response.json()).data;
} else {
result = await response.text();
}
if (!response.ok) {
error = new cliShared.HttpRequestError({
body,
details: result?.error ? cliShared.stringify(result.error) : response.statusText,
headers: response.headers,
status: response.status,
url
});
continue;
}
if (!cliShared.isHex(result)) {
error = new OffchainLookupResponseMalformedError({
result,
url
});
continue;
}
return result;
} catch (err) {
error = new cliShared.HttpRequestError({
body,
details: err.message,
url
});
}
}
throw error;
}
exports.ccipRequest = ccipRequest;
exports.offchainLookup = offchainLookup;
exports.offchainLookupAbiItem = offchainLookupAbiItem;
exports.offchainLookupSignature = offchainLookupSignature;
161 changes: 161 additions & 0 deletions dist/ccip-D8s-6Vk2.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#!/usr/bin/env node
import { B as BaseError, g as getUrl, s as stringify, d as decodeErrorResult, i as isAddressEqual, l as localBatchGatewayUrl, a as localBatchGatewayRequest, c as call, b as concat, e as encodeAbiParameters, H as HttpRequestError, f as isHex } from "./cli-shared-CS0ocOPN.mjs";
class OffchainLookupError extends BaseError {
constructor({ callbackSelector, cause, data, extraData, sender, urls }) {
super(cause.shortMessage || "An error occurred while fetching for an offchain result.", {
cause,
metaMessages: [
...cause.metaMessages || [],
cause.metaMessages?.length ? "" : [],
"Offchain Gateway Call:",
urls && [
" Gateway URL(s):",
...urls.map((url) => ` ${getUrl(url)}`)
],
` Sender: ${sender}`,
` Data: ${data}`,
` Callback selector: ${callbackSelector}`,
` Extra data: ${extraData}`
].flat(),
name: "OffchainLookupError"
});
}
}
class OffchainLookupResponseMalformedError extends BaseError {
constructor({ result, url }) {
super("Offchain gateway response is malformed. Response data must be a hex value.", {
metaMessages: [
`Gateway URL: ${getUrl(url)}`,
`Response: ${stringify(result)}`
],
name: "OffchainLookupResponseMalformedError"
});
}
}
class OffchainLookupSenderMismatchError extends BaseError {
constructor({ sender, to }) {
super("Reverted sender address does not match target contract address (`to`).", {
metaMessages: [
`Contract address: ${to}`,
`OffchainLookup sender address: ${sender}`
],
name: "OffchainLookupSenderMismatchError"
});
}
}
const offchainLookupSignature = "0x556f1830";
const offchainLookupAbiItem = {
name: "OffchainLookup",
type: "error",
inputs: [
{
name: "sender",
type: "address"
},
{
name: "urls",
type: "string[]"
},
{
name: "callData",
type: "bytes"
},
{
name: "callbackFunction",
type: "bytes4"
},
{
name: "extraData",
type: "bytes"
}
]
};
async function offchainLookup(client, { blockNumber, blockTag, data, to }) {
const { args } = decodeErrorResult({
data,
abi: [offchainLookupAbiItem]
});
const [sender, urls, callData, callbackSelector, extraData] = args;
const { ccipRead } = client;
const ccipRequest_ = ccipRead && typeof ccipRead?.request === "function" ? ccipRead.request : ccipRequest;
try {
if (!isAddressEqual(to, sender))
throw new OffchainLookupSenderMismatchError({ sender, to });
const result = urls.includes(localBatchGatewayUrl) ? await localBatchGatewayRequest({
data: callData,
ccipRequest: ccipRequest_
}) : await ccipRequest_({ data: callData, sender, urls });
const { data: data_ } = await call(client, {
blockNumber,
blockTag,
data: concat([
callbackSelector,
encodeAbiParameters([{ type: "bytes" }, { type: "bytes" }], [result, extraData])
]),
to
});
return data_;
} catch (err) {
throw new OffchainLookupError({
callbackSelector,
cause: err,
data,
extraData,
sender,
urls
});
}
}
async function ccipRequest({ data, sender, urls }) {
let error = new Error("An unknown error occurred.");
for (let i = 0; i < urls.length; i++) {
const url = urls[i];
const method = url.includes("{data}") ? "GET" : "POST";
const body = method === "POST" ? { data, sender } : void 0;
const headers = method === "POST" ? { "Content-Type": "application/json" } : {};
try {
const response = await fetch(url.replace("{sender}", sender.toLowerCase()).replace("{data}", data), {
body: JSON.stringify(body),
headers,
method
});
let result;
if (response.headers.get("Content-Type")?.startsWith("application/json")) {
result = (await response.json()).data;
} else {
result = await response.text();
}
if (!response.ok) {
error = new HttpRequestError({
body,
details: result?.error ? stringify(result.error) : response.statusText,
headers: response.headers,
status: response.status,
url
});
continue;
}
if (!isHex(result)) {
error = new OffchainLookupResponseMalformedError({
result,
url
});
continue;
}
return result;
} catch (err) {
error = new HttpRequestError({
body,
details: err.message,
url
});
}
}
throw error;
}
export {
ccipRequest,
offchainLookup,
offchainLookupAbiItem,
offchainLookupSignature
};
Loading
Loading