mirror of
https://github.com/jwinterm/tubbymemes.git
synced 2026-10-17 05:21:28 +02:00
getting some chain syncing going, still very rough
This commit is contained in:
@@ -132,9 +132,6 @@ dmypy.json
|
||||
data/
|
||||
go-ipfs/
|
||||
avalanchego-v1.7.3
|
||||
*jpg
|
||||
*png
|
||||
*svg
|
||||
*mp4
|
||||
*webp
|
||||
*mkv
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import requests
|
||||
from flask import Blueprint
|
||||
from secrets import token_urlsafe
|
||||
|
||||
from suchwowx.factory import db
|
||||
from suchwowx.helpers import get_eth_contract
|
||||
from suchwowx.models import Meme, User
|
||||
from suchwowx import config
|
||||
|
||||
|
||||
bp = Blueprint('cli', 'cli', cli_group=None)
|
||||
@@ -9,3 +14,49 @@ bp = Blueprint('cli', 'cli', cli_group=None)
|
||||
@bp.cli.command('init')
|
||||
def init():
|
||||
db.create_all()
|
||||
|
||||
@bp.cli.command('sync-avax')
|
||||
def sync_avax():
|
||||
"""
|
||||
Synchronize your local database with the tokens minted on Avalanche blockchain.
|
||||
"""
|
||||
contract = get_eth_contract()
|
||||
total_supply = contract.functions.totalSupply().call()
|
||||
# walk backwards through all tokens at top of supply
|
||||
# until you've accounted for the last known
|
||||
for i in range(total_supply, 0, -1):
|
||||
# first get metadata ipfs hash
|
||||
deets = contract.functions.tokenMeme(i).call()
|
||||
try:
|
||||
meme_exists = Meme.query.filter(Meme.meta_ipfs_hash == deets[5]).first() # noqa
|
||||
user_exists = User.query.filter(User.public_address == deets[4].lower()).first() # noqa
|
||||
if meme_exists:
|
||||
if not meme_exists.minted:
|
||||
meme_exists.minted = True
|
||||
db.session.commit()
|
||||
print(f'[+] Marked existing meme {meme_exists.id} as minted')
|
||||
else:
|
||||
print(deets)
|
||||
if not user_exists:
|
||||
user_exists = User(
|
||||
public_address=deets[4].lower()
|
||||
)
|
||||
db.session.add(user_exists)
|
||||
db.session.commit()
|
||||
user_exists.handle = f'anon{user_exists.id}-{token_urlsafe(6)}'
|
||||
db.session.commit()
|
||||
print(f'[+] Created user {user_exists.handle}')
|
||||
res = requests.get(f'{config.IPFS_SERVER}/ipfs/{deets[5]}', timeout=30).json()
|
||||
meme = Meme(
|
||||
title=res['name'],
|
||||
description=res['description'],
|
||||
user_id=user_exists.id,
|
||||
meta_ipfs_hash=deets[5],
|
||||
meme_ipfs_hash=res['image'].split('ipfs://')[1],
|
||||
minted=True
|
||||
)
|
||||
db.session.add(meme)
|
||||
db.session.commit()
|
||||
print(f'[+] Added new meme {meme.id}')
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
@@ -8,6 +8,7 @@ SECRET_KEY = getenv('SECRET_KEY', 'yyyyyyyyyyyyy')
|
||||
DATA_FOLDER = getenv('DATA_FOLDER', '/path/to/uploads')
|
||||
SERVER_NAME = getenv('SERVER_NAME', '127.0.0.1:5000')
|
||||
IPFS_SERVER = getenv('IPFS_SERVER', 'http://127.0.0.1:8080')
|
||||
AVAX_RPC = getenv('AVAX_RPC', 'https://api.avax-test.network/ext/bc/C/rpc')
|
||||
|
||||
# Cache
|
||||
CACHE_HOST = getenv('CACHE_HOST', 'localhost')
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ from suchwowx import config
|
||||
|
||||
|
||||
db = SQLAlchemy()
|
||||
w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:9650')) # noqa
|
||||
w3 = Web3(Web3.HTTPProvider(config.AVAX_RPC))
|
||||
|
||||
|
||||
def setup_db(app: Flask, db: SQLAlchemy = db):
|
||||
|
||||
@@ -6,6 +6,19 @@ from suchwowx.factory import w3
|
||||
from suchwowx import config
|
||||
|
||||
|
||||
def get_eth_contract():
|
||||
"""
|
||||
Return a web3 contract object with the currently
|
||||
deployed SuchWowX smart contract.
|
||||
"""
|
||||
contract_abi = config.CONTRACT_ABI
|
||||
contract_address = w3.toChecksumAddress(config.CONTRACT_ADDRESS)
|
||||
return w3.eth.contract(
|
||||
address=contract_address,
|
||||
abi=contract_abi
|
||||
)
|
||||
|
||||
|
||||
def verify_signature(message, signature, public_address):
|
||||
msg = encode_defunct(text=message)
|
||||
recovered = w3.eth.account.recover_message(msg, signature=signature)
|
||||
|
||||
@@ -21,15 +21,7 @@ def index():
|
||||
memes = Meme.query.filter(
|
||||
Meme.approved == True
|
||||
).order_by(Meme.create_date.desc())
|
||||
w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:9650'))
|
||||
contract_address = w3.toChecksumAddress(config.CONTRACT_ADDRESS)
|
||||
contract_abi = config.CONTRACT_ABI
|
||||
contract = w3.eth.contract(
|
||||
address=contract_address,
|
||||
abi=contract_abi
|
||||
)
|
||||
# total_supply = contract.functions.totalSupply().call()
|
||||
return render_template('index.html', memes=memes, contract=contract)
|
||||
return render_template('index.html', memes=memes)
|
||||
|
||||
|
||||
@bp.route('/mod')
|
||||
|
||||
@@ -27,3 +27,8 @@
|
||||
.wrap {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.mintedAVAX {
|
||||
background-color: rgba(242,37,52,.2);
|
||||
border: 2px solid rgba(243,37,52,1);
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -1,8 +1,9 @@
|
||||
{# expects meme var #}
|
||||
<div class="card">
|
||||
<div class="card {% if meme.minted %}mintedAVAX{% endif %}">
|
||||
<div class="card-image">
|
||||
<figure class="image">
|
||||
<a href="{{ url_for('meme.show', meme_id=meme.id) }}">
|
||||
{% if meme.file_name %}
|
||||
{% if meme.file_name.endswith('mp4') %}
|
||||
<video class="img-fluid" {% if not request.MOBILE %}autoplay{% else %}controls{% endif %} muted loop>
|
||||
<source src="{{ url_for('meta.uploaded_file', filename=meme.file_name) }}" type="video/mp4">
|
||||
@@ -11,6 +12,9 @@
|
||||
{% else %}
|
||||
<img alt="{{ meme.title }}" src="{{ url_for('meta.uploaded_file', filename=meme.file_name) }}" width="200px" class="img-fluid" style="" />
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<img alt="{{ meme.title }}" src="{{ config.IPFS_SERVER }}/ipfs/{{ meme.meme_ipfs_hash }}" width="200px" class="img-fluid" style="" />
|
||||
{% endif %}
|
||||
</a>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
<div id="screen">
|
||||
<div class="screen">
|
||||
{% if meme.file_name %}
|
||||
{% if meme.file_name.endswith('mp4') %}
|
||||
<video style="max-height: 60vh!important;max-width:100%;" {% if not request.MOBILE %}autoplay{% else %}controls{% endif %} muted loop>
|
||||
<source src="{{ meme_url }}" type="video/mp4">
|
||||
@@ -27,10 +28,14 @@
|
||||
{% else %}
|
||||
<img src="{{ meme_url }}" id="memeImage" />
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<br/>
|
||||
<p>Title: <strong>{{ meme.title }}</strong></p>
|
||||
<p>Description: <strong>{{ meme.description }}</strong></p>
|
||||
<p>Poster Address: <a href="{{ url_for('user.show', handle=meme.user.handle) }}">{{ meme.user.handle }}</a></p>
|
||||
{% if meme.user.wownero_address %}
|
||||
<p>Wownero Address: <strong><span style="word-wrap: break-word">{{ meme.user.wownero_address }}</strong></p>
|
||||
{% endif %}
|
||||
{% if meme.meta_ipfs_hash %}
|
||||
<p>Meta IPFS: <a href="{{ meta_url }}" target=_self up-preload up-follow=".container">{{ meme.meta_ipfs_hash }}</a></p>
|
||||
{% endif %}
|
||||
@@ -42,12 +47,14 @@
|
||||
<div class="modal-background"></div>
|
||||
<div class="modal-card">
|
||||
<header class="modal-card-head">
|
||||
<p class="modal-card-title">Modal title</p>
|
||||
<button class="delete" aria-label="close"></button>
|
||||
<p class="modal-card-title">Tip meme in WOW</p>
|
||||
<button class="delete" aria-label="close" onclick="closeModal('profileModal')" id="closeModal"></button>
|
||||
</header>
|
||||
<section class="modal-card-body">
|
||||
<p style="word-wrap: break-word;">Wownero Address: {{ meme.user.wownero_address }}</p>
|
||||
<p style="word-wrap: break-word;">Wownero Address: <span id="wowneroAddress">{{ meme.user.wownero_address | default('?') }}</span></p>
|
||||
</section>
|
||||
<footer class="modal-card-foot">
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
{% if not meme.approved %}
|
||||
@@ -63,19 +70,19 @@
|
||||
{% else %}
|
||||
<br/>
|
||||
<div id="tipButtons" class="columns" style="display:none;">
|
||||
<div class="column">
|
||||
<!-- <div class="column">
|
||||
<a class="button is-info is-12 column" onclick="tipAVAX()">Tip AVAX</a>
|
||||
</div>
|
||||
<div class="column">
|
||||
<a class="button is-info is-12 column" onclick="tipWOWX()">Tip WOWX</a>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="column">
|
||||
<a class="button is-info is-12 column" onclick="tipWOW()">Tip WOW</a>
|
||||
<a class="button is-info is-12 column" onclick="tipWOW()">Tip</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mintButton" class="columns" style="display:none;">
|
||||
<div class="column">
|
||||
<a class="button is-danger is-12 column" onclick="mint()">Mint</a>
|
||||
<a class="button is-danger is-12 column" onclick="mint()" id="mintButtonLoading">Mint</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -96,8 +103,23 @@
|
||||
} else {
|
||||
document.getElementById('mintButton').style.display = "flex";
|
||||
}
|
||||
try {
|
||||
_walletAddress = w3.utils.toChecksumAddress('{{ meme.user.public_address }}');
|
||||
const userProfile = await contract.methods.userProfile(_walletAddress).call();
|
||||
console.log(userProfile)
|
||||
if (userProfile.wowneroAddress){document.getElementById('wowneroAddress').innerHTML = userProfile.wowneroAddress};
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
|
||||
async function tipWOW() {
|
||||
document.getElementById('profileModal').classList.add('is-active');
|
||||
document.getElementById('closeModal').onclick = () => {
|
||||
document.getElementById('profileModal').classList.remove('is-active');
|
||||
}
|
||||
}
|
||||
|
||||
async function tipAVAX() {
|
||||
const tokenId = await getTokenID('{{ meme.meta_ipfs_hash }}');
|
||||
const walletAddress = await getMetamaskAccount();
|
||||
@@ -110,7 +132,7 @@
|
||||
notif(`Tipping meme "{{ meme.id | shorten_address }}" by "{{ meme.user.handle }} ({{ meme.user.public_address | shorten_address }})" to the Avalanche blockchain.`, 'info');
|
||||
let res = await contract.methods.tipAVAX(tokenId).send({
|
||||
from: walletAddress,
|
||||
value: 1000000000000000,
|
||||
value: 1,
|
||||
gasPrice: gasPrice,
|
||||
gas: gasLimit
|
||||
});
|
||||
@@ -126,6 +148,7 @@
|
||||
notif('Already minted!', 'warning');
|
||||
return
|
||||
}
|
||||
document.getElementById('mintButtonLoading').classList.add('is-active');
|
||||
const walletAddress = await getMetamaskAccount();
|
||||
const gasPrice = await w3.eth.getGasPrice();
|
||||
const gasLimit = await contract.methods.mint("{{ meme.meta_ipfs_hash }}", "{{ meme.user.public_address }}").estimateGas({from: walletAddress}, function(err, gas){
|
||||
@@ -140,6 +163,7 @@
|
||||
gas: gasLimit
|
||||
});
|
||||
console.log(res);
|
||||
document.getElementById('mintButtonLoading').classList.remove('is-active');
|
||||
window.location.href = "";
|
||||
} catch(e) {
|
||||
notif(e.message, 'warning');
|
||||
|
||||
Reference in New Issue
Block a user