Skip to content

Commit 9553241

Browse files
committed
fix: make manager safe app compatible
1 parent 8f89823 commit 9553241

File tree

9 files changed

+268
-68
lines changed

9 files changed

+268
-68
lines changed

packages/round-manager/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
"@openzeppelin/merkle-tree": "^1.0.2",
3939
"@rainbow-me/rainbowkit": "2.1.2",
4040
"@reduxjs/toolkit": "^1.8.1",
41+
"@safe-global/safe-apps-provider": "^0.18.5",
42+
"@safe-global/safe-apps-react-sdk": "^4.7.2",
4143
"@sentry/integrations": "^7.28.0",
4244
"@sentry/react": "^7.27.0",
4345
"@sentry/tracing": "^7.26.0",
Lines changed: 31 additions & 0 deletions
Loading
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"short_name": "Manager",
3+
"name": "Gitcoin Safe App Manager",
4+
"description": "Gitcoin Safe App Manager",
5+
"icons": [
6+
{
7+
"src": "manager-logo.svg",
8+
"sizes": "any",
9+
"type": "image/svg+xml"
10+
},
11+
{
12+
"src": "favicon.ico",
13+
"sizes": "64x64 32x32 24x24 16x16",
14+
"type": "image/x-icon"
15+
},
16+
{
17+
"src": "favicon.ico",
18+
"sizes": "64x64 32x32 24x24 16x16",
19+
"type": "image/x-icon"
20+
},
21+
{
22+
"src": "logo192.png",
23+
"type": "image/png",
24+
"sizes": "192x192"
25+
},
26+
{
27+
"src": "logo512.png",
28+
"type": "image/png",
29+
"sizes": "512x512"
30+
}
31+
],
32+
"start_url": ".",
33+
"display": "standalone",
34+
"theme_color": "#FFFFFF",
35+
"background_color": "#FFFFFF"
36+
}

packages/round-manager/setUpProxy.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// App is an express application, we can add an express middleware that will set headers for manifest.json request
2+
// https://create-react-app.dev/docs/proxying-api-requests-in-development/#configuring-the-proxy-manually
3+
4+
module.exports = function (app) {
5+
app.use("/manifest.json", function (req, res, next) {
6+
res.set({
7+
"Access-Control-Allow-Origin": "*",
8+
"Access-Control-Allow-Methods": "GET",
9+
"Access-Control-Allow-Headers":
10+
"X-Requested-With, content-type, Authorization",
11+
});
12+
next();
13+
});
14+
};

packages/round-manager/src/app/wagmi.ts

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,58 @@
11
import "@rainbow-me/rainbowkit/styles.css";
22
import { QueryClient } from "@tanstack/react-query";
3-
import { Chain as RChain, getDefaultConfig } from "@rainbow-me/rainbowkit";
43
import { allNetworks, mainnetNetworks } from "common/src/chains";
54
import { getClient, getConnectorClient } from "@wagmi/core";
65
import { providers } from "ethers";
7-
import { type Account, type Chain, type Client, type Transport } from "viem";
6+
import {
7+
http,
8+
type Account,
9+
type Chain,
10+
type Client,
11+
type Transport,
12+
} from "viem";
813
import { Connector } from "wagmi";
9-
10-
export const allChains: RChain[] =
11-
process.env.REACT_APP_ENV === "development" ? allNetworks : mainnetNetworks;
14+
import {
15+
rainbowWallet,
16+
safeWallet,
17+
walletConnectWallet,
18+
coinbaseWallet,
19+
} from "@rainbow-me/rainbowkit/wallets";
20+
import { connectorsForWallets } from "@rainbow-me/rainbowkit";
1221

