@prb/effect-evm 1.0.0-beta.3 → 1.0.0-beta.5

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.
Files changed (115) hide show
  1. package/DOCS.md +13 -0
  2. package/README.md +1 -0
  3. package/dist/ens/ens.d.ts.map +1 -1
  4. package/dist/ens/ens.js +6 -6
  5. package/dist/ens/ens.js.map +1 -1
  6. package/dist/react-hooks/index.d.ts +4 -2
  7. package/dist/react-hooks/index.d.ts.map +1 -1
  8. package/dist/react-hooks/index.js +4 -2
  9. package/dist/react-hooks/index.js.map +1 -1
  10. package/dist/react-hooks/safe-app-origins.d.ts +8 -0
  11. package/dist/react-hooks/safe-app-origins.d.ts.map +1 -0
  12. package/dist/react-hooks/safe-app-origins.js +124 -0
  13. package/dist/react-hooks/safe-app-origins.js.map +1 -0
  14. package/dist/react-hooks/use-is-host-safe-app.d.ts +2 -0
  15. package/dist/react-hooks/use-is-host-safe-app.d.ts.map +1 -0
  16. package/dist/react-hooks/use-is-host-safe-app.js +16 -0
  17. package/dist/react-hooks/use-is-host-safe-app.js.map +1 -0
  18. package/dist/react-hooks/use-is-safe-app-context.d.ts +2 -0
  19. package/dist/react-hooks/use-is-safe-app-context.d.ts.map +1 -0
  20. package/dist/react-hooks/{use-safe-context.js → use-is-safe-app-context.js} +2 -2
  21. package/dist/react-hooks/use-is-safe-app-context.js.map +1 -0
  22. package/dist/react-hooks/use-is-safe-multisig-wallet.d.ts +2 -0
  23. package/dist/react-hooks/use-is-safe-multisig-wallet.d.ts.map +1 -0
  24. package/dist/react-hooks/use-is-safe-multisig-wallet.js +24 -0
  25. package/dist/react-hooks/use-is-safe-multisig-wallet.js.map +1 -0
  26. package/dist/safe/index.d.ts +1 -1
  27. package/dist/safe/index.d.ts.map +1 -1
  28. package/dist/safe/index.js.map +1 -1
  29. package/dist/safe/live.d.ts.map +1 -1
  30. package/dist/safe/live.js +14 -14
  31. package/dist/safe/live.js.map +1 -1
  32. package/dist/safe/service.d.ts +4 -4
  33. package/dist/safe/service.d.ts.map +1 -1
  34. package/dist/safe/service.js.map +1 -1
  35. package/dist/safe/service.test.integration.js +10 -12
  36. package/dist/safe/service.test.integration.js.map +1 -1
  37. package/dist/safe/simulation/abis.d.ts.map +1 -1
  38. package/dist/safe/simulation/abis.js.map +1 -1
  39. package/dist/safe/simulation/addresses.d.ts.map +1 -1
  40. package/dist/safe/simulation/addresses.js +40 -26
  41. package/dist/safe/simulation/addresses.js.map +1 -1
  42. package/dist/safe/simulation/internal/calldata/calldata.d.ts +5 -0
  43. package/dist/safe/simulation/internal/calldata/calldata.d.ts.map +1 -0
  44. package/dist/safe/simulation/internal/calldata/calldata.js +17 -0
  45. package/dist/safe/simulation/internal/calldata/calldata.js.map +1 -0
  46. package/dist/safe/simulation/internal/calldata/index.d.ts +2 -0
  47. package/dist/safe/simulation/internal/calldata/index.d.ts.map +1 -0
  48. package/dist/safe/simulation/internal/calldata/index.js +2 -0
  49. package/dist/safe/simulation/internal/calldata/index.js.map +1 -0
  50. package/dist/safe/simulation/internal/contracts/contracts.d.ts +5 -0
  51. package/dist/safe/simulation/internal/contracts/contracts.d.ts.map +1 -0
  52. package/dist/safe/simulation/internal/contracts/contracts.js +25 -0
  53. package/dist/safe/simulation/internal/contracts/contracts.js.map +1 -0
  54. package/dist/safe/simulation/internal/contracts/index.d.ts +2 -0
  55. package/dist/safe/simulation/internal/contracts/index.d.ts.map +1 -0
  56. package/dist/safe/simulation/internal/contracts/index.js +2 -0
  57. package/dist/safe/simulation/internal/contracts/index.js.map +1 -0
  58. package/dist/safe/simulation/internal/evaluation/evaluation.d.ts +6 -0
  59. package/dist/safe/simulation/internal/evaluation/evaluation.d.ts.map +1 -0
  60. package/dist/safe/simulation/internal/evaluation/evaluation.js +20 -0
  61. package/dist/safe/simulation/internal/evaluation/evaluation.js.map +1 -0
  62. package/dist/safe/simulation/internal/evaluation/index.d.ts +2 -0
  63. package/dist/safe/simulation/internal/evaluation/index.d.ts.map +1 -0
  64. package/dist/safe/simulation/internal/evaluation/index.js +2 -0
  65. package/dist/safe/simulation/internal/evaluation/index.js.map +1 -0
  66. package/dist/safe/simulation/internal/execution/execution.d.ts +9 -0
  67. package/dist/safe/simulation/internal/execution/execution.d.ts.map +1 -0
  68. package/dist/safe/simulation/internal/execution/execution.js +65 -0
  69. package/dist/safe/simulation/internal/execution/execution.js.map +1 -0
  70. package/dist/safe/simulation/internal/execution/index.d.ts +2 -0
  71. package/dist/safe/simulation/internal/execution/index.d.ts.map +1 -0
  72. package/dist/safe/simulation/internal/execution/index.js +2 -0
  73. package/dist/safe/simulation/internal/execution/index.js.map +1 -0
  74. package/dist/safe/simulation/internal/limits/index.d.ts +2 -0
  75. package/dist/safe/simulation/internal/limits/index.d.ts.map +1 -0
  76. package/dist/safe/simulation/internal/limits/index.js +2 -0
  77. package/dist/safe/simulation/internal/limits/index.js.map +1 -0
  78. package/dist/safe/simulation/internal/limits/limits.d.ts +5 -0
  79. package/dist/safe/simulation/internal/limits/limits.d.ts.map +1 -0
  80. package/dist/safe/simulation/internal/limits/limits.js +18 -0
  81. package/dist/safe/simulation/internal/limits/limits.js.map +1 -0
  82. package/dist/safe/simulation/internal/types/index.d.ts +2 -0
  83. package/dist/safe/simulation/internal/types/index.d.ts.map +1 -0
  84. package/dist/safe/simulation/internal/types/index.js +2 -0
  85. package/dist/safe/simulation/internal/types/index.js.map +1 -0
  86. package/dist/safe/simulation/internal/types/types.d.ts +11 -0
  87. package/dist/safe/simulation/internal/types/types.d.ts.map +1 -0
  88. package/dist/safe/simulation/internal/types/types.js +2 -0
  89. package/dist/safe/simulation/internal/types/types.js.map +1 -0
  90. package/dist/safe/simulation/internal/validation/index.d.ts +2 -0
  91. package/dist/safe/simulation/internal/validation/index.d.ts.map +1 -0
  92. package/dist/safe/simulation/internal/validation/index.js +2 -0
  93. package/dist/safe/simulation/internal/validation/index.js.map +1 -0
  94. package/dist/safe/simulation/internal/validation/validation.d.ts +5 -0
  95. package/dist/safe/simulation/internal/validation/validation.d.ts.map +1 -0
  96. package/dist/safe/simulation/internal/validation/validation.js +27 -0
  97. package/dist/safe/simulation/internal/validation/validation.js.map +1 -0
  98. package/dist/safe/simulation/service.d.ts +1 -1
  99. package/dist/safe/simulation/service.d.ts.map +1 -1
  100. package/dist/safe/simulation/service.js +12 -127
  101. package/dist/safe/simulation/service.js.map +1 -1
  102. package/dist/safe/types.d.ts +14 -14
  103. package/dist/safe/types.d.ts.map +1 -1
  104. package/dist/safe/types.js.map +1 -1
  105. package/dist/telemetry/tracer.d.ts +2 -2
  106. package/dist/telemetry/tracer.js +2 -2
  107. package/dist/telemetry/tracer.js.map +1 -1
  108. package/package.json +1 -1
  109. package/dist/react-hooks/use-is-safe-multisig.d.ts +0 -2
  110. package/dist/react-hooks/use-is-safe-multisig.d.ts.map +0 -1
  111. package/dist/react-hooks/use-is-safe-multisig.js +0 -44
  112. package/dist/react-hooks/use-is-safe-multisig.js.map +0 -1
  113. package/dist/react-hooks/use-safe-context.d.ts +0 -2
  114. package/dist/react-hooks/use-safe-context.d.ts.map +0 -1
  115. package/dist/react-hooks/use-safe-context.js.map +0 -1
package/DOCS.md CHANGED
@@ -229,6 +229,19 @@ function App() {
229
229
  }
