Skip to content
Open
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
2 changes: 1 addition & 1 deletion .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ WATCHTOWER_ENABLED=false
APP_ID=xxx
WATCHTOWER_URL=https://api.watchtower.starknet.id/service/add_message
WATCHTOWER_TOKEN=xxx
LOG_EVERY_X_BLOCK=1
LOG_EVERY_X_BLOCK=1
4 changes: 3 additions & 1 deletion components/verification/DiscordServerInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type DiscordServerInfoProps = {
discordServerName: string;
discordServerIcon?: string | null;
network: string;
networkType: "ethereum" | "starknet";
networkType: "ethereum" | "starknet" | "stellar";
};

const DiscordServerInfo = ({
Expand All @@ -18,11 +18,13 @@ const DiscordServerInfo = ({
const networkIcons = {
ethereum: "/assets/ethereum-icon.png",
starknet: "/assets/starknet-icon.png",
stellar: "/assets/stellar-icon.png",
};

const networkLabels = {
ethereum: "Ethereum network:",
starknet: "Starknet network:",
stellar: "Stellar network:",
};

return (
Expand Down
73 changes: 73 additions & 0 deletions components/verification/DynamicVerificationRouter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { NetworkName } from "../../types/networks";
import {
getChainType,
getVerifyPageForNetwork,
} from "../../utils/networkDetection";

type Props = {
network: NetworkName;
discordServerId: string;
discordMemberId: string;
customLink: string;
};

const DynamicVerificationRouter = ({
network,
discordServerId,
discordMemberId,
customLink,
}: Props) => {
const router = useRouter();
const [isRouting, setIsRouting] = useState(false);

useEffect(() => {
const routeToCorrectPage = async () => {
try {
setIsRouting(true);
const chainType = getChainType(network);

if (!chainType) {
console.error(`Unknown chain type for network: ${network}`);
return;
}

const correctVerifyPage = getVerifyPageForNetwork(network);
const currentPath = router.asPath;
const targetPath = `/${correctVerifyPage}/${discordServerId}/${discordMemberId}/${customLink}`;

// Only route if we're not already on the correct page
if (!currentPath.includes(`/${correctVerifyPage}/`)) {
console.log(
`Routing from current page to ${targetPath} for ${chainType} network`
);
await router.replace(targetPath);
}
} catch (error) {
console.error("Error during dynamic routing:", error);
} finally {
setIsRouting(false);
}
};

if (network && discordServerId && discordMemberId && customLink) {
routeToCorrectPage();
}
}, [network, discordServerId, discordMemberId, customLink, router]);

if (isRouting) {
return (
<div style={{ textAlign: "center", padding: "2rem" }}>
<p>
Detecting network type and routing to the appropriate wallet
connection...
</p>
</div>
);
}

return null;
};

export default DynamicVerificationRouter;
29 changes: 24 additions & 5 deletions components/verification/WalletInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { truncateAddress } from "../../utils/truncateAddess";

type EthereumAccount = string;
type StarknetAccount = { address: string };
type StellarAccount = string;

type WalletInfoProps = {
account: EthereumAccount | StarknetAccount | null;
networkType: "ethereum" | "starknet";
account: EthereumAccount | StarknetAccount | StellarAccount | null;
networkType: "ethereum" | "starknet" | "stellar";
balance?: string | null;
onDisconnect: () => void;
verifiedSignature?: boolean;
Expand Down Expand Up @@ -42,6 +43,8 @@ const WalletInfo = ({
const getAddress = () => {
if (networkType === "ethereum") {
return account as EthereumAccount;
} else if (networkType === "stellar") {
return account as StellarAccount;
} else {
return (account as StarknetAccount).address;
}
Expand All @@ -51,13 +54,29 @@ const WalletInfo = ({

return (
<span className={styles.starknetWallet}>
{networkType === "ethereum" ? "Ethereum wallet" : "Starknet wallet"}:{" "}
<b>{isMobile ? truncateAddress(address) : address}</b>{" "}
{networkType === "ethereum"
? "Ethereum wallet"
: networkType === "stellar"
? "Stellar wallet"
: "Starknet wallet"}
: <b>{isMobile ? truncateAddress(address) : address}</b>{" "}
{!verifiedSignature && <a onClick={onDisconnect}>disconnect</a>}
{networkType === "ethereum" && balance && (
<>
<div>
<br />
Balance: <b>{balance ? `${balance} ETH` : "Loading..."}</b>
</div>
)}
{networkType === "stellar" && balance && (
<div>
<br />
Balance: <b>{balance ? `${balance} XLM` : "Loading..."}</b>
</div>
)}
{networkType === "stellar" && balance && (
<>
<br />
Balance: <b>{balance ? `${balance} XLM` : "Loading..."}</b>
</>
)}
</span>
Expand Down
29 changes: 22 additions & 7 deletions configs/networks.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@
"url": "https://starknet.preview.apibara.org",
"indexer": true,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep this one to true (for your test you can definitely disable it, but please don't commit it)

"description": "The Starknet mainnet",
"verifyPage": "verify"
"verifyPage": "verify",
"chain": "starknet"
},
{
"label": "Starknet Sepolia",
"name": "sepolia",
"url": "coming-soon",
"indexer": false,
"description": "The Starknet testnet",
"verifyPage": "verify"
"verifyPage": "verify",
"chain": "starknet"
},
{
"label": "Ethereum Mainnet",
Expand All @@ -24,16 +26,29 @@
"currency": "ETH",
"indexer": false,
"description": "The Ethereum mainnet",
"verifyPage": "verify-eth"
"verifyPage": "verify-eth",
"chain": "ethereum"
},
{
"label": "Stellar Mainnet",
"name": "stellar-mainnet",
"url": "https://stellar.org",
"explorerUrl": "https://stellar.expert/explorer/public",
"url": "https://horizon.stellar.org",
"explorerUrl": "https://stellarchain.io",
"currency": "XLM",
"indexer": false,
"description": "The Stellar network",
"verifyPage": "verify-stellar"
"description": "The Stellar mainnet",
"verifyPage": "verify-stellar",
"chain": "stellar"
},
{
"label": "Stellar Testnet",
"name": "stellar-testnet",
"url": "https://horizon-testnet.stellar.org",
"explorerUrl": "https://testnet.stellarchain.io",
"currency": "XLM",
"indexer": false,
"description": "The Stellar testnet",
"verifyPage": "verify-stellar",
"chain": "stellar"
}
]
47 changes: 43 additions & 4 deletions discord/interactions/addConfigCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,40 @@ const handleBackToModule = async (
) => {
const currentConfig = ongoingConfigurationsCache[interaction.guildId!];
const network = currentConfig?.network;

const modulesOptions: SelectMenuComponentOptionData[] = [];
for (const starkyModuleId in starkyModules) {
const starkyModule = starkyModules[starkyModuleId];
// Only show modules that support the selected network
if (network && starkyModule.networks && starkyModule.networks.includes(network)) {
if (
network &&
starkyModule.networks &&
starkyModule.networks.includes(network)
) {
// Validate label length (Discord requires 1-25 characters)
let label = starkyModule.name || starkyModuleId;
if (label.length > 25) {
label = label.substring(0, 22) + "...";
}
if (label.length === 0) {
label = starkyModuleId.substring(0, 25);
}

modulesOptions.push({
label: starkyModule.name,
label: label,
value: starkyModuleId,
});
}
}

if (modulesOptions.length === 0) {
await interaction.update({
content: `❌ No Starky modules are available for the network "${network}". Please go back and select a different network.`,
components: [addBackButton("module")],
});
return;
}

const selectRow =
new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
new StringSelectMenuBuilder()
Expand Down Expand Up @@ -466,13 +487,31 @@ export const handleNetworkConfigCommand = async (
const starkyModule = starkyModules[starkyModuleId];
// Only show modules that support the selected network
if (starkyModule.networks && starkyModule.networks.includes(network)) {
// Validate label length (Discord requires 1-25 characters)
let label = starkyModule.name || starkyModuleId;
if (label.length > 25) {
label = label.substring(0, 22) + "...";
}
if (label.length === 0) {
label = starkyModuleId.substring(0, 25);
}

modulesOptions.push({
label: starkyModule.name,
label: label,
value: starkyModuleId,
});
}
}

if (modulesOptions.length === 0) {
await interaction.followUp({
content: `❌ No Starky modules are available for the network "${network}". Please go back and select a different network.`,
components: [addBackButton(CONFIG_STEPS.MODULE)],
ephemeral: true,
});
return;
}

const selectRow =
new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
new StringSelectMenuBuilder()
Expand Down
57 changes: 57 additions & 0 deletions hooks/useStellarSignatureVerification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { useCallback, useState } from "react";
import axios from "axios";
import WatchTowerLogger from "../watchTower";

const useStellarSignatureVerification = (
network: string,
discordServerId: string,
discordMemberId: string,
customLink: string
) => {
const [verifyingSignature, setVerifyingSignature] = useState<boolean>(false);
const [verifiedSignature, setVerifiedSignature] = useState<boolean>(false);
const [unverifiedSignature, setUnverifiedSignature] = useState<string>("");

const verifySignature = useCallback(
async (signature: string, account: string, message: string) => {
if (!account) return;
setUnverifiedSignature("");
setVerifyingSignature(true);
try {
await axios.post("/api/verify-stellar", {
account,
signature,
discordServerId,
discordMemberId,
customLink,
network,
message,
});
setVerifiedSignature(true);
setVerifyingSignature(false);
} catch (e: any) {
WatchTowerLogger.error(
"Stellar signature verification failed with data",
e.response?.data
);
setVerifyingSignature(false);
setUnverifiedSignature(
`${e.response?.data?.message || "Verification failed"}.${
e.response?.data?.error || ""
}` || "Stellar signature verification failed"
);
}
setVerifyingSignature(false);
},
[network, discordServerId, discordMemberId, customLink]
);

return {
verifyingSignature,
verifiedSignature,
unverifiedSignature,
verifySignature,
};
};

export default useStellarSignatureVerification;
Loading