Skip to content

Commit ca58fb0

Browse files
authored
Add perps watcher (#11)
1 parent e3af155 commit ca58fb0

12 files changed

+120
-71
lines changed

.erb/configs/webpack.config.main.prod.ts

+9
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@ const configuration: webpack.Configuration = {
6262
__dirname: false,
6363
__filename: false,
6464
},
65+
module: {
66+
rules: [
67+
// Images
68+
{
69+
test: /\.(svg)$/i,
70+
type: 'asset/resource',
71+
},
72+
],
73+
},
6574
};
6675

6776
export default merge(baseConfig, configuration);

.erb/configs/webpack.config.renderer.dev.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ const configuration: webpack.Configuration = {
137137

138138
new HtmlWebpackPlugin({
139139
filename: path.join('index.html'),
140-
template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
140+
template: path.join(webpackPaths.srcRendererPath, 'index.html'),
141141
minify: {
142142
collapseWhitespace: true,
143143
removeAttributeQuotes: true,

.erb/configs/webpack.config.renderer.prod.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ const configuration: webpack.Configuration = {
107107

108108
new HtmlWebpackPlugin({
109109
filename: 'index.html',
110-
template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
110+
template: path.join(webpackPaths.srcRendererPath, 'index.html'),
111111
minify: {
112112
collapseWhitespace: true,
113113
removeAttributeQuotes: true,

src/dapps.ts

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
export type DappType = {
2+
id: string;
3+
label: string;
4+
icon: () => Promise<{ default: string }>;
5+
ens?: string;
6+
ipns?: string;
7+
url?: string;
8+
};
9+
10+
export const DAPPS: DappType[] = [
11+
{
12+
id: 'kwenta',
13+
label: 'Kwenta',
14+
icon: () => import('./kwenta.svg'),
15+
ens: 'kwenta.eth',
16+
ipns: undefined,
17+
url: undefined,
18+
},
19+
{
20+
id: 'staking',
21+
label: 'Staking V2',
22+
icon: () => import('./synthetix.svg'),
23+
ens: 'staking.synthetix.eth',
24+
ipns: 'k2k4r8jvf8qlg4ytq7y3ta749vkjzms0hisd9i92ohk0lsp0yestbhy3',
25+
url: undefined,
26+
},
27+
{
28+
id: 'watcher',
29+
label: 'Perps V2 Watcher',
30+
icon: () => import('./synthetix.svg'),
31+
ens: undefined,
32+
ipns: 'k2k4r8pf9z20v99lm731p2d8vp0lg6w3sics8iot60mvjyret5tzfefl',
33+
url: undefined,
34+
},
35+
];

src/renderer/DApps/kwenta.svg src/kwenta.svg

+9-9
Loading

src/main/dapps.ts

+21-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { mainnet } from 'viem/chains';
55
import { namehash, normalize } from 'viem/ens';
66
// @ts-ignore
77
import * as contentHash from '@ensdomains/content-hash';
8+
import { DappType } from '../dapps';
89
import { ipfs } from './ipfs';
910
import { getPid } from './pid';
1011

@@ -28,9 +29,18 @@ const resolverAbi = [
2829
];
2930

3031
export async function resolveEns(
31-
ens: string
32+
dapp: DappType
3233
): Promise<{ codec: string; hash: string }> {
33-
const name = normalize(ens);
34+
if (dapp.ipns) {
35+
return {
36+
codec: 'ipns-ns',
37+
hash: dapp.ipns,
38+
};
39+
}
40+
if (!dapp.ens) {
41+
throw new Error('Neither ipns nor ens was set, cannot resolve');
42+
}
43+
const name = normalize(dapp.ens);
3444
const resolverAddress = await client.getEnsResolver({ name });
3545
const hash = await client.readContract({
3646
address: resolverAddress,
@@ -64,31 +74,34 @@ export async function isPinned(qm: string): Promise<boolean> {
6474
}
6575
}
6676

67-
export async function getDappHost(ens: string): Promise<string | undefined> {
77+
export async function getDappHost(dapp: DappType): Promise<string | undefined> {
6878
try {
69-
const { codec, hash } = await resolveEns(ens);
70-
logger.log(ens, 'resolved', codec, hash);
79+
const { codec, hash } = await resolveEns(dapp);
80+
logger.log(dapp.id, 'resolved', codec, hash);
7181
const qm =
7282
codec === 'ipns-ns'
7383
? await resolveQm(hash)
7484
: codec === 'ipfs-ns'
7585
? hash
7686
: undefined;
87+
if (qm !== hash) {
88+
logger.log(dapp.id, 'resolved CID', qm);
89+
}
7790
if (!qm) {
7891
throw new Error(`Codec "${codec}" not supported`);
7992
}
8093
if (await getPid(`pin add --progress ${qm}`)) {
81-
logger.log(ens, 'pinning already in progres...');
94+
logger.log(dapp.id, 'pinning already in progres...');
8295
return undefined;
8396
}
8497
const isDappPinned = await isPinned(qm);
8598
if (!isDappPinned) {
86-
logger.log(ens, 'pinning...', qm);
99+
logger.log(dapp.id, 'pinning...', qm);
87100
await ipfs(`pin add --progress ${qm}`);
88101
}
89102
const bafy = await convertCid(qm);
90103
const url = `${bafy}.ipfs.localhost`;
91-
logger.log(ens, 'local IPFS host:', url);
104+
logger.log(dapp.id, 'local IPFS host:', url);
92105
return url;
93106
} catch (e) {
94107
logger.error(e);

src/main/main.ts

+19-25
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ import * as settings from './settings';
3535
import http from 'http';
3636
import { proxy } from './proxy';
3737

38+
import { DAPPS } from '../dapps';
39+
3840
logger.transports.file.level = 'info';
3941

4042
const isDebug =
@@ -51,15 +53,6 @@ const isDebug =
5153
let tray: Tray | null = null;
5254
let mainWindow: BrowserWindow | null = null;
5355

54-
const dapps: { [key: string]: string | undefined } = {
55-
'kwenta.eth': undefined,
56-
'staking.synthetix.eth': undefined,
57-
};
58-
const localDapps: { [key: string]: string | undefined } = {
59-
'kwenta.eth': 'kwenta',
60-
'staking.synthetix.eth': 'staking',
61-
};
62-
6356
if (process.env.NODE_ENV === 'production') {
6457
const sourceMapSupport = require('source-map-support');
6558
sourceMapSupport.install();
@@ -210,11 +203,11 @@ function generateMenuItems() {
210203
separator: {
211204
type: 'separator',
212205
},
213-
dapps: Object.entries(localDapps).map(([name, shortcut]) => {
206+
dapps: DAPPS.map((dapp) => {
214207
return {
215-
enabled: Boolean(dapps[name]),
216-
label: name,
217-
click: () => shell.openExternal(`http://${shortcut}.localhost:8888`),
208+
enabled: Boolean(dapp.url),
209+
label: dapp.label,
210+
click: () => shell.openExternal(`http://${dapp.id}.localhost:8888`),
218211
};
219212
}),
220213
quit: {
@@ -312,31 +305,32 @@ followerDaemon();
312305
const followerCheck = setInterval(followerDaemon, 10_000);
313306
app.on('will-quit', () => clearInterval(followerCheck));
314307

315-
ipcMain.handle('dapp', async (_event, ens: string) =>
316-
dapps[ens] ? `http://${localDapps[ens]}.localhost:8888` : null
317-
);
308+
ipcMain.handle('dapp', async (_event, id: string) => {
309+
const dapp = DAPPS.find((dapp) => dapp.id === id);
310+
return dapp && dapp.url ? `http://${dapp.id}.localhost:8888` : null;
311+
});
312+
318313
async function updateAllDapps() {
319-
Object.keys(dapps).forEach((ens) =>
320-
getDappHost(ens).then((url) => {
314+
DAPPS.forEach((dapp) =>
315+
getDappHost(dapp).then((url) => {
321316
if (url) {
322-
dapps[ens] = url;
317+
dapp.url = url;
323318
updateContextMenu();
324319
}
325320
})
326321
);
327322
}
323+
328324
const dappsUpdater = setInterval(updateAllDapps, 600_000); // 10 minutes
329325
app.on('will-quit', () => clearInterval(dappsUpdater));
330326
waitForIpfs().then(updateAllDapps).catch(logger.error);
331327

332328
http
333329
.createServer((req, res) => {
334-
const shortcut = `${req.headers.host}`.replace('.localhost:8888', '');
335-
const host = Object.keys(localDapps).find(
336-
(key) => localDapps[key] === shortcut
337-
);
338-
if (host && host in dapps && dapps[host]) {
339-
req.headers.host = dapps[host];
330+
const id = `${req.headers.host}`.replace('.localhost:8888', '');
331+
const dapp = DAPPS.find((dapp) => dapp.id === id);
332+
if (dapp && dapp.url) {
333+
req.headers.host = dapp.url;
340334
proxy({ host: '127.0.0.1', port: 8080 }, req, res);
341335
return;
342336
}

src/renderer/DApps/Dapps.tsx

+19-21
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,35 @@ import {
88
Stack,
99
} from '@chakra-ui/react';
1010
import { ExternalLinkIcon } from '@chakra-ui/icons';
11-
import kwentaIcon from './kwenta.svg';
12-
import stakingIcon from './staking.svg';
1311
import { useDapp } from './useDapp';
12+
import { DAPPS, DappType } from '../../dapps';
13+
import { useQuery } from '@tanstack/react-query';
1414

15-
function DappButton({
16-
ens,
17-
label,
18-
icon,
19-
}: {
20-
ens: string;
21-
label: string;
22-
icon: string;
23-
}) {
24-
const { data: url } = useDapp(ens);
15+
function DappButton({ dapp }: { dapp: DappType }) {
16+
const { data: url } = useDapp(dapp.id);
17+
const { data: src } = useQuery({
18+
queryKey: ['icon', dapp.id],
19+
queryFn: async () => {
20+
const { default: icon } = await dapp.icon();
21+
return icon;
22+
},
23+
initialData: () => '',
24+
placeholderData: '',
25+
});
2526
return (
2627
<Button
2728
as={Link}
2829
href={url}
2930
target="_blank"
30-
aria-label={label}
31+
aria-label={dapp.label}
3132
variant="outline"
3233
colorScheme="teal"
33-
leftIcon={<Image src={icon} alt={label} width="1em" />}
34+
leftIcon={<Image src={src} alt={dapp.label} width="1em" />}
3435
rightIcon={url ? <ExternalLinkIcon /> : <Spinner size="xs" />}
3536
isDisabled={!url}
3637
_hover={{ textDecoration: 'none' }}
3738
>
38-
{label}
39+
{dapp.label}
3940
</Button>
4041
);
4142
}
@@ -48,12 +49,9 @@ export function Dapps() {
4849
Available DApps:
4950
</Heading>
5051
<Stack direction="row" spacing={6} justifyContent="start" mb="2">
51-
<DappButton ens="kwenta.eth" label="Kwenta" icon={kwentaIcon} />
52-
<DappButton
53-
ens="staking.synthetix.eth"
54-
label="Staking V2"
55-
icon={stakingIcon}
56-
/>
52+
{DAPPS.map((dapp) => (
53+
<DappButton key={dapp.id} dapp={dapp} />
54+
))}
5755
</Stack>
5856
</Box>
5957
</Box>

src/renderer/DApps/staking.svg

-3
This file was deleted.

src/renderer/DApps/useDapp.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ import { useQuery } from '@tanstack/react-query';
22

33
const { ipcRenderer } = window?.electron || {};
44

5-
export function useDapp(ens: string) {
5+
export function useDapp(id: string) {
66
return useQuery({
7-
queryKey: ['dapp', ens],
7+
queryKey: ['dapp', id],
88
queryFn: async () => {
9-
const url = await ipcRenderer.invoke('dapp', ens);
9+
const url = await ipcRenderer.invoke('dapp', id);
1010
if (!url) {
1111
return null;
1212
}
File renamed without changes.

src/synthetix.svg

+3
Loading

0 commit comments

Comments
 (0)