230
230
  ```
231
231
 
232
+ ### Safe App vs Safe multisig
233
+
234
+ Use Safe App hooks to detect the host iframe context, and Safe multisig hooks to detect the connected wallet.
235
+
236
+ - Safe App context (SDK): `useIsSafeAppContext`
237
+ - Safe App host (SDK + origin): `useIsHostSafeApp`
238
+ - Safe multisig wallet (SDK + connector + host): `useIsSafeMultisigWallet`
239
+
240
+ Safe App origin utilities let you control the allowed host list:
241
+
242
+ - `DEFAULT_SAFE_APP_ORIGINS`
243
+ - `getSafeAppOrigins`, `setSafeAppOrigins`, `extendSafeAppOrigins`, `subscribeSafeAppOrigins`
244
+
232
245
  ### Primitive hooks
233
246
 
234
247
  Low-level hooks for running Effects and Streams in React:
package/README.md CHANGED
@@ -60,6 +60,7 @@ Effect.runPromise(program.pipe(Effect.provide(EvmLayer)));
60
60
  - **Subscriptions** — `SubscriptionService` (blocks/logs/pending tx)
61
61
  - **EIP-7702** — Delegation and atomic batching for EOAs
62
62
  - **React hooks** — `effect-evm/react-hooks` (primitives + convenience hooks)
63
+ - **Safe App + Safe multisig** — `useIsSafeAppContext`, `useIsHostSafeApp`, `useIsSafeMultisigWallet`
63
64
  - **Wagmi integration** — `effect-evm/wagmi` (build layers from wagmi config)
64
65
  - **Browser persistence** — `browser` namespace (localStorage-backed stores)
65
66
  - **Testing** — `effect-evm/testing-kit` (mocks + `makeEffectEvmTestLayer`)
@@ -1 +1 @@
1
- {"version":3,"file":"ens.d.ts","sourceRoot":"","sources":["../../src/ens/ens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,EAClB,6BAA6B,EAC7B,2BAA2B,EAC3B,oBAAoB,EACrB,MAAM,qBAAqB,CAAC;AAK7B,KAAK,gBAAgB,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAQF,MAAM,MAAM,gBAAgB,GAAG;IAO7B,QAAQ,CAAC,UAAU,EAAE,CACnB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KACzB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,oBAAoB,GAAG,kBAAkB,GAAG,mBAAmB,CAAC,CAAC;IAQ7F,QAAQ,CAAC,SAAS,EAAE,CAClB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;KAAE,KAC3C,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,GAAG,kBAAkB,GAAG,mBAAmB,CAAC,CAAC;IAO9F,QAAQ,CAAC,OAAO,EAAE,CAChB,OAAO,EAAE,OAAO,KACb,MAAM,CAAC,MAAM,CAChB,MAAM,EACN,2BAA2B,GAAG,kBAAkB,GAAG,mBAAmB,CACvE,CAAC;IAOF,QAAQ,CAAC,WAAW,EAAE,CACpB,IAAI,EAAE,MAAM,KACT,MAAM,CAAC,MAAM,CAChB,OAAO,EACP,6BAA6B,GAAG,kBAAkB,GAAG,mBAAmB,CACzE,CAAC;IAQF,QAAQ,CAAC,OAAO,EAAE,CAChB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,KACR,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,kBAAkB,GAAG,mBAAmB,CAAC,CAAC;CAC7F,CAAC;;AAEF,qBAAa,WAAY,SAAQ,gBAA+D;CAAG;AAOnG,eAAO,MAAM,eAAe,sDAgM3B,CAAC"}
1
+ {"version":3,"file":"ens.d.ts","sourceRoot":"","sources":["../../src/ens/ens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAGpC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,EAClB,6BAA6B,EAC7B,2BAA2B,EAC3B,oBAAoB,EACrB,MAAM,qBAAqB,CAAC;AAG7B,KAAK,gBAAgB,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAQF,MAAM,MAAM,gBAAgB,GAAG;IAO7B,QAAQ,CAAC,UAAU,EAAE,CACnB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KACzB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,oBAAoB,GAAG,kBAAkB,GAAG,mBAAmB,CAAC,CAAC;IAQ7F,QAAQ,CAAC,SAAS,EAAE,CAClB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;KAAE,KAC3C,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,GAAG,kBAAkB,GAAG,mBAAmB,CAAC,CAAC;IAO9F,QAAQ,CAAC,OAAO,EAAE,CAChB,OAAO,EAAE,OAAO,KACb,MAAM,CAAC,MAAM,CAChB,MAAM,EACN,2BAA2B,GAAG,kBAAkB,GAAG,mBAAmB,CACvE,CAAC;IAOF,QAAQ,CAAC,WAAW,EAAE,CACpB,IAAI,EAAE,MAAM,KACT,MAAM,CAAC,MAAM,CAChB,OAAO,EACP,6BAA6B,GAAG,kBAAkB,GAAG,mBAAmB,CACzE,CAAC;IAQF,QAAQ,CAAC,OAAO,EAAE,CAChB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,KACR,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,kBAAkB,GAAG,mBAAmB,CAAC,CAAC;CAC7F,CAAC;;AAEF,qBAAa,WAAY,SAAQ,gBAA+D;CAAG;AAOnG,eAAO,MAAM,eAAe,sDAgM3B,CAAC"}
package/dist/ens/ens.js CHANGED
@@ -1,16 +1,16 @@
1
1
  import { Context, Effect, Layer } from "effect";
2
+ import { mainnet } from "viem/chains";
2
3
  import { normalize } from "viem/ens";
3
4
  import { PublicClientService } from "../core/index.js";
4
5
  import { EnsAvatarNotFoundError, EnsNameNotFoundError, EnsResolutionError, EnsResolverNotConfiguredError, EnsReverseNameNotFoundError, EnsTextNotFoundError, } from "../ens/errors.js";
5
6
  import { SpanNames } from "../telemetry/index.js";
6
- const MAINNET_CHAIN_ID = 1;
7
7
  export class EnsResolver extends Context.Tag("ew3/EnsResolver")() {
8
8
  }
9
9
  export const EnsResolverLive = Layer.effect(EnsResolver, Effect.gen(function* () {
10
10
  const publicClientService = yield* PublicClientService;
11
11
  return EnsResolver.of({
12
12
  getAddress: (name, opts) => Effect.gen(function* () {
13
- const client = yield* publicClientService.get(MAINNET_CHAIN_ID);
13
+ const client = yield* publicClientService.get(mainnet.id);
14
14
  const normalizedName = normalize(name);
15
15
  const result = yield* Effect.tryPromise({
16
16
  catch: (cause) => new EnsResolutionError({
@@ -37,7 +37,7 @@ export const EnsResolverLive = Layer.effect(EnsResolver, Effect.gen(function* ()
37
37
  },
38
38
  })),
39
39
  getAvatar: (name, opts) => Effect.gen(function* () {
40
- const client = yield* publicClientService.get(MAINNET_CHAIN_ID);
40
+ const client = yield* publicClientService.get(mainnet.id);
41
41
  const normalizedName = normalize(name);
42
42
  const result = yield* Effect.tryPromise({
43
43
  catch: (cause) => new EnsResolutionError({
@@ -63,7 +63,7 @@ export const EnsResolverLive = Layer.effect(EnsResolver, Effect.gen(function* ()
63
63
  },
64
64
  })),
65
65
  getName: (address) => Effect.gen(function* () {
66
- const client = yield* publicClientService.get(MAINNET_CHAIN_ID);
66
+ const client = yield* publicClientService.get(mainnet.id);
67
67
  const result = yield* Effect.tryPromise({
68
68
  catch: (cause) => new EnsResolutionError({
69
69
  cause,
@@ -87,7 +87,7 @@ export const EnsResolverLive = Layer.effect(EnsResolver, Effect.gen(function* ()
87
87
  },
88
88
  })),
89
89
  getResolver: (name) => Effect.gen(function* () {
90
- const client = yield* publicClientService.get(MAINNET_CHAIN_ID);
90
+ const client = yield* publicClientService.get(mainnet.id);
91
91
  const normalizedName = normalize(name);
92
92
  const result = yield* Effect.tryPromise({
93
93
  catch: (cause) => new EnsResolutionError({
@@ -112,7 +112,7 @@ export const EnsResolverLive = Layer.effect(EnsResolver, Effect.gen(function* ()
112
112
  },
113
113
  })),
114
114
  getText: (name, key) => Effect.gen(function* () {
115
- const client = yield* publicClientService.get(MAINNET_CHAIN_ID);
115
+ const client = yield* publicClientService.get(mainnet.id);
116
116
  const normalizedName = normalize(name);
117
117
  const result = yield* Effect.tryPromise({
118
118
  catch: (cause) => new EnsResolutionError({
@@ -1 +1 @@
1
- {"version":3,"file":"ens.js","sourceRoot":"","sources":["../../src/ens/ens.ts"],"names":[],"mappings":"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","sourcesContent":["import { Context, Effect, Layer } from \"effect\";\nimport type { Address } from \"viem\";\nimport { normalize } from \"viem/ens\";\nimport type { ClientNotFoundError } from \"@/src/core/index.js\";\nimport { PublicClientService } from \"@/src/core/index.js\";\nimport {\n EnsAvatarNotFoundError,\n EnsNameNotFoundError,\n EnsResolutionError,\n EnsResolverNotConfiguredError,\n EnsReverseNameNotFoundError,\n EnsTextNotFoundError,\n} from \"@/src/ens/errors.js\";\nimport { SpanNames } from \"@/src/telemetry/index.js\";\n\nconst MAINNET_CHAIN_ID = 1;\n\ntype AssetGatewayUrls = {\n arweave?: string;\n ipfs?: string;\n};\n\n/**\n * Service for ENS (Ethereum Name Service) resolution\n *\n * All operations target Ethereum mainnet (chainId=1) since ENS\n * primarily lives there. Names are automatically normalized.\n */\nexport type EnsResolverShape = {\n /**\n * Resolve an ENS name to an address\n *\n * @param name - The ENS name to resolve (e.g., \"vitalik.eth\")\n * @param opts.coinType - Optional ENSIP-19 coinType for cross-chain resolution\n */\n readonly getAddress: (\n name: string,\n opts?: { coinType?: bigint }\n ) => Effect.Effect<Address, EnsNameNotFoundError | EnsResolutionError | ClientNotFoundError>;\n\n /**\n * Get the avatar URL for an ENS name\n *\n * @param name - The ENS name to get avatar for\n * @param opts.assetGatewayUrls - Optional gateway URLs for IPFS/Arweave\n */\n readonly getAvatar: (\n name: string,\n opts?: { assetGatewayUrls?: AssetGatewayUrls }\n ) => Effect.Effect<string, EnsAvatarNotFoundError | EnsResolutionError | ClientNotFoundError>;\n\n /**\n * Reverse resolve an address to its primary ENS name\n *\n * @param address - The address to resolve\n */\n readonly getName: (\n address: Address\n ) => Effect.Effect<\n string,\n EnsReverseNameNotFoundError | EnsResolutionError | ClientNotFoundError\n >;\n\n /**\n * Get the resolver contract address for an ENS name\n *\n * @param name - The ENS name to get resolver for\n */\n readonly getResolver: (\n name: string\n ) => Effect.Effect<\n Address,\n EnsResolverNotConfiguredError | EnsResolutionError | ClientNotFoundError\n >;\n\n /**\n * Get a text record for an ENS name\n *\n * @param name - The ENS name to query\n * @param key - The text record key (e.g., \"com.twitter\", \"url\", \"description\")\n */\n readonly getText: (\n name: string,\n key: string\n ) => Effect.Effect<string, EnsTextNotFoundError | EnsResolutionError | ClientNotFoundError>;\n};\n\nexport class EnsResolver extends Context.Tag(\"ew3/EnsResolver\")<EnsResolver, EnsResolverShape>() {}\n\n/**\n * Live implementation of EnsResolver service\n *\n * Requires PublicClientService with mainnet (chainId=1) configured\n */\nexport const EnsResolverLive = Layer.effect(\n EnsResolver,\n Effect.gen(function* () {\n const publicClientService = yield* PublicClientService;\n\n return EnsResolver.of({\n getAddress: (name: string, opts?: { coinType?: bigint }) =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(MAINNET_CHAIN_ID);\n const normalizedName = normalize(name);\n\n const result = yield* Effect.tryPromise({\n catch: (cause) =>\n new EnsResolutionError({\n cause,\n message: `Failed to resolve ENS name: ${String(cause)}`,\n name: normalizedName,\n }),\n try: () =>\n client.getEnsAddress({\n coinType: opts?.coinType,\n name: normalizedName,\n }),\n });\n\n if (result === null) {\n return yield* Effect.fail(\n new EnsNameNotFoundError({\n message: `No address found for ENS name \"${normalizedName}\"`,\n name: normalizedName,\n })\n );\n }\n\n return result;\n }).pipe(\n Effect.withSpan(SpanNames.ENS_GET_ADDRESS, {\n attributes: {\n coinType: opts?.coinType?.toString(),\n name,\n },\n })\n ),\n\n getAvatar: (name: string, opts?: { assetGatewayUrls?: AssetGatewayUrls }) =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(MAINNET_CHAIN_ID);\n const normalizedName = normalize(name);\n\n const result = yield* Effect.tryPromise({\n catch: (cause) =>\n new EnsResolutionError({\n cause,\n message: `Failed to get ENS avatar: ${String(cause)}`,\n name: normalizedName,\n }),\n try: () =>\n client.getEnsAvatar({\n assetGatewayUrls: opts?.assetGatewayUrls,\n name: normalizedName,\n }),\n });\n\n if (result === null) {\n return yield* Effect.fail(\n new EnsAvatarNotFoundError({\n message: `No avatar found for ENS name \"${normalizedName}\"`,\n name: normalizedName,\n })\n );\n }\n\n return result;\n }).pipe(\n Effect.withSpan(SpanNames.ENS_GET_AVATAR, {\n attributes: {\n name,\n },\n })\n ),\n\n getName: (address: Address) =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(MAINNET_CHAIN_ID);\n\n const result = yield* Effect.tryPromise({\n catch: (cause) =>\n new EnsResolutionError({\n cause,\n message: `Failed to reverse resolve address: ${String(cause)}`,\n name: address,\n }),\n try: () =>\n client.getEnsName({\n address,\n }),\n });\n\n if (result === null) {\n return yield* Effect.fail(\n new EnsReverseNameNotFoundError({\n address,\n message: `No ENS name found for address \"${address}\"`,\n })\n );\n }\n\n return result;\n }).pipe(\n Effect.withSpan(SpanNames.ENS_GET_NAME, {\n attributes: {\n address,\n },\n })\n ),\n\n getResolver: (name: string) =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(MAINNET_CHAIN_ID);\n const normalizedName = normalize(name);\n\n const result = yield* Effect.tryPromise({\n catch: (cause) =>\n new EnsResolutionError({\n cause,\n message: `Failed to get ENS resolver: ${String(cause)}`,\n name: normalizedName,\n }),\n try: () =>\n client.getEnsResolver({\n name: normalizedName,\n }),\n });\n\n if (result === null || result === \"0x0000000000000000000000000000000000000000\") {\n return yield* Effect.fail(\n new EnsResolverNotConfiguredError({\n message: `No resolver configured for ENS name \"${normalizedName}\"`,\n name: normalizedName,\n })\n );\n }\n\n return result;\n }).pipe(\n Effect.withSpan(SpanNames.ENS_GET_RESOLVER, {\n attributes: {\n name,\n },\n })\n ),\n\n getText: (name: string, key: string) =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(MAINNET_CHAIN_ID);\n const normalizedName = normalize(name);\n\n const result = yield* Effect.tryPromise({\n catch: (cause) =>\n new EnsResolutionError({\n cause,\n message: `Failed to get ENS text record: ${String(cause)}`,\n name: normalizedName,\n }),\n try: () =>\n client.getEnsText({\n key,\n name: normalizedName,\n }),\n });\n\n if (result === null) {\n return yield* Effect.fail(\n new EnsTextNotFoundError({\n key,\n message: `No text record \"${key}\" found for ENS name \"${normalizedName}\"`,\n name: normalizedName,\n })\n );\n }\n\n return result;\n }).pipe(\n Effect.withSpan(SpanNames.ENS_GET_TEXT, {\n attributes: {\n key,\n name,\n },\n })\n ),\n });\n })\n);\n"]}
1
+ {"version":3,"file":"ens.js","sourceRoot":"","sources":["../../src/ens/ens.ts"],"names":[],"mappings":"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","sourcesContent":["import { Context, Effect, Layer } from \"effect\";\nimport type { Address } from \"viem\";\nimport { mainnet } from \"viem/chains\";\nimport { normalize } from \"viem/ens\";\nimport type { ClientNotFoundError } from \"@/src/core/index.js\";\nimport { PublicClientService } from \"@/src/core/index.js\";\nimport {\n EnsAvatarNotFoundError,\n EnsNameNotFoundError,\n EnsResolutionError,\n EnsResolverNotConfiguredError,\n EnsReverseNameNotFoundError,\n EnsTextNotFoundError,\n} from \"@/src/ens/errors.js\";\nimport { SpanNames } from \"@/src/telemetry/index.js\";\n\ntype AssetGatewayUrls = {\n arweave?: string;\n ipfs?: string;\n};\n\n/**\n * Service for ENS (Ethereum Name Service) resolution\n *\n * All operations target Ethereum mainnet (chainId=1) since ENS\n * primarily lives there. Names are automatically normalized.\n */\nexport type EnsResolverShape = {\n /**\n * Resolve an ENS name to an address\n *\n * @param name - The ENS name to resolve (e.g., \"vitalik.eth\")\n * @param opts.coinType - Optional ENSIP-19 coinType for cross-chain resolution\n */\n readonly getAddress: (\n name: string,\n opts?: { coinType?: bigint }\n ) => Effect.Effect<Address, EnsNameNotFoundError | EnsResolutionError | ClientNotFoundError>;\n\n /**\n * Get the avatar URL for an ENS name\n *\n * @param name - The ENS name to get avatar for\n * @param opts.assetGatewayUrls - Optional gateway URLs for IPFS/Arweave\n */\n readonly getAvatar: (\n name: string,\n opts?: { assetGatewayUrls?: AssetGatewayUrls }\n ) => Effect.Effect<string, EnsAvatarNotFoundError | EnsResolutionError | ClientNotFoundError>;\n\n /**\n * Reverse resolve an address to its primary ENS name\n *\n * @param address - The address to resolve\n */\n readonly getName: (\n address: Address\n ) => Effect.Effect<\n string,\n EnsReverseNameNotFoundError | EnsResolutionError | ClientNotFoundError\n >;\n\n /**\n * Get the resolver contract address for an ENS name\n *\n * @param name - The ENS name to get resolver for\n */\n readonly getResolver: (\n name: string\n ) => Effect.Effect<\n Address,\n EnsResolverNotConfiguredError | EnsResolutionError | ClientNotFoundError\n >;\n\n /**\n * Get a text record for an ENS name\n *\n * @param name - The ENS name to query\n * @param key - The text record key (e.g., \"com.twitter\", \"url\", \"description\")\n */\n readonly getText: (\n name: string,\n key: string\n ) => Effect.Effect<string, EnsTextNotFoundError | EnsResolutionError | ClientNotFoundError>;\n};\n\nexport class EnsResolver extends Context.Tag(\"ew3/EnsResolver\")<EnsResolver, EnsResolverShape>() {}\n\n/**\n * Live implementation of EnsResolver service\n *\n * Requires PublicClientService with mainnet (chainId=1) configured\n */\nexport const EnsResolverLive = Layer.effect(\n EnsResolver,\n Effect.gen(function* () {\n const publicClientService = yield* PublicClientService;\n\n return EnsResolver.of({\n getAddress: (name: string, opts?: { coinType?: bigint }) =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(mainnet.id);\n const normalizedName = normalize(name);\n\n const result = yield* Effect.tryPromise({\n catch: (cause) =>\n new EnsResolutionError({\n cause,\n message: `Failed to resolve ENS name: ${String(cause)}`,\n name: normalizedName,\n }),\n try: () =>\n client.getEnsAddress({\n coinType: opts?.coinType,\n name: normalizedName,\n }),\n });\n\n if (result === null) {\n return yield* Effect.fail(\n new EnsNameNotFoundError({\n message: `No address found for ENS name \"${normalizedName}\"`,\n name: normalizedName,\n })\n );\n }\n\n return result;\n }).pipe(\n Effect.withSpan(SpanNames.ENS_GET_ADDRESS, {\n attributes: {\n coinType: opts?.coinType?.toString(),\n name,\n },\n })\n ),\n\n getAvatar: (name: string, opts?: { assetGatewayUrls?: AssetGatewayUrls }) =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(mainnet.id);\n const normalizedName = normalize(name);\n\n const result = yield* Effect.tryPromise({\n catch: (cause) =>\n new EnsResolutionError({\n cause,\n message: `Failed to get ENS avatar: ${String(cause)}`,\n name: normalizedName,\n }),\n try: () =>\n client.getEnsAvatar({\n assetGatewayUrls: opts?.assetGatewayUrls,\n name: normalizedName,\n }),\n });\n\n if (result === null) {\n return yield* Effect.fail(\n new EnsAvatarNotFoundError({\n message: `No avatar found for ENS name \"${normalizedName}\"`,\n name: normalizedName,\n })\n );\n }\n\n return result;\n }).pipe(\n Effect.withSpan(SpanNames.ENS_GET_AVATAR, {\n attributes: {\n name,\n },\n })\n ),\n\n getName: (address: Address) =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(mainnet.id);\n\n const result = yield* Effect.tryPromise({\n catch: (cause) =>\n new EnsResolutionError({\n cause,\n message: `Failed to reverse resolve address: ${String(cause)}`,\n name: address,\n }),\n try: () =>\n client.getEnsName({\n address,\n }),\n });\n\n if (result === null) {\n return yield* Effect.fail(\n new EnsReverseNameNotFoundError({\n address,\n message: `No ENS name found for address \"${address}\"`,\n })\n );\n }\n\n return result;\n }).pipe(\n Effect.withSpan(SpanNames.ENS_GET_NAME, {\n attributes: {\n address,\n },\n })\n ),\n\n getResolver: (name: string) =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(mainnet.id);\n const normalizedName = normalize(name);\n\n const result = yield* Effect.tryPromise({\n catch: (cause) =>\n new EnsResolutionError({\n cause,\n message: `Failed to get ENS resolver: ${String(cause)}`,\n name: normalizedName,\n }),\n try: () =>\n client.getEnsResolver({\n name: normalizedName,\n }),\n });\n\n if (result === null || result === \"0x0000000000000000000000000000000000000000\") {\n return yield* Effect.fail(\n new EnsResolverNotConfiguredError({\n message: `No resolver configured for ENS name \"${normalizedName}\"`,\n name: normalizedName,\n })\n );\n }\n\n return result;\n }).pipe(\n Effect.withSpan(SpanNames.ENS_GET_RESOLVER, {\n attributes: {\n name,\n },\n })\n ),\n\n getText: (name: string, key: string) =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(mainnet.id);\n const normalizedName = normalize(name);\n\n const result = yield* Effect.tryPromise({\n catch: (cause) =>\n new EnsResolutionError({\n cause,\n message: `Failed to get ENS text record: ${String(cause)}`,\n name: normalizedName,\n }),\n try: () =>\n client.getEnsText({\n key,\n name: normalizedName,\n }),\n });\n\n if (result === null) {\n return yield* Effect.fail(\n new EnsTextNotFoundError({\n key,\n message: `No text record \"${key}\" found for ENS name \"${normalizedName}\"`,\n name: normalizedName,\n })\n );\n }\n\n return result;\n }).pipe(\n Effect.withSpan(SpanNames.ENS_GET_TEXT, {\n attributes: {\n key,\n name,\n },\n })\n ),\n });\n })\n);\n"]}
@@ -4,6 +4,8 @@ export type { EffectEvmLayerProviderProps, EffectEvmProviderProps, } from "../in
4
4
  export { EffectEvmLayerProvider, EffectEvmProvider, EffectEvmProviderSync, useEffectEvmLayer, useEffectEvmRuntime, } from "../integrations/react-hooks/provider.js";
