@farcaster/snap 2.7.0 → 2.7.1

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.
@@ -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;
@@ -42,6 +63,8 @@ export type SnapActionHandlers = {
42
63
  sellToken?: string;
43
64
  buyToken?: string;
44
65
  }) => void;
66
+ send_transaction?: (params: SnapSendTransactionParams) => void;
67
+ send_calls?: (params: SnapSendCallsParams) => void;
45
68
  };
46
69
  export type { SnapRenderState };
47
70
  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;
@@ -330,6 +338,38 @@ export function SnapViewCore({ snap, handlers, loading = false, appearance = "da
330
338
  buyToken: p.buyToken ? String(p.buyToken) : undefined,
331
339
  });
332
340
  break;
341
+ case "send_transaction":
342
+ handlers.send_transaction?.({
343
+ chainId: String(p.chainId ?? ""),
344
+ to: String(p.to ?? ""),
345
+ data: optionalString(p.data),
346
+ value: optionalString(p.value),
347
+ gas: optionalString(p.gas),
348
+ gasPrice: optionalString(p.gasPrice),
349
+ maxFeePerGas: optionalString(p.maxFeePerGas),
350
+ maxPriorityFeePerGas: optionalString(p.maxPriorityFeePerGas),
351
+ });
352
+ break;
353
+ case "send_calls":
354
+ handlers.send_calls?.({
355
+ version: p.version === "1.0" ? "1.0" : undefined,
356
+ chainId: String(p.chainId ?? ""),
357
+ atomicRequired: typeof p.atomicRequired === "boolean"
358
+ ? p.atomicRequired
359
+ : undefined,
360
+ id: optionalString(p.id),
361
+ calls: Array.isArray(p.calls)
362
+ ? p.calls.map((call) => {
363
+ const c = asRecord(call);
364
+ return {
365
+ to: optionalString(c.to),
366
+ data: optionalString(c.data),
367
+ value: optionalString(c.value),
368
+ };
369
+ })
370
+ : [],
371
+ });
372
+ break;
333
373
  default:
334
374
  break;
335
375
  }
@@ -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;
@@ -155,6 +163,38 @@ export function SnapViewCoreInner({ snap, handlers, loading = false, loadingOver
155
163
  buyToken: p.buyToken ? String(p.buyToken) : undefined,
156
164
  });
157
165
  break;
166
+ case "send_transaction":
167
+ h.send_transaction?.({
168
+ chainId: String(p.chainId ?? ""),
169
+ to: String(p.to ?? ""),
170
+ data: optionalString(p.data),
171
+ value: optionalString(p.value),
172
+ gas: optionalString(p.gas),
173
+ gasPrice: optionalString(p.gasPrice),
174
+ maxFeePerGas: optionalString(p.maxFeePerGas),
175
+ maxPriorityFeePerGas: optionalString(p.maxPriorityFeePerGas),
176
+ });
177
+ break;
178
+ case "send_calls":
179
+ h.send_calls?.({
180
+ version: p.version === "1.0" ? "1.0" : undefined,
181
+ chainId: String(p.chainId ?? ""),
182
+ atomicRequired: typeof p.atomicRequired === "boolean"
183
+ ? p.atomicRequired
184
+ : undefined,
185
+ id: optionalString(p.id),
186
+ calls: Array.isArray(p.calls)
187
+ ? p.calls.map((call) => {
188
+ const c = asRecord(call);
189
+ return {
190
+ to: optionalString(c.to),
191
+ data: optionalString(c.data),
192
+ value: optionalString(c.value),
193
+ };
194
+ })
195
+ : [],
196
+ });
197
+ break;
158
198
  default:
159
199
  break;
160
200
  }
@@ -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;
@@ -41,4 +62,6 @@ export type SnapActionHandlers = {
41
62
  sellToken?: string;
42
63
  buyToken?: string;
43
64
  }) => void;
65
+ send_transaction?: (params: SnapSendTransactionParams) => void;
66
+ send_calls?: (params: SnapSendCallsParams) => void;
44
67
  };
@@ -572,6 +572,33 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
572
572
  buyToken: z.ZodOptional<z.ZodString>;
573
573
  }, z.core.$strip>;
574
574
  };