1322
/* TODO: remove hardcoded value once we have environment variables validation */
1423
const projectId =
1524
process.env.REACT_APP_WALLETCONNECT_PROJECT_ID ??
1625
"2685061cae0bcaf2b244446153eda9e1";
26+
const connectors = connectorsForWallets(
27+
[
28+
{
29+
groupName: "Popular",
30+
wallets: [safeWallet, rainbowWallet, walletConnectWallet, coinbaseWallet],
31+
},
32+
],
33+
{
34+
appName: "Gitcoin Manager",
35+
projectId,
36+
}
37+
);
38+
export const allChains: Chain[] =
39+
process.env.REACT_APP_ENV === "development" ? allNetworks : mainnetNetworks;
40+
41+
import { createConfig } from "wagmi";
42+
43+
const transports = allChains.reduce(
44+
(acc, chain) => {
45+
acc[chain.id] = http();
46+
return acc;
47+
},
48+
{} as Record<number, ReturnType<typeof http>>
49+
);
1750

18-
export const config = getDefaultConfig({
19-
appName: "Gitcoin Manager",
20-
projectId,
21-
chains: [...allChains] as [Chain, ...Chain[]],
22-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
23-
}) as any;
51+
export const config = createConfig({
52+
chains: [...allChains] as unknown as readonly [Chain, ...Chain[]],
53+
connectors,
54+
transports,
55+
});
2456

2557
const queryClient = new QueryClient();
2658

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { useEffect } from "react";
2+
3+
import { useConnect, useAccount } from "wagmi";
4+
5+
const AUTOCONNECTED_CONNECTOR_IDS = ["safe"];
6+
7+
function useAutoConnect() {
8+
const { connect, connectors } = useConnect();
9+
const { address } = useAccount();
10+
11+
useEffect(() => {
12+
AUTOCONNECTED_CONNECTOR_IDS.forEach((connector) => {
13+
const connectorInstance = connectors.find((c) => c.id === connector);
14+
const isIframe = window.top !== window.self;
15+
if (connectorInstance && isIframe) {
16+
connect({ connector: connectorInstance });
17+
}
18+
});
19+
}, [connect, connectors, address]);
20+
}
21+
22+
export const SafeAutoConnect = ({
23+
children,
24+
}: {
25+
children: JSX.Element | JSX.Element[];
26+
}) => {
27+
useAutoConnect();
28+
return <>{children}</>;
29+
};

packages/round-manager/src/features/round/ViewApplicationPage.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ export default function ViewApplicationPage() {
170170
};
171171

172172
if (roundChainId) fetchApplications();
173-
}, [roundChainId, roundId]);
173+
}, [roundChainId, roundId, id, dataLayer]);
174174