5
5
  export type { WalletProviderRefActions } from "../integrations/react-hooks/wallet-provider-ref.js";
6
6
  export { useWalletProviderRef } from "../integrations/react-hooks/wallet-provider-ref.js";
7
- export { useIsSafeMultisig } from "./use-is-safe-multisig.js";
8
- export { useSafeContext } from "./use-safe-context.js";
7
+ export { DEFAULT_SAFE_APP_ORIGINS, extendSafeAppOrigins, getSafeAppOrigins, setSafeAppOrigins, } from "./safe-app-origins.js";
8
+ export { useIsHostSafeApp } from "./use-is-host-safe-app.js";
9
+ export { useIsSafeAppContext } from "./use-is-safe-app-context.js";
10
+ export { useIsSafeMultisigWallet } from "./use-is-safe-multisig-wallet.js";
9
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react-hooks/index.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,eAAe,GAChB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,SAAS,EACT,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,8CAA8C,CAAC;AACtD,YAAY,EACV,2BAA2B,EAC3B,sBAAsB,GACvB,MAAM,4CAA4C,CAAC;AACpD,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,4CAA4C,CAAC;AACpD,YAAY,EAAE,wBAAwB,EAAE,MAAM,uDAAuD,CAAC;AACtG,OAAO,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react-hooks/index.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,eAAe,GAChB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,SAAS,EACT,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,8CAA8C,CAAC;AACtD,YAAY,EACV,2BAA2B,EAC3B,sBAAsB,GACvB,MAAM,4CAA4C,CAAC;AACpD,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,4CAA4C,CAAC;AACpD,YAAY,EAAE,wBAAwB,EAAE,MAAM,uDAAuD,CAAC;AACtG,OAAO,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAC7F,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC"}
@@ -2,6 +2,8 @@
2
2
  export { useEffectMemo, useEffectMemoFactory, useEffectOnce, useForkEffect, useStream, useStreamEffect, useStreamValue, useSubscriptionRef, useSubscriptionRefValue, } from "../integrations/react-hooks/primitives.js";
