A Discord bot that enables you to authenticate users with Ethereum. The infrastructure is fully serverless and based on AWS Lambda.
The bot is based on:
- austintgriffith/scaffold-eth/serverless-auth to handle the Ethereum authentication flow.
- ytausch/serverless-discord-bot for the interaction with Discord through slash commands.
If you find this repository useful, any ETH, NFT, or other tokens are greatly appreciated.
ETH Address: 0xa8624937a437F53382d4B48f1AE13E0CF5C9F8cB
- A Discord account and a server where you're an administrator
- AWS Account with console and programmatic access
- A domain name registered with AWS
- Local AWS credentials profile
- Node version 14
- SAM CLI
- Create a Discord server if you don't have one already. Create the role you want to give the user after they've authenticated with Ethereum. For example, I named my role eth-authenticated. Important: this role must be below in the hierarchy than the one for the bot you create in the next step, otherwise you'll get a missing access error. See here how to move a role up or down in the hierarchy.
- Set up an application for your bot
- Select the following boxes in the OAuth2 tab. Open the link marked in red and choose your server to add the bot.
- Create an access key pair for your AWS user as explained here (this user must have administrator access).
- Create file
.aws/credentials
with the same structure as.aws/credentials.example
(including the "[scaffold-eth]" part), and fill in the parametersaws_access_key_id
andaws_secret_access_key
with the values you obtained from the previous step.
- Create a certificate in Certificate Manager for the API endpoint you'll later deploy to be linked to. For instance, mine is at dev.api.vorder.io. Don't forget to add the DNS record to your domain as mentioned in the verification prompt that shows up once you create the certificate. You won't be able to deploy the Ethereum Authentication Infrastructure correctly without the certificate Status showing up as Issued, so wait for it to complete before doing that part.
All the secrets necessary for the bot to run are retrieved from an AWS Secrets Manager secret named /dev/serverless_discord_bot/discord
you have to create that secret manually before deploying the stack. When creating the secret choose the option Other type of secrets.
The secret must contain the following key/value pairs:
app_id
, from the application you've created in the Discord Setup.public_key
, from the application you've created in the Discord Setup.bot_token
, from the application you've created in the Discord Setup.server_id
- Right-click your server on Discord and select Copy ID to get this.channel_id
. Right-click your channel on Discord and select Copy ID to get this.role_id
. Right-click the role you've created in the Discord setup and select Copy ID to get this. You can see your server's roles by right-clicking your server > Server Settings > Roles.jwt_secret
. This is the secret which will be used to encode/decode the authentication JWTs. Anything works here, but choose something strong enough.
We'll now go through the deployment of the infrastructure responsible for interacting with Discord. This includes creating the slash-command and handling the role assignment when a user is successfuly authenticated.
-
cd
into packages/discord-interaction/src/commands_layer/nodejs and install the layer dependencies usingnpm install
. This is the only install required for this infrastructure. The rest is auto-installed by SAM. -
cd
back into packages/discord-interaction/ and dosam build
. Once the build is complete dosam deploy --guided
and choose the following parameters:Stack Name [dev-discord-interaction]: dev-discord-interaction
AWS Region [us-east-2]: us-east-2
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]: n
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]: y
DiscordHandlerFunction may not have authorization defined, Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: y
SAM configuration file [samconfig.toml]: samconfig.toml
SAM configuration environment [default]: default
-
Once the deployment is complete copy the API Gateway endpoint URL stack output and paste it in the Discord Developer Portal as Interactions Endpoint URL. If Discord was able to successfuly ping our Lambda you'll get a message saying "All your edits have been carefully recorded" at the top of the screen.
-
Check that you now have a stack called dev-discord-interaction in Cloudformation. Cross your fingers 🤞 and call the command
/eth-auth
in your Discord channel. If everything went right with the deploy, the bot should respond with a URL.
Now let's deploy the API that will talk to the front-end and handle the Ethereum authentication flow.
- In the root folder run
yarn install
. You'll get quite a lot of warnings regarding workspace dependencies, but those are harmless. Note: All the packages for this infrastructure (and also for the front-end and the chain) are installed throughyarn
workspaces. The api package dependencies will later be installed usingnpm
.
cd
into packages/serverless-infrastructure and runnpm run deploy
. After this runs, you should now have a stack called dev-scaffold-eth-infra-dynamodb in Cloudformation.
cd
into packages/api and install the dependencies usingnpm install
.- Change the URL that will be linked to your API in the following files - this is the same URL that you've created the Certificate above for, e.g. for me it's dev.api.vorder.io (I probably should have put this in an environment variable but oh well):
- In the file packages/api/serverless.yml, change the variable domainName so that it matches your URL. ${self:custom.stage} is set to dev by default already.
- In the file packages/react-app/src/util change baseUrl to that same URL so that the front-end knows where the API is located.
- Link your API to the URL by running
npx serverless create_domain
. - Finally, deploy the infrastucture using
npm run deploy
.
In the root folder run in two separate command prompts:
yarn react-app:start
to start the local react app server.yarn chain
to start the local chain server. Note: This example runs with a local chain, but you can set the chain to whatever you want. Just edit the variable targetNetwork in packages/react-app/src/App.jsx to change to a different chain.
Once the the local react app and chain servers are ready all is set up to try the bot.
- Call the command
/eth-auth
in the channel. - Click the link that the bot gives you.
- Click the login button at the upper right corner and login into your metamask wallet (note: you'll probably have to change the network on metamask to localhost).
- Once you've logged in, click the Authenticate button. You're prompted by metamask for a signature. After you provide the signature, if all went well, you'll receive a message from the bot saying that you've been sucessfully authenticated and you should now have the new role attributed to you in the Discord server.
- Remove hardcoding for
server_id
andchannel_id
, and make them dynamic depending on the server the bot is responding to. - The set up has quite a lot of steps and streamlining it further would be ideal.
- Using SAM for the deployment of all the serverless infrastructure would be best. I developed this project for an hackathon and had limited time, so had to work with the repos I had available. If there's interest I'll port the API infrastructure to SAM.
- After the authentication there are many possibilities to what can be done. For example you might wish to check what balance the user has in their wallet or check which tokens they have for some specific purpose.