diff --git a/.gitignore b/.gitignore index 2e1118c..b04b154 100644 --- a/.gitignore +++ b/.gitignore @@ -132,9 +132,6 @@ dmypy.json data/ go-ipfs/ avalanchego-v1.7.3 -*jpg -*png -*svg *mp4 *webp *mkv diff --git a/suchwowx/cli/cli.py b/suchwowx/cli/cli.py index 7f8fdc1..bb6c005 100644 --- a/suchwowx/cli/cli.py +++ b/suchwowx/cli/cli.py @@ -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) diff --git a/suchwowx/config.py b/suchwowx/config.py index 412379f..8468944 100644 --- a/suchwowx/config.py +++ b/suchwowx/config.py @@ -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') diff --git a/suchwowx/factory.py b/suchwowx/factory.py index 49bf5f3..21f875b 100644 --- a/suchwowx/factory.py +++ b/suchwowx/factory.py @@ -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): diff --git a/suchwowx/helpers.py b/suchwowx/helpers.py index a3974d6..8b268dc 100644 --- a/suchwowx/helpers.py +++ b/suchwowx/helpers.py @@ -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) diff --git a/suchwowx/routes/meme.py b/suchwowx/routes/meme.py index aa81f10..3d0fcaf 100644 --- a/suchwowx/routes/meme.py +++ b/suchwowx/routes/meme.py @@ -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') diff --git a/suchwowx/static/css/custom.css b/suchwowx/static/css/custom.css index afdf0e6..f172702 100644 --- a/suchwowx/static/css/custom.css +++ b/suchwowx/static/css/custom.css @@ -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); +} diff --git a/suchwowx/static/img/logo.png b/suchwowx/static/img/logo.png new file mode 100644 index 0000000..08951f9 Binary files /dev/null and b/suchwowx/static/img/logo.png differ diff --git a/suchwowx/templates/includes/meme_card.html b/suchwowx/templates/includes/meme_card.html index f51346a..15ce290 100644 --- a/suchwowx/templates/includes/meme_card.html +++ b/suchwowx/templates/includes/meme_card.html @@ -1,8 +1,9 @@ {# expects meme var #} -
+
diff --git a/suchwowx/templates/meme.html b/suchwowx/templates/meme.html index f572bb2..522a1d3 100644 --- a/suchwowx/templates/meme.html +++ b/suchwowx/templates/meme.html @@ -19,6 +19,7 @@
+ {% if meme.file_name %} {% if meme.file_name.endswith('mp4') %}
{% if not meme.approved %} @@ -63,19 +70,19 @@ {% else %}