Skip to content

Commit

Permalink
Merge pull request #54 from Crypto-Phunks/feature/dao_extension_impl
Browse files Browse the repository at this point in the history
implementation of a DAO governance plugin
  • Loading branch information
tat2bu authored Dec 30, 2023
2 parents 6561651 + a26a908 commit 5225a5f
Show file tree
Hide file tree
Showing 40 changed files with 14,196 additions and 19,569 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
token_metadatas_cache/*.json
*.txt
bids_images
db.db
token_images
Expand Down Expand Up @@ -40,3 +42,8 @@ lerna-debug.log*
!.vscode/launch.json
!.vscode/extensions.json
auction_images
wrapped_punks
wrapped_punks_old
new
original_punks_images
punks_images
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<h1>Twitter NFT sales bot</h1>
<h1>Discord and Twitter NFT sales bot</h1>

[![coverage](https://crypto-phunks.github.io/nft-sales-twitter-bot/badge-lines.svg?update2)](https://crypto-phunks.github.io/nft-sales-twitter-bot/)

Expand Down Expand Up @@ -55,7 +55,7 @@ Just add a `DISCORD_TOKEN` in your `.env` file, also add `saleMessageDiscord` an

You can add a link to the tweet that's been generated in the discord message using `<tweetLink>` in your `saleMessageDiscord` template.

To setup the bot, lead to https://discord.com/developers and create an application and a bot, then invite the bot you just created using the following link: https://discord.com/api/oauth2/authorize?client_id=[yourDiscordAppclientId]&permissions=2048&scope=bot%20applications.commands, then ensure that the invited bot is allowed to access the channel ID you want your bot to post into.
To setup the bot, lead to https://discord.com/developers and create an application and a bot, then invite the bot you just created using the following link: https://discord.com/api/oauth2/authorize?client_id=[yourDiscordAppclientId]&permissions=268512336&scope=bot%20applications.commands, then ensure that the invited bot is allowed to access the channel ID you want your bot to post into.

## Statistics module

Expand All @@ -73,6 +73,25 @@ block `statistic_initial_block`. Once indexed, the discord bot will reply to the

The message templates for each command can be customized through the configuration file.

## DAO module

You can enable the optional DAO module in the `AppModule` definition file `app.module.ts`, it requires
the statistics module to be enabled as well. When enabled, it will make available commands to let users
bind their web3 wallets to their discord account through the `/bind` command ; creating a bridge between
web3 ownership tracability and discord community management features.

This binding enable a lot of possibilities:

- The bounded wallets can be used to grant specific roles on the configured discord server, check out the
[sample configuration file](https://github.com/Crypto-Phunks/nft-sales-twitter-bot/blob/main/src/config.ts) to see
how to grant roles for users owning a token of the collection, for the ones who originally minted the collection,
or the ones owning tokens with a specific trait.

- The DAO module includes a voting mechanism that let the discord administrators to create polls for the communities,
these votes are anonymous and administrable through the `/createpoll <description> <duration> <roles>`, `/pollresults <id>`,
and `/listpolls` commands.


## CLI mode

You can use this app as a standalone cli using the following command line along with the `block` and `tx` parameter. The optional `contract` parameter can be used to override the contract from the configuration. ie:
Expand Down
Binary file added client/fonts/RetroComputer.woff
Binary file not shown.
Binary file added client/fonts/RetroComputer.woff2
Binary file not shown.
192 changes: 192 additions & 0 deletions client/fonts/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, noarchive">
<meta name="format-detection" content="telephone=no">
<title>Transfonter demo</title>
<link href="stylesheet.css" rel="stylesheet">
<style>
/*
http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/* demo styles */
body {
background: #f0f0f0;
color: #000;
}
.page {
background: #fff;
width: 920px;
margin: 0 auto;
padding: 20px 20px 0 20px;
overflow: hidden;
}
.font-container {
overflow-x: auto;
overflow-y: hidden;
margin-bottom: 40px;
line-height: 1.3;
white-space: nowrap;
padding-bottom: 5px;
}
h1 {
position: relative;
background: #444;
font-size: 32px;
color: #fff;
padding: 10px 20px;
margin: 0 -20px 12px -20px;
}
.letters {
font-size: 25px;
margin-bottom: 20px;
}
.s10:before {
content: '10px';
}
.s11:before {
content: '11px';
}
.s12:before {
content: '12px';
}
.s14:before {
content: '14px';
}
.s18:before {
content: '18px';
}
.s24:before {
content: '24px';
}
.s30:before {
content: '30px';
}
.s36:before {
content: '36px';
}
.s48:before {
content: '48px';
}
.s60:before {
content: '60px';
}
.s72:before {
content: '72px';
}
.s10:before, .s11:before, .s12:before, .s14:before,
.s18:before, .s24:before, .s30:before, .s36:before,
.s48:before, .s60:before, .s72:before {
font-family: Arial, sans-serif;
font-size: 10px;
font-weight: normal;
font-style: normal;
color: #999;
padding-right: 6px;
}
pre {
display: block;
padding: 9px;
margin: 0 0 12px;
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
font-size: 13px;
line-height: 1.428571429;
color: #333;
font-weight: normal;
font-style: normal;
background-color: #f5f5f5;
border: 1px solid #ccc;
overflow-x: auto;
border-radius: 4px;
}
/* responsive */
@media (max-width: 959px) {
.page {
width: auto;
margin: 0;
}
}
</style>
</head>
<body>
<div class="page">
<div class="demo">
<h1 style="font-family: 'Retro Computer'; font-weight: normal; font-style: normal;">Retro Computer</h1>
<pre title="Usage">.your-style {
font-family: 'Retro Computer';
font-weight: normal;
font-style: normal;
}</pre>
<pre title="Preload (optional)">
&lt;link rel=&quot;preload&quot; href=&quot;RetroComputer.woff2&quot; as=&quot;font&quot; type=&quot;font/woff2&quot; crossorigin&gt;</pre>
<div class="font-container" style="font-family: 'Retro Computer'; font-weight: normal; font-style: normal;">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#&lt;&gt;$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>

