@m2msentinel/sdk 1.1.1 → 1.1.2

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 CHANGED
@@ -2,33 +2,122 @@
2
2
 
3
3
  Production API Base URL: `https://api.m2msentinel.com` (with fallback `https://m2msentinel.com`).
4
4
 
5
- M2M Sentinel reports selected static EVM bytecode capabilities, common proxy structures, evidence quality, and sourced Base market observations. Factual static capability observation — not a formal reachability audit, safety guarantee, or transaction advice. Transaction middleware therefore requires a caller-defined policy and has no built-in allow threshold.
5
+ Deterministic EVM bytecode and proxy capability intelligence on Base. Factual static capability observation — not a formal reachability audit, safety guarantee, or transaction advice. Live latency depends on RPC availability and deployment geography; transaction middleware requires a caller-defined policy and has no built-in decision threshold.
6
+
7
+ ---
8
+
9
+ ## 🏗️ Recommended Defense-in-Depth Pipeline for Agents
10
+
11
+ Autonomous agents handling value must never rely on a single oracle or heuristic. M2M Sentinel can supply static observations as Layer 1 of a caller-owned pipeline:
12
+
13
+ ```text
14
+ [Agent Intent]
15
+
16
+
17
+ [Transaction Builder]
18
+
19
+
20
+ [Stage 1: M2M Sentinel Observation] ── (Bytecode hash, proxy target, selected opcode/selector evidence)
21
+
22
+
23
+ [Stage 2: Local Policy Engine] ── (Caller-defined rules: Check spending bounds, reject DELEGATECALL, verify allowlist)
24
+
25
+
26
+ [Stage 3: Execution Simulation] ── (eth_call / Tenderly / Trace state simulation)
27
+
28
+
29
+ [Stage 4: Sub-Wallet Signing] ── (Scoped ephemeral wallet signs & broadcasts on Base)
30
+ ```
31
+
32
+ ---
6
33
 
7
34
  ## Installation
8
35
 
9
36
  ### JavaScript / TypeScript (npm)
10
37
 
11
38
  ```bash
12
- npm install m2m-sentinel-sdk@1.1.1
39
+ # Scoped package (recommended)
40
+ npm install @m2msentinel/sdk
41
+
42
+ # Or unscoped package
43
+ npm install m2m-sentinel-sdk@1.1.2
13
44
  ```
14
45
 
15
46
  ### Python (PyPI)
16
47
 
17
48
  ```bash
18
- pip install m2m-sentinel==1.1.0
49
+ pip install m2m-sentinel==1.1.2
19
50
  ```
20
51
 
21
52
  ### MCP Server (Model Context Protocol)
22
53
 
23
54
  ```bash
24
- npx -y m2m-sentinel-sdk
55
+ npx -y @m2msentinel/sdk
25
56
  # or
26
- npx -y m2m-sentinel-mcp
57
+ npx -y m2m-sentinel-sdk
58
+ ```
59
+
60
+ ---
61
+
62
+ ## Quickstart: JavaScript / TypeScript
63
+
64
+ ```javascript
65
+ const { M2MSentinelClient, X402SignerClient } = require('@m2msentinel/sdk');
66
+
67
+ // 1. Standard API Client (Header Authentication)
68
+ const client = new M2MSentinelClient({
69
+ apiKey: process.env.M2M_SENTINEL_API_KEY,
70
+ baseUrl: 'https://api.m2msentinel.com'
71
+ });
72
+
73
+ // Inspect contract capabilities before transaction
74
+ const audit = await client.auditContract('0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913');
75
+ console.log('Contract capabilities:', audit.audit.verdict.executableCapabilities);
76
+ console.log('Capability evidence:', audit.audit.dissection.capabilities);
77
+ console.log('Proxy Target:', audit.audit.proxyResolution.targetAddress);
78
+ console.log('Reachability:', audit.audit.reachability || 'NOT_ESTABLISHED');
79
+
80
+ // 2. Autonomous Headless x402 Micropayments (EIP-3009 Local Signing)
81
+ const x402Client = new X402SignerClient({
82
+ walletSigner: myAgentWallet, // ethers / viem signer
83
+ baseUrl: 'https://api.m2msentinel.com',
84
+ maxPriceUsd: 0.01 // Optional: strict spending limit (default $0.05)
85
+ });
86
+
87
+ const res = await x402Client.fetchWithAutoPayment('/v1/audit/0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913');
88
+ console.log('Paid analysis result:', res.json);
89
+ ```
90
+
91
+ ---
92
+
93
+ ## 🛡️ Autonomous Wallet Policy & Security Boundaries
94
+
95
+ To prevent autonomous AI agents from blindly signing arbitrary or spoofed HTTP 402 challenges from untrusted sources, `X402SignerClient` enforces **4 strict client-side invariants** locally before generating any cryptographic signature:
96
+
97
+ | Client Invariant | Enforced Value | Security Protection |
98
+ | :--- | :--- | :--- |
99
+ | **Chain ID** | `8453` (Base Mainnet) | Rejects signing on any unapproved EVM chain. |
100
+ | **Asset Contract** | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | Rejects signing for unapproved tokens (Base USDC only). |
101
+ | **Payout Recipient** | `0x6d6c398390cfb88f1cd42715b84906a0bd6652aa` | Rejects signing payments to unexpected recipient addresses. |
102
+ | **Price Ceiling** | `maxPriceUsd` (Default: `$0.05`) | Throws if remote challenge requests funds exceeding caller's authorized ceiling. |
103
+
104
+ ```javascript
105
+ import { X402SignerClient } from '@m2msentinel/sdk';
106
+
107
+ // Fully policy-constrained autonomous signer with immutable recipient & domain constants
108
+ const signer = new X402SignerClient({
109
+ wallet: agentWallet,
110
+ maxPriceUsd: 0.005 // Strict spending limit: 0.5 cents max per decision (default $0.05)
111
+ });
27
112
  ```