575
+ send_transaction: {
576
+ description: string;
577
+ params: z.ZodObject<{
578
+ chainId: z.ZodString;
579
+ to: z.ZodString;
580
+ data: z.ZodOptional<z.ZodString>;
581
+ value: z.ZodOptional<z.ZodString>;
582
+ gas: z.ZodOptional<z.ZodString>;
583
+ gasPrice: z.ZodOptional<z.ZodString>;
584
+ maxFeePerGas: z.ZodOptional<z.ZodString>;
585
+ maxPriorityFeePerGas: z.ZodOptional<z.ZodString>;
586
+ }, z.core.$strip>;
587
+ };
588
+ send_calls: {
589
+ description: string;
590
+ params: z.ZodObject<{
591
+ version: z.ZodOptional<z.ZodLiteral<"1.0">>;
592
+ chainId: z.ZodString;
593
+ atomicRequired: z.ZodOptional<z.ZodBoolean>;
594
+ id: z.ZodOptional<z.ZodString>;
595
+ calls: z.ZodArray<z.ZodObject<{
596
+ to: z.ZodOptional<z.ZodString>;
597
+ data: z.ZodOptional<z.ZodString>;
598
+ value: z.ZodOptional<z.ZodString>;
599
+ }, z.core.$strip>>;
600
+ }, z.core.$strip>;
601
+ };
575
602
  paginator_next: {
576
603
  description: string;
577
604
  params: z.ZodObject<{
@@ -151,6 +151,33 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
151
151
  buyToken: z.string().optional(),
152
152
  }),
153
153
  },
154
+ send_transaction: {
155
+ description: "Request an EVM transaction through the host wallet using eth_sendTransaction.",
156
+ params: z.object({
157
+ chainId: z.string(),
158
+ to: z.string(),
159
+ data: z.string().optional(),
160
+ value: z.string().optional(),
161
+ gas: z.string().optional(),
162
+ gasPrice: z.string().optional(),
163
+ maxFeePerGas: z.string().optional(),
164
+ maxPriorityFeePerGas: z.string().optional(),
165
+ }),
166
+ },
167
+ send_calls: {
168
+ description: "Request one or more EVM calls through the host wallet using wallet_sendCalls.",
169
+ params: z.object({
170
+ version: z.literal("1.0").optional(),
171
+ chainId: z.string(),
172
+ atomicRequired: z.boolean().optional(),
173
+ id: z.string().optional(),
174
+ calls: z.array(z.object({
175
+ to: z.string().optional(),
176
+ data: z.string().optional(),
177
+ value: z.string().optional(),
178
+ })),
179
+ }),
180
+ },
154
181
  paginator_next: {
155
182
  description: "Move the snap's paginator to the next page locally. Does not POST and is ignored when no paginator is rendered.",
156
183
  params: z.object({ page: z.number().int().min(0).optional() }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farcaster/snap",
3
- "version": "2.7.0",
3
+ "version": "2.7.1",
4
4
  "description": "Farcaster Snaps 🫰",
5
5
  "repository": {
6
6
  "type": "git",
@@ -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;
@@ -45,6 +68,8 @@ export type SnapActionHandlers = {
45
68
  recipientAddress?: string;
46
69
  }) => void;
47
70
  swap_token: (params: { sellToken?: string; buyToken?: string }) => void;
71
+ send_transaction?: (params: SnapSendTransactionParams) => void;
72
+ send_calls?: (params: SnapSendCallsParams) => void;
48
73
  };
49
74
 
50
75
  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<
@@ -493,6 +503,39 @@ export function SnapViewCore({
493
503
  buyToken: p.buyToken ? String(p.buyToken) : undefined,
494
504
  });
495
505
  break;
506
+ case "send_transaction":
507
+ handlers.send_transaction?.({
508
+ chainId: String(p.chainId ?? ""),
509
+ to: String(p.to ?? ""),
510
+ data: optionalString(p.data),
511
+ value: optionalString(p.value),
512
+ gas: optionalString(p.gas),
513
+ gasPrice: optionalString(p.gasPrice),
514
+ maxFeePerGas: optionalString(p.maxFeePerGas),
515
+ maxPriorityFeePerGas: optionalString(p.maxPriorityFeePerGas),
516
+ });
517
+ break;
518
+ case "send_calls":
519
+ handlers.send_calls?.({
520
+ version: p.version === "1.0" ? "1.0" : undefined,
521
+ chainId: String(p.chainId ?? ""),
522
+ atomicRequired:
523
+ typeof p.atomicRequired === "boolean"
524
+ ? p.atomicRequired
525
+ : undefined,
526
+ id: optionalString(p.id),
527
+ calls: Array.isArray(p.calls)
528
+ ? p.calls.map((call) => {
529
+ const c = asRecord(call);
530
+ return {
531
+ to: optionalString(c.to),
532
+ data: optionalString(c.data),
533
+ value: optionalString(c.value),
534
+ };
535
+ })
536
+ : [],
537
+ });
538
+ break;
496
539
  default:
497
540
  break;
498
541
  }
