-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ready for real-world testing I guess
- Loading branch information
root
authored and
signorecello
committed
Jan 16, 2025
1 parent
e1959ab
commit 68291ba
Showing
20 changed files
with
301 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
.env | ||
node_modules | ||
bun.lockb | ||
.vercel | ||
.dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,13 @@ | ||
FROM oven/bun:latest | ||
|
||
RUN apt update && apt install -y curl | ||
RUN curl -fsSL https://get.docker.com | bash | ||
|
||
WORKDIR /app | ||
COPY package.json ./ | ||
COPY bun.lockb ./ | ||
COPY src ./ | ||
COPY src ./src | ||
COPY .env ./ | ||
|
||
RUN bun install | ||
CMD ["bun", "run", "start"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Sparta | ||
|
||
Welcome to Sparta, the Discord bot. It's like having a virtual assistant, but with less features and less judgment. | ||
|
||
Here's a quick rundown of what this codebase is all about: | ||
|
||
## What is Sparta? | ||
|
||
Sparta is a Discord bot that lives to serve (and occasionally sass) testnet participants. | ||
|
||
## Features (WIP) | ||
|
||
- **Chain Info**: Need to know the latest on your blockchain? Sparta's got you covered with the `/get-info` command. It's like having a blockchain oracle, but without the cryptic riddles. | ||
|
||
- **Add Validators**: Are you an S&P Participant and want to be added to the validator set? Just go `/validator add` and send your address, you can then query it with... | ||
|
||
- **Check Validators**: ... `/validator check`, which tells you if you're in the validator set (also tells you if you're in the committee) | ||
|
||
## Getting Started | ||
|
||
To get Sparta up and running, you'll need to: | ||
|
||
1. Clone the repo. | ||
2. Install the dependencies with `bun install`. | ||
3. Copy .env.example and set up with your environment stuff | ||
4. Start the bot with `bun run start`. | ||
|
||
And just like that, you're ready to unleash Sparta on your Discord server! | ||
|
||
## Contributing | ||
|
||
Want to make Sparta even better? Feel free to fork the repo and submit a pull request. Just remember, with great power comes great responsibility (and maybe a few more memes). | ||
|
||
## License | ||
|
||
This project is licensed under the MIT License. Because sharing is caring. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { SlashCommandBuilder } from "discord.js"; | ||
import { ValidatorService } from "../services/validator-service.js"; | ||
import { ChainInfoService } from "../services/chaininfo-service.js"; | ||
export default { | ||
data: new SlashCommandBuilder() | ||
.setName("validator") | ||
.setDescription("Manage validator addresses") | ||
.addSubcommand((subcommand) => subcommand | ||
.setName("add") | ||
.setDescription("Add yourself to the validator set") | ||
.addStringOption((option) => option | ||
.setName("address") | ||
.setDescription("Your validator address"))) | ||
.addSubcommand((subcommand) => subcommand | ||
.setName("check") | ||
.setDescription("Check if you are a validator") | ||
.addStringOption((option) => option | ||
.setName("address") | ||
.setDescription("The validator address to check"))), | ||
execute: async (interaction) => { | ||
const address = interaction.options.getString("address"); | ||
if (!address) { | ||
return interaction.reply({ | ||
content: "Address is required.", | ||
ephemeral: true, | ||
}); | ||
} | ||
// Basic address validation | ||
if (!address.match(/^0x[a-fA-F0-9]{40}$/)) { | ||
return interaction.reply({ | ||
content: "Please provide a valid Ethereum address.", | ||
ephemeral: true, | ||
}); | ||
} | ||
await interaction.deferReply(); | ||
if (interaction.options.getSubcommand() === "add") { | ||
try { | ||
await ValidatorService.addValidator(address); | ||
await interaction.editReply({ | ||
content: `Successfully added validator address: ${address}`, | ||
}); | ||
} | ||
catch (error) { | ||
await interaction.editReply({ | ||
content: `Failed to add validator address: ${error instanceof Error ? error.message : String(error)}`, | ||
}); | ||
} | ||
} | ||
else if (interaction.options.getSubcommand() === "check") { | ||
try { | ||
const info = await ChainInfoService.getInfo(); | ||
const { validators, committee } = info; | ||
let reply = ""; | ||
if (validators.includes(address)) { | ||
reply += "You are a validator\n"; | ||
} | ||
if (committee.includes(address)) { | ||
reply += "You are a committee member\n"; | ||
} | ||
await interaction.editReply({ | ||
content: reply, | ||
}); | ||
} | ||
catch (error) { | ||
await interaction.editReply({ | ||
content: `Failed to check validator address: ${error instanceof Error ? error.message : String(error)}`, | ||
}); | ||
} | ||
} | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { SlashCommandBuilder } from "discord.js"; | ||
import { ChainInfoService } from "../services/chaininfo-service.js"; | ||
export default { | ||
data: new SlashCommandBuilder() | ||
.setName("get-info") | ||
.setDescription("Get chain info"), | ||
execute: async (interaction) => { | ||
await interaction.deferReply(); | ||
try { | ||
const { pendingBlockNum, provenBlockNum, currentEpoch, currentSlot, proposerNow, } = await ChainInfoService.getInfo(); | ||
await interaction.editReply({ | ||
content: `Pending block: ${pendingBlockNum}\nProven block: ${provenBlockNum}\nCurrent epoch: ${currentEpoch}\nCurrent slot: ${currentSlot}\nProposer now: ${proposerNow}`, | ||
}); | ||
} | ||
catch (error) { | ||
console.error("Error in get-info command:", error); | ||
await interaction.editReply({ | ||
content: `Failed to get chain info`, | ||
}); | ||
} | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import addValidator from "./addValidator.js"; | ||
import getChainInfo from "./getChainInfo.js"; | ||
export default { | ||
addValidator, | ||
getChainInfo, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { REST, Routes } from "discord.js"; | ||
import commands from "./commands/index.js"; | ||
import { BOT_TOKEN, BOT_CLIENT_ID, GUILD_ID } from "./env.js"; | ||
export const deployCommands = async () => { | ||
const rest = new REST({ version: "10" }).setToken(BOT_TOKEN); | ||
try { | ||
console.log("Started refreshing application (/) commands."); | ||
const commandsData = Object.values(commands).map((command) => command.data.toJSON()); | ||
await rest.put(Routes.applicationGuildCommands(BOT_CLIENT_ID, GUILD_ID), { | ||
body: commandsData, | ||
}); | ||
console.log("Successfully reloaded application (/) commands."); | ||
} | ||
catch (error) { | ||
console.error(error); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import dotenv from "dotenv"; | ||
dotenv.config(); | ||
export const { TOKEN, CLIENT_ID, GUILD_ID, PRODUCTION_CHANNEL_NAME, DEV_CHANNEL_NAME, PRODUCTION_CHANNEL_ID, DEV_CHANNEL_ID, ETHEREUM_HOST, ETHEREUM_ROLLUP_ADDRESS, ETHEREUM_ADMIN_ADDRESS, ETHEREUM_CHAIN_ID, ETHEREUM_MNEMONIC, ETHEREUM_PRIVATE_KEY, ETHEREUM_VALUE, BOT_TOKEN, BOT_CLIENT_ID, ENVIRONMENT, } = process.env; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { Client, GatewayIntentBits, Collection, MessageFlags, } from "discord.js"; | ||
import { deployCommands } from "./deploy-commands.js"; | ||
import commands from "./commands/index.js"; | ||
import { BOT_TOKEN, PRODUCTION_CHANNEL_ID, DEV_CHANNEL_ID, ENVIRONMENT, PRODUCTION_CHANNEL_NAME, DEV_CHANNEL_NAME, } from "./env.js"; | ||
const client = new Client({ | ||
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages], | ||
}); | ||
client.commands = new Collection(); | ||
for (const command of Object.values(commands)) { | ||
client.commands.set(command.data.name, command); | ||
} | ||
client.once("ready", () => { | ||
console.log("Sparta bot is ready!"); | ||
deployCommands(); | ||
}); | ||
client.on("interactionCreate", async (interaction) => { | ||
if (!interaction.isChatInputCommand()) | ||
return; | ||
// Determine which channel to use based on environment | ||
const targetChannelId = ENVIRONMENT === "production" ? PRODUCTION_CHANNEL_ID : DEV_CHANNEL_ID; | ||
// Check if the command is in the correct channel | ||
if (interaction.channelId !== targetChannelId) { | ||
const channelName = ENVIRONMENT === "production" | ||
? PRODUCTION_CHANNEL_NAME | ||
: DEV_CHANNEL_NAME; | ||
return interaction.reply({ | ||
content: `This command can only be used in the ${channelName} channel.`, | ||
flags: MessageFlags.Ephemeral, | ||
}); | ||
} | ||
const command = client.commands.get(interaction.commandName); | ||
if (!command) | ||
return; | ||
try { | ||
console.log("Executing command:", command.data.name); | ||
const response = await command.execute(interaction); | ||
} | ||
catch (error) { | ||
console.error(error); | ||
await interaction.reply({ | ||
content: "There was an error executing this command!", | ||
flags: MessageFlags.Ephemeral, | ||
}); | ||
} | ||
}); | ||
client.login(BOT_TOKEN); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { exec } from "child_process"; | ||
import { promisify } from "util"; | ||
import { ETHEREUM_HOST, ETHEREUM_ROLLUP_ADDRESS, ETHEREUM_CHAIN_ID, } from "../env.js"; | ||
const execAsync = promisify(exec); | ||
export class ChainInfoService { | ||
static async getInfo() { | ||
try { | ||
// Add validator to the set | ||
const command = `docker run --rm aztecprotocol/aztec:unhinged-unicorn debug-rollup -u ${ETHEREUM_HOST} --rollup ${ETHEREUM_ROLLUP_ADDRESS} --l1-chain-id ${ETHEREUM_CHAIN_ID} `; | ||
const { stdout, stderr } = await execAsync(command); | ||
if (stderr) { | ||
throw new Error(stderr); | ||
} | ||
// looks like hell, but it just parses the output of the command | ||
// into a key-value object | ||
const info = stdout | ||
.split("\n") | ||
.map((line) => line.trim()) | ||
.filter(Boolean) | ||
.reduce((acc, s) => { | ||
const [key, value] = s.split(": "); | ||
const sanitizedKey = key | ||
.toLowerCase() | ||
.replace(/\s+(.)/g, (_, c) => c.toUpperCase()); | ||
return { ...acc, [sanitizedKey]: value }; | ||
}, {}); | ||
return info; | ||
} | ||
catch (error) { | ||
console.error("Error getting chain info:", error); | ||
throw error; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { exec } from "child_process"; | ||
import { promisify } from "util"; | ||
import { ETHEREUM_HOST, ETHEREUM_ROLLUP_ADDRESS, ETHEREUM_ADMIN_ADDRESS, ETHEREUM_CHAIN_ID, ETHEREUM_MNEMONIC, ETHEREUM_PRIVATE_KEY, ETHEREUM_VALUE, } from "../env.js"; | ||
const execAsync = promisify(exec); | ||
export class ValidatorService { | ||
static async addValidator(address) { | ||
try { | ||
// Send ETH to the validator address | ||
await this.fundValidator(address); | ||
// Add validator to the set | ||
const command = `docker run --rm aztecprotocol/aztec:unhinged-unicorn add-l1-validator -u ${ETHEREUM_HOST} --validator ${address} --rollup ${ETHEREUM_ROLLUP_ADDRESS} --withdrawer ${ETHEREUM_ADMIN_ADDRESS} --l1-chain-id ${ETHEREUM_CHAIN_ID} --mnemonic "${ETHEREUM_MNEMONIC}"`; | ||
const { stdout, stderr } = await execAsync(command); | ||
if (stderr) { | ||
throw new Error(stderr); | ||
} | ||
return stdout; | ||
} | ||
catch (error) { | ||
console.error("Error adding validator:", error); | ||
throw error; | ||
} | ||
} | ||
static async fundValidator(address) { | ||
try { | ||
const command = `cast send --value ${ETHEREUM_VALUE} --rpc-url ${ETHEREUM_HOST} --chain-id ${ETHEREUM_CHAIN_ID} --private-key ${ETHEREUM_PRIVATE_KEY} ${address}`; | ||
const { stdout, stderr } = await execAsync(command); | ||
if (stderr) { | ||
throw new Error(stderr); | ||
} | ||
return stdout; | ||
} | ||
catch (error) { | ||
console.error("Error funding validator:", error); | ||
throw error; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
name: Sparta | ||
services: | ||
sparta: | ||
volumes: | ||
- /var/run/docker.sock:/var/run/docker.sock | ||
build: | ||
context: . |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
import address from "./addValidator"; | ||
import chainInfo from "./getChainInfo"; | ||
import addValidator from "./addValidator.js"; | ||
import getChainInfo from "./getChainInfo.js"; | ||
|
||
export default { | ||
address, | ||
chainInfo, | ||
addValidator, | ||
getChainInfo, | ||
}; |
Oops, something went wrong.