successfully generates the wireguard config file
This commit is contained in:
parent
cf3d999a2e
commit
c4a50e8b3b
@ -1,8 +1,22 @@
|
||||
import { Box, Card, CardContent, Typography, Link, Button, Avatar, Stack } from "@mui/material";
|
||||
import GitHubIcon from "@mui/icons-material/GitHub";
|
||||
import GetAppIcon from "@mui/icons-material/GetApp";
|
||||
|
||||
const WIREGUARD_COLOR = "#88171A";
|
||||
|
||||
function WireGuardLogo({ size = 40 }: { size?: number }) {
|
||||
return (
|
||||
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
|
||||
<circle cx="12" cy="12" r="12" fill={WIREGUARD_COLOR} />
|
||||
<path d="M6 12c0-3.314 2.686-6 6-6s6 2.686 6 6-2.686 6-6 6S6 15.314 6 12z" fill="#fff" opacity="0.15" />
|
||||
<path d="M8.5 11.5c1-2 3-3 5-3s4 1 5 3" stroke="#fff" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default function About() {
|
||||
const repo = "https://github.com/cochrane2063/MSBD5017-Depin-WebClient";
|
||||
const wireguard = "https://www.wireguard.com/install/";
|
||||
|
||||
return (
|
||||
<Box sx={{ display: "flex", justifyContent: "center", p: 3 }}>
|
||||
@ -32,6 +46,59 @@ export default function About() {
|
||||
</Stack>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
sx={{
|
||||
width: 420,
|
||||
maxWidth: "100%",
|
||||
borderLeft: `6px solid ${WIREGUARD_COLOR}`,
|
||||
background: "linear-gradient(180deg, rgba(122,193,67,0.04), transparent 60%)",
|
||||
}}
|
||||
>
|
||||
<CardContent>
|
||||
<Stack direction="row" spacing={2} alignItems="center" sx={{ mb: 1 }}>
|
||||
<Avatar sx={{ bgcolor: "transparent" }}>
|
||||
<WireGuardLogo />
|
||||
</Avatar>
|
||||
<Typography variant="h5" sx={{ color: WIREGUARD_COLOR, fontWeight: 700 }}>
|
||||
Download Wireguard Client
|
||||
</Typography>
|
||||
</Stack>
|
||||
|
||||
<Typography variant="body1" color="text.secondary" paragraph>
|
||||
Wireguard client for the MSBD5017 Depin project.
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body2" color="text.secondary" paragraph>
|
||||
This project uses the Wireguard VPN protocol. You can download the Wireguard client from the official website.
|
||||
</Typography>
|
||||
|
||||
<Stack direction="row" spacing={2} alignItems="center">
|
||||
<Link href={wireguard} target="_blank" rel="noopener noreferrer" underline="none">
|
||||
<Button
|
||||
startIcon={<GetAppIcon />}
|
||||
variant="contained"
|
||||
sx={{
|
||||
bgcolor: WIREGUARD_COLOR,
|
||||
"&:hover": { bgcolor: "#65a836" },
|
||||
}}
|
||||
>
|
||||
Download WireGuard
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Button
|
||||
variant="outlined"
|
||||
href="https://www.wireguard.com/quickstart/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
sx={{ borderColor: WIREGUARD_COLOR, color: WIREGUARD_COLOR }}
|
||||
>
|
||||
Quickstart Guide
|
||||
</Button>
|
||||
</Stack>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
420
app/Components/Contracts/CLRToken/CLRToken.json
Normal file
420
app/Components/Contracts/CLRToken/CLRToken.json
Normal file
@ -0,0 +1,420 @@
|
||||
[
|
||||
{
|
||||
"inputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "allowance",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "needed",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "ERC20InsufficientAllowance",
|
||||
"type": "error"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "balance",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "needed",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "ERC20InsufficientBalance",
|
||||
"type": "error"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "approver",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "ERC20InvalidApprover",
|
||||
"type": "error"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "receiver",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "ERC20InvalidReceiver",
|
||||
"type": "error"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "ERC20InvalidSender",
|
||||
"type": "error"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "ERC20InvalidSpender",
|
||||
"type": "error"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "OwnableInvalidOwner",
|
||||
"type": "error"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "account",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "OwnableUnauthorizedAccount",
|
||||
"type": "error"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Approval",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "previousOwner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "OwnershipTransferred",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Transfer",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "allowance",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "approve",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "account",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "balanceOf",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "burn",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "decimals",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint8",
|
||||
"name": "",
|
||||
"type": "uint8"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "mint",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "name",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "owner",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "renounceOwnership",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "symbol",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "totalSupply",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "transfer",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "transferFrom",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "transferOwnership",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
@ -615,6 +615,25 @@
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "activeChannelIds",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
@ -740,6 +759,48 @@
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "getActivePaymentChannels",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address[]",
|
||||
"name": "",
|
||||
"type": "address[]"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_offset",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_limit",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "getActivePaymentChannelsPaginated",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address[]",
|
||||
"name": "channels",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "total",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
@ -1,28 +1,87 @@
|
||||
import { Web3 } from 'web3';
|
||||
import clearNetJson from './ClearNet.json';
|
||||
import type { Node, NodeInfo, PaymentChannelInfo } from '../Util';
|
||||
import clearNetJson from './ClearNet/ClearNet.json';
|
||||
import clrTokenJson from './CLRTOKEN/CLRToken.json';
|
||||
|
||||
const clearNetABI = (clearNetJson as any).abi ?? clearNetJson;
|
||||
const clearNetAddress = "0xf04cbb756045b276ea962ea98d938a0ed8101f51";
|
||||
const clrTokenABI = (clrTokenJson as any).abi ?? clrTokenJson;
|
||||
const clearNetAddress = "0xb6f537b38b82d08ff3ed796754d9d85b5cfe9cb5";
|
||||
const clrTokenAddress = "0xf1664c17887767c8f58695846babb349ca61d2e9";
|
||||
const DEFAULT_MIN_STAKE = BigInt(10000) * BigInt(1e18); // 10000 CLR
|
||||
|
||||
export const getActiveNodes = async (provider: any) => {
|
||||
|
||||
export const getActiveNodes = async (provider: any): Promise<Node[]> => {
|
||||
if (!provider) {
|
||||
return [];
|
||||
}
|
||||
const web3 = new Web3(provider);
|
||||
const contract = new web3.eth.Contract(clearNetABI, clearNetAddress);
|
||||
const activeNodes = await contract.methods.getActiveNodes().call();
|
||||
return activeNodes;
|
||||
const clearnet_contract = new web3.eth.Contract(clearNetABI, clearNetAddress);
|
||||
const activeNodes: string[] = await clearnet_contract.methods.getActiveNodes().call();
|
||||
const nodes: Node[] = await Promise.all(activeNodes.map(async (node: string) => {
|
||||
const nodeInfo: NodeInfo = await clearnet_contract.methods.getNodeInfo(node).call();
|
||||
return {
|
||||
ip: nodeInfo.ipAddress,
|
||||
port: Number(nodeInfo.port),
|
||||
traffic: 0,
|
||||
price: Number(nodeInfo.pricePerMinute) / 1e18,
|
||||
rating: Number(nodeInfo.reputationScore) / 1000,
|
||||
};
|
||||
}));
|
||||
console.log("Fetched nodes:", nodes);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export async function registerNode(provider: any,account: string) {
|
||||
export async function approveCLRTokenSpending(provider: any,account: string) {
|
||||
const web3 = new Web3(provider);
|
||||
const contract = new web3.eth.Contract(clearNetABI, clearNetAddress);
|
||||
const clr_token_contract = new web3.eth.Contract(clrTokenABI, clrTokenAddress);
|
||||
const gasPrice = await web3.eth.getGasPrice();
|
||||
const gasLimit = 300000;
|
||||
const tx = await contract.methods.registerNode("57.158.82.48", 51820, 1000000000000000000n).send({
|
||||
const tx = await clr_token_contract.methods.approve(clearNetAddress, DEFAULT_MIN_STAKE).send({
|
||||
from: account,
|
||||
gas: String(gasLimit),
|
||||
gasPrice: String(gasPrice),
|
||||
});
|
||||
console.log(tx);
|
||||
}
|
||||
|
||||
export async function openPaymentChannel(provider: any,account: string,amount: BigInt) {
|
||||
const web3 = new Web3(provider);
|
||||
const clearnet_contract = new web3.eth.Contract(clearNetABI, clearNetAddress);
|
||||
const gasPrice = await web3.eth.getGasPrice();
|
||||
const gasLimit = 300000;
|
||||
const tx = await clearnet_contract.methods.openPaymentChannel(amount).send({
|
||||
from: account,
|
||||
gas: String(gasLimit),
|
||||
gasPrice: String(gasPrice),
|
||||
});
|
||||
|
||||
console.log(tx);
|
||||
}
|
||||
|
||||
export async function closePaymentChannel(provider: any,account: string) {
|
||||
const web3 = new Web3(provider);
|
||||
const clearnet_contract = new web3.eth.Contract(clearNetABI, clearNetAddress);
|
||||
const gasPrice = await web3.eth.getGasPrice();
|
||||
const gasLimit = 300000;
|
||||
const tx = await clearnet_contract.methods.closePaymentChannel().send({
|
||||
from: account,
|
||||
gas: String(gasLimit),
|
||||
gasPrice: String(gasPrice),
|
||||
});
|
||||
console.log(tx);
|
||||
|
||||
}
|
||||
|
||||
export async function getPaymentChannelInfo(provider: any,account: string) : Promise<PaymentChannelInfo> {
|
||||
if (!provider) {
|
||||
return { balance: BigInt(0), nonce: BigInt(0), isActive: false};
|
||||
}
|
||||
const web3 = new Web3(provider);
|
||||
const clearnet_contract = new web3.eth.Contract(clearNetABI, clearNetAddress);
|
||||
const channelInfo: PaymentChannelInfo = await clearnet_contract.methods.getPaymentChannelInfo(account).call();
|
||||
return {
|
||||
balance: channelInfo.balance,
|
||||
nonce: channelInfo.nonce,
|
||||
isActive: channelInfo.isActive,
|
||||
};
|
||||
}
|
||||
@ -16,8 +16,6 @@ export const signMessage = async (message: string,provider: EIP1193Provider,user
|
||||
// For historical reasons, you must submit the message to sign in hex-encoded UTF-8.
|
||||
// This uses a Node.js-style buffer shim in the browser.
|
||||
|
||||
// const bytes = new TextEncoder().encode(String(publicKey));
|
||||
// const msg = '0x' + Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
const msg = `0x${Buffer.from(message, "utf8").toString("hex")}`
|
||||
const sig = await provider.request({
|
||||
method: "personal_sign",
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
// ...existing code...
|
||||
import React, { useState } from "react";
|
||||
import { useSyncProviders } from "./useSyncProviders";
|
||||
import useAuth from "~/hooks/useAuth";
|
||||
@ -123,4 +122,3 @@ export const DiscoverWalletProviders: React.FC = () => {
|
||||
};
|
||||
|
||||
export default DiscoverWalletProviders;
|
||||
// ...existing code...
|
||||
@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { NavLink } from "react-router";
|
||||
import AppBar from '@mui/material/AppBar';
|
||||
import Box from '@mui/material/Box';
|
||||
@ -7,13 +7,16 @@ import Button from "@mui/material/Button";
|
||||
import LoginIcon from "@mui/icons-material/Login";
|
||||
import { Typography, Menu, MenuItem, IconButton, Avatar, Tooltip } from "@mui/material";
|
||||
import useAuth from "~/hooks/useAuth";
|
||||
import { signMessage } from './Metamask/Connections';
|
||||
import type { PaymentChannelInfo } from './Util';
|
||||
import { approveCLRTokenSpending, openPaymentChannel, closePaymentChannel, getPaymentChannelInfo } from './Contracts/Connections';
|
||||
|
||||
export default function ButtonAppBar() {
|
||||
const { auth, setAuth } = useAuth();
|
||||
const account = auth?.accounts?.[0];
|
||||
const isAuthed = Boolean(account);
|
||||
|
||||
const [paymentChannelInfo, setPaymentChannelInfo] = React.useState<PaymentChannelInfo | null>(null);
|
||||
const [registered, setRegistered] = React.useState<boolean>(false);
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const open = Boolean(anchorEl);
|
||||
const handleOpen = (e: React.MouseEvent<HTMLElement>) => setAnchorEl(e.currentTarget);
|
||||
@ -27,14 +30,28 @@ export default function ButtonAppBar() {
|
||||
};
|
||||
|
||||
const register = async () => {
|
||||
const sig = await signMessage("H8zfXnSclIQ/wLy7GSt7GNqa1utAi4Uvr7Dg3p9vdHQ=",auth.providerWithInfo.provider, auth.accounts[0]);
|
||||
try {
|
||||
const res_string = sig;
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
const clr_deposit_amount = BigInt(10000) * BigInt(1e18); // 10000 CLR
|
||||
await approveCLRTokenSpending(auth.providerWithInfo.provider, account!);
|
||||
await openPaymentChannel(auth.providerWithInfo.provider, account!, clr_deposit_amount);
|
||||
setRegistered(true);
|
||||
}
|
||||
|
||||
const deRegister = async () => {
|
||||
await closePaymentChannel(auth.providerWithInfo.provider, account!);
|
||||
setRegistered(false);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getPaymentChannelInfo(auth.providerWithInfo ? auth.providerWithInfo.provider : undefined, account!).then((info) => {
|
||||
setPaymentChannelInfo(info);
|
||||
if(registered !== info.isActive) {
|
||||
setRegistered(info.isActive);
|
||||
}
|
||||
console.log("Payment Channel Info:", info);
|
||||
});
|
||||
}, [account, auth.providerWithInfo?.provider,registered]);
|
||||
|
||||
|
||||
return (
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<AppBar position="static">
|
||||
@ -79,7 +96,6 @@ export default function ButtonAppBar() {
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{}
|
||||
{isAuthed && (
|
||||
<>
|
||||
<Tooltip title={account ? `Account: ${account}` : "Account"}>
|
||||
@ -105,7 +121,7 @@ export default function ButtonAppBar() {
|
||||
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
|
||||
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
|
||||
>
|
||||
<MenuItem onClick={register}>Register</MenuItem>
|
||||
{(paymentChannelInfo && paymentChannelInfo.isActive) ? (<MenuItem onClick={deRegister}>DeRegister</MenuItem>) : (<MenuItem onClick={register}>Register</MenuItem>)}
|
||||
<MenuItem onClick={handleLogout}>Logout</MenuItem>
|
||||
</Menu>
|
||||
</>
|
||||
|
||||
@ -2,27 +2,41 @@ import * as React from 'react';
|
||||
import ButtonGroup from '@mui/material/ButtonGroup';
|
||||
import Button from '@mui/material/Button';
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import { Grid, Card, CardContent, CardActions, Typography, Box, Chip, Dialog, DialogTitle, DialogContent, DialogActions, TextField } from "@mui/material";
|
||||
import {
|
||||
Grid,
|
||||
Card,
|
||||
CardContent,
|
||||
CardActions,
|
||||
Typography,
|
||||
Box,
|
||||
Chip,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
CircularProgress,
|
||||
} from "@mui/material";
|
||||
import ServerIcon from '@mui/icons-material/Dns';
|
||||
import SignalCellularAltIcon from '@mui/icons-material/SignalCellularAlt';
|
||||
import AttachMoneyIcon from '@mui/icons-material/AttachMoney';
|
||||
import StarIcon from '@mui/icons-material/Star';
|
||||
import Rating from '@mui/material/Rating';
|
||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||
import useAuth from '~/hooks/useAuth';
|
||||
import type { AccountInfo } from '~/context/AuthProvider';
|
||||
import { signMessage } from './Metamask/Connections';
|
||||
import { downloadWireguardConfig } from './WireguardConfig';
|
||||
import { generateWireguardKeyPair, downloadWireguardConfig } from './WireguardConfig';
|
||||
import type { Node } from './Util';
|
||||
import { getActiveNodes } from './Contracts/Connections';
|
||||
import axios from 'axios';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
interface Node {
|
||||
ip: string;
|
||||
traffic: number;
|
||||
price : number;
|
||||
rating : number;
|
||||
}
|
||||
|
||||
function NodeItem({node}: {node: Node}) {
|
||||
|
||||
function NodeItem({node, auth}: {node: Node, auth: AccountInfo}) {
|
||||
const port = 8080;
|
||||
const { auth } = useAuth();
|
||||
const [ratingOpen, setRatingOpen] = React.useState(false);
|
||||
const [ratingValue, setRatingValue] = React.useState<number | null>(null);
|
||||
const [submittingRating, setSubmittingRating] = React.useState(false);
|
||||
@ -31,13 +45,16 @@ function NodeItem({node}: {node: Node}) {
|
||||
// const publicKey = await getPublicKey(auth.providerWithInfo.provider, auth.accounts[0]);
|
||||
try {
|
||||
const iv = await axios.get(getUrl() + "/connect");
|
||||
console.log(iv.data);
|
||||
const { privatekey: clientPrivateKey, publicKey: clientPublicKey } = generateWireguardKeyPair();
|
||||
|
||||
const sig = await signMessage(iv.data + "H8zfXnSclIQ/wLy7GSt7GNqa1utAi4Uvr7Dg3p9vdHQ=",auth.providerWithInfo.provider, auth.accounts[0]);
|
||||
const res_string = iv.data + '\n' + "H8zfXnSclIQ/wLy7GSt7GNqa1utAi4Uvr7Dg3p9vdHQ=" + '\n' + sig;
|
||||
const sig = await signMessage(iv.data + clientPublicKey,auth.providerWithInfo.provider, auth.accounts[0]);
|
||||
const res_string = iv.data + '\n' + clientPublicKey + '\n' + sig;
|
||||
let response = await axios.post(getUrl() + "/connect", res_string);
|
||||
const clientCIDR = response.data.WireguardClientCIDR;
|
||||
const serverPublicKey = response.data.WireguardServerPublicKey;
|
||||
const dns = response.data.WireguardDNS;
|
||||
console.log(response.data);
|
||||
downloadWireguardConfig("", "", "", "", node.ip, "51820", "0.0.0.0/0");
|
||||
downloadWireguardConfig(clientPrivateKey, serverPublicKey, clientCIDR, dns, node.ip, String(node.port), "0.0.0.0/0");
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
@ -180,33 +197,69 @@ function NodeItem({node}: {node: Node}) {
|
||||
}
|
||||
|
||||
export default function FolderList() {
|
||||
const [nodes, setNodes] = React.useState<Node[]>([
|
||||
{ ip: "57.158.82.48", traffic: 5, price: 10, rating: 3 },
|
||||
{ ip: "8.210.33.199", traffic: 3, price: 15, rating: 4 },
|
||||
{ ip: "45.77.12.5", traffic: 7, price: 20, rating: 5 },
|
||||
{ ip: "203.120.45.78", traffic: 2, price: 8, rating: 2 },
|
||||
{ ip: "91.189.88.25", traffic: 6, price: 12, rating: 4 },
|
||||
{ ip: "132.148.9.201", traffic: 9, price: 18, rating: 5 },
|
||||
{ ip: "60.12.180.99", traffic: 4, price: 14, rating: 3 },
|
||||
{ ip: "199.59.243.100", traffic: 1, price: 6, rating: 1 },
|
||||
{ ip: "34.216.77.3", traffic: 8, price: 22, rating: 5 },
|
||||
{ ip: "185.199.108.153", traffic: 5, price: 11, rating: 4 },
|
||||
{ ip: "13.107.21.200", traffic: 7, price: 16, rating: 4 },
|
||||
{ ip: "216.58.214.14", traffic: 3, price: 9, rating: 2 },
|
||||
{ ip: "104.21.44.33", traffic: 10, price: 25, rating: 5 },
|
||||
{ ip: "47.90.12.201", traffic: 2, price: 7, rating: 1 },
|
||||
{ ip: "23.45.67.89", traffic: 6, price: 13, rating: 3 },
|
||||
{ ip: "192.0.2.123", traffic: 4, price: 17, rating: 4 },
|
||||
]);
|
||||
const { auth } = useAuth();
|
||||
const [nodes, setNodes] = React.useState<Node[]>([]);
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
const fetchNodes = React.useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const provider = auth?.providerWithInfo?.provider;
|
||||
const fetchedNodes = await getActiveNodes(provider);
|
||||
setNodes(fetchedNodes);
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch nodes", err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [auth]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchNodes();
|
||||
}, [fetchNodes]);
|
||||
// const [nodes, setNodes] = React.useState<Node[]>([
|
||||
// { ip: "57.158.82.48", traffic: 5, price: 10, rating: 3 },
|
||||
// { ip: "8.210.33.199", traffic: 3, price: 15, rating: 4 },
|
||||
// { ip: "45.77.12.5", traffic: 7, price: 20, rating: 5 },
|
||||
// { ip: "203.120.45.78", traffic: 2, price: 8, rating: 2 },
|
||||
// { ip: "91.189.88.25", traffic: 6, price: 12, rating: 4 },
|
||||
// { ip: "132.148.9.201", traffic: 9, price: 18, rating: 5 },
|
||||
// { ip: "60.12.180.99", traffic: 4, price: 14, rating: 3 },
|
||||
// { ip: "199.59.243.100", traffic: 1, price: 6, rating: 1 },
|
||||
// { ip: "34.216.77.3", traffic: 8, price: 22, rating: 5 },
|
||||
// { ip: "185.199.108.153", traffic: 5, price: 11, rating: 4 },
|
||||
// { ip: "13.107.21.200", traffic: 7, price: 16, rating: 4 },
|
||||
// { ip: "216.58.214.14", traffic: 3, price: 9, rating: 2 },
|
||||
// { ip: "104.21.44.33", traffic: 10, price: 25, rating: 5 },
|
||||
// { ip: "47.90.12.201", traffic: 2, price: 7, rating: 1 },
|
||||
// { ip: "23.45.67.89", traffic: 6, price: 13, rating: 3 },
|
||||
// { ip: "192.0.2.123", traffic: 4, price: 17, rating: 4 },
|
||||
// ]);
|
||||
|
||||
return (
|
||||
<Box sx={{ flexGrow: 1, p: 3 }}>
|
||||
<Typography variant="h4" gutterBottom component="div" sx={{ mb: 4, fontWeight: 'bold' }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 3 }}>
|
||||
<Typography variant="h4" component="div" sx={{ fontWeight: 'bold' }}>
|
||||
Available Servers
|
||||
</Typography>
|
||||
|
||||
<Box>
|
||||
<Tooltip title="Refresh servers">
|
||||
<span>
|
||||
<IconButton
|
||||
onClick={fetchNodes}
|
||||
disabled={loading || auth?.providerWithInfo === undefined}
|
||||
color="primary"
|
||||
aria-label="refresh servers"
|
||||
>
|
||||
{loading ? <CircularProgress size={20} /> : <RefreshIcon />}
|
||||
</IconButton>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</Box>
|
||||
<Grid container spacing={3}>
|
||||
{nodes.map((node, index) => (
|
||||
<NodeItem key={index} node={node} />
|
||||
<NodeItem key={index} node={node} auth={auth}/>
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
|
||||
23
app/Components/Util.tsx
Normal file
23
app/Components/Util.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
export interface Node {
|
||||
ip: string;
|
||||
port: number;
|
||||
traffic: number;
|
||||
price : number;
|
||||
rating : number;
|
||||
}
|
||||
|
||||
export interface NodeInfo {
|
||||
ipAddress: string;
|
||||
port: number;
|
||||
pricePerMinute : BigInt;
|
||||
reputationScore : BigInt;
|
||||
totalMinutesServed : BigInt;
|
||||
totalEarnings : BigInt;
|
||||
}
|
||||
|
||||
export interface PaymentChannelInfo {
|
||||
balance: BigInt;
|
||||
nonce: BigInt;
|
||||
isActive: boolean;
|
||||
}
|
||||
@ -1,13 +1,57 @@
|
||||
// import { utils } from 'noble-ed25519';
|
||||
import nacl from "tweetnacl";
|
||||
|
||||
function bytesToBase64(bytes: Uint8Array) {
|
||||
let binary = '';
|
||||
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
||||
return btoa(binary);
|
||||
}
|
||||
|
||||
function base64ToBytes(base64: string): Uint8Array {
|
||||
// support URL-safe base64
|
||||
base64 = base64.replace(/-/g, "+").replace(/_/g, "/");
|
||||
// pad to multiple of 4
|
||||
const pad = base64.length % 4;
|
||||
if (pad) base64 += "=".repeat(4 - pad);
|
||||
|
||||
const binary = atob(base64);
|
||||
const len = binary.length;
|
||||
const bytes = new Uint8Array(len);
|
||||
for (let i = 0; i < len; i++) {
|
||||
bytes[i] = binary.charCodeAt(i);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
const generateWireGuardPrivateKey = () => {
|
||||
// const privateKeyBytes = utils.randomPrivateKey();
|
||||
// const privateKeyBase64 = bytesToBase64(privateKeyBytes);
|
||||
const privateKey = nacl.randomBytes(32);
|
||||
|
||||
return bytesToBase64(privateKey);
|
||||
}
|
||||
|
||||
const getWireguardPublicKey = (privateKey: string) => {
|
||||
const privateKeyBytes = base64ToBytes(privateKey);
|
||||
const publicKey = nacl.scalarMult.base(privateKeyBytes);
|
||||
return bytesToBase64(publicKey);
|
||||
}
|
||||
|
||||
export const generateWireguardKeyPair = () => {
|
||||
const privatekey = generateWireGuardPrivateKey();
|
||||
const publicKey = getWireguardPublicKey(privatekey);
|
||||
return { privatekey, publicKey };
|
||||
}
|
||||
|
||||
export const downloadWireguardConfig = async (clientPrivateKey: string, serverPubcliKey: string ,localCIDR: string, dns: string, peerIp: string, peerPort: string, allowedIPs: string) => {
|
||||
|
||||
export const downloadWireguardConfig = (privateKey: string, publicKey: string, localCIDR: string, dns: string, peerIp: string, peerPort: string, allowedIPs: string) => {
|
||||
const content = `[Interface]`+'\n'+
|
||||
`PrivateKey = ${privateKey}`+'\n'+
|
||||
`PrivateKey = ${clientPrivateKey}`+'\n'+
|
||||
`Address = ${localCIDR}`+'\n'+
|
||||
`DNS = ${dns}`+'\n'+
|
||||
'\n'+
|
||||
`[Peer]`+'\n'+
|
||||
`PublicKey = ${publicKey}`+'\n'+
|
||||
`PublicKey = ${serverPubcliKey}`+'\n'+
|
||||
`AllowedIPs = ${allowedIPs}`+'\n'+
|
||||
`Endpoint = ${peerIp}:${peerPort}`;
|
||||
|
||||
|
||||
15
package-lock.json
generated
15
package-lock.json
generated
@ -14,9 +14,11 @@
|
||||
"axios": "^1.13.2",
|
||||
"buffer": "^6.0.3",
|
||||
"isbot": "^5.1.31",
|
||||
"noble-ed25519": "^1.2.6",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-router": "^7.9.2",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"web3": "^4.16.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -4513,6 +4515,13 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/noble-ed25519": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/noble-ed25519/-/noble-ed25519-1.2.6.tgz",
|
||||
"integrity": "sha512-zfnWqg9FVMp8CnzUpAjbt1nDXpDjCvxYiCXdnW1mY8zQHw/6twUlkFm14VPdojVzc0kcd+i9zT79+26GcNbsuQ==",
|
||||
"deprecated": "Switch to namespaced @noble/ed25519 for security and feature updates",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
@ -5676,6 +5685,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tweetnacl": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
|
||||
"license": "Unlicense"
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
|
||||
@ -18,9 +18,11 @@
|
||||
"axios": "^1.13.2",
|
||||
"buffer": "^6.0.3",
|
||||
"isbot": "^5.1.31",
|
||||
"noble-ed25519": "^1.2.6",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-router": "^7.9.2",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"web3": "^4.16.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user