3
3
  export { EffectEvmLayerProvider, EffectEvmProvider, EffectEvmProviderSync, useEffectEvmLayer, useEffectEvmRuntime, } from "../integrations/react-hooks/provider.js";
4
4
  export { useWalletProviderRef } from "../integrations/react-hooks/wallet-provider-ref.js";
5
- export { useIsSafeMultisig } from "./use-is-safe-multisig.js";
6
- export { useSafeContext } from "./use-safe-context.js";
5
+ export { DEFAULT_SAFE_APP_ORIGINS, extendSafeAppOrigins, getSafeAppOrigins, setSafeAppOrigins, } from "./safe-app-origins.js";
6
+ export { useIsHostSafeApp } from "./use-is-host-safe-app.js";
7
+ export { useIsSafeAppContext } from "./use-is-safe-app-context.js";
8
+ export { useIsSafeMultisigWallet } from "./use-is-safe-multisig-wallet.js";
7
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react-hooks/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAOb,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,SAAS,EACT,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,8CAA8C,CAAC;AAKtD,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC","sourcesContent":["\"use client\";\n\nexport type {\n EffectMemoOptions,\n StreamState,\n UseEffectResult,\n} from \"@/src/integrations/react-hooks/primitives.js\";\nexport {\n useEffectMemo,\n useEffectMemoFactory,\n useEffectOnce,\n useForkEffect,\n useStream,\n useStreamEffect,\n useStreamValue,\n useSubscriptionRef,\n useSubscriptionRefValue,\n} from \"@/src/integrations/react-hooks/primitives.js\";\nexport type {\n EffectEvmLayerProviderProps,\n EffectEvmProviderProps,\n} from \"@/src/integrations/react-hooks/provider.js\";\nexport {\n EffectEvmLayerProvider,\n EffectEvmProvider,\n EffectEvmProviderSync,\n useEffectEvmLayer,\n useEffectEvmRuntime,\n} from \"@/src/integrations/react-hooks/provider.js\";\nexport type { WalletProviderRefActions } from \"@/src/integrations/react-hooks/wallet-provider-ref.js\";\nexport { useWalletProviderRef } from \"@/src/integrations/react-hooks/wallet-provider-ref.js\";\nexport { useIsSafeMultisig } from \"./use-is-safe-multisig.js\";\nexport { useSafeContext } from \"./use-safe-context.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react-hooks/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAOb,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,SAAS,EACT,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,8CAA8C,CAAC;AAKtD,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAC7F,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC","sourcesContent":["\"use client\";\n\nexport type {\n EffectMemoOptions,\n StreamState,\n UseEffectResult,\n} from \"@/src/integrations/react-hooks/primitives.js\";\nexport {\n useEffectMemo,\n useEffectMemoFactory,\n useEffectOnce,\n useForkEffect,\n useStream,\n useStreamEffect,\n useStreamValue,\n useSubscriptionRef,\n useSubscriptionRefValue,\n} from \"@/src/integrations/react-hooks/primitives.js\";\nexport type {\n EffectEvmLayerProviderProps,\n EffectEvmProviderProps,\n} from \"@/src/integrations/react-hooks/provider.js\";\nexport {\n EffectEvmLayerProvider,\n EffectEvmProvider,\n EffectEvmProviderSync,\n useEffectEvmLayer,\n useEffectEvmRuntime,\n} from \"@/src/integrations/react-hooks/provider.js\";\nexport type { WalletProviderRefActions } from \"@/src/integrations/react-hooks/wallet-provider-ref.js\";\nexport { useWalletProviderRef } from \"@/src/integrations/react-hooks/wallet-provider-ref.js\";\nexport {\n DEFAULT_SAFE_APP_ORIGINS,\n extendSafeAppOrigins,\n getSafeAppOrigins,\n setSafeAppOrigins,\n} from \"./safe-app-origins.js\";\nexport { useIsHostSafeApp } from \"./use-is-host-safe-app.js\";\nexport { useIsSafeAppContext } from \"./use-is-safe-app-context.js\";\nexport { useIsSafeMultisigWallet } from \"./use-is-safe-multisig-wallet.js\";\n"]}
@@ -0,0 +1,8 @@
1
+ export declare const DEFAULT_SAFE_APP_ORIGINS: readonly ["https://app.safe.global", "https://gnosis-safe.io", "https://safe.global", "https://safe.berachain.com", "https://safe.chiliz.com", "https://safe.lightlink.io", "https://safe.optimism.io"];
2
+ export declare function setSafeAppOrigins(origins: readonly string[]): void;
3
+ export declare function extendSafeAppOrigins(origins: readonly string[]): void;
4
+ export declare function getSafeAppOrigins(): readonly string[];
5
+ export declare function subscribeSafeAppOrigins(listener: () => void): () => void;
6
+ export declare function isValidSafeAppOrigin(): boolean;
7
+ export declare function isHostEmbedded(): boolean;
8
+ //# sourceMappingURL=safe-app-origins.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-app-origins.d.ts","sourceRoot":"","sources":["../../src/react-hooks/safe-app-origins.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,wBAAwB,yMAU3B,CAAC;AASX,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,QAE3D;AAGD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,QAE9D;AAGD,wBAAgB,iBAAiB,IAAI,SAAS,MAAM,EAAE,CAErD;AAGD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAKxE;AAGD,wBAAgB,oBAAoB,IAAI,OAAO,CAM9C;AAGD,wBAAgB,cAAc,IAAI,OAAO,CAExC"}
@@ -0,0 +1,124 @@
1
+ "use client";
2
+ export const DEFAULT_SAFE_APP_ORIGINS = [
3
+ "https://app.safe.global",
4
+ "https://gnosis-safe.io",
5
+ "https://safe.global",
6
+ "https://safe.berachain.com",
7
+ "https://safe.chiliz.com",
8
+ "https://safe.lightlink.io",
9
+ "https://safe.optimism.io",
10
+ ];
11
+ const ORIGIN_PROTOCOL_PATTERN = /^[a-z]+:\/\//i;
12
+ let safeAppOrigins = normalizeOrigins(DEFAULT_SAFE_APP_ORIGINS);
13
+ let safeAppOriginSet = new Set(safeAppOrigins);
14
+ const safeAppOriginListeners = new Set();
15
+ let safeAppOriginsConfigured = false;
16
+ export function setSafeAppOrigins(origins) {
17
+ configureSafeAppOrigins(normalizeOrigins(origins));
18
+ }
19
+ export function extendSafeAppOrigins(origins) {
20
+ configureSafeAppOrigins(normalizeOrigins([...safeAppOrigins, ...origins]));
21
+ }
22
+ export function getSafeAppOrigins() {
23
+ return [...safeAppOrigins];
24
+ }
25
+ export function subscribeSafeAppOrigins(listener) {
26
+ safeAppOriginListeners.add(listener);
27
+ return () => {
28
+ safeAppOriginListeners.delete(listener);
29
+ };
30
+ }
31
+ export function isValidSafeAppOrigin() {
32
+ const origin = getAncestorOrigin();
33
+ if (!origin) {
34
+ return false;
35
+ }
36
+ return safeAppOriginSet.has(origin);
37
+ }
38
+ export function isHostEmbedded() {
39
+ return typeof window !== "undefined" && window.parent !== window;
40
+ }
41
+ function getAncestorOrigin() {
42
+ if (typeof window === "undefined") {
43
+ return null;
44
+ }
45
+ try {
46
+ return window.parent.location.origin;
47
+ }
48
+ catch {
49
+ if (window.location.ancestorOrigins?.length) {
50
+ return window.location.ancestorOrigins[0];
51
+ }
52
+ if (document.referrer) {
53
+ try {
54
+ return new URL(document.referrer).origin;
55
+ }
56
+ catch {
57
+ return null;
58
+ }
59
+ }
60
+ return null;
61
+ }
62
+ }
63
+ function updateSafeAppOrigins(nextOrigins) {
64
+ if (areSameOrigins(safeAppOrigins, nextOrigins)) {
65
+ return;
66
+ }
67
+ safeAppOrigins = nextOrigins;
68
+ safeAppOriginSet = new Set(safeAppOrigins);
69
+ notifySafeAppOriginListeners();
70
+ }
71
+ function configureSafeAppOrigins(nextOrigins) {
72
+ if (safeAppOriginsConfigured) {
73
+ throw new Error("Safe App origins already configured.");
74
+ }
75
+ safeAppOriginsConfigured = true;
76
+ updateSafeAppOrigins(nextOrigins);
77
+ }
78
+ function notifySafeAppOriginListeners() {
79
+ for (const listener of safeAppOriginListeners) {
80
+ listener();
81
+ }
82
+ }
83
+ function normalizeOrigins(origins) {
84
+ const normalized = [];
85
+ const seen = new Set();
86
+ for (const origin of origins) {
87
+ const normalizedOrigin = normalizeOrigin(origin);
88
+ if (!normalizedOrigin || seen.has(normalizedOrigin)) {
89
+ continue;
90
+ }
91
+ seen.add(normalizedOrigin);
92
+ normalized.push(normalizedOrigin);
93
+ }
94
+ return normalized;
95
+ }
96
+ function normalizeOrigin(origin) {
97
+ const trimmed = origin.trim();
98
+ if (!trimmed) {
99
+ return null;
100
+ }
101
+ const candidate = ORIGIN_PROTOCOL_PATTERN.test(trimmed) ? trimmed : `https://${trimmed}`;
102
+ try {
103
+ const url = new URL(candidate);
104
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
105
+ return null;
106
+ }
107
+ return url.origin;
108
+ }
109
+ catch {
110
+ return null;
111
+ }
112
+ }
113
+ function areSameOrigins(left, right) {
114
+ if (left.length !== right.length) {
115
+ return false;
116
+ }
117
+ for (let index = 0; index < left.length; index += 1) {
118
+ if (left[index] !== right[index]) {
119
+ return false;
120
+ }
121
+ }
122
+ return true;
123
+ }
124
+ //# sourceMappingURL=safe-app-origins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-app-origins.js","sourceRoot":"","sources":["../../src/react-hooks/safe-app-origins.ts"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\n/**\n * Known Safe App domains for iframe origin validation.\n * Includes the main Safe App and chain-specific Safe deployments.\n */\nexport const DEFAULT_SAFE_APP_ORIGINS = [\n // Main Safe domains\n \"https://app.safe.global\",\n \"https://gnosis-safe.io\",\n \"https://safe.global\",\n // Chain-specific Safe deployments\n \"https://safe.berachain.com\",\n \"https://safe.chiliz.com\",\n \"https://safe.lightlink.io\",\n \"https://safe.optimism.io\",\n] as const;\n\nconst ORIGIN_PROTOCOL_PATTERN = /^[a-z]+:\\/\\//i;\nlet safeAppOrigins = normalizeOrigins(DEFAULT_SAFE_APP_ORIGINS);\nlet safeAppOriginSet = new Set(safeAppOrigins);\nconst safeAppOriginListeners = new Set<() => void>();\nlet safeAppOriginsConfigured = false;\n\n/** Replace the Safe App origins list (one-time configuration). */\nexport function setSafeAppOrigins(origins: readonly string[]) {\n configureSafeAppOrigins(normalizeOrigins(origins));\n}\n\n/** Extend the Safe App origins list (one-time configuration). */\nexport function extendSafeAppOrigins(origins: readonly string[]) {\n configureSafeAppOrigins(normalizeOrigins([...safeAppOrigins, ...origins]));\n}\n\n/** Read the currently configured Safe App origins list. */\nexport function getSafeAppOrigins(): readonly string[] {\n return [...safeAppOrigins];\n}\n\n/** Subscribe to Safe App origin changes. */\nexport function subscribeSafeAppOrigins(listener: () => void): () => void {\n safeAppOriginListeners.add(listener);\n return () => {\n safeAppOriginListeners.delete(listener);\n };\n}\n\n/** Check if the parent browsing context origin is a Safe App domain. */\nexport function isValidSafeAppOrigin(): boolean {\n const origin = getAncestorOrigin();\n if (!origin) {\n return false;\n }\n return safeAppOriginSet.has(origin);\n}\n\n/** Check whether the app is running inside an iframe. */\nexport function isHostEmbedded(): boolean {\n return typeof window !== \"undefined\" && window.parent !== window;\n}\n\n/**\n * Get the origin of the parent browsing context.\n * Returns null if it cannot be determined due to cross-origin restrictions.\n */\nfunction getAncestorOrigin(): string | null {\n if (typeof window === \"undefined\") {\n return null;\n }\n\n try {\n return window.parent.location.origin;\n } catch {\n if (window.location.ancestorOrigins?.length) {\n return window.location.ancestorOrigins[0];\n }\n\n if (document.referrer) {\n try {\n return new URL(document.referrer).origin;\n } catch {\n return null;\n }\n }\n\n return null;\n }\n}\n\nfunction updateSafeAppOrigins(nextOrigins: string[]) {\n if (areSameOrigins(safeAppOrigins, nextOrigins)) {\n return;\n }\n\n safeAppOrigins = nextOrigins;\n safeAppOriginSet = new Set(safeAppOrigins);\n notifySafeAppOriginListeners();\n}\n\nfunction configureSafeAppOrigins(nextOrigins: string[]) {\n if (safeAppOriginsConfigured) {\n throw new Error(\"Safe App origins already configured.\");\n }\n\n safeAppOriginsConfigured = true;\n updateSafeAppOrigins(nextOrigins);\n}\n\nfunction notifySafeAppOriginListeners() {\n for (const listener of safeAppOriginListeners) {\n listener();\n }\n}\n\nfunction normalizeOrigins(origins: readonly string[]): string[] {\n const normalized: string[] = [];\n const seen = new Set<string>();\n\n for (const origin of origins) {\n const normalizedOrigin = normalizeOrigin(origin);\n if (!normalizedOrigin || seen.has(normalizedOrigin)) {\n continue;\n }\n seen.add(normalizedOrigin);\n normalized.push(normalizedOrigin);\n }\n\n return normalized;\n}\n\nfunction normalizeOrigin(origin: string): string | null {\n const trimmed = origin.trim();\n if (!trimmed) {\n return null;\n }\n\n const candidate = ORIGIN_PROTOCOL_PATTERN.test(trimmed) ? trimmed : `https://${trimmed}`;\n\n try {\n const url = new URL(candidate);\n if (url.protocol !== \"https:\" && url.protocol !== \"http:\") {\n return null;\n }\n return url.origin;\n } catch {\n return null;\n }\n}\n\nfunction areSameOrigins(left: readonly string[], right: readonly string[]): boolean {\n if (left.length !== right.length) {\n return false;\n }\n\n for (let index = 0; index < left.length; index += 1) {\n if (left[index] !== right[index]) {\n return false;\n }\n }\n\n return true;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function useIsHostSafeApp(): boolean;
2
+ //# sourceMappingURL=use-is-host-safe-app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-is-host-safe-app.d.ts","sourceRoot":"","sources":["../../src/react-hooks/use-is-host-safe-app.ts"],"names":[],"mappings":"AAsBA,wBAAgB,gBAAgB,IAAI,OAAO,CAS1C"}
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { useSyncExternalStore } from "react";
3
+ import { isHostEmbedded, isValidSafeAppOrigin, subscribeSafeAppOrigins, } from "./safe-app-origins.js";
4
+ import { useIsSafeAppContext } from "./use-is-safe-app-context.js";
5
+ export function useIsHostSafeApp() {
6
+ const isSafeContext = useIsSafeAppContext();
7
+ const isSafeHost = useSyncExternalStore(subscribeSafeAppOrigins, getSafeHostSnapshot, getServerSnapshot);
8
+ return isSafeContext || isSafeHost;
9
+ }
10
+ function getSafeHostSnapshot() {
11
+ return isHostEmbedded() && isValidSafeAppOrigin();
12
+ }
13
+ function getServerSnapshot() {
14
+ return false;
15
+ }
16
+ //# sourceMappingURL=use-is-host-safe-app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-is-host-safe-app.js","sourceRoot":"","sources":["../../src/react-hooks/use-is-host-safe-app.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAcnE,MAAM,UAAU,gBAAgB;IAC9B,MAAM,aAAa,GAAG,mBAAmB,EAAE,CAAC;IAC5C,MAAM,UAAU,GAAG,oBAAoB,CACrC,uBAAuB,EACvB,mBAAmB,EACnB,iBAAiB,CAClB,CAAC;IAEF,OAAO,aAAa,IAAI,UAAU,CAAC;AACrC,CAAC;AAED,SAAS,mBAAmB;IAC1B,OAAO,cAAc,EAAE,IAAI,oBAAoB,EAAE,CAAC;AACpD,CAAC;AAED,SAAS,iBAAiB;IACxB,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["\"use client\";\n\nimport { useSyncExternalStore } from \"react\";\nimport {\n isHostEmbedded,\n isValidSafeAppOrigin,\n subscribeSafeAppOrigins,\n} from \"./safe-app-origins.js\";\nimport { useIsSafeAppContext } from \"./use-is-safe-app-context.js\";\n\n/**\n * Detect if the app is running within a Safe App context.\n *\n * This hook returns `true` when either:\n * - Safe Apps SDK confirms the Safe context (async, most reliable), or\n * - The app is embedded in a Safe App-origin iframe (sync check).\n *\n * Notes:\n * - This answers “is the host Safe App?” and will return true even without a wallet.\n * - For full wallet detection heuristics, use `useIsSafeMultisigWallet`.\n * - For SDK-only checks, use `useIsSafeAppContext`.\n */\nexport function useIsHostSafeApp(): boolean {\n const isSafeContext = useIsSafeAppContext();\n const isSafeHost = useSyncExternalStore(\n subscribeSafeAppOrigins,\n getSafeHostSnapshot,\n getServerSnapshot\n );\n\n return isSafeContext || isSafeHost;\n}\n\nfunction getSafeHostSnapshot(): boolean {\n return isHostEmbedded() && isValidSafeAppOrigin();\n}\n\nfunction getServerSnapshot(): boolean {\n return false;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function useIsSafeAppContext(): boolean;
2
+ //# sourceMappingURL=use-is-safe-app-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-is-safe-app-context.d.ts","sourceRoot":"","sources":["../../src/react-hooks/use-is-safe-app-context.ts"],"names":[],"mappings":"AAuCA,wBAAgB,mBAAmB,IAAI,OAAO,CA6C7C"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { useEffect, useState } from "react";
3
3
  const SAFE_SDK_TIMEOUT = 3000;
