Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connect wallet feature (BLOCKED) #872

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions packages/admin-ui/src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ export interface ContainerLabelTypes {
"dappnode.dnp.serviceName": string;
"dappnode.dnp.instanceName": string;
"dappnode.dnp.dependencies": Dependencies;
"dappnode.dnp.wallet": Wallet;
"dappnode.dnp.avatar": string;
"dappnode.dnp.origin": string;
"dappnode.dnp.chain": ChainDriver;
Expand Down Expand Up @@ -457,6 +458,7 @@ export interface PackageContainer {
canBeFullnode?: boolean;
isMain?: boolean;
dockerTimeout?: number;
wallet?: Wallet;
// Note: environment is only accessible doing a container inspect or reading the compose
// envs?: PackageEnvs;
}
Expand All @@ -478,6 +480,7 @@ export type InstalledPackageData = Pick<
| "chain"
| "domainAlias"
| "canBeFullnode"
| "wallet"
> & {
containers: PackageContainer[];
};
Expand Down Expand Up @@ -576,6 +579,19 @@ export interface DirectoryDnp {
avatar?: string;
}

export interface Wallet {
chainId: string; // A 0x-prefixed hexadecimal string
chainName: string;
nativeCurrency: {
name: string;
symbol: string; // 2-6 characters long
decimals: 18;
};
rpcUrls: string[];
blockExplorerUrls?: string[];
iconUrls?: string[]; // Currently ignored.
}

export interface ChainData {
dnpName: string; // "geth.dnp.dappnode.eth"
name?: string; // Optional pretty name: "Geth"
Expand All @@ -584,6 +600,7 @@ export interface ChainData {
message: string; // "Blocks synced: 543000 / 654000"
help?: string; // External link to show as help if needed: "http://geth.help"
progress?: number; // 0.83027522935
wallet?: Wallet;
}

export interface ProgressLog {
Expand Down
82 changes: 79 additions & 3 deletions packages/admin-ui/src/pages/dashboard/components/ChainCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import ProgressBar from "react-bootstrap/ProgressBar";
import Card from "components/Card";
import RenderMarkdown from "components/RenderMarkdown";
import { prettyDnpName } from "utils/format";
import { ChainData } from "types";
import { ChainData, Wallet } from "types";
import { HelpTo } from "components/Help";
import { Link } from "react-router-dom";
import { rootPath as packagesRootPath } from "pages/packages";
import Button from "components/Button";
import { ethers } from "ethers";

export function ChainCards() {
const chainData = useChainData();
Expand All @@ -22,7 +24,16 @@ export function ChainCards() {
}

function ChainCard(chain: ChainData) {
const { dnpName, name, message, help, progress, error, syncing } = chain;
const {
dnpName,
name,
message,
help,
progress,
error,
syncing,
wallet
} = chain;
return (
<Card className="chain-card">
<div className="name">
Expand All @@ -41,7 +52,20 @@ function ChainCard(chain: ChainData) {
) : error ? (
<ProgressBar now={100} variant="warning" />
) : (
<ProgressBar now={100} variant="success" />
<>
<ProgressBar now={100} variant="success" />
{wallet ? <ConnectWallet wallet={wallet} /> : null}
{dnpName === "nethermind-xdai.dnp.dappnode.eth" && (
<ConnectWallet
wallet={{
chainId: "0x64",
chainName: "Gnosis chain",
nativeCurrency: { name: "Gosis", symbol: "GNO", decimals: 18 },
rpcUrls: ["https://rpc.gnosischain.com"]
}}
/>
)}
</>
)}

<div className="message">
Expand All @@ -53,3 +77,55 @@ function ChainCard(chain: ChainData) {
</Card>
);
}

declare global {
interface Window {
ethereum: any;
}
}

function ConnectWallet({ wallet }: { wallet: Wallet }) {
async function walletConnect() {
const provider = new ethers.providers.Web3Provider(window.ethereum);
console.log("provider: ", provider);
try {
console.log("trying..");

// https://eips.ethereum.org/EIPS/eip-3326
await provider.send("wallet_switchEthereumChain", [
{ chainId: wallet.chainId }
]);
console.log("failed");
} catch (switchError) {
console.error(switchError);
// This error code indicates that the chain has not been added to MetaMask.
if (switchError.code === 4902) {
try {
// https://eips.ethereum.org/EIPS/eip-3085
await provider.send(
"wallet_addEthereumChain",
// IMPORTANT! RPC without HTTPs is not allowed
// IMPORTANT! Add new chains with a default chain ID in metamask is not allowed family horn own sense negative orient tomorrow cheap recall mutual addict inmate
[
{
chainId: wallet.chainId,
rpcUrls: [wallet.rpcUrls]
}
]
);
} catch (addError) {
// handle "add" error
throw addError;
}
}
// handle other "switch" errors
throw switchError;
}
}

return (
<Button variant="dappnode" onClick={() => walletConnect()}>
Connect Wallet
</Button>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { PackageUpdates } from "./PackageUpdates";
// Components
import SubTitle from "components/SubTitle";
import Title from "components/Title";

import "./dashboard.scss";

export default function Dashboard() {
Expand Down
6 changes: 3 additions & 3 deletions packages/dappmanager/src/modules/chains/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ export async function getChainsData(): Promise<ChainData[]> {
// Ethereum 2.0 multiservice should be handled in the driver
if (dnp.containers.every(container => !container.running)) return;

const chainData = await runWithChainDriver(dnp, chainDriverName);
const chainDataResult = await runWithChainDriver(dnp, chainDriverName);
loggedErrors.delete(dnp.dnpName); // Reset last seen error

if (chainData)
if (chainDataResult)
chainsData.push({
dnpName: dnp.dnpName,
...chainData
...chainDataResult
});
} catch (e) {
// Only log chain errors the first time they are seen
Expand Down
2 changes: 1 addition & 1 deletion packages/dappmanager/src/modules/chains/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ export interface Chain {
driverName: ChainDriver; // ethereum
}

export type ChainDataResult = Omit<ChainData, "dnpName">;
export type ChainDataResult = Omit<ChainData, "dnpName" | "wallet">;
3 changes: 3 additions & 0 deletions packages/dappmanager/src/modules/compose/labelsDb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const labelParseFns: {
"dappnode.dnp.serviceName": parseString,
"dappnode.dnp.instanceName": parseString,
"dappnode.dnp.dependencies": value => parseJsonSafe(value) || {},
"dappnode.dnp.wallet": value => parseJsonSafe(value),
"dappnode.dnp.avatar": parseString,
"dappnode.dnp.origin": parseString,
"dappnode.dnp.chain": value => {
Expand Down Expand Up @@ -80,6 +81,8 @@ const labelStringifyFns: {
"dappnode.dnp.serviceName": writeString,
"dappnode.dnp.instanceName": writeString,
"dappnode.dnp.dependencies": writeJson,
"dappnode.dnp.wallet": value =>
writeJson(value as unknown as Record<string, unknown>),
"dappnode.dnp.avatar": writeString,
"dappnode.dnp.origin": writeString,
"dappnode.dnp.chain": value =>
Expand Down