Skip to content

Commit 7a96690

Browse files
committed
feat: implement SafeRPCStrategy
For signature validations we need to make contract read calls. Safe protocol kit expects an RPC URL to make these calls, but on Filecoin mainnet and Filecoin Calibration they need to be JWT authenticated. This poses a problem with the initializer of the Safe SDK so we decided to use public RPCs on these two networks.
1 parent c252033 commit 7a96690

File tree

3 files changed

+49
-6
lines changed

3 files changed

+49
-6
lines changed

src/client/evmClient.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,10 @@ export class EvmClientFactory {
107107

108108
static getPublicRpcUrl(chainId: number): string {
109109
const chain = ChainFactory.getChain(chainId);
110-
if (!chain.rpcUrls.public.http[0]) {
111-
throw new Error(
112-
`(viem) No public RPC URL available for chain ${chainId}`,
113-
);
110+
if (!chain.rpcUrls?.default?.http?.[0]) {
111+
throw new Error(`No public RPC URL available for chain ${chainId}`);
114112
}
115-
return chain.rpcUrls.public.http[0];
113+
return chain.rpcUrls.default.http[0];
116114
}
117115

118116
// Keep this for backward compatibility

src/lib/safe-signature-verification/SafeSignatureVerifier.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { getAddress, hashTypedData, type HashTypedDataParameters } from "viem";
33

44
import { EvmClientFactory } from "../../client/evmClient.js";
55

6+
import { RpcStrategyFactory } from "./safe-rpc-urls.js";
7+
68
export default abstract class SafeSignatureVerifier {
79
protected chainId: number;
810
protected safeAddress: `0x${string}`;
@@ -11,7 +13,10 @@ export default abstract class SafeSignatureVerifier {
1113
constructor(chainId: number, safeAddress: `0x${string}`) {
1214
this.chainId = chainId;
1315
this.safeAddress = getAddress(safeAddress);
14-
this.rpcUrl = EvmClientFactory.getPublicRpcUrl(chainId);
16+
this.rpcUrl = RpcStrategyFactory.getStrategy(
17+
chainId,
18+
EvmClientFactory,
19+
).getUrl(chainId);
1520
}
1621

1722
hashTypedData() {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { EvmClientFactory } from "../../client/evmClient.js";
2+
3+
export interface SafeRpcStrategy {
4+
getUrl(chainId: number): string;
5+
}
6+
7+
export class FilecoinRpcStrategy implements SafeRpcStrategy {
8+
constructor(private evmClientFactory: typeof EvmClientFactory) {}
9+
10+
getUrl(chainId: number): string {
11+
return this.evmClientFactory.getPublicRpcUrl(chainId);
12+
}
13+
}
14+
15+
export class RandomRpcStrategy implements SafeRpcStrategy {
16+
constructor(private evmClientFactory: typeof EvmClientFactory) {}
17+
18+
getUrl(chainId: number): string {
19+
const urls = this.evmClientFactory.getAllAvailableUrls(chainId);
20+
if (urls.length === 0) {
21+
throw new Error(`No RPC URL available for chain ${chainId}`);
22+
}
23+
const randomIndex = Math.floor(Math.random() * urls.length);
24+
return urls[randomIndex];
25+
}
26+
}
27+
28+
export class RpcStrategyFactory {
29+
static getStrategy(
30+
chainId: number,
31+
evmClientFactory: typeof EvmClientFactory,
32+
): SafeRpcStrategy {
33+
// Filecoin chains use public RPC
34+
if (chainId === 314 || chainId === 314159) {
35+
return new FilecoinRpcStrategy(evmClientFactory);
36+
}
37+
// All other chains use random selection from available RPCs
38+
return new RandomRpcStrategy(evmClientFactory);
39+
}
40+
}

0 commit comments

Comments
 (0)