@prb/effect-evm 1.0.0-beta.3 → 1.0.0-beta.4
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/ens/ens.d.ts.map +1 -1
- package/dist/ens/ens.js +6 -6
- package/dist/ens/ens.js.map +1 -1
- package/dist/react-hooks/index.d.ts +3 -1
- package/dist/react-hooks/index.d.ts.map +1 -1
- package/dist/react-hooks/index.js +3 -1
- package/dist/react-hooks/index.js.map +1 -1
- package/dist/react-hooks/safe-origins.d.ts +8 -0
- package/dist/react-hooks/safe-origins.d.ts.map +1 -0
- package/dist/react-hooks/safe-origins.js +124 -0
- package/dist/react-hooks/safe-origins.js.map +1 -0
- package/dist/react-hooks/use-is-host-safe-multisig.d.ts +2 -0
- package/dist/react-hooks/use-is-host-safe-multisig.d.ts.map +1 -0
- package/dist/react-hooks/use-is-host-safe-multisig.js +16 -0
- package/dist/react-hooks/use-is-host-safe-multisig.js.map +1 -0
- package/dist/react-hooks/use-is-wallet-safe-multisig.d.ts +2 -0
- package/dist/react-hooks/use-is-wallet-safe-multisig.d.ts.map +1 -0
- package/dist/react-hooks/use-is-wallet-safe-multisig.js +24 -0
- package/dist/react-hooks/use-is-wallet-safe-multisig.js.map +1 -0
- package/dist/react-hooks/use-safe-context.d.ts.map +1 -1
- package/dist/react-hooks/use-safe-context.js.map +1 -1
- package/dist/safe/simulation/abis.d.ts.map +1 -1
- package/dist/safe/simulation/abis.js.map +1 -1
- package/dist/safe/simulation/addresses.d.ts.map +1 -1
- package/dist/safe/simulation/addresses.js +40 -26
- package/dist/safe/simulation/addresses.js.map +1 -1
- package/dist/safe/simulation/internal/calldata/calldata.d.ts +5 -0
- package/dist/safe/simulation/internal/calldata/calldata.d.ts.map +1 -0
- package/dist/safe/simulation/internal/calldata/calldata.js +17 -0
- package/dist/safe/simulation/internal/calldata/calldata.js.map +1 -0
- package/dist/safe/simulation/internal/calldata/index.d.ts +2 -0
- package/dist/safe/simulation/internal/calldata/index.d.ts.map +1 -0
- package/dist/safe/simulation/internal/calldata/index.js +2 -0
- package/dist/safe/simulation/internal/calldata/index.js.map +1 -0
- package/dist/safe/simulation/internal/contracts/contracts.d.ts +5 -0
- package/dist/safe/simulation/internal/contracts/contracts.d.ts.map +1 -0
- package/dist/safe/simulation/internal/contracts/contracts.js +25 -0
- package/dist/safe/simulation/internal/contracts/contracts.js.map +1 -0
- package/dist/safe/simulation/internal/contracts/index.d.ts +2 -0
- package/dist/safe/simulation/internal/contracts/index.d.ts.map +1 -0
- package/dist/safe/simulation/internal/contracts/index.js +2 -0
- package/dist/safe/simulation/internal/contracts/index.js.map +1 -0
- package/dist/safe/simulation/internal/evaluation/evaluation.d.ts +6 -0
- package/dist/safe/simulation/internal/evaluation/evaluation.d.ts.map +1 -0
- package/dist/safe/simulation/internal/evaluation/evaluation.js +20 -0
- package/dist/safe/simulation/internal/evaluation/evaluation.js.map +1 -0
- package/dist/safe/simulation/internal/evaluation/index.d.ts +2 -0
- package/dist/safe/simulation/internal/evaluation/index.d.ts.map +1 -0
- package/dist/safe/simulation/internal/evaluation/index.js +2 -0
- package/dist/safe/simulation/internal/evaluation/index.js.map +1 -0
- package/dist/safe/simulation/internal/execution/execution.d.ts +9 -0
- package/dist/safe/simulation/internal/execution/execution.d.ts.map +1 -0
- package/dist/safe/simulation/internal/execution/execution.js +65 -0
- package/dist/safe/simulation/internal/execution/execution.js.map +1 -0
- package/dist/safe/simulation/internal/execution/index.d.ts +2 -0
- package/dist/safe/simulation/internal/execution/index.d.ts.map +1 -0
- package/dist/safe/simulation/internal/execution/index.js +2 -0
- package/dist/safe/simulation/internal/execution/index.js.map +1 -0
- package/dist/safe/simulation/internal/limits/index.d.ts +2 -0
- package/dist/safe/simulation/internal/limits/index.d.ts.map +1 -0
- package/dist/safe/simulation/internal/limits/index.js +2 -0
- package/dist/safe/simulation/internal/limits/index.js.map +1 -0
- package/dist/safe/simulation/internal/limits/limits.d.ts +5 -0
- package/dist/safe/simulation/internal/limits/limits.d.ts.map +1 -0
- package/dist/safe/simulation/internal/limits/limits.js +18 -0
- package/dist/safe/simulation/internal/limits/limits.js.map +1 -0
- package/dist/safe/simulation/internal/types/index.d.ts +2 -0
- package/dist/safe/simulation/internal/types/index.d.ts.map +1 -0
- package/dist/safe/simulation/internal/types/index.js +2 -0
- package/dist/safe/simulation/internal/types/index.js.map +1 -0
- package/dist/safe/simulation/internal/types/types.d.ts +11 -0
- package/dist/safe/simulation/internal/types/types.d.ts.map +1 -0
- package/dist/safe/simulation/internal/types/types.js +2 -0
- package/dist/safe/simulation/internal/types/types.js.map +1 -0
- package/dist/safe/simulation/internal/validation/index.d.ts +2 -0
- package/dist/safe/simulation/internal/validation/index.d.ts.map +1 -0
- package/dist/safe/simulation/internal/validation/index.js +2 -0
- package/dist/safe/simulation/internal/validation/index.js.map +1 -0
- package/dist/safe/simulation/internal/validation/validation.d.ts +5 -0
- package/dist/safe/simulation/internal/validation/validation.d.ts.map +1 -0
- package/dist/safe/simulation/internal/validation/validation.js +27 -0
- package/dist/safe/simulation/internal/validation/validation.js.map +1 -0
- package/dist/safe/simulation/service.d.ts +1 -1
- package/dist/safe/simulation/service.d.ts.map +1 -1
- package/dist/safe/simulation/service.js +12 -127
- package/dist/safe/simulation/service.js.map +1 -1
- package/package.json +1 -1
- package/dist/react-hooks/use-is-safe-multisig.d.ts +0 -2
- package/dist/react-hooks/use-is-safe-multisig.d.ts.map +0 -1
- package/dist/react-hooks/use-is-safe-multisig.js +0 -44
- package/dist/react-hooks/use-is-safe-multisig.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/safe/simulation/service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Safe batch simulation service using Effect-TS.\n *\n * Simulates Safe multisig batch transactions to estimate gas consumption before execution.\n * Uses Safe's simulateAndRevert algorithm to get accurate gas estimates.\n *\n * @see https://github.com/safe-global/safe-smart-account/blob/c4859f4/contracts/common/StorageAccessible.sol#L32-L43\n */\n\nimport { Context, Effect, Layer } from \"effect\";\nimport { BaseError as CoreError, encodeFunctionData, zeroAddress } from \"viem\";\nimport type { ClientNotFoundError } from \"@/src/core/index.js\";\nimport { PublicClientService } from \"@/src/core/index.js\";\nimport { safeAbis } from \"./abis.js\";\nimport { getMultiSendAddress, getSimulateAccessorAddress } from \"./addresses.js\";\nimport { decodeSimulationData, encodeMultiSend } from \"./encoding.js\";\nimport {\n GasLimitOverflowError,\n InvalidGasThresholdError,\n SafeContractsNotDeployedError,\n SafeSimulationFailedError,\n SimulationDecodeError,\n TransactionSizeTooLargeError,\n} from \"./errors.js\";\nimport type { SafeSimulateBatchParams, SafeSimulationResult } from \"./types.js\";\n\nexport type SafeSimulationServiceShape = {\n /**\n * Simulate a batch of transactions in Safe context.\n *\n * Uses simulateAndRevert algorithm to estimate gas consumption. This always reverts,\n * and we decode the revert data to extract the gas estimate.\n *\n * @param params - Simulation parameters including chainId, safeAddress, and transactions\n * @returns Gas estimate and success flag\n */\n readonly simulateBatch: (\n params: SafeSimulateBatchParams\n ) => Effect.Effect<\n SafeSimulationResult,\n | ClientNotFoundError\n | InvalidGasThresholdError\n | SafeContractsNotDeployedError\n | TransactionSizeTooLargeError\n | SafeSimulationFailedError\n | SimulationDecodeError\n | GasLimitOverflowError\n >;\n};\n\nexport class SafeSimulationService extends Context.Tag(\"ew3/SafeSimulation\")<\n SafeSimulationService,\n SafeSimulationServiceShape\n>() {}\n\nexport const SafeSimulationServiceLive = Layer.effect(\n SafeSimulationService,\n Effect.gen(function* () {\n const publicClientService = yield* PublicClientService;\n\n return SafeSimulationService.of({\n simulateBatch: (params: SafeSimulateBatchParams) =>\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Safe simulation requires validation and multi-step orchestration\n Effect.gen(function* () {\n const { chainId, safeAddress, transactions, txSizeLimit, gasThresholdPercent } = params;\n\n // 0. Validate inputs\n if (transactions.length === 0) {\n return yield* Effect.fail(\n new SafeSimulationFailedError({\n message: \"Cannot simulate empty transaction batch\",\n })\n );\n }\n\n if (safeAddress === zeroAddress) {\n return yield* Effect.fail(\n new SafeSimulationFailedError({\n message: \"Invalid Safe address: cannot be zero address\",\n })\n );\n }\n\n if (\n gasThresholdPercent !== undefined &&\n (gasThresholdPercent < 1 || gasThresholdPercent > 100)\n ) {\n return yield* Effect.fail(\n new InvalidGasThresholdError({\n message: \"gasThresholdPercent must be between 1 and 100 (inclusive)\",\n value: gasThresholdPercent,\n })\n );\n }\n\n // 1. Check Safe contracts are deployed\n const multiSendAddr = getMultiSendAddress(chainId);\n const simulateAccessorAddr = getSimulateAccessorAddress(chainId);\n\n if (!multiSendAddr) {\n return yield* Effect.fail(\n new SafeContractsNotDeployedError({\n chainId,\n message: \"MultiSend contract not deployed on this chain\",\n missingContract: \"multiSend\",\n })\n );\n }\n\n if (!simulateAccessorAddr) {\n return yield* Effect.fail(\n new SafeContractsNotDeployedError({\n chainId,\n message: \"SimulateAccessor contract not deployed on this chain\",\n missingContract: \"simulateAccessor\",\n })\n );\n }\n\n // 2. Encode multiSend calldata\n const multiSendCalldata = encodeMultiSend(transactions);\n\n // 3. Encode simulateAccessor.simulate() calldata\n const simulateAccessorCalldata = encodeFunctionData({\n abi: safeAbis.simulateAccessor,\n args: [multiSendAddr, 0n, multiSendCalldata, 1], // 1 = DelegateCall\n functionName: \"simulate\",\n });\n\n // 4. Encode safe.simulateAndRevert() calldata\n const safeCalldata = encodeFunctionData({\n abi: safeAbis.multisig,\n args: [simulateAccessorAddr, simulateAccessorCalldata],\n functionName: \"simulateAndRevert\",\n });\n\n // 5. Check transaction size limit for ZK rollups\n if (txSizeLimit) {\n // Calculate size in bytes (remove \"0x\" prefix and divide by 2)\n const sizeInBytes = (safeCalldata.length - 2) / 2;\n if (sizeInBytes > txSizeLimit) {\n return yield* Effect.fail(\n new TransactionSizeTooLargeError({\n actualSize: sizeInBytes,\n maxSize: txSizeLimit,\n message: `Transaction size (${sizeInBytes} bytes) exceeds chain limit (${txSizeLimit} bytes). Try splitting into smaller batches.`,\n })\n );\n }\n }\n\n // 6. Get public client\n const client = yield* publicClientService.get(chainId);\n\n // 7. Execute simulation call and fetch block in parallel\n const simulationEffect = Effect.gen(function* () {\n // Execute the simulation call\n const revertData = yield* Effect.tryPromise({\n catch: (error) =>\n new SafeSimulationFailedError({\n cause: error,\n message: \"Network error or unexpected behavior during simulation\",\n }),\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Async error extraction requires try-catch\n try: async () => {\n try {\n await client.call({\n account: safeAddress,\n data: safeCalldata,\n to: safeAddress,\n });\n // Should never reach here\n throw new Error(\"simulateAndRevert did not revert\");\n } catch (error: unknown) {\n // Use viem's official BaseError API to extract revert data\n if (error instanceof CoreError) {\n // viem's BaseError.walk() traverses the error chain to find matching errors\n // We use it to find an error with revert data (the 'data' property)\n const revertError = error.walk((err) => {\n const typedErr = err as unknown as Record<string, unknown>;\n return typeof typedErr.data === \"string\";\n });\n if (revertError) {\n const typedErr = revertError as unknown as Record<string, unknown>;\n const extractedData = typedErr.data;\n if (typeof extractedData === \"string\") {\n return extractedData;\n }\n }\n }\n throw error;\n }\n },\n });\n\n // Decode the revert data\n return yield* Effect.try({\n catch: (error) =>\n new SimulationDecodeError({\n cause: error,\n message: \"Failed to decode simulation revert data - unexpected format\",\n revertData,\n }),\n try: () => decodeSimulationData(revertData),\n });\n });\n\n const [result, block] = yield* Effect.all(\n [\n simulationEffect,\n Effect.tryPromise({\n catch: (e) =>\n new SafeSimulationFailedError({\n cause: e,\n message: `Failed to fetch block: ${e}`,\n }),\n try: () => client.getBlock({ blockTag: \"latest\" }),\n }),\n ],\n { concurrency: \"unbounded\" }\n );\n\n // 8. Check if gas exceeds threshold\n const threshold = (block.gasLimit * BigInt(params.gasThresholdPercent ?? 95)) / 100n;\n\n if (result.success && result.gas > threshold) {\n return yield* Effect.fail(\n new GasLimitOverflowError({\n blockGasLimit: block.gasLimit,\n estimatedGas: result.gas,\n message:\n \"Gas consumption exceeds threshold of block gas limit. Try splitting into smaller batches.\",\n threshold,\n })\n );\n }\n\n if (!result.success) {\n return yield* Effect.fail(\n new SafeSimulationFailedError({\n message: \"Transaction simulation failed - the transaction would revert\",\n })\n );\n }\n\n return { estimatedGas: result.gas, success: true };\n }),\n });\n })\n);\n"]}
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/safe/simulation/service.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAEhD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAS1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AA2B1E,MAAM,OAAO,qBAAsB,SAAQ,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAGzE;CAAG;AAEN,MAAM,CAAC,MAAM,yBAAyB,GAAG,KAAK,CAAC,MAAM,CACnD,qBAAqB,EACrB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,mBAAmB,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAAC;IAEvD,OAAO,qBAAqB,CAAC,EAAE,CAAC;QAC9B,aAAa,EAAE,CAAC,MAA+B,EAAE,EAAE,CACjD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,mBAAmB,EAAE,GAC5E,KAAK,CAAC,CAAC,wBAAwB,CAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;YACvD,MAAM,YAAY,GAAG,iBAAiB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;YAEhE,KAAK,CAAC,CAAC,kBAAkB,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;YAErD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACvD,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CACvC,CAAC,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC,EAChF,EAAE,WAAW,EAAE,WAAW,EAAE,CAC7B,CAAC;YAEF,OAAO,KAAK,CAAC,CAAC,wBAAwB,CAAC,MAAM,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC;QAC7E,CAAC,CAAC;KACL,CAAC,CAAC;AACL,CAAC,CAAC,CACH,CAAC","sourcesContent":["/**\n * Safe batch simulation service using Effect-TS.\n *\n * Simulates Safe multisig batch transactions to estimate gas consumption before execution.\n * Uses Safe's simulateAndRevert algorithm to get accurate gas estimates.\n *\n * @see https://github.com/safe-global/safe-smart-account/blob/c4859f4/contracts/common/StorageAccessible.sol#L32-L43\n */\n\nimport { Context, Effect, Layer } from \"effect\";\nimport type { ClientNotFoundError } from \"@/src/core/index.js\";\nimport { PublicClientService } from \"@/src/core/index.js\";\nimport type {\n GasLimitOverflowError,\n InvalidGasThresholdError,\n SafeContractsNotDeployedError,\n SafeSimulationFailedError,\n SimulationDecodeError,\n TransactionSizeTooLargeError,\n} from \"./errors.js\";\nimport { buildSafeCalldata } from \"./internal/calldata/index.js\";\nimport { resolveSafeContracts } from \"./internal/contracts/index.js\";\nimport { evaluateSimulationResult } from \"./internal/evaluation/index.js\";\nimport { fetchLatestBlock, simulateAndDecode } from \"./internal/execution/index.js\";\nimport { enforceTxSizeLimit } from \"./internal/limits/index.js\";\nimport { validateSimulationParams } from \"./internal/validation/index.js\";\nimport type { SafeSimulateBatchParams, SafeSimulationResult } from \"./types.js\";\n\nexport type SafeSimulationServiceShape = {\n /**\n * Simulate a batch of transactions in Safe context.\n *\n * Uses simulateAndRevert algorithm to estimate gas consumption. This always reverts,\n * and we decode the revert data to extract the gas estimate.\n *\n * @param params - Simulation parameters including chainId, safeAddress, and transactions\n * @returns Gas estimate and success flag\n */\n readonly simulateBatch: (\n params: SafeSimulateBatchParams\n ) => Effect.Effect<\n SafeSimulationResult,\n | ClientNotFoundError\n | InvalidGasThresholdError\n | SafeContractsNotDeployedError\n | TransactionSizeTooLargeError\n | SafeSimulationFailedError\n | SimulationDecodeError\n | GasLimitOverflowError\n >;\n};\n\nexport class SafeSimulationService extends Context.Tag(\"ew3/SafeSimulation\")<\n SafeSimulationService,\n SafeSimulationServiceShape\n>() {}\n\nexport const SafeSimulationServiceLive = Layer.effect(\n SafeSimulationService,\n Effect.gen(function* () {\n const publicClientService = yield* PublicClientService;\n\n return SafeSimulationService.of({\n simulateBatch: (params: SafeSimulateBatchParams) =>\n Effect.gen(function* () {\n const { chainId, safeAddress, transactions, txSizeLimit, gasThresholdPercent } =\n yield* validateSimulationParams(params);\n const contracts = yield* resolveSafeContracts(chainId);\n const safeCalldata = buildSafeCalldata(contracts, transactions);\n\n yield* enforceTxSizeLimit(safeCalldata, txSizeLimit);\n\n const client = yield* publicClientService.get(chainId);\n const [result, block] = yield* Effect.all(\n [simulateAndDecode(client, safeAddress, safeCalldata), fetchLatestBlock(client)],\n { concurrency: \"unbounded\" }\n );\n\n return yield* evaluateSimulationResult(result, block, gasThresholdPercent);\n }),\n });\n })\n);\n"]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-is-safe-multisig.d.ts","sourceRoot":"","sources":["../../src/react-hooks/use-is-safe-multisig.ts"],"names":[],"mappings":"AAgCA,wBAAgB,iBAAiB,IAAI,OAAO,CAyB3C"}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
import { useAccount } from "wagmi";
|
|
4
|
-
import { useSafeContext } from "./use-safe-context.js";
|
|
5
|
-
const SAFE_ORIGINS = [
|
|
6
|
-
"https://app.safe.global",
|
|
7
|
-
"https://gnosis-safe.io",
|
|
8
|
-
"https://safe.global",
|
|
9
|
-
"https://safe.berachain.com",
|
|
10
|
-
"https://safe.chiliz.com",
|
|
11
|
-
"https://safe.lightlink.io",
|
|
12
|
-
"https://safe.optimism.io",
|
|
13
|
-
];
|
|
14
|
-
export function useIsSafeMultisig() {
|
|
15
|
-
const { connector, isConnected } = useAccount();
|
|
16
|
-
const isSafeContext = useSafeContext();
|
|
17
|
-
const [isSafeIframe, setIsSafeIframe] = useState(false);
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
if (window.parent !== window && isValidSafeOrigin()) {
|
|
20
|
-
setIsSafeIframe(true);
|
|
21
|
-
}
|
|
22
|
-
}, []);
|
|
23
|
-
if (isSafeContext) {
|
|
24
|
-
return true;
|
|
25
|
-
}
|
|
26
|
-
if (isConnected && connector?.id === "safe") {
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
return isSafeIframe;
|
|
30
|
-
}
|
|
31
|
-
function isValidSafeOrigin() {
|
|
32
|
-
try {
|
|
33
|
-
const parentOrigin = window.parent.location.origin;
|
|
34
|
-
return SAFE_ORIGINS.some((origin) => parentOrigin === origin);
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
if (window.location.ancestorOrigins?.length) {
|
|
38
|
-
const ancestorOrigin = window.location.ancestorOrigins[0];
|
|
39
|
-
return SAFE_ORIGINS.some((origin) => ancestorOrigin === origin);
|
|
40
|
-
}
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
//# sourceMappingURL=use-is-safe-multisig.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"use-is-safe-multisig.js","sourceRoot":"","sources":["../../src/react-hooks/use-is-safe-multisig.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAMvD,MAAM,YAAY,GAAG;IAEnB,yBAAyB;IACzB,wBAAwB;IACxB,qBAAqB;IAErB,4BAA4B;IAC5B,yBAAyB;IACzB,2BAA2B;IAC3B,0BAA0B;CAClB,CAAC;AAYX,MAAM,UAAU,iBAAiB;IAC/B,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,UAAU,EAAE,CAAC;IAChD,MAAM,aAAa,GAAG,cAAc,EAAE,CAAC;IAIvC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,IAAI,iBAAiB,EAAE,EAAE,CAAC;YACpD,eAAe,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAGP,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;AAMD,SAAS,iBAAiB;IACxB,IAAI,CAAC;QAEH,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QACnD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,KAAK,MAAM,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QAEP,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;YAC5C,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAC1D,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,cAAc,KAAK,MAAM,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { useAccount } from \"wagmi\";\nimport { useSafeContext } from \"./use-safe-context.js\";\n\n/**\n * Known Safe wallet domains for iframe origin validation.\n * Includes the main Safe app and chain-specific Safe deployments.\n */\nconst SAFE_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\n/**\n * Detect if the connected wallet is a Safe multisig.\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 */\nexport function useIsSafeMultisig(): boolean {\n const { connector, isConnected } = useAccount();\n const isSafeContext = useSafeContext();\n\n // Method 3: Iframe origin fallback (may fail cross-origin)\n // Deferred to useEffect to avoid SSR hydration mismatch\n const [isSafeIframe, setIsSafeIframe] = useState(false);\n useEffect(() => {\n if (window.parent !== window && isValidSafeOrigin()) {\n setIsSafeIframe(true);\n }\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\n/**\n * Check if the parent window origin matches known Safe domains.\n * This prevents false positives from other iframe contexts.\n */\nfunction isValidSafeOrigin(): boolean {\n try {\n // Try to access parent origin (may throw SecurityError for cross-origin)\n const parentOrigin = window.parent.location.origin;\n return SAFE_ORIGINS.some((origin) => parentOrigin === origin);\n } catch {\n // Cross-origin access blocked - check ancestorOrigins if available\n if (window.location.ancestorOrigins?.length) {\n const ancestorOrigin = window.location.ancestorOrigins[0];\n return SAFE_ORIGINS.some((origin) => ancestorOrigin === origin);\n }\n // Cannot determine origin - default to false to avoid false positives\n return false;\n }\n}\n"]}
|