</div>
</body>
</html>
9 changes: 9 additions & 0 deletions client/fonts/stylesheet.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@font-face {
font-family: 'Retro Computer';
src: url('RetroComputer.woff2') format('woff2'),
url('RetroComputer.woff') format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}

109 changes: 109 additions & 0 deletions client/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<html>
<head>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="/fonts/stylesheet.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono&display=swap" rel="stylesheet">
<style>
body {
font-family: "Roboto Mono";
background: #222;
color: white;
}
h1 {
font-family: "Retro Computer";
font-size: 27px;
}
a {
color: white;
}
</style>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js" type="application/javascript"></script>
<script>
window.onload = () => {
let discordUsername, discordUserId, discordAccessToken;
const cw3 = document.getElementById('connect-web3')
const fragment = new URLSearchParams(window.location.hash.slice(1));
if (fragment.has('access_token')) {
const [accessToken, tokenType] = [fragment.get('access_token'), fragment.get('token_type')];
discordAccessToken = accessToken
fetch('https://discord.com/api/users/@me', {
headers: {
authorization: `${tokenType} ${accessToken}`,
},
}).then(result => {
result.json().then(response => {
console.log(response)
const { username, discriminator } = response;
const dc = document.getElementById('discord-connected')
const du = document.getElementById('discord-username')
const cd = document.getElementById('connect-discord')
cd.style.display = 'none'
dc.style.display = 'block'
du.innerHTML = `${username}`
discordUsername = username
discordUserId = response.id
cw3.style.display = 'block'
})
})
}
console.log(cw3)
cw3.addEventListener('click', () => {
const provider = new ethers.providers.Web3Provider(window.ethereum)
provider.send("eth_requestAccounts", []).then(account => {
const signer = provider.getSigner()
const signature = signer.signMessage(`This signature is safe and will bind your wallet to your discord user ID.`).then(signature => {
console.log(`account: ${account} signature: ${signature}`)
sendSignature(account[0], signature, discordUsername, discordUserId, discordAccessToken)
});
})
})
}

function sendSignature(account, signature, discordUsername, discordUserId, discordAccessToken) {
const cw3 = document.getElementById('connect-web3')
const resultDiv = document.getElementById('result')

fetch('/dao/bind/web3', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
discordAccessToken: discordAccessToken,
account,
signature,
discordUsername,
discordUserId
})
}).then(result => {
result.json().then(response => {
console.log(response)
cw3.style.display = 'none'
if (response.result === 'ok') {
resultDiv.innerHTML = 'Your web3 wallet is now tied to your discord account, you can safely close this window.'
} else {
resultDiv.innerHTML = 'An error occured, please refresh this page and retry.'
}
resultDiv.style.display = 'block'
})
})
}
</script>
</head>
<body>
<h1>Cryptophunk Discord / Web3 wallet binder</h1>

<a id="connect-discord" href="https://discord.com/api/oauth2/authorize?client_id=1139547496033558561&redirect_uri=http%3A%2F%2F192.168.0.32%3A3000%2F&response_type=token&scope=identify">connect discord</a>

<div id="discord-connected" style="display:none;">
Discord username: <span id="discord-username"></span>
</div>

<a id="connect-web3" style="margin-top: 10px; display:none;" href="#">Connect Web3 Wallet</a>

<div id="result" style="margin-top: 10px; display:none;"></div>
</body>
</html>
Loading

0 comments on commit 5225a5f

Please sign in to comment.