@@ -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<
@@ -228,6 +238,39 @@ export function SnapViewCoreInner({
228
238
  buyToken: p.buyToken ? String(p.buyToken) : undefined,
229
239
  });
230
240
  break;
241
+ case "send_transaction":
242
+ h.send_transaction?.({
243
+ chainId: String(p.chainId ?? ""),
244
+ to: String(p.to ?? ""),
245
+ data: optionalString(p.data),
246
+ value: optionalString(p.value),
247
+ gas: optionalString(p.gas),
248
+ gasPrice: optionalString(p.gasPrice),
249
+ maxFeePerGas: optionalString(p.maxFeePerGas),
250
+ maxPriorityFeePerGas: optionalString(p.maxPriorityFeePerGas),
251
+ });
252
+ break;
253
+ case "send_calls":
254
+ h.send_calls?.({
255
+ version: p.version === "1.0" ? "1.0" : undefined,
256
+ chainId: String(p.chainId ?? ""),
257
+ atomicRequired:
258
+ typeof p.atomicRequired === "boolean"
259
+ ? p.atomicRequired
260
+ : undefined,
261
+ id: optionalString(p.id),
262
+ calls: Array.isArray(p.calls)
263
+ ? p.calls.map((call) => {
264
+ const c = asRecord(call);
265
+ return {
266
+ to: optionalString(c.to),
267
+ data: optionalString(c.data),
268
+ value: optionalString(c.value),
269
+ };
270
+ })
271
+ : [],
272
+ });
273
+ break;
231
274
  default:
232
275
  break;
233
276
  }
@@ -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;
@@ -38,4 +61,6 @@ export type SnapActionHandlers = {
38
61
  recipientAddress?: string;
39
62
  }) => void;
40
63
  swap_token: (params: { sellToken?: string; buyToken?: string }) => void;
64
+ send_transaction?: (params: SnapSendTransactionParams) => void;
65
+ send_calls?: (params: SnapSendCallsParams) => void;
41
66
  };
package/src/ui/catalog.ts CHANGED
@@ -172,6 +172,37 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
172
172
  buyToken: z.string().optional(),
173
173
  }),
174
174
  },
175
+ send_transaction: {
176
+ description:
177
+ "Request an EVM transaction through the host wallet using eth_sendTransaction.",
178
+ params: z.object({
179
+ chainId: z.string(),
180
+ to: z.string(),
181
+ data: z.string().optional(),
182
+ value: z.string().optional(),
183
+ gas: z.string().optional(),
184
+ gasPrice: z.string().optional(),
185
+ maxFeePerGas: z.string().optional(),
186
+ maxPriorityFeePerGas: z.string().optional(),
187
+ }),
188
+ },
189
+ send_calls: {
190
+ description:
191
+ "Request one or more EVM calls through the host wallet using wallet_sendCalls.",
192
+ params: z.object({
193
+ version: z.literal("1.0").optional(),
194
+ chainId: z.string(),
195
+ atomicRequired: z.boolean().optional(),
196
+ id: z.string().optional(),
197
+ calls: z.array(
198
+ z.object({
199
+ to: z.string().optional(),
200
+ data: z.string().optional(),
201
+ value: z.string().optional(),
202
+ }),
203
+ ),
204
+ }),
205
+ },
175
206
  paginator_next: {
176
207
  description:
177
208
  "Move the snap's paginator to the next page locally. Does not POST and is ignored when no paginator is rendered.",