mofu-sdk 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -82,6 +82,19 @@ if (event.type === "owner_changed") pause(event.token!.address);
82
82
 
83
83
  `parseWebhook` throws when the signature is wrong or older than five minutes; `verifyWebhook` returns a boolean instead.
84
84
 
85
+ ## Read a verdict on-chain
86
+
87
+ Mofu publishes verdicts to its MofuVerdicts registry on Robinhood Chain. Read one straight from the chain, without Mofu's API limits:
88
+
89
+ ```ts
90
+ const v = await mofu.onchainVerdict(token); // finds the registry once via mofu.works
91
+ v.verdict; // "clean" | "caution" | "risky" | null (not published)
92
+ v.flags.sellFailed; // also honeypotCode, canMint, canPause, canBlock, upgradeable, fakeMofu
93
+ v.scannedAt; // Date | null
94
+ ```
95
+
96
+ Pass `{ registry, rpcUrl }` to skip the lookup or use your own node.
97
+
85
98
  ## Errors
86
99
 
87
100
  Failures throw `MofuError` with `status` and `code`: `daily_limit` (429), `bad_address` (400), `chain_unreachable` (503), `network` (Mofu couldn't be reached).
package/dist/index.d.ts CHANGED
@@ -39,6 +39,14 @@ export declare class Mofu {
39
39
  scanToken(address: string): Promise<Checked<TokenReport>>;
40
40
  /** Wallet Health: every active approval (risky ones flagged) and the tokens a wallet holds. */
41
41
  checkWallet(address: string): Promise<Checked<WalletReport>>;
42
+ /**
43
+ * A token's verdict as published on Robinhood Chain (the MofuVerdicts registry), read straight
44
+ * from the chain with one eth_call. Pass `registry` to skip asking mofu.works where it is.
45
+ */
46
+ onchainVerdict(token: string, options?: {
47
+ registry?: string;
48
+ rpcUrl?: string;
49
+ }): Promise<OnchainVerdict>;
42
50
  /** Scans a token and applies a buy rule. Says no, with a reason, when Mofu can't be reached. */
43
51
  checkBeforeBuy(address: string, policy?: Partial<Policy>): Promise<Decision>;
44
52
  readonly webhooks: {
@@ -98,3 +106,21 @@ export declare function parseWebhook(signatureHeader: string | null | undefined,
98
106
  toleranceSeconds?: number;
99
107
  now?: number;
100
108
  }): Promise<WebhookEvent>;
109
+ export interface OnchainVerdict {
110
+ registry: string;
111
+ /** null when Mofu hasn't published one for this token. */
112
+ verdict: "clean" | "caution" | "risky" | null;
113
+ flags: {
114
+ sellFailed: boolean;
115
+ honeypotCode: boolean;
116
+ canMint: boolean;
117
+ canPause: boolean;
118
+ canBlock: boolean;
119
+ upgradeable: boolean;
120
+ fakeMofu: boolean;
121
+ };
122
+ scannedAt: Date | null;
123
+ fingerprint: string | null;
124
+ }
125
+ /** Decodes verdictOf(address) → (uint8 verdict, uint8 flags, uint40 scannedAt, bytes16 fingerprint). */
126
+ export declare function decodeOnchainVerdict(result: string, registry: string): OnchainVerdict;
package/dist/index.js CHANGED
@@ -64,6 +64,41 @@ export class Mofu {
64
64
  checkWallet(address) {
65
65
  return this.call(`/api/v1/wallet/${Mofu.address(address, "address")}`);
66
66
  }
67
+ /**
68
+ * A token's verdict as published on Robinhood Chain (the MofuVerdicts registry), read straight
69
+ * from the chain with one eth_call. Pass `registry` to skip asking mofu.works where it is.
70
+ */
71
+ async onchainVerdict(token, options = {}) {
72
+ const address = Mofu.address(token, "token");
73
+ let registry = options.registry;
74
+ if (!registry) {
75
+ const info = await this.call("/api/v1/onchain");
76
+ if (!info.registry)
77
+ throw new MofuError("Mofu isn't publishing verdicts on-chain yet", 404, "not_published");
78
+ registry = info.registry;
79
+ }
80
+ const res = await this.fetchFn(options.rpcUrl ?? "https://robinhood-rpc.publicnode.com", {
81
+ method: "POST",
82
+ headers: { "Content-Type": "application/json" },
83
+ body: JSON.stringify({
84
+ jsonrpc: "2.0",
85
+ id: 1,
86
+ method: "eth_call",
87
+ // verdictOf(address)
88
+ params: [
89
+ { to: registry, data: `0x371ad2ae${address.slice(2).padStart(64, "0")}` },
90
+ "latest",
91
+ ],
92
+ }),
93
+ signal: AbortSignal.timeout(this.timeoutMs),
94
+ }).catch((err) => {
95
+ throw new MofuError(`Couldn't reach Robinhood Chain: ${err.message}`, 0, "network");
96
+ });
97
+ const body = (await res.json().catch(() => null));
98
+ if (!body?.result || body.result.length < 2 + 64 * 4)
99
+ throw new MofuError("Unexpected answer from the chain", 502, "bad_rpc");
100
+ return decodeOnchainVerdict(body.result, registry);
101
+ }
67
102
  /** Scans a token and applies a buy rule. Says no, with a reason, when Mofu can't be reached. */
68
103
  async checkBeforeBuy(address, policy = {}) {
69
104
  try {
@@ -170,3 +205,27 @@ export async function parseWebhook(signatureHeader, rawBody, secret, options) {
170
205
  throw new MofuError("The webhook signature doesn't match", 401, "bad_signature");
171
206
  return JSON.parse(rawBody);
172
207
  }
208
+ /** Decodes verdictOf(address) → (uint8 verdict, uint8 flags, uint40 scannedAt, bytes16 fingerprint). */
209
+ export function decodeOnchainVerdict(result, registry) {
210
+ const words = result.replace(/^0x/, "").match(/.{64}/g) ?? [];
211
+ const n = (i) => BigInt(`0x${words[i] ?? "0"}`);
212
+ const code = Number(n(0));
213
+ const f = Number(n(1));
214
+ const at = Number(n(2));
215
+ const fp = (words[3] ?? "").slice(0, 32);
216
+ return {
217
+ registry,
218
+ verdict: code === 1 ? "clean" : code === 2 ? "caution" : code === 3 ? "risky" : null,
219
+ flags: {
220
+ sellFailed: !!(f & 1),
221
+ honeypotCode: !!(f & 2),
222
+ canMint: !!(f & 4),
223
+ canPause: !!(f & 8),
224
+ canBlock: !!(f & 16),
225
+ upgradeable: !!(f & 32),
226
+ fakeMofu: !!(f & 64),
227
+ },
228
+ scannedAt: at ? new Date(at * 1000) : null,
229
+ fingerprint: /^0+$/.test(fp) || !fp ? null : fp,
230
+ };
231
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mofu-sdk",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Robinhood Chain token and wallet checks for agents, bots and scripts: Mofu's Token Scanner, Wallet Health, webhooks and a buy rule.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://mofu.works/docs/#sdk",