@farcaster/snap 2.7.0 → 2.8.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/dist/react/index.d.ts +26 -0
- package/dist/react/snap-view-core.js +43 -0
- package/dist/react-native/snap-view-core.js +43 -0
- package/dist/react-native/types.d.ts +26 -0
- package/dist/ui/catalog.d.ts +33 -0
- package/dist/ui/catalog.js +31 -0
- package/llms.txt +2 -1
- package/package.json +1 -1
- package/src/react/index.tsx +26 -0
- package/src/react/snap-view-core.tsx +46 -0
- package/src/react-native/snap-view-core.tsx +46 -0
- package/src/react-native/types.ts +26 -0
- package/src/ui/catalog.ts +35 -0
package/dist/react/index.d.ts
CHANGED
|
@@ -13,6 +13,27 @@ export type SnapPage = {
|
|
|
13
13
|
effects?: string[];
|
|
14
14
|
ui: Spec;
|
|
15
15
|
};
|
|
16
|
+
export type SnapSendTransactionParams = {
|
|
17
|
+
chainId: string;
|
|
18
|
+
to: string;
|
|
19
|
+
data?: string;
|
|
20
|
+
value?: string;
|
|
21
|
+
gas?: string;
|
|
22
|
+
gasPrice?: string;
|
|
23
|
+
maxFeePerGas?: string;
|
|
24
|
+
maxPriorityFeePerGas?: string;
|
|
25
|
+
};
|
|
26
|
+
export type SnapSendCallsParams = {
|
|
27
|
+
version?: "1.0";
|
|
28
|
+
chainId: string;
|
|
29
|
+
atomicRequired?: boolean;
|
|
30
|
+
id?: string;
|
|
31
|
+
calls: Array<{
|
|
32
|
+
to?: string;
|
|
33
|
+
data?: string;
|
|
34
|
+
value?: string;
|
|
35
|
+
}>;
|
|
36
|
+
};
|
|
16
37
|
export type SnapActionHandlers = {
|
|
17
38
|
submit: (target: string, inputs: Record<string, JsonValue>) => void;
|
|
18
39
|
open_url: (target: string) => void;
|
|
@@ -24,6 +45,9 @@ export type SnapActionHandlers = {
|
|
|
24
45
|
view_profile: (params: {
|
|
25
46
|
fid: number;
|
|
26
47
|
}) => void;
|
|
48
|
+
view_channel: (params: {
|
|
49
|
+
channelKey: string;
|
|
50
|
+
}) => void;
|
|
27
51
|
compose_cast: (params: {
|
|
28
52
|
text?: string;
|
|
29
53
|
channelKey?: string;
|
|
@@ -42,6 +66,8 @@ export type SnapActionHandlers = {
|
|
|
42
66
|
sellToken?: string;
|
|
43
67
|
buyToken?: string;
|
|
44
68
|
}) => void;
|
|
69
|
+
send_transaction?: (params: SnapSendTransactionParams) => void;
|
|
70
|
+
send_calls?: (params: SnapSendCallsParams) => void;
|
|
45
71
|
};
|
|
46
72
|
export type { SnapRenderState };
|
|
47
73
|
export declare function SnapCard({ snap, handlers, loading, appearance, maxWidth, showOverflowWarning, onValidationError, validationErrorFallback, actionError, plain, loadingOverlay, initialRenderState, onRenderStateChange, }: {
|
|
@@ -8,6 +8,14 @@ import { resolveSnapPaletteHex } from "./lib/resolve-palette-hex.js";
|
|
|
8
8
|
import { snapPreviewPrimaryCssProperties } from "./lib/preview-primary-css.js";
|
|
9
9
|
import { applyStatePaths, buildInitialRenderState, cloneSnapRenderState, getUnpresentedSnapEffects, markSnapEffectsPresented, } from "../render-state.js";
|
|
10
10
|
import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
11
|
+
function asRecord(value) {
|
|
12
|
+
return value && typeof value === "object"
|
|
13
|
+
? value
|
|
14
|
+
: {};
|
|
15
|
+
}
|
|
16
|
+
function optionalString(value) {
|
|
17
|
+
return value ? String(value) : undefined;
|
|
18
|
+
}
|
|
11
19
|
function withDefaultElementProps(spec) {
|
|
12
20
|
if (!spec || typeof spec !== "object" || !("elements" in spec))
|
|
13
21
|
return spec;
|
|
@@ -302,6 +310,9 @@ export function SnapViewCore({ snap, handlers, loading = false, appearance = "da
|
|
|
302
310
|
case "view_profile":
|
|
303
311
|
handlers.view_profile({ fid: Number(p.fid ?? 0) });
|
|
304
312
|
break;
|
|
313
|
+
case "view_channel":
|
|
314
|
+
handlers.view_channel({ channelKey: String(p.channelKey ?? "") });
|
|
315
|
+
break;
|
|
305
316
|
case "compose_cast":
|
|
306
317
|
handlers.compose_cast({
|
|
307
318
|
text: p.text ? String(p.text) : undefined,
|
|
@@ -330,6 +341,38 @@ export function SnapViewCore({ snap, handlers, loading = false, appearance = "da
|
|
|
330
341
|
buyToken: p.buyToken ? String(p.buyToken) : undefined,
|
|
331
342
|
});
|
|
332
343
|
break;
|
|
344
|
+
case "send_transaction":
|
|
345
|
+
handlers.send_transaction?.({
|
|
346
|
+
chainId: String(p.chainId ?? ""),
|
|
347
|
+
to: String(p.to ?? ""),
|
|
348
|
+
data: optionalString(p.data),
|
|
349
|
+
value: optionalString(p.value),
|
|
350
|
+
gas: optionalString(p.gas),
|
|
351
|
+
gasPrice: optionalString(p.gasPrice),
|
|
352
|
+
maxFeePerGas: optionalString(p.maxFeePerGas),
|
|
353
|
+
maxPriorityFeePerGas: optionalString(p.maxPriorityFeePerGas),
|
|
354
|
+
});
|
|
355
|
+
break;
|
|
356
|
+
case "send_calls":
|
|
357
|
+
handlers.send_calls?.({
|
|
358
|
+
version: p.version === "1.0" ? "1.0" : undefined,
|
|
359
|
+
chainId: String(p.chainId ?? ""),
|
|
360
|
+
atomicRequired: typeof p.atomicRequired === "boolean"
|
|
361
|
+
? p.atomicRequired
|
|
362
|
+
: undefined,
|
|
363
|
+
id: optionalString(p.id),
|
|
364
|
+
calls: Array.isArray(p.calls)
|
|
365
|
+
? p.calls.map((call) => {
|
|
366
|
+
const c = asRecord(call);
|
|
367
|
+
return {
|
|
368
|
+
to: optionalString(c.to),
|
|
369
|
+
data: optionalString(c.data),
|
|
370
|
+
value: optionalString(c.value),
|
|
371
|
+
};
|
|
372
|
+
})
|
|
373
|
+
: [],
|
|
374
|
+
});
|
|
375
|
+
break;
|
|
333
376
|
default:
|
|
334
377
|
break;
|
|
335
378
|
}
|
|
@@ -9,6 +9,14 @@ import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
|
9
9
|
import { ActivityIndicator, StyleSheet, View } from "react-native";
|
|
10
10
|
import { DEFAULT_THEME_ACCENT, PALETTE_LIGHT_HEX, PALETTE_DARK_HEX, } from "@farcaster/snap";
|
|
11
11
|
import { applyStatePaths, buildInitialRenderState, cloneSnapRenderState, getUnpresentedSnapEffects, markSnapEffectsPresented, } from "../render-state.js";
|
|
12
|
+
function asRecord(value) {
|
|
13
|
+
return value && typeof value === "object"
|
|
14
|
+
? value
|
|
15
|
+
: {};
|
|
16
|
+
}
|
|
17
|
+
function optionalString(value) {
|
|
18
|
+
return value ? String(value) : undefined;
|
|
19
|
+
}
|
|
12
20
|
function withDefaultElementProps(spec) {
|
|
13
21
|
if (!spec || typeof spec !== "object" || !("elements" in spec))
|
|
14
22
|
return spec;
|
|
@@ -129,6 +137,9 @@ export function SnapViewCoreInner({ snap, handlers, loading = false, loadingOver
|
|
|
129
137
|
case "view_profile":
|
|
130
138
|
h.view_profile({ fid: Number(p.fid ?? 0) });
|
|
131
139
|
break;
|
|
140
|
+
case "view_channel":
|
|
141
|
+
h.view_channel({ channelKey: String(p.channelKey ?? "") });
|
|
142
|
+
break;
|
|
132
143
|
case "compose_cast":
|
|
133
144
|
h.compose_cast({
|
|
134
145
|
text: p.text ? String(p.text) : undefined,
|
|
@@ -155,6 +166,38 @@ export function SnapViewCoreInner({ snap, handlers, loading = false, loadingOver
|
|
|
155
166
|
buyToken: p.buyToken ? String(p.buyToken) : undefined,
|
|
156
167
|
});
|
|
157
168
|
break;
|
|
169
|
+
case "send_transaction":
|
|
170
|
+
h.send_transaction?.({
|
|
171
|
+
chainId: String(p.chainId ?? ""),
|
|
172
|
+
to: String(p.to ?? ""),
|
|
173
|
+
data: optionalString(p.data),
|
|
174
|
+
value: optionalString(p.value),
|
|
175
|
+
gas: optionalString(p.gas),
|
|
176
|
+
gasPrice: optionalString(p.gasPrice),
|
|
177
|
+
maxFeePerGas: optionalString(p.maxFeePerGas),
|
|
178
|
+
maxPriorityFeePerGas: optionalString(p.maxPriorityFeePerGas),
|
|
179
|
+
});
|
|
180
|
+
break;
|
|
181
|
+
case "send_calls":
|
|
182
|
+
h.send_calls?.({
|
|
183
|
+
version: p.version === "1.0" ? "1.0" : undefined,
|
|
184
|
+
chainId: String(p.chainId ?? ""),
|
|
185
|
+
atomicRequired: typeof p.atomicRequired === "boolean"
|
|
186
|
+
? p.atomicRequired
|
|
187
|
+
: undefined,
|
|
188
|
+
id: optionalString(p.id),
|
|
189
|
+
calls: Array.isArray(p.calls)
|
|
190
|
+
? p.calls.map((call) => {
|
|
191
|
+
const c = asRecord(call);
|
|
192
|
+
return {
|
|
193
|
+
to: optionalString(c.to),
|
|
194
|
+
data: optionalString(c.data),
|
|
195
|
+
value: optionalString(c.value),
|
|
196
|
+
};
|
|
197
|
+
})
|
|
198
|
+
: [],
|
|
199
|
+
});
|
|
200
|
+
break;
|
|
158
201
|
default:
|
|
159
202
|
break;
|
|
160
203
|
}
|
|
@@ -12,6 +12,27 @@ export type SnapPage = {
|
|
|
12
12
|
effects?: string[];
|
|
13
13
|
ui: Spec;
|
|
14
14
|
};
|
|
15
|
+
export type SnapSendTransactionParams = {
|
|
16
|
+
chainId: string;
|
|
17
|
+
to: string;
|
|
18
|
+
data?: string;
|
|
19
|
+
value?: string;
|
|
20
|
+
gas?: string;
|
|
21
|
+
gasPrice?: string;
|
|
22
|
+
maxFeePerGas?: string;
|
|
23
|
+
maxPriorityFeePerGas?: string;
|
|
24
|
+
};
|
|
25
|
+
export type SnapSendCallsParams = {
|
|
26
|
+
version?: "1.0";
|
|
27
|
+
chainId: string;
|
|
28
|
+
atomicRequired?: boolean;
|
|
29
|
+
id?: string;
|
|
30
|
+
calls: Array<{
|
|
31
|
+
to?: string;
|
|
32
|
+
data?: string;
|
|
33
|
+
value?: string;
|
|
34
|
+
}>;
|
|
35
|
+
};
|
|
15
36
|
export type SnapActionHandlers = {
|
|
16
37
|
submit: (target: string, inputs: Record<string, JsonValue>) => void;
|
|
17
38
|
open_url: (target: string) => void;
|
|
@@ -23,6 +44,9 @@ export type SnapActionHandlers = {
|
|
|
23
44
|
view_profile: (params: {
|
|
24
45
|
fid: number;
|
|
25
46
|
}) => void;
|
|
47
|
+
view_channel: (params: {
|
|
48
|
+
channelKey: string;
|
|
49
|
+
}) => void;
|
|
26
50
|
compose_cast: (params: {
|
|
27
51
|
text?: string;
|
|
28
52
|
channelKey?: string;
|
|
@@ -41,4 +65,6 @@ export type SnapActionHandlers = {
|
|
|
41
65
|
sellToken?: string;
|
|
42
66
|
buyToken?: string;
|
|
43
67
|
}) => void;
|
|
68
|
+
send_transaction?: (params: SnapSendTransactionParams) => void;
|
|
69
|
+
send_calls?: (params: SnapSendCallsParams) => void;
|
|
44
70
|
};
|
package/dist/ui/catalog.d.ts
CHANGED
|
@@ -542,6 +542,12 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
542
542
|
fid: z.ZodNumber;
|
|
543
543
|
}, z.core.$strip>;
|
|
544
544
|
};
|
|
545
|
+
view_channel: {
|
|
546
|
+
description: string;
|
|
547
|
+
params: z.ZodObject<{
|
|
548
|
+
channelKey: z.ZodString;
|
|
549
|
+
}, z.core.$strip>;
|
|
550
|
+
};
|
|
545
551
|
compose_cast: {
|
|
546
552
|
description: string;
|
|
547
553
|
params: z.ZodObject<{
|
|
@@ -572,6 +578,33 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
572
578
|
buyToken: z.ZodOptional<z.ZodString>;
|
|
573
579
|
}, z.core.$strip>;
|
|
574
580
|
};
|
|
581
|
+
send_transaction: {
|
|
582
|
+
description: string;
|
|
583
|
+
params: z.ZodObject<{
|
|
584
|
+
chainId: z.ZodString;
|
|
585
|
+
to: z.ZodString;
|
|
586
|
+
data: z.ZodOptional<z.ZodString>;
|
|
587
|
+
value: z.ZodOptional<z.ZodString>;
|
|
588
|
+
gas: z.ZodOptional<z.ZodString>;
|
|
589
|
+
gasPrice: z.ZodOptional<z.ZodString>;
|
|
590
|
+
maxFeePerGas: z.ZodOptional<z.ZodString>;
|
|
591
|
+
maxPriorityFeePerGas: z.ZodOptional<z.ZodString>;
|
|
592
|
+
}, z.core.$strip>;
|
|
593
|
+
};
|
|
594
|
+
send_calls: {
|
|
595
|
+
description: string;
|
|
596
|
+
params: z.ZodObject<{
|
|
597
|
+
version: z.ZodOptional<z.ZodLiteral<"1.0">>;
|
|
598
|
+
chainId: z.ZodString;
|
|
599
|
+
atomicRequired: z.ZodOptional<z.ZodBoolean>;
|
|
600
|
+
id: z.ZodOptional<z.ZodString>;
|
|
601
|
+
calls: z.ZodArray<z.ZodObject<{
|
|
602
|
+
to: z.ZodOptional<z.ZodString>;
|
|
603
|
+
data: z.ZodOptional<z.ZodString>;
|
|
604
|
+
value: z.ZodOptional<z.ZodString>;
|
|
605
|
+
}, z.core.$strip>>;
|
|
606
|
+
}, z.core.$strip>;
|
|
607
|
+
};
|
|
575
608
|
paginator_next: {
|
|
576
609
|
description: string;
|
|
577
610
|
params: z.ZodObject<{
|
package/dist/ui/catalog.js
CHANGED
|
@@ -123,6 +123,10 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
123
123
|
description: "Navigate to a user profile by FID.",
|
|
124
124
|
params: z.object({ fid: z.number() }),
|
|
125
125
|
},
|
|
126
|
+
view_channel: {
|
|
127
|
+
description: "Navigate to a Farcaster channel by channel key.",
|
|
128
|
+
params: z.object({ channelKey: z.string() }),
|
|
129
|
+
},
|
|
126
130
|
compose_cast: {
|
|
127
131
|
description: "Open the cast composer with optional pre-filled content.",
|
|
128
132
|
params: z.object({
|
|
@@ -151,6 +155,33 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
151
155
|
buyToken: z.string().optional(),
|
|
152
156
|
}),
|
|
153
157
|
},
|
|
158
|
+
send_transaction: {
|
|
159
|
+
description: "Request an EVM transaction through the host wallet using eth_sendTransaction.",
|
|
160
|
+
params: z.object({
|
|
161
|
+
chainId: z.string(),
|
|
162
|
+
to: z.string(),
|
|
163
|
+
data: z.string().optional(),
|
|
164
|
+
value: z.string().optional(),
|
|
165
|
+
gas: z.string().optional(),
|
|
166
|
+
gasPrice: z.string().optional(),
|
|
167
|
+
maxFeePerGas: z.string().optional(),
|
|
168
|
+
maxPriorityFeePerGas: z.string().optional(),
|
|
169
|
+
}),
|
|
170
|
+
},
|
|
171
|
+
send_calls: {
|
|
172
|
+
description: "Request one or more EVM calls through the host wallet using wallet_sendCalls.",
|
|
173
|
+
params: z.object({
|
|
174
|
+
version: z.literal("1.0").optional(),
|
|
175
|
+
chainId: z.string(),
|
|
176
|
+
atomicRequired: z.boolean().optional(),
|
|
177
|
+
id: z.string().optional(),
|
|
178
|
+
calls: z.array(z.object({
|
|
179
|
+
to: z.string().optional(),
|
|
180
|
+
data: z.string().optional(),
|
|
181
|
+
value: z.string().optional(),
|
|
182
|
+
})),
|
|
183
|
+
}),
|
|
184
|
+
},
|
|
154
185
|
paginator_next: {
|
|
155
186
|
description: "Move the snap's paginator to the next page locally. Does not POST and is ignored when no paginator is rendered.",
|
|
156
187
|
params: z.object({ page: z.number().int().min(0).optional() }),
|
package/llms.txt
CHANGED
|
@@ -172,7 +172,7 @@ Field values are sent in POST `inputs[name]` when a `submit` action fires.
|
|
|
172
172
|
- `label` (string, optional, max 60)
|
|
173
173
|
- POST value: string (single) or string[] (multiple)
|
|
174
174
|
|
|
175
|
-
## Actions (
|
|
175
|
+
## Actions (11 types)
|
|
176
176
|
|
|
177
177
|
Bound to buttons via `on.press`:
|
|
178
178
|
|
|
@@ -184,6 +184,7 @@ Bound to buttons via `on.press`:
|
|
|
184
184
|
| `open_mini_app` | `target` (URL) | Open as Farcaster mini app |
|
|
185
185
|
| `view_cast` | `hash` (string) | Navigate to a cast |
|
|
186
186
|
| `view_profile` | `fid` (number) | Navigate to a profile |
|
|
187
|
+
| `view_channel` | `channelKey` (string) | Navigate to a channel |
|
|
187
188
|
| `compose_cast` | `text?`, `channelKey?`, `embeds?` | Open cast composer. Put URLs in `embeds`, not `text` |
|
|
188
189
|
| `view_token` | `token` (CAIP-19) | View token in wallet |
|
|
189
190
|
| `send_token` | `token`, `amount?`, `recipientFid?`, `recipientAddress?` | Send token flow |
|
package/package.json
CHANGED
package/src/react/index.tsx
CHANGED
|
@@ -25,6 +25,29 @@ export type SnapPage = {
|
|
|
25
25
|
ui: Spec;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
export type SnapSendTransactionParams = {
|
|
29
|
+
chainId: string;
|
|
30
|
+
to: string;
|
|
31
|
+
data?: string;
|
|
32
|
+
value?: string;
|
|
33
|
+
gas?: string;
|
|
34
|
+
gasPrice?: string;
|
|
35
|
+
maxFeePerGas?: string;
|
|
36
|
+
maxPriorityFeePerGas?: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type SnapSendCallsParams = {
|
|
40
|
+
version?: "1.0";
|
|
41
|
+
chainId: string;
|
|
42
|
+
atomicRequired?: boolean;
|
|
43
|
+
id?: string;
|
|
44
|
+
calls: Array<{
|
|
45
|
+
to?: string;
|
|
46
|
+
data?: string;
|
|
47
|
+
value?: string;
|
|
48
|
+
}>;
|
|
49
|
+
};
|
|
50
|
+
|
|
28
51
|
export type SnapActionHandlers = {
|
|
29
52
|
submit: (target: string, inputs: Record<string, JsonValue>) => void;
|
|
30
53
|
open_url: (target: string) => void;
|
|
@@ -32,6 +55,7 @@ export type SnapActionHandlers = {
|
|
|
32
55
|
open_mini_app: (target: string) => void;
|
|
33
56
|
view_cast: (params: { hash: string }) => void;
|
|
34
57
|
view_profile: (params: { fid: number }) => void;
|
|
58
|
+
view_channel: (params: { channelKey: string }) => void;
|
|
35
59
|
compose_cast: (params: {
|
|
36
60
|
text?: string;
|
|
37
61
|
channelKey?: string;
|
|
@@ -45,6 +69,8 @@ export type SnapActionHandlers = {
|
|
|
45
69
|
recipientAddress?: string;
|
|
46
70
|
}) => void;
|
|
47
71
|
swap_token: (params: { sellToken?: string; buyToken?: string }) => void;
|
|
72
|
+
send_transaction?: (params: SnapSendTransactionParams) => void;
|
|
73
|
+
send_calls?: (params: SnapSendCallsParams) => void;
|
|
48
74
|
};
|
|
49
75
|
|
|
50
76
|
export type { SnapRenderState };
|
|
@@ -26,6 +26,16 @@ import {
|
|
|
26
26
|
} from "react";
|
|
27
27
|
import type { JsonValue, SnapActionHandlers, SnapPage } from "./index";
|
|
28
28
|
|
|
29
|
+
function asRecord(value: unknown): Record<string, unknown> {
|
|
30
|
+
return value && typeof value === "object"
|
|
31
|
+
? (value as Record<string, unknown>)
|
|
32
|
+
: {};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function optionalString(value: unknown): string | undefined {
|
|
36
|
+
return value ? String(value) : undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
29
39
|
function withDefaultElementProps(spec: Spec): Spec {
|
|
30
40
|
if (!spec || typeof spec !== "object" || !("elements" in spec)) return spec;
|
|
31
41
|
const elements = spec.elements as unknown as Record<
|
|
@@ -465,6 +475,9 @@ export function SnapViewCore({
|
|
|
465
475
|
case "view_profile":
|
|
466
476
|
handlers.view_profile({ fid: Number(p.fid ?? 0) });
|
|
467
477
|
break;
|
|
478
|
+
case "view_channel":
|
|
479
|
+
handlers.view_channel({ channelKey: String(p.channelKey ?? "") });
|
|
480
|
+
break;
|
|
468
481
|
case "compose_cast":
|
|
469
482
|
handlers.compose_cast({
|
|
470
483
|
text: p.text ? String(p.text) : undefined,
|
|
@@ -493,6 +506,39 @@ export function SnapViewCore({
|
|
|
493
506
|
buyToken: p.buyToken ? String(p.buyToken) : undefined,
|
|
494
507
|
});
|
|
495
508
|
break;
|
|
509
|
+
case "send_transaction":
|
|
510
|
+
handlers.send_transaction?.({
|
|
511
|
+
chainId: String(p.chainId ?? ""),
|
|
512
|
+
to: String(p.to ?? ""),
|
|
513
|
+
data: optionalString(p.data),
|
|
514
|
+
value: optionalString(p.value),
|
|
515
|
+
gas: optionalString(p.gas),
|
|
516
|
+
gasPrice: optionalString(p.gasPrice),
|
|
517
|
+
maxFeePerGas: optionalString(p.maxFeePerGas),
|
|
518
|
+
maxPriorityFeePerGas: optionalString(p.maxPriorityFeePerGas),
|
|
519
|
+
});
|
|
520
|
+
break;
|
|
521
|
+
case "send_calls":
|
|
522
|
+
handlers.send_calls?.({
|
|
523
|
+
version: p.version === "1.0" ? "1.0" : undefined,
|
|
524
|
+
chainId: String(p.chainId ?? ""),
|
|
525
|
+
atomicRequired:
|
|
526
|
+
typeof p.atomicRequired === "boolean"
|
|
527
|
+
? p.atomicRequired
|
|
528
|
+
: undefined,
|
|
529
|
+
id: optionalString(p.id),
|
|
530
|
+
calls: Array.isArray(p.calls)
|
|
531
|
+
? p.calls.map((call) => {
|
|
532
|
+
const c = asRecord(call);
|
|
533
|
+
return {
|
|
534
|
+
to: optionalString(c.to),
|
|
535
|
+
data: optionalString(c.data),
|
|
536
|
+
value: optionalString(c.value),
|
|
537
|
+
};
|
|
538
|
+
})
|
|
539
|
+
: [],
|
|
540
|
+
});
|
|
541
|
+
break;
|
|
496
542
|
default:
|
|
497
543
|
break;
|
|
498
544
|
}
|
|
@@ -30,6 +30,16 @@ import {
|
|
|
30
30
|
} from "../render-state";
|
|
31
31
|
import type { SnapPage, SnapActionHandlers, JsonValue } from "./types";
|
|
32
32
|
|
|
33
|
+
function asRecord(value: unknown): Record<string, unknown> {
|
|
34
|
+
return value && typeof value === "object"
|
|
35
|
+
? (value as Record<string, unknown>)
|
|
36
|
+
: {};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function optionalString(value: unknown): string | undefined {
|
|
40
|
+
return value ? String(value) : undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
33
43
|
function withDefaultElementProps(spec: Spec): Spec {
|
|
34
44
|
if (!spec || typeof spec !== "object" || !("elements" in spec)) return spec;
|
|
35
45
|
const elements = spec.elements as unknown as Record<
|
|
@@ -202,6 +212,9 @@ export function SnapViewCoreInner({
|
|
|
202
212
|
case "view_profile":
|
|
203
213
|
h.view_profile({ fid: Number(p.fid ?? 0) });
|
|
204
214
|
break;
|
|
215
|
+
case "view_channel":
|
|
216
|
+
h.view_channel({ channelKey: String(p.channelKey ?? "") });
|
|
217
|
+
break;
|
|
205
218
|
case "compose_cast":
|
|
206
219
|
h.compose_cast({
|
|
207
220
|
text: p.text ? String(p.text) : undefined,
|
|
@@ -228,6 +241,39 @@ export function SnapViewCoreInner({
|
|
|
228
241
|
buyToken: p.buyToken ? String(p.buyToken) : undefined,
|
|
229
242
|
});
|
|
230
243
|
break;
|
|
244
|
+
case "send_transaction":
|
|
245
|
+
h.send_transaction?.({
|
|
246
|
+
chainId: String(p.chainId ?? ""),
|
|
247
|
+
to: String(p.to ?? ""),
|
|
248
|
+
data: optionalString(p.data),
|
|
249
|
+
value: optionalString(p.value),
|
|
250
|
+
gas: optionalString(p.gas),
|
|
251
|
+
gasPrice: optionalString(p.gasPrice),
|
|
252
|
+
maxFeePerGas: optionalString(p.maxFeePerGas),
|
|
253
|
+
maxPriorityFeePerGas: optionalString(p.maxPriorityFeePerGas),
|
|
254
|
+
});
|
|
255
|
+
break;
|
|
256
|
+
case "send_calls":
|
|
257
|
+
h.send_calls?.({
|
|
258
|
+
version: p.version === "1.0" ? "1.0" : undefined,
|
|
259
|
+
chainId: String(p.chainId ?? ""),
|
|
260
|
+
atomicRequired:
|
|
261
|
+
typeof p.atomicRequired === "boolean"
|
|
262
|
+
? p.atomicRequired
|
|
263
|
+
: undefined,
|
|
264
|
+
id: optionalString(p.id),
|
|
265
|
+
calls: Array.isArray(p.calls)
|
|
266
|
+
? p.calls.map((call) => {
|
|
267
|
+
const c = asRecord(call);
|
|
268
|
+
return {
|
|
269
|
+
to: optionalString(c.to),
|
|
270
|
+
data: optionalString(c.data),
|
|
271
|
+
value: optionalString(c.value),
|
|
272
|
+
};
|
|
273
|
+
})
|
|
274
|
+
: [],
|
|
275
|
+
});
|
|
276
|
+
break;
|
|
231
277
|
default:
|
|
232
278
|
break;
|
|
233
279
|
}
|
|
@@ -18,6 +18,29 @@ export type SnapPage = {
|
|
|
18
18
|
ui: Spec;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
+
export type SnapSendTransactionParams = {
|
|
22
|
+
chainId: string;
|
|
23
|
+
to: string;
|
|
24
|
+
data?: string;
|
|
25
|
+
value?: string;
|
|
26
|
+
gas?: string;
|
|
27
|
+
gasPrice?: string;
|
|
28
|
+
maxFeePerGas?: string;
|
|
29
|
+
maxPriorityFeePerGas?: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type SnapSendCallsParams = {
|
|
33
|
+
version?: "1.0";
|
|
34
|
+
chainId: string;
|
|
35
|
+
atomicRequired?: boolean;
|
|
36
|
+
id?: string;
|
|
37
|
+
calls: Array<{
|
|
38
|
+
to?: string;
|
|
39
|
+
data?: string;
|
|
40
|
+
value?: string;
|
|
41
|
+
}>;
|
|
42
|
+
};
|
|
43
|
+
|
|
21
44
|
export type SnapActionHandlers = {
|
|
22
45
|
submit: (target: string, inputs: Record<string, JsonValue>) => void;
|
|
23
46
|
open_url: (target: string) => void;
|
|
@@ -25,6 +48,7 @@ export type SnapActionHandlers = {
|
|
|
25
48
|
open_mini_app: (target: string) => void;
|
|
26
49
|
view_cast: (params: { hash: string }) => void;
|
|
27
50
|
view_profile: (params: { fid: number }) => void;
|
|
51
|
+
view_channel: (params: { channelKey: string }) => void;
|
|
28
52
|
compose_cast: (params: {
|
|
29
53
|
text?: string;
|
|
30
54
|
channelKey?: string;
|
|
@@ -38,4 +62,6 @@ export type SnapActionHandlers = {
|
|
|
38
62
|
recipientAddress?: string;
|
|
39
63
|
}) => void;
|
|
40
64
|
swap_token: (params: { sellToken?: string; buyToken?: string }) => void;
|
|
65
|
+
send_transaction?: (params: SnapSendTransactionParams) => void;
|
|
66
|
+
send_calls?: (params: SnapSendCallsParams) => void;
|
|
41
67
|
};
|
package/src/ui/catalog.ts
CHANGED
|
@@ -144,6 +144,10 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
144
144
|
description: "Navigate to a user profile by FID.",
|
|
145
145
|
params: z.object({ fid: z.number() }),
|
|
146
146
|
},
|
|
147
|
+
view_channel: {
|
|
148
|
+
description: "Navigate to a Farcaster channel by channel key.",
|
|
149
|
+
params: z.object({ channelKey: z.string() }),
|
|
150
|
+
},
|
|
147
151
|
compose_cast: {
|
|
148
152
|
description: "Open the cast composer with optional pre-filled content.",
|
|
149
153
|
params: z.object({
|
|
@@ -172,6 +176,37 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
172
176
|
buyToken: z.string().optional(),
|
|
173
177
|
}),
|
|
174
178
|
},
|
|
179
|
+
send_transaction: {
|
|
180
|
+
description:
|
|
181
|
+
"Request an EVM transaction through the host wallet using eth_sendTransaction.",
|
|
182
|
+
params: z.object({
|
|
183
|
+
chainId: z.string(),
|
|
184
|
+
to: z.string(),
|
|
185
|
+
data: z.string().optional(),
|
|
186
|
+
value: z.string().optional(),
|
|
187
|
+
gas: z.string().optional(),
|
|
188
|
+
gasPrice: z.string().optional(),
|
|
189
|
+
maxFeePerGas: z.string().optional(),
|
|
190
|
+
maxPriorityFeePerGas: z.string().optional(),
|
|
191
|
+
}),
|
|
192
|
+
},
|
|
193
|
+
send_calls: {
|
|
194
|
+
description:
|
|
195
|
+
"Request one or more EVM calls through the host wallet using wallet_sendCalls.",
|
|
196
|
+
params: z.object({
|
|
197
|
+
version: z.literal("1.0").optional(),
|
|
198
|
+
chainId: z.string(),
|
|
199
|
+
atomicRequired: z.boolean().optional(),
|
|
200
|
+
id: z.string().optional(),
|
|
201
|
+
calls: z.array(
|
|
202
|
+
z.object({
|
|
203
|
+
to: z.string().optional(),
|
|
204
|
+
data: z.string().optional(),
|
|
205
|
+
value: z.string().optional(),
|
|
206
|
+
}),
|
|
207
|
+
),
|
|
208
|
+
}),
|
|
209
|
+
},
|
|
175
210
|
paginator_next: {
|
|
176
211
|
description:
|
|
177
212
|
"Move the snap's paginator to the next page locally. Does not POST and is ignored when no paginator is rendered.",
|