4
- export function useSafeContext() {
4
+ export function useIsSafeAppContext() {
5
5
  const [isSafe, setIsSafe] = useState(false);
6
6
  useEffect(() => {
7
7
  if (typeof window === "undefined") {
@@ -38,4 +38,4 @@ export function useSafeContext() {
38
38
  }, []);
39
39
  return isSafe;
40
40
  }
41
- //# sourceMappingURL=use-safe-context.js.map
41
+ //# sourceMappingURL=use-is-safe-app-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-is-safe-app-context.js","sourceRoot":"","sources":["../../src/react-hooks/use-is-safe-app-context.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAM5C,MAAM,gBAAgB,GAAG,IAAI,CAAC;AA+B9B,MAAM,UAAU,mBAAmB;IACjC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE5C,SAAS,CAAC,GAAG,EAAE;QAEb,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,OAAO;QACT,CAAC;QAED,IAAI,SAAS,GAAG,KAAK,CAAC;QAGtB,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;QACH,CAAC,EAAE,gBAAgB,CAAC,CAAC;QAGrB,MAAM,CAAC,4BAA4B,CAAC;aACjC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE;YACjC,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC;YAC9B,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,CAAC,CAAC;aACD,IAAI,CAAC,GAAG,EAAE;YACT,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;QACH,CAAC,CAAC;aACD,OAAO,CAAC,GAAG,EAAE;YACZ,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QAEL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;YACjB,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\n/**\n * Timeout for Safe SDK detection in milliseconds.\n * Safe Apps SDK uses postMessage which can hang if not in Safe context.\n */\nconst SAFE_SDK_TIMEOUT = 3000;\n\n/**\n * Detect if the app is running in a Safe App context using the Safe Apps SDK.\n *\n * This hook asynchronously checks with the Safe Apps SDK to determine if\n * we're running inside a Safe App iframe. More reliable than iframe origin\n * detection because:\n * - Uses postMessage (works cross-origin)\n * - Gets definitive answer from Safe\n * - Includes timeout to prevent hangs\n *\n * @returns true if running in Safe App context, false otherwise\n *\n * Notes:\n * - This only verifies the Safe Apps SDK context (async).\n * - For a host-based sync check, use `useIsHostSafeApp`.\n * - For a full wallet detection heuristic, use `useIsSafeMultisigWallet`.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const isSafeContext = useIsSafeAppContext();\n *\n * if (isSafeContext) {\n * return <p>Running in Safe App</p>;\n * }\n * return <p>Regular browser context</p>;\n * }\n * ```\n */\nexport function useIsSafeAppContext(): boolean {\n const [isSafe, setIsSafe] = useState(false);\n\n useEffect(() => {\n // SSR guard\n if (typeof window === \"undefined\") {\n return;\n }\n\n let cancelled = false;\n\n // Timeout fallback - resolve to false if SDK doesn't respond\n const timeout = setTimeout(() => {\n if (!cancelled) {\n setIsSafe(false);\n }\n }, SAFE_SDK_TIMEOUT);\n\n // Dynamically import SDK to keep it optional\n import(\"@safe-global/safe-apps-sdk\")\n .then(({ default: SafeAppsSDK }) => {\n const sdk = new SafeAppsSDK();\n return sdk.safe.getInfo();\n })\n .then(() => {\n if (!cancelled) {\n setIsSafe(true);\n }\n })\n .catch(() => {\n if (!cancelled) {\n setIsSafe(false);\n }\n })\n .finally(() => {\n clearTimeout(timeout);\n });\n\n return () => {\n cancelled = true;\n clearTimeout(timeout);\n };\n }, []);\n\n return isSafe;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function useIsSafeMultisigWallet(): boolean;
2
+ //# sourceMappingURL=use-is-safe-multisig-wallet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-is-safe-multisig-wallet.d.ts","sourceRoot":"","sources":["../../src/react-hooks/use-is-safe-multisig-wallet.ts"],"names":[],"mappings":"AA0BA,wBAAgB,uBAAuB,IAAI,OAAO,CAuBjD"}
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import { useSyncExternalStore } from "react";
3
+ import { useAccount } from "wagmi";
4
+ import { isHostEmbedded, isValidSafeAppOrigin, subscribeSafeAppOrigins, } from "./safe-app-origins.js";
5
+ import { useIsSafeAppContext } from "./use-is-safe-app-context.js";
6
+ export function useIsSafeMultisigWallet() {
7
+ const { connector, isConnected } = useAccount();
8
+ const isSafeContext = useIsSafeAppContext();
9
+ const isSafeIframe = useSyncExternalStore(subscribeSafeAppOrigins, getSafeIframeSnapshot, getServerSnapshot);
10
+ if (isSafeContext) {
11
+ return true;
12
+ }
13
+ if (isConnected && connector?.id === "safe") {
14
+ return true;
15
+ }
16
+ return isSafeIframe;
17
+ }
18
+ function getSafeIframeSnapshot() {
19
+ return isHostEmbedded() && isValidSafeAppOrigin();
20
+ }
21
+ function getServerSnapshot() {
22
+ return false;
23
+ }
24
+ //# sourceMappingURL=use-is-safe-multisig-wallet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-is-safe-multisig-wallet.js","sourceRoot":"","sources":["../../src/react-hooks/use-is-safe-multisig-wallet.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAiBnE,MAAM,UAAU,uBAAuB;IACrC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,UAAU,EAAE,CAAC;IAChD,MAAM,aAAa,GAAG,mBAAmB,EAAE,CAAC;IAG5C,MAAM,YAAY,GAAG,oBAAoB,CACvC,uBAAuB,EACvB,qBAAqB,EACrB,iBAAiB,CAClB,CAAC;IAGF,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAGD,IAAI,WAAW,IAAI,SAAS,EAAE,EAAE,KAAK,MAAM,EAAE,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IAGD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAS,qBAAqB;IAC5B,OAAO,cAAc,EAAE,IAAI,oBAAoB,EAAE,CAAC;AACpD,CAAC;AAED,SAAS,iBAAiB;IACxB,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["\"use client\";\n\nimport { useSyncExternalStore } from \"react\";\nimport { useAccount } from \"wagmi\";\nimport {\n isHostEmbedded,\n isValidSafeAppOrigin,\n subscribeSafeAppOrigins,\n} from \"./safe-app-origins.js\";\nimport { useIsSafeAppContext } from \"./use-is-safe-app-context.js\";\n\n/**\n * Detect if the connected wallet is a Safe multisig wallet.\n *\n * Detection strategy (in order of reliability):\n * 1. Safe Apps SDK detection via postMessage (most reliable, works cross-origin)\n * 2. Wagmi connector ID check\n * 3. Iframe origin validation (fallback, may fail cross-origin)\n *\n * @returns true if wallet is a Safe multisig\n *\n * Notes:\n * - This is a broader heuristic: SDK context, connector ID, then host origin.\n * - For just SDK context, use `useIsSafeAppContext`.\n * - For a sync host-only check, use `useIsHostSafeApp`.\n */\nexport function useIsSafeMultisigWallet(): boolean {\n const { connector, isConnected } = useAccount();\n const isSafeContext = useIsSafeAppContext();\n\n // Method 3: Iframe origin fallback (may fail cross-origin)\n const isSafeIframe = useSyncExternalStore(\n subscribeSafeAppOrigins,\n getSafeIframeSnapshot,\n getServerSnapshot\n );\n\n // Method 1: Safe Apps SDK (most reliable - uses postMessage)\n if (isSafeContext) {\n return true;\n }\n\n // Method 2: Connected via Safe connector\n if (isConnected && connector?.id === \"safe\") {\n return true;\n }\n\n // Method 3: Fallback\n return isSafeIframe;\n}\n\nfunction getSafeIframeSnapshot(): boolean {\n return isHostEmbedded() && isValidSafeAppOrigin();\n}\n\nfunction getServerSnapshot(): boolean {\n return false;\n}\n"]}
@@ -4,5 +4,5 @@ export { NotInSafeAppContextError, OffchainSignatureTimeoutError, SafeInfoUnavai
4
4
  export { type SafeAppsServiceConfig, SafeAppsServiceLive } from "./live.js";
5
5
  export { SafeAppsService, type SafeAppsServiceShape } from "./service.js";
6
6
  export * from "./simulation/index.js";
7
- export type { EIP712TypedData, OffchainSignaturePolicy, OffchainSignatureResult, SafeInfo, SafeTransaction, SafeTxResult, SafeTxSubmission, SafeWaitPolicy, SignTypedDataResult, } from "./types.js";
7
+ export type { EIP712TypedData, OffchainSignaturePolicy, OffchainSignatureResult, SafeInfo, SafeMultisigTx, SafeTxResult, SafeTxSubmission, SafeWaitPolicy, SignTypedDataResult, } from "./types.js";
8
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/safe/index.ts"],"names":[],"mappings":"AAEA,YAAY,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE/E,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpE,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,wBAAwB,EACxB,uBAAuB,EACvB,iBAAiB,EACjB,2BAA2B,EAC3B,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAE1E,cAAc,uBAAuB,CAAC;AAEtC,YAAY,EACV,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/safe/index.ts"],"names":[],"mappings":"AAEA,YAAY,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE/E,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpE,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,wBAAwB,EACxB,uBAAuB,EACvB,iBAAiB,EACjB,2BAA2B,EAC3B,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAE1E,cAAc,uBAAuB,CAAC;AAEtC,YAAY,EACV,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,QAAQ,EACR,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/safe/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpE,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,wBAAwB,EACxB,uBAAuB,EACvB,iBAAiB,EACjB,2BAA2B,EAC3B,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAA8B,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,eAAe,EAA6B,MAAM,cAAc,CAAC;AAE1E,cAAc,uBAAuB,CAAC","sourcesContent":["// Service and layer\n\nexport type { SafeDetectionParams, SafeDetectionResult } from \"./detection.js\";\n// Detection\nexport { isSafeMultisig, SafeDetectionError } from \"./detection.js\";\n\n// Errors\nexport {\n NotInSafeAppContextError,\n OffchainSignatureTimeoutError,\n SafeInfoUnavailableError,\n SafeSdkUnavailableError,\n SafeSettingsError,\n SafeTxExecutionTimeoutError,\n SafeTxLookupError,\n SafeTxSubmissionError,\n SignTypedDataError,\n} from \"./errors.js\";\nexport { type SafeAppsServiceConfig, SafeAppsServiceLive } from \"./live.js\";\nexport { SafeAppsService, type SafeAppsServiceShape } from \"./service.js\";\n// Simulation\nexport * from \"./simulation/index.js\";\n// Types\nexport type {\n EIP712TypedData,\n OffchainSignaturePolicy,\n OffchainSignatureResult,\n SafeInfo,\n SafeTransaction,\n SafeTxResult,\n SafeTxSubmission,\n SafeWaitPolicy,\n SignTypedDataResult,\n} from \"./types.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/safe/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpE,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,wBAAwB,EACxB,uBAAuB,EACvB,iBAAiB,EACjB,2BAA2B,EAC3B,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAA8B,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,eAAe,EAA6B,MAAM,cAAc,CAAC;AAE1E,cAAc,uBAAuB,CAAC","sourcesContent":["// Service and layer\n\nexport type { SafeDetectionParams, SafeDetectionResult } from \"./detection.js\";\n// Detection\nexport { isSafeMultisig, SafeDetectionError } from \"./detection.js\";\n\n// Errors\nexport {\n NotInSafeAppContextError,\n OffchainSignatureTimeoutError,\n SafeInfoUnavailableError,\n SafeSdkUnavailableError,\n SafeSettingsError,\n SafeTxExecutionTimeoutError,\n SafeTxLookupError,\n SafeTxSubmissionError,\n SignTypedDataError,\n} from \"./errors.js\";\nexport { type SafeAppsServiceConfig, SafeAppsServiceLive } from \"./live.js\";\nexport { SafeAppsService, type SafeAppsServiceShape } from \"./service.js\";\n// Simulation\nexport * from \"./simulation/index.js\";\n// Types\nexport type {\n EIP712TypedData,\n OffchainSignaturePolicy,\n OffchainSignatureResult,\n SafeInfo,\n SafeMultisigTx,\n SafeTxResult,\n SafeTxSubmission,\n SafeWaitPolicy,\n SignTypedDataResult,\n} from \"./types.js\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../src/safe/live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,EAAe,MAAM,QAAQ,CAAC;AAU9D,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EACL,wBAAwB,EAQzB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG/C,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;AA+CtD,eAAO,MAAM,mBAAmB,GAAI,SAAS,qBAAqB,sHAgX/D,CAAC"}
1
+ {"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../src/safe/live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,EAAe,MAAM,QAAQ,CAAC;AAU9D,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EACL,wBAAwB,EAQzB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG/C,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;AA+CtD,eAAO,MAAM,mBAAmB,GAAI,SAAS,qBAAqB,sHA6W/D,CAAC"}
package/dist/safe/live.js CHANGED
@@ -56,7 +56,7 @@ export const SafeAppsServiceLive = (config) => Layer.scoped(SafeAppsService, Eff
56
56
  yield* Ref.set(infoRef, safeInfo);
57
57
  return safeInfo;
58
58
  }).pipe(Effect.withSpan(SpanNames.SAFE_GET_INFO));
59
- const sendTransactions = (txs, params) => Effect.gen(function* () {
59
+ const sendTxs = (txs, params) => Effect.gen(function* () {
60
60
  const sdkTxs = txs.map((tx) => ({
61
61
  data: tx.data,
62
62
  to: tx.to,
@@ -65,11 +65,11 @@ export const SafeAppsServiceLive = (config) => Layer.scoped(SafeAppsService, Eff
65
65
  const result = yield* Effect.tryPromise({
66
66
  catch: (cause) => new SafeTxSubmissionError({
67
67
  cause,
68
- message: "Failed to submit transactions to Safe",
68
+ message: "Failed to submit txs to Safe",
69
69
  }),
70
70
  try: () => sdk.txs.send({ params, txs: sdkTxs }),
71
71
  });
72
- const safeTxHash = yield* validateHash(result.safeTxHash, "sendTransactions").pipe(Effect.catchTag("SafeTxLookupError", (e) => Effect.fail(new SafeTxSubmissionError({ cause: e, message: e.message }))));
72
+ const safeTxHash = yield* validateHash(result.safeTxHash, "sendTxs").pipe(Effect.catchTag("SafeTxLookupError", (e) => Effect.fail(new SafeTxSubmissionError({ cause: e, message: e.message }))));
73
73
  const info = yield* getInfo();
74
74
  return {
75
75
  chainId: info.chainId,
@@ -79,22 +79,22 @@ export const SafeAppsServiceLive = (config) => Layer.scoped(SafeAppsService, Eff
79
79
  })
80
80
  .pipe(Effect.catchTag("SafeInfoUnavailableError", (error) => Effect.fail(new SafeTxSubmissionError({
81
81
  cause: error,
82
- message: "Failed to get Safe info after transaction submission",
82
+ message: "Failed to get Safe info after tx submission",
83
83
  }))))
84
84
  .pipe(Effect.withSpan(SpanNames.SAFE_SEND_TXS, {
85
85
  attributes: { txCount: txs.length },
86
86
  }));
87
- const getTransaction = (safeTxHash) => Effect.gen(function* () {
87
+ const getTx = (safeTxHash) => Effect.gen(function* () {
88
88
  const tx = yield* Effect.tryPromise({
89
89
  catch: (cause) => new SafeTxLookupError({
90
90
  cause,
91
- message: `Failed to lookup Safe transaction ${safeTxHash}`,
91
+ message: `Failed to lookup Safe tx ${safeTxHash}`,
92
92
  retryable: true,
93
93
  safeTxHash,
94
94
  }),
95
95
  try: () => sdk.txs.getBySafeTxHash(safeTxHash),
96
96
  });
97
- const txHash = tx.txHash ? yield* validateHash(tx.txHash, "getTransaction") : null;
97
+ const txHash = tx.txHash ? yield* validateHash(tx.txHash, "getTx") : null;
98
98
  return {
99
99
  status: tx.txStatus ?? "AWAITING_CONFIRMATIONS",
100
100
  txHash: txHash ? Option.some(txHash) : Option.none(),
@@ -102,7 +102,7 @@ export const SafeAppsServiceLive = (config) => Layer.scoped(SafeAppsService, Eff
102
102
  }).pipe(Effect.withSpan(SpanNames.SAFE_GET_TX, {
103
103
  attributes: { safeTxHash },
104
104
  }));
105
- const waitForTransactionReceipt = (safeTxHash, policy = {}) => Effect.gen(function* () {
105
+ const waitForTxReceipt = (safeTxHash, policy = {}) => Effect.gen(function* () {
106
106
  const info = yield* getInfo();
107
107
  const pollInterval = policy.pollInterval ?? SAFE_POLL_INTERVAL;
108
108
  const executionTimeout = policy.executionTimeout ?? SAFE_EXECUTION_TIMEOUT;
@@ -111,7 +111,7 @@ export const SafeAppsServiceLive = (config) => Layer.scoped(SafeAppsService, Eff
111
111
  let found = null;
112
112
  const pollEffect = Effect.gen(function* () {
113
113
  while (found === null) {
114
- const tx = yield* getTransaction(safeTxHash);
114
+ const tx = yield* getTx(safeTxHash);
115
115
  lastStatus = tx.status;
116
116
  if (Option.isSome(tx.txHash)) {
117
117
  found = tx.txHash.value;
@@ -123,14 +123,14 @@ export const SafeAppsServiceLive = (config) => Layer.scoped(SafeAppsService, Eff
123
123
  });
124
124
  yield* pollEffect.pipe(Effect.timeout(Duration.millis(executionTimeout)), Effect.catchTag("TimeoutException", () => Effect.fail(new SafeTxExecutionTimeoutError({
125
125
  lastStatus,
126
- message: `Safe transaction ${safeTxHash} not executed within ${executionTimeout}ms (last status: ${lastStatus})`,
126
+ message: `Safe tx ${safeTxHash} not executed within ${executionTimeout}ms (last status: ${lastStatus})`,
127
127
  safeTxHash,
128
128
  timeout: executionTimeout,
129
129
  }))));
130
130
  if (found === null) {
131
131
  return yield* Effect.fail(new SafeTxExecutionTimeoutError({
132
132
  lastStatus,
133
- message: `Safe transaction ${safeTxHash} not executed within timeout`,
133
+ message: `Safe tx ${safeTxHash} not executed within timeout`,
134
134
  safeTxHash,
135
135
  timeout: executionTimeout,
136
136
  }));
@@ -240,11 +240,11 @@ export const SafeAppsServiceLive = (config) => Layer.scoped(SafeAppsService, Eff
240
240
  enableOffchainSigning,
241
241
  getInfo,
242
242
  getOffchainSignature,
243
- getTransaction,
243
+ getTx,
244
244
  pollOffchainSignature,
245
- sendTransactions,
245
+ sendTxs,
246
246
  signTypedData,
247
- waitForTransactionReceipt,
247
+ waitForTxReceipt,
248
248
  });
249
249
  }));
250
250
  //# sourceMappingURL=live.js.map