perp-cli 0.9.8 → 0.11.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.
@@ -0,0 +1,18 @@
1
+ import type { EvmSigner } from "./interface.js";
2
+ /**
3
+ * EVM signer backed by Open Wallet Standard.
4
+ * Keys never leave the OWS encrypted vault.
5
+ */
6
+ export declare class OwsEvmSigner implements EvmSigner {
7
+ private _address;
8
+ private _walletName;
9
+ private _passphrase;
10
+ private constructor();
11
+ static create(walletName: string, passphrase?: string): OwsEvmSigner;
12
+ getAddress(): string;
13
+ signTypedData(domain: Record<string, unknown>, types: Record<string, Array<{
14
+ name: string;
15
+ type: string;
16
+ }>>, value: Record<string, unknown>): Promise<string>;
17
+ signMessage(message: string | Uint8Array): Promise<string>;
18
+ }
@@ -0,0 +1,67 @@
1
+ import { loadOws } from "./ows-loader.js";
2
+ /**
3
+ * EVM signer backed by Open Wallet Standard.
4
+ * Keys never leave the OWS encrypted vault.
5
+ */
6
+ export class OwsEvmSigner {
7
+ _address;
8
+ _walletName;
9
+ _passphrase;
10
+ constructor(walletName, address, passphrase) {
11
+ this._walletName = walletName;
12
+ this._address = address;
13
+ this._passphrase = passphrase;
14
+ }
15
+ static create(walletName, passphrase = "") {
16
+ const ows = loadOws();
17
+ const wallet = ows.getWallet(walletName);
18
+ const evmAccount = wallet.accounts.find((a) => a.chainId.startsWith("eip155:"));
19
+ if (!evmAccount) {
20
+ throw new Error(`OWS wallet "${walletName}" has no EVM account`);
21
+ }
22
+ return new OwsEvmSigner(walletName, evmAccount.address, passphrase);
23
+ }
24
+ getAddress() {
25
+ return this._address;
26
+ }
27
+ async signTypedData(domain, types, value) {
28
+ const ows = loadOws();
29
+ // Build EIP-712 structure expected by OWS
30
+ const typedData = JSON.stringify({
31
+ types: {
32
+ EIP712Domain: Object.keys(domain).map((key) => ({
33
+ name: key,
34
+ type: inferEip712DomainType(key),
35
+ })),
36
+ ...types,
37
+ },
38
+ primaryType: Object.keys(types)[0],
39
+ domain,
40
+ message: value,
41
+ });
42
+ const result = ows.signTypedData(this._walletName, "evm", typedData, this._passphrase);
43
+ // OWS returns hex signature + recoveryId; combine to 65-byte EIP-712 sig
44
+ const sig = result.signature.startsWith("0x") ? result.signature : `0x${result.signature}`;
45
+ const v = result.recoveryId !== undefined ? result.recoveryId + 27 : 27;
46
+ return `${sig}${v.toString(16).padStart(2, "0")}`;
47
+ }
48
+ async signMessage(message) {
49
+ const ows = loadOws();
50
+ const msgStr = typeof message === "string"
51
+ ? message
52
+ : Buffer.from(message).toString("hex");
53
+ const encoding = typeof message === "string" ? "utf8" : "hex";
54
+ const result = ows.signMessage(this._walletName, "evm", msgStr, this._passphrase, encoding);
55
+ const sig = result.signature.startsWith("0x") ? result.signature : `0x${result.signature}`;
56
+ const v = result.recoveryId !== undefined ? result.recoveryId + 27 : 27;
57
+ return `${sig}${v.toString(16).padStart(2, "0")}`;
58
+ }
59
+ }
60
+ function inferEip712DomainType(key) {
61
+ switch (key) {
62
+ case "chainId": return "uint256";
63
+ case "verifyingContract": return "address";
64
+ case "salt": return "bytes32";
65
+ default: return "string";
66
+ }
67
+ }
@@ -0,0 +1,2 @@
1
+ /** Lazy-load the OWS native module (NAPI binding, requires CJS require). */
2
+ export declare function loadOws(): typeof import("@open-wallet-standard/core");
@@ -0,0 +1,6 @@
1
+ import { createRequire } from "node:module";
2
+ const _require = createRequire(import.meta.url);
3
+ /** Lazy-load the OWS native module (NAPI binding, requires CJS require). */
4
+ export function loadOws() {
5
+ return _require("@open-wallet-standard/core");
6
+ }
@@ -0,0 +1,25 @@
1
+ import type { SolanaSigner } from "./interface.js";
2
+ /**
3
+ * Solana signer backed by Open Wallet Standard.
4
+ * Keys never leave the OWS encrypted vault.
5
+ */
6
+ export declare class OwsSolanaSigner implements SolanaSigner {
7
+ private _address;
8
+ private _walletName;
9
+ private _passphrase;
10
+ private constructor();
11
+ static create(walletName: string, passphrase?: string): OwsSolanaSigner;
12
+ getPublicKeyBase58(): string;
13
+ signMessage(message: Uint8Array): Promise<Uint8Array>;
14
+ signTransaction(tx: {
15
+ sign(keypair: unknown): void;
16
+ }): void;
17
+ partialSignTransaction(tx: {
18
+ partialSign(keypair: unknown): void;
19
+ }): void;
20
+ /**
21
+ * Sign raw Solana transaction bytes via OWS.
22
+ * The caller is responsible for serializing/deserializing the transaction.
23
+ */
24
+ signTransactionBytes(txBytes: Uint8Array): Uint8Array;
25
+ }
@@ -0,0 +1,56 @@
1
+ import { loadOws } from "./ows-loader.js";
2
+ /**
3
+ * Solana signer backed by Open Wallet Standard.
4
+ * Keys never leave the OWS encrypted vault.
5
+ */
6
+ export class OwsSolanaSigner {
7
+ _address;
8
+ _walletName;
9
+ _passphrase;
10
+ constructor(walletName, address, passphrase) {
11
+ this._walletName = walletName;
12
+ this._address = address;
13
+ this._passphrase = passphrase;
14
+ }
15
+ static create(walletName, passphrase = "") {
16
+ const ows = loadOws();
17
+ const wallet = ows.getWallet(walletName);
18
+ const solAccount = wallet.accounts.find((a) => a.chainId.startsWith("solana:"));
19
+ if (!solAccount) {
20
+ throw new Error(`OWS wallet "${walletName}" has no Solana account`);
21
+ }
22
+ return new OwsSolanaSigner(walletName, solAccount.address, passphrase);
23
+ }
24
+ getPublicKeyBase58() {
25
+ return this._address;
26
+ }
27
+ async signMessage(message) {
28
+ const ows = loadOws();
29
+ const msgHex = Buffer.from(message).toString("hex");
30
+ const result = ows.signMessage(this._walletName, "solana", msgHex, this._passphrase, "hex");
31
+ // Convert hex signature to Uint8Array
32
+ const sigHex = result.signature.startsWith("0x") ? result.signature.slice(2) : result.signature;
33
+ return Uint8Array.from(Buffer.from(sigHex, "hex"));
34
+ }
35
+ signTransaction(tx) {
36
+ // OWS doesn't expose raw keypairs. For Solana transactions that require
37
+ // a keypair, we serialize -> sign via OWS -> inject signature back.
38
+ throw new Error("OWS signer does not support in-place tx.sign(). " +
39
+ "Use signTransactionBytes() or the deposit relayer instead.");
40
+ }
41
+ partialSignTransaction(tx) {
42
+ throw new Error("OWS signer does not support in-place tx.partialSign(). " +
43
+ "Use signTransactionBytes() or the deposit relayer instead.");
44
+ }
45
+ /**
46
+ * Sign raw Solana transaction bytes via OWS.
47
+ * The caller is responsible for serializing/deserializing the transaction.
48
+ */
49
+ signTransactionBytes(txBytes) {
50
+ const ows = loadOws();
51
+ const txHex = Buffer.from(txBytes).toString("hex");
52
+ const result = ows.signTransaction(this._walletName, "solana", txHex, this._passphrase);
53
+ const sigHex = result.signature.startsWith("0x") ? result.signature.slice(2) : result.signature;
54
+ return Uint8Array.from(Buffer.from(sigHex, "hex"));
55
+ }
56
+ }
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "perp-cli",
3
- "version": "0.9.8",
3
+ "version": "0.11.0",
4
4
  "description": "Multi-DEX Perpetual Futures CLI - Pacifica, Hyperliquid, Lighter, Aster",
5
5
  "bin": {
6
6
  "perp": "dist/index.js",
7
- "perp-mcp": "dist/mcp-server.js"
7
+ "perp-mcp": "dist/mcp-server.js",
8
+ "perp-guardrail": "dist/guardrail/perp-guardrail.js"
8
9
  },
9
10
  "files": [
10
11
  "dist",
@@ -45,6 +46,7 @@
45
46
  "dependencies": {
46
47
  "@modelcontextprotocol/sdk": "^1.27.1",
47
48
  "@msgpack/msgpack": "^3.1.3",
49
+ "@open-wallet-standard/core": "1.2.0",
48
50
  "@solana/web3.js": "^1.98.0",
49
51
  "@types/react": "^19.2.14",
50
52
  "bs58": "^6.0.0",