175175
useEffect(() => {
176176
if (contractUpdatingStatus === ProgressStatus.IS_ERROR) {
@@ -334,7 +334,10 @@ export default function ViewApplicationPage() {
334334

335335
if (application?.answers && application.answers.length > 0) {
336336
for (let _answerBlock of application.answers) {
337-
if (_answerBlock.encryptedAnswer && !isLitUnavailable(round.chainId!)) {
337+
if (
338+
_answerBlock.encryptedAnswer &&
339+
!isLitUnavailable(round.chainId!)
340+
) {
338341
try {
339342
const encryptedAnswer = _answerBlock.encryptedAnswer;
340343
const base64EncryptedString = [
@@ -349,7 +352,7 @@ export default function ViewApplicationPage() {
349352
chainId: Number(roundChainId!),
350353
contract: roundId.startsWith("0x")
351354
? roundId
352-
: round?.payoutStrategy.id ?? "",
355+
: (round?.payoutStrategy.id ?? ""),
353356
});
354357

355358
const decryptedString = await lit.decryptString(
@@ -816,7 +819,7 @@ export default function ViewApplicationPage() {
816819
answerBlocks?.map((block: AnswerBlock) => {
817820
const answerText = Array.isArray(block.answer)
818821
? block.answer.join(", ")
819-
: block.answer ?? "";
822+
: (block.answer ?? "");
820823

821824
return (
822825
<div key={block.questionId} className="pb-5">

packages/round-manager/src/index.tsx

Lines changed: 59 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { UpdateRoundProvider } from "./context/round/UpdateRoundContext";
3535
import { UpdateRolesProvider } from "./context/round/UpdateRolesContext";
3636
import { UpdateRolesProvider as UpdateRolesProviderProgram } from "./context/program/UpdateRolesContext";
3737
import AlloWrapper from "./features/api/AlloWrapper";
38+
import { SafeAutoConnect } from "./features/api/SafeAutoConnect";
3839
import { DataLayer, DataLayerProvider } from "data-layer";
3940
import { getConfig } from "common/src/config";
4041
import { initPosthog } from "./posthog";
@@ -126,59 +127,64 @@ root.render(
126127
},
127128
}}
128129
>
129-
<AlloWrapper>
130-
<DataLayerProvider client={dataLayerConfig}>
131-
<HashRouter>
132-
<Routes>
133-
{/* Protected Routes */}
134-
<Route element={<Auth />}>
135-
{/* Default Route */}
136-
<Route path="/" element={landing} />
137-
138-
{/* Round Routes */}
139-
<Route
140-
path="/round/create"
141-
element={
142-
<ReadProgramProvider>
143-
<CreateRound />
144-
</ReadProgramProvider>
145-
}
146-
/>
147-
<Route path="/round/:id" element={viewRoundPage} />
148-
<Route
149-
path="/chain/:chainId/round/:id"
150-
element={viewRoundPage}
151-
/>
152-
<Route
153-
path="/chain/:chainId/round/:roundId/application/:id"
154-
element={viewApplication}
155-
/>
156-
<Route
157-
path="/round/:roundId/application/:id"
158-
element={viewApplication}
159-
/>
160-
161-
{/* Program Routes */}
162-
<Route
163-
path="/program/create"
164-
element={<CreateProgram />}
165-
/>
166-
<Route
167-
path="/chain/:chainId/program/:id"
168-
element={viewProgram}
169-
/>
170-
<Route path="/program/:id" element={viewProgram} />
171-
172-
{/* Access Denied */}
173-
<Route path="/access-denied" element={<AccessDenied />} />
174-
175-
{/* 404 */}
176-
<Route path="*" element={<NotFound />} />
177-
</Route>
178-
</Routes>
179-
</HashRouter>
180-
</DataLayerProvider>
181-
</AlloWrapper>
130+
<SafeAutoConnect>
131+
<AlloWrapper>
132+
<DataLayerProvider client={dataLayerConfig}>
133+
<HashRouter>
134+
<Routes>
135+
{/* Protected Routes */}
136+
<Route element={<Auth />}>
137+
{/* Default Route */}
138+
<Route path="/" element={landing} />
139+
140+
{/* Round Routes */}
141+
<Route
142+
path="/round/create"
143+
element={
144+
<ReadProgramProvider>
145+
<CreateRound />
146+
</ReadProgramProvider>
147+
}
148+
/>
149+
<Route path="/round/:id" element={viewRoundPage} />
150+
<Route
151+
path="/chain/:chainId/round/:id"
152+
element={viewRoundPage}
153+
/>
154+
<Route
155+
path="/chain/:chainId/round/:roundId/application/:id"
156+
element={viewApplication}
157+
/>
158+
<Route
159+
path="/round/:roundId/application/:id"
160+
element={viewApplication}
161+
/>
162+
163+
{/* Program Routes */}
164+
<Route
165+
path="/program/create"
166+
element={<CreateProgram />}
167+
/>
168+
<Route
169+
path="/chain/:chainId/program/:id"
170+
element={viewProgram}
171+
/>
172+
<Route path="/program/:id" element={viewProgram} />
173+
174+
{/* Access Denied */}
175+
<Route
176+
path="/access-denied"
177+
element={<AccessDenied />}
178+
/>
179+
180+
{/* 404 */}
181+
<Route path="*" element={<NotFound />} />
182+
</Route>
183+
</Routes>
184+
</HashRouter>
185+
</DataLayerProvider>
186+
</AlloWrapper>
187+
</SafeAutoConnect>
182188
</RainbowKitProvider>
183189
</QueryClientProvider>
184190
</WagmiProvider>

0 commit comments

Comments
 (0)