28
113
 
114
+ ---
115
+
29
116
  ## Authentication and x402
30
117
 
31
- Send API keys only in `x-api-key` (or `Authorization: Bearer`). Query-string credentials are rejected with HTTP 401. Payable routes also support x402 v2 on Base USDC. An unpaid call returns a base64 `PAYMENT-REQUIRED` challenge when the facilitator is ready; a successful settlement returns `PAYMENT-RESPONSE`.
118
+ Send API keys only in `x-api-key` (or `Authorization: Bearer`). Query-string credentials are rejected with HTTP 401. Payable routes also support x402 v2 on Base USDC. An unpaid call returns a base64 `PAYMENT-REQUIRED` challenge; a successful settlement returns `PAYMENT-RESPONSE`.
119
+
120
+ ---
32
121
 
33
122
  ## Public Routes
34
123
 
@@ -40,7 +129,7 @@ Send API keys only in `x-api-key` (or `Authorization: Bearer`). Query-string cre
40
129
 
41
130
  The JavaScript, TypeScript, and Python clients expose multi-period purchase/renewal and wallet recovery without requiring callers to hand-build requests:
42
131
 
43
- ```js
132
+ ```javascript
44
133
  await client.createSubscriptionIntent('GROWTH', wallet, {
45
134
  durationDays: 90,
46
135
  renewExistingKey: true,
@@ -50,8 +139,8 @@ const challenge = await client.createRecoveryChallenge(wallet, { txHash });
50
139
  await client.claimRecoveredKey(challenge.intent.id, walletSignature);
51
140
  ```
52
141
 
53
- `getPublicStats()` returns the counter-free privacy envelope. Operator-only detail has a deliberately separate `getOperatorAggregateStats(days, token)` method and sends the operator token only as `Authorization: Bearer`. This is for private server/operator tooling only: never embed or bundle the operator token in browser, mobile, SDK-distribution, or customer code.
142
+ ---
54
143
 
55
144
  ## Disclaimer & Limitations
56
145
 
57
- M2M Sentinel extracts static EVM opcode capabilities and EIP-1967/UUPS proxy implementation slots on Base Mainnet. Factual static capability observation — not a formal reachability audit, safety guarantee, or transaction advice.
146
+ Deterministic EVM bytecode and proxy capability intelligence on Base. Factual static capability observation — not a formal reachability audit, safety guarantee, or transaction advice. Live latency depends on RPC availability and deployment geography.
package/agent_adapter.js CHANGED
@@ -13,6 +13,31 @@ const http = require('http');
13
13
  const DEFAULT_BASE_URL = process.env.M2M_SENTINEL_BASE_URL || 'https://api.m2msentinel.com';
14
14
  const DEFAULT_TIMEOUT_MS = Number(process.env.M2M_SENTINEL_TIMEOUT_MS || 30000);
15
15
 
16
+ function summarizeAuditResponse(body, requestedAddress) {
17
+ const audit = body && body.audit ? body.audit : {};
18
+ const proxy = audit.proxyResolution || {};
19
+ const capabilities = Array.isArray(audit.verdict && audit.verdict.executableCapabilities)
20
+ ? audit.verdict.executableCapabilities
21
+ : (audit.dissection && Array.isArray(audit.dissection.capabilities)
22
+ ? audit.dissection.capabilities
23
+ .map((item) => typeof item === 'string' ? item : item && item.type)
24
+ .filter(Boolean)
25
+ : []);
26
+
27
+ return {
28
+ address: audit.address || requestedAddress,
29
+ isContract: Boolean(audit.dissection && audit.dissection.isValidContract),
30
+ isProxy: Boolean(proxy.isProxy),
31
+ proxyType: proxy.proxyType || 'NONE',
32
+ targetAddress: proxy.targetAddress || null,
33
+ executableCapabilities: capabilities,
34
+ reachability: audit.reachability || 'NOT_ESTABLISHED',
35
+ trustLevel: audit.provenance && audit.provenance.trustLevel
36
+ ? audit.provenance.trustLevel
37
+ : 'NOT_REPORTED'
38
+ };
39
+ }
40
+
16
41
  class M2MSentinelActionProvider {
17
42
  constructor(options = {}) {
18
43
  this.name = 'm2m_sentinel';
@@ -42,7 +67,7 @@ class M2MSentinelActionProvider {
42
67
 
43
68
  const headers = {
44
69
  Accept: 'application/json',
45
- 'User-Agent': 'M2MSentinel-AgentKit/1.1.1',
70
+ 'User-Agent': 'M2MSentinel-AgentKit/1.1.2',
46
71
  ...options.headers
47
72
  };
48
73
  if (this.apiKey && !headers['x-api-key']) {
@@ -98,11 +123,13 @@ class M2MSentinelActionProvider {
98
123
  });
99
124
  }
100
125
 
126
+ const observation = summarizeAuditResponse(res.body, address);
101
127
  return JSON.stringify({
102
128
  status: 'SUCCESS',
103
129
  data: res.body,
104
130
  notASafetyGuarantee: true,
105
- observationSummary: `Contract ${address}: Type=${res.body.bytecodeAnalysis?.contractType || 'UNKNOWN'}, isProxy=${Boolean(res.body.proxyDetection?.isProxy)}`
131
+ observation,
132
+ observationSummary: `Contract ${observation.address}: isContract=${observation.isContract}, isProxy=${observation.isProxy}, proxyTarget=${observation.targetAddress || 'UNRESOLVED'}, capabilities=${observation.executableCapabilities.join(',') || 'NONE_OBSERVED'}, reachability=${observation.reachability}`
106
133
  });
107
134
  }
108
135
 
@@ -244,5 +271,6 @@ class M2MSentinelAgentTool extends M2MSentinelActionProvider {}
244
271
  module.exports = {
245
272
  M2MSentinelActionProvider,
246
273
  m2mSentinelActionProvider,
247
- M2MSentinelAgentTool
274
+ M2MSentinelAgentTool,
275
+ summarizeAuditResponse
248
276
  };
package/eliza_plugin.js CHANGED
@@ -1,4 +1,9 @@
1
- // UNSUPPORTED / COMMUNITY PREVIEW — not covered by the supported-SDK guarantee; verify against /openapi.json before production use.
1
+ /**
2
+ * M2M Sentinel ElizaOS Production Adapter Plugin
3
+ *
4
+ * Provides automated pre-transaction contract capability preflight and proxy inspection
5
+ * actions for autonomous agents running on the ElizaOS runtime framework.
6
+ */
2
7
 
3
8
  const { M2MSentinelClient } = require('./index.js');
4
9
 
@@ -81,4 +86,4 @@ const m2mSentinelPlugin = {
81
86
  ]
82
87
  };
83
88
 
84
- module.exports = { m2mSentinelPlugin };
89
+ module.exports = { m2mSentinelPlugin };
package/index.d.ts CHANGED
@@ -1,94 +1,113 @@
1
- export interface M2MSentinelClientOptions {
2
- apiKey?: string;
3
- baseUrl?: string;
4
- timeoutMs?: number;
5
- paymentSignature?: string;
6
- }
7
-
8
- export interface CreateSubscriptionIntentOptions extends M2MSentinelClientOptions {
9
- durationDays?: 31 | 90 | 365;
10
- renewExistingKey?: boolean;
11
- }
12
-
13
- export interface RecoveryChallengeOptions {
14
- txHash?: string;
15
- }
16
-
17
- export interface M2MSentinelErrorOptions {
18
- status?: number;
19
- body?: unknown;
20
- retryAfter?: string | null;
21
- paymentRequired?: unknown;
22
- paymentResponse?: unknown;
23
- }
24
-
25
- export class M2MSentinelError extends Error {
26
- readonly status?: number;
27
- readonly body?: unknown;
28
- readonly retryAfter?: string | null;
29
- readonly paymentRequired?: unknown;
30
- readonly paymentResponse?: unknown;
31
- constructor(message: string, options?: M2MSentinelErrorOptions);
32
- }
33
-
34
- export class PaymentRequiredError extends M2MSentinelError {}
35
- export class RateLimitedError extends M2MSentinelError {}
36
- export class DataSourceUnavailableError extends M2MSentinelError {}
37
-
38
- export class M2MSentinelClient {
39
- constructor(options?: M2MSentinelClientOptions);
40
- constructor(apiKey?: string, baseUrl?: string);
41
- request(method: string, path: string, body?: unknown, options?: M2MSentinelClientOptions): Promise<any>;
42
- getStatus(): Promise<any>;
43
- getPublicStats(days?: number): Promise<any>;
44
- /** Backward-compatible alias for getPublicStats; customer keys never reveal operator counters. */
45
- getAggregateStats(days?: number): Promise<any>;
46
- getOperatorAggregateStats(days: number, operatorToken: string): Promise<any>;
47
- getPlans(): Promise<any>;
48
- demoAudit(address: string): Promise<any>;
49
- createFreeChallenge(userWallet: string): Promise<any>;
50
- claimFreeTier(intentId: string, signature: string): Promise<any>;
51
- createSubscriptionIntent(tier: string, userWallet: string, options?: CreateSubscriptionIntentOptions): Promise<any>;
52
- claimSubscription(intentId: string, signature: string, txHash: string): Promise<any>;
53
- createRecoveryChallenge(userWallet: string, options?: RecoveryChallengeOptions): Promise<any>;
54
- claimRecoveredKey(intentId: string, signature: string): Promise<any>;
55
- auditContract(address: string, options?: M2MSentinelClientOptions): Promise<any>;
56
- getCapabilityScore(address: string, options?: M2MSentinelClientOptions): Promise<any>;
57
- /** Legacy alias. The response is a capability coverage index, not a safety score. */
58
- getSecurityScore(address: string, options?: M2MSentinelClientOptions): Promise<any>;
59
- getGasFees(options?: M2MSentinelClientOptions): Promise<any>;
60
- getDexMetrics(options?: M2MSentinelClientOptions): Promise<any>;
61
- getTokenPrice(symbol: string, options?: M2MSentinelClientOptions): Promise<any>;
62
- getWhaleSignals(options?: M2MSentinelClientOptions): Promise<any>;
63
- getKeySelf(): Promise<any>;
64
- revokeKey(confirm?: boolean): Promise<any>;
65
- }
66
-
67
- export type SentinelPolicy = (
68
- analysis: any,
69
- context: { targetAddress: string; integration: string }
70
- ) => boolean | { allow: boolean; reason?: string } | Promise<boolean | { allow: boolean; reason?: string }>;
71
-
72
- export function enforceCallerPolicy(
73
- policy: SentinelPolicy | undefined,
74
- analysis: any,
75
- context: { targetAddress: string; integration: string }
76
- ): Promise<void>;
77
-
78
- export function createEthersSentinelMiddleware(
79
- apiKey?: string,
80
- baseUrl?: string,
81
- policy?: SentinelPolicy
82
- ): {
83
- client: M2MSentinelClient;
84
- verifyContractBeforeTx(targetAddress: string, policyOverride?: SentinelPolicy): Promise<any>;
85
- };
86
-
87
- export function createViemSentinelInterceptor(
88
- apiKey?: string,
89
- baseUrl?: string,
90
- policy?: SentinelPolicy
91
- ): {
92
- client: M2MSentinelClient;
93
- inspectSwapTarget(address: string, policyOverride?: SentinelPolicy): Promise<any>;
94
- };
1
+ export interface M2MSentinelClientOptions {
2
+ apiKey?: string;
3
+ baseUrl?: string;
4
+ timeoutMs?: number;
5
+ paymentSignature?: string;
6
+ }
7
+
8
+ export interface CreateSubscriptionIntentOptions extends M2MSentinelClientOptions {
9
+ durationDays?: 31 | 90 | 365;
10
+ renewExistingKey?: boolean;
11
+ }
12
+
13
+ export interface RecoveryChallengeOptions {
14
+ txHash?: string;
15
+ }
16
+
17
+ export interface M2MSentinelErrorOptions {
18
+ status?: number;
19
+ body?: unknown;
20
+ retryAfter?: string | null;
21
+ paymentRequired?: unknown;
22
+ paymentResponse?: unknown;
23
+ }
24
+
25
+ export class M2MSentinelError extends Error {
26
+ readonly status?: number;
27
+ readonly body?: unknown;
28
+ readonly retryAfter?: string | null;
29
+ readonly paymentRequired?: unknown;
30
+ readonly paymentResponse?: unknown;
31
+ constructor(message: string, options?: M2MSentinelErrorOptions);
32
+ }
33
+
34
+ export class PaymentRequiredError extends M2MSentinelError {}
35
+ export class RateLimitedError extends M2MSentinelError {}
36
+ export class DataSourceUnavailableError extends M2MSentinelError {}
37
+
38
+ export class M2MSentinelClient {
39
+ constructor(options?: M2MSentinelClientOptions);
40
+ constructor(apiKey?: string, baseUrl?: string);
41
+ request(method: string, path: string, body?: unknown, options?: M2MSentinelClientOptions): Promise<any>;
42
+ getStatus(): Promise<any>;
43
+ getPublicStats(days?: number): Promise<any>;
44
+ /** Backward-compatible alias for getPublicStats; customer keys never reveal operator counters. */
45
+ getAggregateStats(days?: number): Promise<any>;
46
+ getOperatorAggregateStats(days: number, operatorToken: string): Promise<any>;
47
+ getPlans(): Promise<any>;
48
+ demoAudit(address: string): Promise<any>;
49
+ createFreeChallenge(userWallet: string): Promise<any>;
50
+ claimFreeTier(intentId: string, signature: string): Promise<any>;
51
+ createSubscriptionIntent(tier: string, userWallet: string, options?: CreateSubscriptionIntentOptions): Promise<any>;
52
+ claimSubscription(intentId: string, signature: string, txHash: string): Promise<any>;
53
+ createRecoveryChallenge(userWallet: string, options?: RecoveryChallengeOptions): Promise<any>;
54
+ claimRecoveredKey(intentId: string, signature: string): Promise<any>;
55
+ auditContract(address: string, options?: M2MSentinelClientOptions): Promise<any>;
56
+ getCapabilityScore(address: string, options?: M2MSentinelClientOptions): Promise<any>;
57
+ /** Legacy alias. The response is a capability coverage index, not a safety score. */
58
+ getSecurityScore(address: string, options?: M2MSentinelClientOptions): Promise<any>;
59
+ getGasFees(options?: M2MSentinelClientOptions): Promise<any>;
60
+ getDexMetrics(options?: M2MSentinelClientOptions): Promise<any>;
61
+ getTokenPrice(symbol: string, options?: M2MSentinelClientOptions): Promise<any>;
62
+ getWhaleSignals(options?: M2MSentinelClientOptions): Promise<any>;
63
+ getKeySelf(): Promise<any>;
64
+ revokeKey(confirm?: boolean): Promise<any>;
65
+ }
66
+
67
+ export type SentinelPolicy = (
68
+ analysis: any,
69
+ context: { targetAddress: string; integration: string }
70
+ ) => boolean | { allow: boolean; reason?: string } | Promise<boolean | { allow: boolean; reason?: string }>;
71
+
72
+ export function enforceCallerPolicy(
73
+ policy: SentinelPolicy | undefined,
74
+ analysis: any,
75
+ context: { targetAddress: string; integration: string }
76
+ ): Promise<void>;
77
+
78
+ export function createEthersSentinelMiddleware(
79
+ apiKey?: string,
80
+ baseUrl?: string,
81
+ policy?: SentinelPolicy
82
+ ): {
83
+ client: M2MSentinelClient;
84
+ verifyContractBeforeTx(targetAddress: string, policyOverride?: SentinelPolicy): Promise<any>;
85
+ };
86
+
87
+ export function createViemSentinelInterceptor(
88
+ apiKey?: string,
89
+ baseUrl?: string,
90
+ policy?: SentinelPolicy
91
+ ): {
92
+ client: M2MSentinelClient;
93
+ inspectSwapTarget(address: string, policyOverride?: SentinelPolicy): Promise<any>;
94
+ };
95
+
96
+ export interface X402SignerClientOptions {
97
+ wallet?: any;
98
+ walletSigner?: any;
99
+ privateKey?: string;
100
+ baseUrl?: string;
101
+ timeoutMs?: number;
102
+ }
103
+
104
+ export class X402SignerClient {
105
+ constructor(options?: X402SignerClientOptions);
106
+ signPaymentAuthorization(challenge: any): Promise<any>;
107
+ fetchWithAutoPayment(path: string, options?: any): Promise<any>;
108
+ }
109
+
110
+ export function x402SignerClient(options?: X402SignerClientOptions): X402SignerClient;
111
+ export function parsePaymentHeader(value: string | object | null): any;
112
+ export function parsePriceToUnits(priceStr: string | number, decimals?: number): bigint;
113
+