From 1f5b86fabddea39161ab44b0fec36882d21a8597 Mon Sep 17 00:00:00 2001 From: Mohamad Bastin Date: Tue, 24 Oct 2023 15:41:31 +0200 Subject: [PATCH 01/13] change global setting field names --- faucet/admin.py | 33 +++--- ...limit_globalsettings_gastap_claim_limit.py | 18 +++ ...globalsettings_gastap_round_claim_limit.py | 18 +++ ...obalsettings_tokentap_round_claim_limit.py | 18 +++ ...obalsettings_prizetap_round_claim_limit.py | 18 +++ faucet/models.py | 104 +++++++----------- .../migrations/0019_alter_constraint_name.py | 18 +++ 7 files changed, 145 insertions(+), 82 deletions(-) create mode 100644 faucet/migrations/0060_rename_weekly_chain_claim_limit_globalsettings_gastap_claim_limit.py create mode 100644 faucet/migrations/0061_rename_gastap_claim_limit_globalsettings_gastap_round_claim_limit.py create mode 100644 faucet/migrations/0062_rename_tokentap_weekly_claim_limit_globalsettings_tokentap_round_claim_limit.py create mode 100644 faucet/migrations/0063_rename_prizetap_weekly_claim_limit_globalsettings_prizetap_round_claim_limit.py create mode 100644 tokenTap/migrations/0019_alter_constraint_name.py diff --git a/faucet/admin.py b/faucet/admin.py index ccb83759..e95f9b50 100644 --- a/faucet/admin.py +++ b/faucet/admin.py @@ -1,5 +1,15 @@ from django.contrib import admin -from .models import * + +from .models import ( + BrightUser, + Chain, + ClaimReceipt, + DonationReceipt, + GlobalSettings, + LightningConfig, + TransactionBatch, + WalletAccount, +) class ChainAdmin(admin.ModelAdmin): @@ -28,8 +38,8 @@ def last_updated_with_seconds(obj): class TXHashFilter(admin.SimpleListFilter): - title = 'has tx hash' # or use _('country') for translated title - parameter_name = 'has_tx_hash' + title = "has tx hash" # or use _('country') for translated title + parameter_name = "has_tx_hash" def lookups(self, request, model_admin): return ( @@ -66,8 +76,8 @@ class WalletAccountAdmin(admin.ModelAdmin): class GlobalSettingsAdmin(admin.ModelAdmin): - list_display = ["pk", "weekly_chain_claim_limit", "tokentap_weekly_claim_limit"] - list_editable = ["weekly_chain_claim_limit", "tokentap_weekly_claim_limit"] + list_display = ["pk", "gastap_round_claim_limit", "tokentap_round_claim_limit"] + list_editable = ["gastap_round_claim_limit", "tokentap_round_claim_limit"] class TransactionBatchAdmin(admin.ModelAdmin): @@ -92,16 +102,9 @@ class LightningConfigAdmin(admin.ModelAdmin): class DonationReceiptAdmin(admin.ModelAdmin): - list_display = [ - 'tx_hash', - 'user_profile', - 'chain', - 'value', - 'total_price', - 'datetime' - ] - search_fields = ['tx_hash'] - list_filter = ['chain', 'user_profile'] + list_display = ["tx_hash", "user_profile", "chain", "value", "total_price", "datetime"] + search_fields = ["tx_hash"] + list_filter = ["chain", "user_profile"] admin.site.register(WalletAccount, WalletAccountAdmin) diff --git a/faucet/migrations/0060_rename_weekly_chain_claim_limit_globalsettings_gastap_claim_limit.py b/faucet/migrations/0060_rename_weekly_chain_claim_limit_globalsettings_gastap_claim_limit.py new file mode 100644 index 00000000..553c8071 --- /dev/null +++ b/faucet/migrations/0060_rename_weekly_chain_claim_limit_globalsettings_gastap_claim_limit.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2023-10-24 13:33 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('faucet', '0059_chain_explorer_api_key_chain_explorer_api_url'), + ] + + operations = [ + migrations.RenameField( + model_name='globalsettings', + old_name='weekly_chain_claim_limit', + new_name='gastap_claim_limit', + ), + ] diff --git a/faucet/migrations/0061_rename_gastap_claim_limit_globalsettings_gastap_round_claim_limit.py b/faucet/migrations/0061_rename_gastap_claim_limit_globalsettings_gastap_round_claim_limit.py new file mode 100644 index 00000000..ab52234f --- /dev/null +++ b/faucet/migrations/0061_rename_gastap_claim_limit_globalsettings_gastap_round_claim_limit.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2023-10-24 13:34 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('faucet', '0060_rename_weekly_chain_claim_limit_globalsettings_gastap_claim_limit'), + ] + + operations = [ + migrations.RenameField( + model_name='globalsettings', + old_name='gastap_claim_limit', + new_name='gastap_round_claim_limit', + ), + ] diff --git a/faucet/migrations/0062_rename_tokentap_weekly_claim_limit_globalsettings_tokentap_round_claim_limit.py b/faucet/migrations/0062_rename_tokentap_weekly_claim_limit_globalsettings_tokentap_round_claim_limit.py new file mode 100644 index 00000000..fe8c1d4a --- /dev/null +++ b/faucet/migrations/0062_rename_tokentap_weekly_claim_limit_globalsettings_tokentap_round_claim_limit.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2023-10-24 13:35 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('faucet', '0061_rename_gastap_claim_limit_globalsettings_gastap_round_claim_limit'), + ] + + operations = [ + migrations.RenameField( + model_name='globalsettings', + old_name='tokentap_weekly_claim_limit', + new_name='tokentap_round_claim_limit', + ), + ] diff --git a/faucet/migrations/0063_rename_prizetap_weekly_claim_limit_globalsettings_prizetap_round_claim_limit.py b/faucet/migrations/0063_rename_prizetap_weekly_claim_limit_globalsettings_prizetap_round_claim_limit.py new file mode 100644 index 00000000..f4ffffbe --- /dev/null +++ b/faucet/migrations/0063_rename_prizetap_weekly_claim_limit_globalsettings_prizetap_round_claim_limit.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2023-10-24 13:35 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('faucet', '0062_rename_tokentap_weekly_claim_limit_globalsettings_tokentap_round_claim_limit'), + ] + + operations = [ + migrations.RenameField( + model_name='globalsettings', + old_name='prizetap_weekly_claim_limit', + new_name='prizetap_round_claim_limit', + ), + ] diff --git a/faucet/models.py b/faucet/models.py index f0fd8d17..6e6a8e6e 100644 --- a/faucet/models.py +++ b/faucet/models.py @@ -1,25 +1,21 @@ -from decimal import Decimal -from datetime import datetime, timedelta +import binascii import logging -from django.db import models import uuid +from datetime import datetime, timedelta + +from bip_utils import Bip44, Bip44Coins +from django.conf import settings +from django.core.cache import cache +from django.db import models from django.utils import timezone from encrypted_model_fields.fields import EncryptedCharField -import binascii -from bip_utils import Bip44Coins, Bip44 -from web3.exceptions import TimeExhausted -from django.conf import settings -from authentication.models import NetworkTypes, UserProfile, Wallet -from solders.pubkey import Pubkey from solders.keypair import Keypair -from faucet.faucet_manager.lnpay_client import LNPayClient -from django.core.cache import cache -from core.models import BigNumField +from solders.pubkey import Pubkey +from authentication.models import NetworkTypes, UserProfile from brightIDfaucet.settings import BRIGHT_ID_INTERFACE - -# import django transaction -from django.db import transaction +from core.models import BigNumField +from faucet.faucet_manager.lnpay_client import LNPayClient def get_cache_time(id): @@ -29,22 +25,20 @@ def get_cache_time(id): class WalletAccount(models.Model): name = models.CharField(max_length=255, blank=True, null=True) private_key = EncryptedCharField(max_length=100) - network_type = models.CharField( - choices=NetworkTypes.networks, max_length=10, default=NetworkTypes.EVM - ) + network_type = models.CharField(choices=NetworkTypes.networks, max_length=10, default=NetworkTypes.EVM) @property def address(self): try: - node = Bip44.FromPrivateKey( - binascii.unhexlify(self.private_key), Bip44Coins.ETHEREUM - ) + node = Bip44.FromPrivateKey(binascii.unhexlify(self.private_key), Bip44Coins.ETHEREUM) return node.PublicKey().ToAddress() - except: + except Exception as e: + logging.exception(f"Error getting address for {self.name} error is {e}") try: keypair = Keypair.from_base58_string(self.private_key) return str(keypair.pubkey()) - except: + except Exception as e2: + logging.exception(f"Error getting address for {self.name} error is {e2}") pass def __str__(self) -> str: @@ -83,12 +77,8 @@ class BrightUser(models.Model): address = models.CharField(max_length=45, unique=True) context_id = models.UUIDField(default=uuid.uuid4, unique=True) - _verification_status = models.CharField( - max_length=1, choices=states, default=PENDING - ) - _last_verified_datetime = models.DateTimeField( - default=timezone.make_aware(datetime.utcfromtimestamp(0)) - ) + _verification_status = models.CharField(max_length=1, choices=states, default=PENDING) + _last_verified_datetime = models.DateTimeField(default=timezone.make_aware(datetime.utcfromtimestamp(0))) _sponsored = models.BooleanField(default=False) objects = BrightUserManager() @@ -191,9 +181,7 @@ def claims_count(): cached_count = cache.get("gastap_claims_count") if cached_count: return cached_count - count = ClaimReceipt.objects.filter( - _status__in=[ClaimReceipt.VERIFIED, BrightUser.VERIFIED] - ).count() + count = ClaimReceipt.objects.filter(_status__in=[ClaimReceipt.VERIFIED, BrightUser.VERIFIED]).count() cache.set("gastap_claims_count", count, 600) return count @@ -222,9 +210,7 @@ class Chain(models.Model): fund_manager_address = models.CharField(max_length=255) tokentap_contract_address = models.CharField(max_length=255, null=True, blank=True) - wallet = models.ForeignKey( - WalletAccount, related_name="chains", on_delete=models.PROTECT - ) + wallet = models.ForeignKey(WalletAccount, related_name="chains", on_delete=models.PROTECT) max_gas_price = models.BigIntegerField(default=250000000000) gas_multiplier = models.FloatField(default=1) @@ -232,9 +218,7 @@ class Chain(models.Model): needs_funding = models.BooleanField(default=False) is_testnet = models.BooleanField(default=False) - chain_type = models.CharField( - max_length=10, choices=NetworkTypes.networks, default=NetworkTypes.EVM - ) + chain_type = models.CharField(max_length=10, choices=NetworkTypes.networks, default=NetworkTypes.EVM) order = models.IntegerField(default=0) is_active = models.BooleanField(default=True) @@ -276,9 +260,7 @@ def get_manager_balance(self): if self.chain_type == NetworkTypes.EVM or int(self.chain_id) == 500: if self.chain_id == 500: logging.debug("chain XDC NONEVM is checking its balances") - funds = EVMFundManager(self).w3.eth.get_balance( - self.fund_manager_address - ) + funds = EVMFundManager(self).w3.eth.get_balance(self.fund_manager_address) return funds elif self.chain_type == NetworkTypes.SOLANA: @@ -295,9 +277,7 @@ def get_manager_balance(self): raise Exception("Invalid chain type") except Exception as e: - logging.exception( - f"Error getting manager balance for {self.chain_name} error is {e}" - ) + logging.exception(f"Error getting manager balance for {self.chain_name} error is {e}") return 0 @property @@ -318,9 +298,7 @@ def get_wallet_balance(self): return EVMFundManager(self).w3.eth.get_balance(self.wallet.address) elif self.chain_type == NetworkTypes.SOLANA: fund_manager = SolanaFundManager(self) - v = fund_manager.w3.get_balance( - Pubkey.from_string(self.wallet.address) - ).value + v = fund_manager.w3.get_balance(Pubkey.from_string(self.wallet.address)).value return v elif self.chain_type == NetworkTypes.LIGHTNING: lnpay_client = LNPayClient( @@ -331,9 +309,7 @@ def get_wallet_balance(self): return lnpay_client.get_balance() raise Exception("Invalid chain type") except Exception as e: - logging.exception( - f"Error getting wallet balance for {self.chain_name} error is {e}" - ) + logging.exception(f"Error getting wallet balance for {self.chain_name} error is {e}") return 0 @property @@ -352,7 +328,8 @@ def gas_price(self): from faucet.faucet_manager.fund_manager import EVMFundManager return EVMFundManager(self).w3.eth.gas_price - except: + except Exception as e: + logging.exception(f"Error getting gas price for {self.chain_name} error is {e}") return self.max_gas_price + 1 @property @@ -364,7 +341,8 @@ def is_gas_price_too_high(self): from faucet.faucet_manager.fund_manager import EVMFundManager return EVMFundManager(self).is_gas_price_too_high - except: + except Exception as e: + logging.exception(f"Error getting gas price for {self.chain_name} error is {e}") return True @property @@ -384,9 +362,7 @@ def total_claims(self): @property def total_claims_since_last_monday(self): - cached_total_claims_since_last_monday = cache.get( - f"gas_tap_chain_total_claims_since_last_monday_{self.pk}" - ) + cached_total_claims_since_last_monday = cache.get(f"gas_tap_chain_total_claims_since_last_monday_{self.pk}") if cached_total_claims_since_last_monday: return cached_total_claims_since_last_monday from faucet.faucet_manager.claim_manager import WeeklyCreditStrategy @@ -405,9 +381,7 @@ def total_claims_since_last_monday(self): @property def total_claims_for_last_round(self): - cached_total_claims_for_last_round = cache.get( - f"gas_tap_chain_total_claims_for_last_round_{self.pk}" - ) + cached_total_claims_for_last_round = cache.get(f"gas_tap_chain_total_claims_for_last_round_{self.pk}") if cached_total_claims_for_last_round: return cached_total_claims_for_last_round from faucet.faucet_manager.claim_manager import WeeklyCreditStrategy @@ -427,9 +401,7 @@ def total_claims_for_last_round(self): @property def total_claims_since_last_round(self): - cached_total_claims_since_last_round = cache.get( - f"gas_tap_chain_total_claims_since_last_round_{self.pk}" - ) + cached_total_claims_since_last_round = cache.get(f"gas_tap_chain_total_claims_since_last_round_{self.pk}") if cached_total_claims_since_last_round: return cached_total_claims_since_last_round from faucet.faucet_manager.claim_manager import WeeklyCreditStrategy @@ -448,16 +420,14 @@ def total_claims_since_last_round(self): class GlobalSettings(models.Model): - weekly_chain_claim_limit = models.IntegerField(default=5) - tokentap_weekly_claim_limit = models.IntegerField(default=3) - prizetap_weekly_claim_limit = models.IntegerField(default=3) + gastap_round_claim_limit = models.IntegerField(default=5) + tokentap_round_claim_limit = models.IntegerField(default=3) + prizetap_round_claim_limit = models.IntegerField(default=3) is_gas_tap_available = models.BooleanField(default=True) class TransactionBatch(models.Model): - chain = models.ForeignKey( - Chain, related_name="batches", on_delete=models.PROTECT, db_index=True - ) + chain = models.ForeignKey(Chain, related_name="batches", on_delete=models.PROTECT, db_index=True) datetime = models.DateTimeField(auto_now_add=True) tx_hash = models.CharField(max_length=255, blank=True, null=True, db_index=True) diff --git a/tokenTap/migrations/0019_alter_constraint_name.py b/tokenTap/migrations/0019_alter_constraint_name.py new file mode 100644 index 00000000..6092aee2 --- /dev/null +++ b/tokenTap/migrations/0019_alter_constraint_name.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2023-10-24 13:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tokenTap', '0018_constraint_icon_url'), + ] + + operations = [ + migrations.AlterField( + model_name='constraint', + name='name', + field=models.CharField(choices=[('BrightIDMeetVerification', 'BrightIDMeetVerification'), ('BrightIDAuraVerification', 'BrightIDAuraVerification'), ('OncePerWeekVerification', 'OncePerWeekVerification'), ('OncePerMonthVerification', 'OncePerMonthVerification'), ('OnceInALifeTimeVerification', 'OnceInALifeTimeVerification'), ('OptimismHasClaimedGasInThisRound', 'OptimismHasClaimedGasInThisRound')], max_length=255, unique=True), + ), + ] From 20bf3bf5375ee744e94d99581906bea9c8550388 Mon Sep 17 00:00:00 2001 From: Shayan Shiravani Date: Thu, 26 Oct 2023 17:43:11 +0330 Subject: [PATCH 02/13] Fix prizetap auto tasks according to new contracts --- brightIDfaucet/celery.py | 28 +- prizetap/constants.py | 5316 +++++------------ .../migrations/0036_raffle_winners_count.py | 18 + .../migrations/0037_alter_raffle_status.py | 18 + prizetap/models.py | 46 +- prizetap/tasks.py | 189 +- prizetap/utils.py | 78 +- 7 files changed, 1744 insertions(+), 3949 deletions(-) create mode 100644 prizetap/migrations/0036_raffle_winners_count.py create mode 100644 prizetap/migrations/0037_alter_raffle_status.py diff --git a/brightIDfaucet/celery.py b/brightIDfaucet/celery.py index 8e010675..29f4112c 100644 --- a/brightIDfaucet/celery.py +++ b/brightIDfaucet/celery.py @@ -38,34 +38,26 @@ "task": "faucet.tasks.update_tokentap_claim_for_verified_lightning_claims", "schedule": 3, }, - 'update-tokens-price': { + "update-tokens-price": { "task": "faucet.tasks.update_tokens_price", "schedule": 600, }, - 'update-donation-receipt-status': { + "update-donation-receipt-status": { "task": "faucet.tasks.update_donation_receipt_pending_status", "schedule": 180, }, - "draw-prizetap-raffles": { - "task": "prizetap.tasks.draw_the_expired_raffles", - "schedule": 300 - }, - "set-raffle-winner": { - "task": "prizetap.tasks.set_the_winner_of_raffles", - "schedule": 300 + "request-random-words-for-raffles": { + "task": "prizetap.tasks.request_random_words_for_expired_raffles", + "schedule": 120, }, + "set-raffle-random-words": {"task": "prizetap.tasks.set_raffle_random_words", "schedule": 120}, + "set-raffle-winners": {"task": "prizetap.tasks.set_raffle_winners", "schedule": 300}, + "get-raffle-winners": {"task": "prizetap.tasks.get_raffle_winners", "schedule": 300}, "request-random-words-for-linea-raffles": { "task": "prizetap.tasks.request_random_words_for_expired_linea_raffles", - "schedule": 150 - }, - "draw-linea-raffles": { - "task": "prizetap.tasks.draw_expired_linea_raffles", - "schedule": 60 + "schedule": 150, }, - "set-linea-raffle-winners": { - "task": "prizetap.tasks.set_the_winner_of_linea_raffles", - "schedule": 60 - } + "set-linea-raffle-winners": {"task": "prizetap.tasks.set_the_winner_of_linea_raffles", "schedule": 60}, } # Load task modules from all registered Django apps. diff --git a/prizetap/constants.py b/prizetap/constants.py index 840296da..bf271bb0 100644 --- a/prizetap/constants.py +++ b/prizetap/constants.py @@ -1,4501 +1,2161 @@ PRIZETAP_ERC20_ABI = [ - { - "inputs": [ - { - "internalType": "address", - "name": "_chainlinkVRFCoordinator", - "type": "address" - }, - { - "internalType": "uint64", - "name": "_chainlinkVRFSubscriptionId", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "_chainlinkKeyHash", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "_muonAppId", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "parity", - "type": "uint8" - } + { + "inputs": [ + {"internalType": "uint256", "name": "_muonAppId", "type": "uint256"}, + { + "components": [ + {"internalType": "uint256", "name": "x", "type": "uint256"}, + {"internalType": "uint8", "name": "parity", "type": "uint8"}, + ], + "internalType": "struct IMuonClient.PublicKey", + "name": "_muonPublicKey", + "type": "tuple", + }, + {"internalType": "address", "name": "_muon", "type": "address"}, + {"internalType": "address", "name": "_muonValidGateway", "type": "address"}, + {"internalType": "address", "name": "_admin", "type": "address"}, + {"internalType": "address", "name": "_operator", "type": "address"}, + ], + "stateMutability": "nonpayable", + "type": "constructor", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "address", "name": "user", "type": "address"}, + {"indexed": False, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"indexed": False, "internalType": "uint256", "name": "multiplier", "type": "uint256"}, + ], + "name": "Participate", + "type": "event", + }, + { + "anonymous": False, + "inputs": [{"indexed": False, "internalType": "address", "name": "account", "type": "address"}], + "name": "Paused", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"indexed": True, "internalType": "address", "name": "winner", "type": "address"}, + ], + "name": "PrizeClaimed", + "type": "event", + }, + { + "anonymous": False, + "inputs": [{"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}], + "name": "PrizeRefunded", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "address", "name": "initiator", "type": "address"}, + {"indexed": False, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + ], + "name": "RaffleCreated", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"indexed": True, "internalType": "address", "name": "rejector", "type": "address"}, + ], + "name": "RaffleRejected", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "bytes32", "name": "previousAdminRole", "type": "bytes32"}, + {"indexed": True, "internalType": "bytes32", "name": "newAdminRole", "type": "bytes32"}, + ], + "name": "RoleAdminChanged", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "address", "name": "account", "type": "address"}, + {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, + ], + "name": "RoleGranted", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "address", "name": "account", "type": "address"}, + {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, + ], + "name": "RoleRevoked", + "type": "event", + }, + { + "anonymous": False, + "inputs": [{"indexed": False, "internalType": "address", "name": "account", "type": "address"}], + "name": "Unpaused", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"indexed": False, "internalType": "uint256", "name": "fromId", "type": "uint256"}, + {"indexed": False, "internalType": "uint256", "name": "toId", "type": "uint256"}, + ], + "name": "WinnersSpecified", + "type": "event", + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "MAX_NUM_WINNERS", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "OPERATOR_ROLE", + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], + "name": "claimPrize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "amount", "type": "uint256"}, + {"internalType": "address", "name": "currency", "type": "address"}, + {"internalType": "uint256", "name": "maxParticipants", "type": "uint256"}, + {"internalType": "uint256", "name": "maxMultiplier", "type": "uint256"}, + {"internalType": "uint256", "name": "startTime", "type": "uint256"}, + {"internalType": "uint256", "name": "endTime", "type": "uint256"}, + {"internalType": "uint256", "name": "winnersCount", "type": "uint256"}, + {"internalType": "bytes32", "name": "requirementsHash", "type": "bytes32"}, + ], + "name": "createRaffle", + "outputs": [], + "stateMutability": "payable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "fromId", "type": "uint256"}, + {"internalType": "uint256", "name": "toId", "type": "uint256"}, + ], + "name": "getParticipants", + "outputs": [{"internalType": "address[]", "name": "participants", "type": "address[]"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32"}], + "name": "getRoleAdmin", + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "fromId", "type": "uint256"}, + {"internalType": "uint256", "name": "toId", "type": "uint256"}, + ], + "name": "getWinners", + "outputs": [{"internalType": "address[]", "name": "winners", "type": "address[]"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], + "name": "getWinnersCount", + "outputs": [{"internalType": "uint256", "name": "winnersCount", "type": "uint256"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, + ], + "name": "hasRole", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "address", "name": "", "type": "address"}, + {"internalType": "uint256", "name": "", "type": "uint256"}, + ], + "name": "isParticipated", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "address", "name": "", "type": "address"}, + ], + "name": "isWinner", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "address", "name": "", "type": "address"}, + ], + "name": "isWinnerClaimed", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "lastRaffleId", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "muon", + "outputs": [{"internalType": "contract IMuonClient", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "muonAppId", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "muonPublicKey", + "outputs": [ + {"internalType": "uint256", "name": "x", "type": "uint256"}, + {"internalType": "uint8", "name": "parity", "type": "uint8"}, + ], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "muonValidGateway", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "address", "name": "", "type": "address"}, + {"internalType": "uint256", "name": "", "type": "uint256"}, + ], + "name": "participantPositions", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "multiplier", "type": "uint256"}, + {"internalType": "bytes", "name": "reqId", "type": "bytes"}, + { + "components": [ + {"internalType": "uint256", "name": "signature", "type": "uint256"}, + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "nonce", "type": "address"}, + ], + "internalType": "struct IMuonClient.SchnorrSign", + "name": "signature", + "type": "tuple", + }, + {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, + ], + "name": "participateInRaffle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + {"inputs": [], "name": "pause", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, + { + "inputs": [], + "name": "paused", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "uint256", "name": "", "type": "uint256"}, + ], + "name": "raffleParticipants", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "uint256", "name": "", "type": "uint256"}, + ], + "name": "raffleWinners", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "name": "raffles", + "outputs": [ + {"internalType": "address", "name": "initiator", "type": "address"}, + {"internalType": "uint256", "name": "prizeAmount", "type": "uint256"}, + {"internalType": "address", "name": "currency", "type": "address"}, + {"internalType": "uint256", "name": "maxParticipants", "type": "uint256"}, + {"internalType": "uint256", "name": "maxMultiplier", "type": "uint256"}, + {"internalType": "uint256", "name": "startTime", "type": "uint256"}, + {"internalType": "uint256", "name": "endTime", "type": "uint256"}, + {"internalType": "uint256", "name": "lastParticipantIndex", "type": "uint256"}, + {"internalType": "uint256", "name": "lastWinnerIndex", "type": "uint256"}, + {"internalType": "uint256", "name": "participantsCount", "type": "uint256"}, + {"internalType": "uint256", "name": "winnersCount", "type": "uint256"}, + {"internalType": "bool", "name": "exists", "type": "bool"}, + {"internalType": "enum AbstractPrizetapRaffle.Status", "name": "status", "type": "uint8"}, + {"internalType": "bytes32", "name": "requirementsHash", "type": "bytes32"}, + ], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], + "name": "refundPrize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], + "name": "refundRemainingPrizes", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], + "name": "rejectRaffle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "address", "name": "_muonAddress", "type": "address"}], + "name": "setMuonAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "_muonAppId", "type": "uint256"}], + "name": "setMuonAppId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "address", "name": "_gatewayAddress", "type": "address"}], + "name": "setMuonGateway", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + { + "components": [ + {"internalType": "uint256", "name": "x", "type": "uint256"}, + {"internalType": "uint8", "name": "parity", "type": "uint8"}, + ], + "internalType": "struct IMuonClient.PublicKey", + "name": "_muonPublicKey", + "type": "tuple", + } + ], + "name": "setMuonPublicKey", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "expirationTime", "type": "uint256"}, + {"internalType": "uint256[]", "name": "randomNumbers", "type": "uint256[]"}, + {"internalType": "bytes", "name": "reqId", "type": "bytes"}, + { + "components": [ + {"internalType": "uint256", "name": "signature", "type": "uint256"}, + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "nonce", "type": "address"}, + ], + "internalType": "struct IMuonClient.SchnorrSign", + "name": "signature", + "type": "tuple", + }, + {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, + ], + "name": "setRaffleRandomNumbers", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "periodSeconds", "type": "uint256"}], + "name": "setValidationPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "toId", "type": "uint256"}, + ], + "name": "setWinners", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "bytes4", "name": "interfaceId", "type": "bytes4"}], + "name": "supportsInterface", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function", + }, + {"inputs": [], "name": "unpause", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, + { + "inputs": [], + "name": "validationPeriod", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "multiplier", "type": "uint256"}, + {"internalType": "bytes", "name": "reqId", "type": "bytes"}, + { + "components": [ + {"internalType": "uint256", "name": "signature", "type": "uint256"}, + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "nonce", "type": "address"}, + ], + "internalType": "struct IMuonClient.SchnorrSign", + "name": "sign", + "type": "tuple", + }, + {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, + ], + "name": "verifyParticipationSig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "expirationTime", "type": "uint256"}, + {"internalType": "uint256[]", "name": "randomNumbers", "type": "uint256[]"}, + {"internalType": "bytes", "name": "reqId", "type": "bytes"}, + { + "components": [ + {"internalType": "uint256", "name": "signature", "type": "uint256"}, + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "nonce", "type": "address"}, + ], + "internalType": "struct IMuonClient.SchnorrSign", + "name": "sign", + "type": "tuple", + }, + {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, + ], + "name": "verifyRandomNumberSig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, +] + +PRIZETAP_ERC721_ABI = [ + { + "inputs": [ + {"internalType": "uint256", "name": "_muonAppId", "type": "uint256"}, + { + "components": [ + {"internalType": "uint256", "name": "x", "type": "uint256"}, + {"internalType": "uint8", "name": "parity", "type": "uint8"}, + ], + "internalType": "struct IMuonClient.PublicKey", + "name": "_muonPublicKey", + "type": "tuple", + }, + {"internalType": "address", "name": "_muon", "type": "address"}, + {"internalType": "address", "name": "_muonValidGateway", "type": "address"}, + {"internalType": "address", "name": "_admin", "type": "address"}, + {"internalType": "address", "name": "_operator", "type": "address"}, + ], + "stateMutability": "nonpayable", + "type": "constructor", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "address", "name": "user", "type": "address"}, + {"indexed": False, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"indexed": False, "internalType": "uint256", "name": "multiplier", "type": "uint256"}, + ], + "name": "Participate", + "type": "event", + }, + { + "anonymous": False, + "inputs": [{"indexed": False, "internalType": "address", "name": "account", "type": "address"}], + "name": "Paused", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"indexed": True, "internalType": "address", "name": "winner", "type": "address"}, + ], + "name": "PrizeClaimed", + "type": "event", + }, + { + "anonymous": False, + "inputs": [{"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}], + "name": "PrizeRefunded", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "address", "name": "initiator", "type": "address"}, + {"indexed": False, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + ], + "name": "RaffleCreated", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"indexed": True, "internalType": "address", "name": "rejector", "type": "address"}, + ], + "name": "RaffleRejected", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "bytes32", "name": "previousAdminRole", "type": "bytes32"}, + {"indexed": True, "internalType": "bytes32", "name": "newAdminRole", "type": "bytes32"}, + ], + "name": "RoleAdminChanged", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "address", "name": "account", "type": "address"}, + {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, + ], + "name": "RoleGranted", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "address", "name": "account", "type": "address"}, + {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, + ], + "name": "RoleRevoked", + "type": "event", + }, + { + "anonymous": False, + "inputs": [{"indexed": False, "internalType": "address", "name": "account", "type": "address"}], + "name": "Unpaused", + "type": "event", + }, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"indexed": False, "internalType": "uint256", "name": "fromId", "type": "uint256"}, + {"indexed": False, "internalType": "uint256", "name": "toId", "type": "uint256"}, + ], + "name": "WinnersSpecified", + "type": "event", + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "MAX_NUM_WINNERS", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "OPERATOR_ROLE", + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "_ERC721_RECEIVED", + "outputs": [{"internalType": "bytes4", "name": "", "type": "bytes4"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], + "name": "claimPrize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "address", "name": "collection", "type": "address"}, + {"internalType": "uint256[]", "name": "tokenIds", "type": "uint256[]"}, + {"internalType": "uint256", "name": "maxParticipants", "type": "uint256"}, + {"internalType": "uint256", "name": "maxMultiplier", "type": "uint256"}, + {"internalType": "uint256", "name": "startTime", "type": "uint256"}, + {"internalType": "uint256", "name": "endTime", "type": "uint256"}, + {"internalType": "uint256", "name": "winnersCount", "type": "uint256"}, + {"internalType": "bytes32", "name": "requirementsHash", "type": "bytes32"}, + ], + "name": "createRaffle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "fromId", "type": "uint256"}, + {"internalType": "uint256", "name": "toId", "type": "uint256"}, + ], + "name": "getParticipants", + "outputs": [{"internalType": "address[]", "name": "participants", "type": "address[]"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32"}], + "name": "getRoleAdmin", + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "fromId", "type": "uint256"}, + {"internalType": "uint256", "name": "toId", "type": "uint256"}, + ], + "name": "getWinners", + "outputs": [{"internalType": "address[]", "name": "winners", "type": "address[]"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], + "name": "getWinnersCount", + "outputs": [{"internalType": "uint256", "name": "winnersCount", "type": "uint256"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, + ], + "name": "hasRole", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "address", "name": "", "type": "address"}, + {"internalType": "uint256", "name": "", "type": "uint256"}, + ], + "name": "isParticipated", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "address", "name": "", "type": "address"}, + ], + "name": "isWinner", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "address", "name": "", "type": "address"}, + ], + "name": "isWinnerClaimed", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "lastRaffleId", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "muon", + "outputs": [{"internalType": "contract IMuonClient", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "muonAppId", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "muonPublicKey", + "outputs": [ + {"internalType": "uint256", "name": "x", "type": "uint256"}, + {"internalType": "uint8", "name": "parity", "type": "uint8"}, + ], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [], + "name": "muonValidGateway", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "address", "name": "", "type": "address"}, + {"internalType": "address", "name": "", "type": "address"}, + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "bytes", "name": "", "type": "bytes"}, + ], + "name": "onERC721Received", + "outputs": [{"internalType": "bytes4", "name": "", "type": "bytes4"}], + "stateMutability": "pure", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "address", "name": "", "type": "address"}, + {"internalType": "uint256", "name": "", "type": "uint256"}, + ], + "name": "participantPositions", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "multiplier", "type": "uint256"}, + {"internalType": "bytes", "name": "reqId", "type": "bytes"}, + { + "components": [ + {"internalType": "uint256", "name": "signature", "type": "uint256"}, + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "nonce", "type": "address"}, + ], + "internalType": "struct IMuonClient.SchnorrSign", + "name": "signature", + "type": "tuple", + }, + {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, + ], + "name": "participateInRaffle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + {"inputs": [], "name": "pause", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, + { + "inputs": [], + "name": "paused", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "uint256", "name": "", "type": "uint256"}, ], - "internalType": "struct IMuonClient.PublicKey", - "name": "_muonPublicKey", - "type": "tuple" - }, - { - "internalType": "address", - "name": "_muon", - "type": "address" - }, - { - "internalType": "address", - "name": "_muonValidGateway", - "type": "address" - }, - { - "internalType": "address", - "name": "_admin", - "type": "address" - }, - { - "internalType": "address", - "name": "_operator", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "have", - "type": "address" - }, - { - "internalType": "address", - "name": "want", - "type": "address" - } - ], - "name": "OnlyCoordinatorCanFulfill", - "type": "error" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": False, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": False, - "internalType": "uint256", - "name": "multiplier", - "type": "uint256" - } - ], - "name": "Participate", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": True, - "internalType": "address", - "name": "winner", - "type": "address" - } - ], - "name": "PrizeClaimed", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "PrizeRefunded", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "address", - "name": "initiator", - "type": "address" - }, - { - "indexed": False, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "RaffleCreated", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": True, - "internalType": "address", - "name": "organizer", - "type": "address" - } - ], - "name": "RaffleHeld", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": True, - "internalType": "address", - "name": "rejector", - "type": "address" - } - ], - "name": "RaffleRejected", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "bytes32", - "name": "previousAdminRole", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "bytes32", - "name": "newAdminRole", - "type": "bytes32" - } - ], - "name": "RoleAdminChanged", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": True, - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "RoleGranted", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": True, - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "RoleRevoked", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - }, - { - "indexed": False, - "internalType": "uint256[]", - "name": "randomWords", - "type": "uint256[]" - } - ], - "name": "VRFRequestFulfilled", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - } - ], - "name": "VRFRequestSent", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": True, - "internalType": "address", - "name": "winner", - "type": "address" - } - ], - "name": "WinnerSpecified", - "type": "event" - }, - { - "inputs": [], - "name": "DEFAULT_ADMIN_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "OPERATOR_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "claimPrize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "currency", - "type": "address" - }, - { - "internalType": "uint256", - "name": "maxParticipants", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxMultiplier", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "endTime", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "requirementsHash", - "type": "bytes32" - } - ], - "name": "createRaffle", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "getParticipants", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - } - ], - "name": "getRoleAdmin", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "grantRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "hasRole", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "heldRaffle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "isParticipated", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastRaffleId", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "muon", - "outputs": [ - { - "internalType": "contract IMuonClient", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "muonAppId", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "muonPublicKey", - "outputs": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "parity", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "muonValidGateway", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "multiplier", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "reqId", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signature", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "nonce", - "type": "address" - } + "name": "raffleParticipants", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "uint256", "name": "", "type": "uint256"}, ], - "internalType": "struct IMuonClient.SchnorrSign", - "name": "signature", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "gatewaySignature", - "type": "bytes" - } - ], - "name": "participateInRaffle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "raffles", - "outputs": [ - { - "internalType": "address", - "name": "initiator", - "type": "address" - }, - { - "internalType": "uint256", - "name": "prizeAmount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "currency", - "type": "address" - }, - { - "internalType": "uint256", - "name": "maxParticipants", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxMultiplier", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "endTime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "participantsCount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "winner", - "type": "address" - }, - { - "internalType": "bool", - "name": "exists", - "type": "bool" - }, - { - "internalType": "enum AbstractPrizetapRaffle.Status", - "name": "status", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "requirementsHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - }, - { - "internalType": "uint256[]", - "name": "randomWords", - "type": "uint256[]" - } - ], - "name": "rawFulfillRandomWords", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "refundPrize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "rejectRaffle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "renounceRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "revokeRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint32", - "name": "gaslimit", - "type": "uint32" - } - ], - "name": "setCallbackGasLimit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_muonAddress", - "type": "address" - } - ], - "name": "setMuonAddress", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_muonAppId", - "type": "uint256" - } - ], - "name": "setMuonAppId", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_gatewayAddress", - "type": "address" - } - ], - "name": "setMuonGateway", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "parity", - "type": "uint8" - } + "name": "raffleWinners", + "outputs": [{"internalType": "address", "name": "", "type": "address"}], + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "name": "raffles", + "outputs": [ + {"internalType": "address", "name": "initiator", "type": "address"}, + {"internalType": "address", "name": "collection", "type": "address"}, + {"internalType": "uint256", "name": "maxParticipants", "type": "uint256"}, + {"internalType": "uint256", "name": "maxMultiplier", "type": "uint256"}, + {"internalType": "uint256", "name": "startTime", "type": "uint256"}, + {"internalType": "uint256", "name": "endTime", "type": "uint256"}, + {"internalType": "uint256", "name": "lastParticipantIndex", "type": "uint256"}, + {"internalType": "uint256", "name": "lastWinnerIndex", "type": "uint256"}, + {"internalType": "uint256", "name": "participantsCount", "type": "uint256"}, + {"internalType": "uint256", "name": "winnersCount", "type": "uint256"}, + {"internalType": "uint256", "name": "lastNotClaimedTokenIndex", "type": "uint256"}, + {"internalType": "bool", "name": "exists", "type": "bool"}, + {"internalType": "enum AbstractPrizetapRaffle.Status", "name": "status", "type": "uint8"}, + {"internalType": "bytes32", "name": "requirementsHash", "type": "bytes32"}, ], - "internalType": "struct IMuonClient.PublicKey", - "name": "_muonPublicKey", - "type": "tuple" - } - ], - "name": "setMuonPublicKey", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "periodSeconds", - "type": "uint256" - } - ], - "name": "setValidationPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "keyHash", - "type": "bytes32" - } - ], - "name": "setVrfKeyHash", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "count", - "type": "uint16" - } - ], - "name": "setVrfRequestConfirmations", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "id", - "type": "uint64" - } - ], - "name": "setVrfSubscriptionId", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validationPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "multiplier", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "reqId", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signature", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "nonce", - "type": "address" - } + "stateMutability": "view", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], + "name": "refundPrize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], + "name": "refundRemainingPrizes", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], + "name": "rejectRaffle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], - "internalType": "struct IMuonClient.SchnorrSign", - "name": "sign", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "gatewaySignature", - "type": "bytes" - } - ], - "name": "verifyTSSAndGateway", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "vrfRequests", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] - -PRIZETAP_ERC721_ABI = [ - { - "inputs": [ - { - "internalType": "address", - "name": "_chainlinkVRFCoordinator", - "type": "address" - }, - { - "internalType": "uint64", - "name": "_chainlinkVRFSubscriptionId", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "_chainlinkKeyHash", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "_muonAppId", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "parity", - "type": "uint8" - } + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], - "internalType": "struct IMuonClient.PublicKey", - "name": "_muonPublicKey", - "type": "tuple" - }, - { - "internalType": "address", - "name": "_muon", - "type": "address" - }, - { - "internalType": "address", - "name": "_muonValidGateway", - "type": "address" - }, - { - "internalType": "address", - "name": "_admin", - "type": "address" - }, - { - "internalType": "address", - "name": "_operator", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "have", - "type": "address" - }, - { - "internalType": "address", - "name": "want", - "type": "address" - } - ], - "name": "OnlyCoordinatorCanFulfill", - "type": "error" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": False, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": False, - "internalType": "uint256", - "name": "multiplier", - "type": "uint256" - } - ], - "name": "Participate", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": True, - "internalType": "address", - "name": "winner", - "type": "address" - } - ], - "name": "PrizeClaimed", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "PrizeRefunded", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "address", - "name": "initiator", - "type": "address" - }, - { - "indexed": False, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "RaffleCreated", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": True, - "internalType": "address", - "name": "organizer", - "type": "address" - } - ], - "name": "RaffleHeld", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": True, - "internalType": "address", - "name": "rejector", - "type": "address" - } - ], - "name": "RaffleRejected", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "bytes32", - "name": "previousAdminRole", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "bytes32", - "name": "newAdminRole", - "type": "bytes32" - } - ], - "name": "RoleAdminChanged", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": True, - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "RoleGranted", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": True, - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "RoleRevoked", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - }, - { - "indexed": False, - "internalType": "uint256[]", - "name": "randomWords", - "type": "uint256[]" - } - ], - "name": "VRFRequestFulfilled", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - } - ], - "name": "VRFRequestSent", - "type": "event" - }, - { - "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": True, - "internalType": "address", - "name": "winner", - "type": "address" - } - ], - "name": "WinnerSpecified", - "type": "event" - }, - { - "inputs": [], - "name": "DEFAULT_ADMIN_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "OPERATOR_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "_ERC721_RECEIVED", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "claimPrize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "collection", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxParticipants", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxMultiplier", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "endTime", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "requirementsHash", - "type": "bytes32" - } - ], - "name": "createRaffle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "getParticipants", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - } - ], - "name": "getRoleAdmin", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "grantRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "hasRole", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "heldRaffle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "isParticipated", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "lastRaffleId", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "muon", - "outputs": [ - { - "internalType": "contract IMuonClient", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "muonAppId", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "muonPublicKey", - "outputs": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "parity", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "muonValidGateway", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "onERC721Received", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "multiplier", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "reqId", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signature", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "nonce", - "type": "address" - } + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "address", "name": "_muonAddress", "type": "address"}], + "name": "setMuonAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "_muonAppId", "type": "uint256"}], + "name": "setMuonAppId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "address", "name": "_gatewayAddress", "type": "address"}], + "name": "setMuonGateway", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + { + "components": [ + {"internalType": "uint256", "name": "x", "type": "uint256"}, + {"internalType": "uint8", "name": "parity", "type": "uint8"}, + ], + "internalType": "struct IMuonClient.PublicKey", + "name": "_muonPublicKey", + "type": "tuple", + } ], - "internalType": "struct IMuonClient.SchnorrSign", - "name": "signature", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "gatewaySignature", - "type": "bytes" - } - ], - "name": "participateInRaffle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "raffles", - "outputs": [ - { - "internalType": "address", - "name": "initiator", - "type": "address" - }, - { - "internalType": "address", - "name": "collection", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxParticipants", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxMultiplier", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "endTime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "participantsCount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "winner", - "type": "address" - }, - { - "internalType": "bool", - "name": "exists", - "type": "bool" - }, - { - "internalType": "enum AbstractPrizetapRaffle.Status", - "name": "status", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "requirementsHash", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - }, - { - "internalType": "uint256[]", - "name": "randomWords", - "type": "uint256[]" - } - ], - "name": "rawFulfillRandomWords", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "refundPrize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], - "name": "rejectRaffle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "renounceRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "revokeRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint32", - "name": "gaslimit", - "type": "uint32" - } - ], - "name": "setCallbackGasLimit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_muonAddress", - "type": "address" - } - ], - "name": "setMuonAddress", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_muonAppId", - "type": "uint256" - } - ], - "name": "setMuonAppId", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_gatewayAddress", - "type": "address" - } - ], - "name": "setMuonGateway", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "parity", - "type": "uint8" - } + "name": "setMuonPublicKey", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "expirationTime", "type": "uint256"}, + {"internalType": "uint256[]", "name": "randomNumbers", "type": "uint256[]"}, + {"internalType": "bytes", "name": "reqId", "type": "bytes"}, + { + "components": [ + {"internalType": "uint256", "name": "signature", "type": "uint256"}, + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "nonce", "type": "address"}, + ], + "internalType": "struct IMuonClient.SchnorrSign", + "name": "signature", + "type": "tuple", + }, + {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, ], - "internalType": "struct IMuonClient.PublicKey", - "name": "_muonPublicKey", - "type": "tuple" - } - ], - "name": "setMuonPublicKey", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "periodSeconds", - "type": "uint256" - } - ], - "name": "setValidationPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "keyHash", - "type": "bytes32" - } - ], - "name": "setVrfKeyHash", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "count", - "type": "uint16" - } - ], - "name": "setVrfRequestConfirmations", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "id", - "type": "uint64" - } - ], - "name": "setVrfSubscriptionId", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "validationPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "multiplier", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "reqId", - "type": "bytes" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "signature", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "nonce", - "type": "address" - } + "name": "setRaffleRandomNumbers", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "uint256", "name": "periodSeconds", "type": "uint256"}], + "name": "setValidationPeriod", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "toId", "type": "uint256"}, ], - "internalType": "struct IMuonClient.SchnorrSign", - "name": "sign", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "gatewaySignature", - "type": "bytes" - } - ], - "name": "verifyTSSAndGateway", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "vrfRequests", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - } -] - -UNITAP_PASS_ABI = [ + "name": "setWinners", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [{"internalType": "bytes4", "name": "interfaceId", "type": "bytes4"}], + "name": "supportsInterface", + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], + "stateMutability": "view", + "type": "function", + }, + {"inputs": [], "name": "unpause", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, { "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" + "name": "validationPeriod", + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], + "stateMutability": "view", + "type": "function", }, { - "anonymous": False, "inputs": [ + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "multiplier", "type": "uint256"}, + {"internalType": "bytes", "name": "reqId", "type": "bytes"}, { - "indexed": True, - "internalType": "address", - "name": "owner", - "type": "address" + "components": [ + {"internalType": "uint256", "name": "signature", "type": "uint256"}, + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "nonce", "type": "address"}, + ], + "internalType": "struct IMuonClient.SchnorrSign", + "name": "sign", + "type": "tuple", }, + {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, + ], + "name": "verifyParticipationSig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, + { + "inputs": [ + {"internalType": "uint256", "name": "expirationTime", "type": "uint256"}, + {"internalType": "uint256[]", "name": "randomNumbers", "type": "uint256[]"}, + {"internalType": "bytes", "name": "reqId", "type": "bytes"}, { - "indexed": True, - "internalType": "address", - "name": "approved", - "type": "address" + "components": [ + {"internalType": "uint256", "name": "signature", "type": "uint256"}, + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "nonce", "type": "address"}, + ], + "internalType": "struct IMuonClient.SchnorrSign", + "name": "sign", + "type": "tuple", }, - { - "indexed": True, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } + {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, + ], + "name": "verifyRandomNumberSig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + }, +] + +UNITAP_PASS_ABI = [ + {"inputs": [], "stateMutability": "nonpayable", "type": "constructor"}, + { + "anonymous": False, + "inputs": [ + {"indexed": True, "internalType": "address", "name": "owner", "type": "address"}, + {"indexed": True, "internalType": "address", "name": "approved", "type": "address"}, + {"indexed": True, "internalType": "uint256", "name": "tokenId", "type": "uint256"}, ], "name": "Approval", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": True, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": False, - "internalType": "bool", - "name": "approved", - "type": "bool" - } + {"indexed": True, "internalType": "address", "name": "owner", "type": "address"}, + {"indexed": True, "internalType": "address", "name": "operator", "type": "address"}, + {"indexed": False, "internalType": "bool", "name": "approved", "type": "bool"}, ], "name": "ApprovalForAll", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "bytes32", - "name": "previousAdminRole", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "bytes32", - "name": "newAdminRole", - "type": "bytes32" - } + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "bytes32", "name": "previousAdminRole", "type": "bytes32"}, + {"indexed": True, "internalType": "bytes32", "name": "newAdminRole", "type": "bytes32"}, ], "name": "RoleAdminChanged", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": True, - "internalType": "address", - "name": "sender", - "type": "address" - } + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "address", "name": "account", "type": "address"}, + {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, ], "name": "RoleGranted", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": True, - "internalType": "address", - "name": "sender", - "type": "address" - } + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "address", "name": "account", "type": "address"}, + {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, ], "name": "RoleRevoked", - "type": "event" + "type": "event", }, { "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "string", - "name": "baseURI", - "type": "string" - } - ], + "inputs": [{"indexed": False, "internalType": "string", "name": "baseURI", "type": "string"}], "name": "SetBaseURI", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": True, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": True, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } + {"indexed": True, "internalType": "address", "name": "from", "type": "address"}, + {"indexed": True, "internalType": "address", "name": "to", "type": "address"}, + {"indexed": True, "internalType": "uint256", "name": "tokenId", "type": "uint256"}, ], "name": "Transfer", - "type": "event" + "type": "event", }, { "inputs": [], "name": "DEFAULT_ADMIN_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "MINTER_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } + {"internalType": "address", "name": "to", "type": "address"}, + {"internalType": "uint256", "name": "tokenId", "type": "uint256"}, ], "name": "approve", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], + "inputs": [{"internalType": "address", "name": "owner", "type": "address"}], "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "baseURI", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], + "outputs": [{"internalType": "string", "name": "", "type": "string"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "tokenId", "type": "uint256"}], "name": "getApproved", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], + "outputs": [{"internalType": "address", "name": "", "type": "address"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - } - ], + "inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32"}], "name": "getRoleAdmin", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], "name": "grantRole", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], "name": "hasRole", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "operator", - "type": "address" - } + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "operator", "type": "address"}, ], "name": "isApprovedForAll", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], + "outputs": [{"internalType": "string", "name": "", "type": "string"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "tokenId", "type": "uint256"}], "name": "ownerOf", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], + "outputs": [{"internalType": "address", "name": "", "type": "address"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], "name": "renounceRole", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], "name": "revokeRole", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - } - ], + "inputs": [{"internalType": "address", "name": "to", "type": "address"}], "name": "safeMint", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } + {"internalType": "address", "name": "from", "type": "address"}, + {"internalType": "address", "name": "to", "type": "address"}, + {"internalType": "uint256", "name": "tokenId", "type": "uint256"}, ], "name": "safeTransferFrom", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } + {"internalType": "address", "name": "from", "type": "address"}, + {"internalType": "address", "name": "to", "type": "address"}, + {"internalType": "uint256", "name": "tokenId", "type": "uint256"}, + {"internalType": "bytes", "name": "data", "type": "bytes"}, ], "name": "safeTransferFrom", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } + {"internalType": "address", "name": "operator", "type": "address"}, + {"internalType": "bool", "name": "approved", "type": "bool"}, ], "name": "setApprovalForAll", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, - { - "inputs": [ - { - "internalType": "string", - "name": "baseURI_", - "type": "string" - } - ], + { + "inputs": [{"internalType": "string", "name": "baseURI_", "type": "string"}], "name": "setBaseURI", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], + "inputs": [{"internalType": "bytes4", "name": "interfaceId", "type": "bytes4"}], "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], + "outputs": [{"internalType": "string", "name": "", "type": "string"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "tokenIdCounter", - "outputs": [ - { - "internalType": "uint256", - "name": "idCounter", - "type": "uint256" - } - ], + "outputs": [{"internalType": "uint256", "name": "idCounter", "type": "uint256"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "tokenId", "type": "uint256"}], "name": "tokenURI", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], + "outputs": [{"internalType": "string", "name": "", "type": "string"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } + {"internalType": "address", "name": "from", "type": "address"}, + {"internalType": "address", "name": "to", "type": "address"}, + {"internalType": "uint256", "name": "tokenId", "type": "uint256"}, ], "name": "transferFrom", "outputs": [], "stateMutability": "nonpayable", - "type": "function" - } + "type": "function", + }, ] VRF_CLIENT_ABI = [ { "inputs": [ - { - "internalType": "address", - "name": "_chainlinkVRFCoordinator", - "type": "address" - }, - { - "internalType": "uint64", - "name": "_chainlinkVRFSubscriptionId", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "_chainlinkKeyHash", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "_admin", - "type": "address" - }, - { - "internalType": "address", - "name": "_operator", - "type": "address" - } + {"internalType": "address", "name": "_chainlinkVRFCoordinator", "type": "address"}, + {"internalType": "uint64", "name": "_chainlinkVRFSubscriptionId", "type": "uint64"}, + {"internalType": "bytes32", "name": "_chainlinkKeyHash", "type": "bytes32"}, + {"internalType": "address", "name": "_admin", "type": "address"}, + {"internalType": "address", "name": "_operator", "type": "address"}, ], "stateMutability": "nonpayable", - "type": "constructor" + "type": "constructor", }, { "inputs": [ - { - "internalType": "address", - "name": "have", - "type": "address" - }, - { - "internalType": "address", - "name": "want", - "type": "address" - } + {"internalType": "address", "name": "have", "type": "address"}, + {"internalType": "address", "name": "want", "type": "address"}, ], "name": "OnlyCoordinatorCanFulfill", - "type": "error" + "type": "error", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "bytes32", - "name": "previousAdminRole", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "bytes32", - "name": "newAdminRole", - "type": "bytes32" - } + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "bytes32", "name": "previousAdminRole", "type": "bytes32"}, + {"indexed": True, "internalType": "bytes32", "name": "newAdminRole", "type": "bytes32"}, ], "name": "RoleAdminChanged", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": True, - "internalType": "address", - "name": "sender", - "type": "address" - } + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "address", "name": "account", "type": "address"}, + {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, ], "name": "RoleGranted", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": True, - "internalType": "address", - "name": "sender", - "type": "address" - } + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "address", "name": "account", "type": "address"}, + {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, ], "name": "RoleRevoked", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": False, - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - }, - { - "indexed": False, - "internalType": "uint256[]", - "name": "randomWords", - "type": "uint256[]" - } + {"indexed": False, "internalType": "uint256", "name": "requestId", "type": "uint256"}, + {"indexed": False, "internalType": "uint256[]", "name": "randomWords", "type": "uint256[]"}, ], "name": "VRFRequestFulfilled", - "type": "event" + "type": "event", }, { "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - } - ], + "inputs": [{"indexed": False, "internalType": "uint256", "name": "requestId", "type": "uint256"}], "name": "VRFRequestSent", - "type": "event" + "type": "event", }, { "inputs": [], "name": "DEFAULT_ADMIN_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "OPERATOR_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "callbackGasLimit", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], + "outputs": [{"internalType": "uint32", "name": "", "type": "uint32"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "chainlinkKeyHash", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "chainlinkVrfSubscriptionId", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], + "outputs": [{"internalType": "uint64", "name": "", "type": "uint64"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "requestId", "type": "uint256"}], "name": "getRandomWords", - "outputs": [ - { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - } - ], + "outputs": [{"internalType": "uint256[]", "name": "", "type": "uint256[]"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - } - ], + "inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32"}], "name": "getRoleAdmin", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], "name": "grantRole", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], "name": "hasRole", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "lastRequestId", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "uint256", - "name": "requestId", - "type": "uint256" - }, - { - "internalType": "uint256[]", - "name": "randomWords", - "type": "uint256[]" - } + {"internalType": "uint256", "name": "requestId", "type": "uint256"}, + {"internalType": "uint256[]", "name": "randomWords", "type": "uint256[]"}, ], "name": "rawFulfillRandomWords", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], "name": "renounceRole", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint32", - "name": "numWords", - "type": "uint32" - } - ], + "inputs": [{"internalType": "uint32", "name": "numWords", "type": "uint32"}], "name": "requestRandomWords", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], "name": "revokeRole", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint32", - "name": "gaslimit", - "type": "uint32" - } - ], + "inputs": [{"internalType": "uint32", "name": "gaslimit", "type": "uint32"}], "name": "setCallbackGasLimit", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "period", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "period", "type": "uint256"}], "name": "setValidityPeriod", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "bytes32", - "name": "keyHash", - "type": "bytes32" - } - ], + "inputs": [{"internalType": "bytes32", "name": "keyHash", "type": "bytes32"}], "name": "setVrfKeyHash", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint16", - "name": "count", - "type": "uint16" - } - ], + "inputs": [{"internalType": "uint16", "name": "count", "type": "uint16"}], "name": "setVrfRequestConfirmations", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint64", - "name": "id", - "type": "uint64" - } - ], + "inputs": [{"internalType": "uint64", "name": "id", "type": "uint64"}], "name": "setVrfSubscriptionId", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], + "inputs": [{"internalType": "bytes4", "name": "interfaceId", "type": "bytes4"}], "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "validityPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "vrfRequestConfirmations", - "outputs": [ - { - "internalType": "uint16", - "name": "", - "type": "uint16" - } - ], + "outputs": [{"internalType": "uint16", "name": "", "type": "uint16"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "name": "vrfRequests", "outputs": [ - { - "internalType": "uint256", - "name": "expirationTime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "numWords", - "type": "uint256" - } + {"internalType": "uint256", "name": "expirationTime", "type": "uint256"}, + {"internalType": "uint256", "name": "numWords", "type": "uint256"}, ], "stateMutability": "view", - "type": "function" - } + "type": "function", + }, ] LINEA_PRIZETAP_ABI = [ { "inputs": [ - { - "internalType": "uint256", - "name": "_muonAppId", - "type": "uint256" - }, + {"internalType": "uint256", "name": "_muonAppId", "type": "uint256"}, { "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "parity", - "type": "uint8" - } + {"internalType": "uint256", "name": "x", "type": "uint256"}, + {"internalType": "uint8", "name": "parity", "type": "uint8"}, ], "internalType": "struct IMuonClient.PublicKey", "name": "_muonPublicKey", - "type": "tuple" - }, - { - "internalType": "address", - "name": "_muon", - "type": "address" - }, - { - "internalType": "address", - "name": "_muonValidGateway", - "type": "address" - }, - { - "internalType": "address", - "name": "_admin", - "type": "address" + "type": "tuple", }, - { - "internalType": "address", - "name": "_operator", - "type": "address" - } + {"internalType": "address", "name": "_muon", "type": "address"}, + {"internalType": "address", "name": "_muonValidGateway", "type": "address"}, + {"internalType": "address", "name": "_admin", "type": "address"}, + {"internalType": "address", "name": "_operator", "type": "address"}, ], "stateMutability": "nonpayable", - "type": "constructor" + "type": "constructor", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "indexed": False, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": False, - "internalType": "uint256", - "name": "multiplier", - "type": "uint256" - } + {"indexed": True, "internalType": "address", "name": "user", "type": "address"}, + {"indexed": False, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"indexed": False, "internalType": "uint256", "name": "multiplier", "type": "uint256"}, ], "name": "Participate", - "type": "event" + "type": "event", }, { "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "address", - "name": "account", - "type": "address" - } - ], + "inputs": [{"indexed": False, "internalType": "address", "name": "account", "type": "address"}], "name": "Paused", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": True, - "internalType": "address", - "name": "winner", - "type": "address" - } + {"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"indexed": True, "internalType": "address", "name": "winner", "type": "address"}, ], "name": "PrizeClaimed", - "type": "event" + "type": "event", }, { "anonymous": False, - "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], + "inputs": [{"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}], "name": "PrizeRefunded", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "address", - "name": "initiator", - "type": "address" - }, - { - "indexed": False, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } + {"indexed": True, "internalType": "address", "name": "initiator", "type": "address"}, + {"indexed": False, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, ], "name": "RaffleCreated", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": True, - "internalType": "address", - "name": "rejector", - "type": "address" - } + {"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"indexed": True, "internalType": "address", "name": "rejector", "type": "address"}, ], "name": "RaffleRejected", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "bytes32", - "name": "previousAdminRole", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "bytes32", - "name": "newAdminRole", - "type": "bytes32" - } + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "bytes32", "name": "previousAdminRole", "type": "bytes32"}, + {"indexed": True, "internalType": "bytes32", "name": "newAdminRole", "type": "bytes32"}, ], "name": "RoleAdminChanged", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": True, - "internalType": "address", - "name": "sender", - "type": "address" - } + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "address", "name": "account", "type": "address"}, + {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, ], "name": "RoleGranted", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "indexed": True, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": True, - "internalType": "address", - "name": "sender", - "type": "address" - } + {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"indexed": True, "internalType": "address", "name": "account", "type": "address"}, + {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, ], "name": "RoleRevoked", - "type": "event" + "type": "event", }, { "anonymous": False, - "inputs": [ - { - "indexed": False, - "internalType": "address", - "name": "account", - "type": "address" - } - ], + "inputs": [{"indexed": False, "internalType": "address", "name": "account", "type": "address"}], "name": "Unpaused", - "type": "event" + "type": "event", }, { "anonymous": False, "inputs": [ - { - "indexed": True, - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "indexed": True, - "internalType": "address[]", - "name": "winner", - "type": "address[]" - } + {"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"indexed": True, "internalType": "address[]", "name": "winner", "type": "address[]"}, ], "name": "WinnersSpecified", - "type": "event" + "type": "event", }, { "inputs": [], - "name": "DEFAULT_ADMIN_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "MAX_NUM_WINNERS", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], + "outputs": [{"internalType": "uint32", "name": "", "type": "uint32"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "OPERATOR_ROLE", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "_ERC721_RECEIVED", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], + "outputs": [{"internalType": "bytes4", "name": "", "type": "bytes4"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "uint256", - "name": "_raffleId", - "type": "uint256" - }, - { - "internalType": "address[]", - "name": "_participants", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "_multipliers", - "type": "uint256[]" - } + {"internalType": "uint256", "name": "_raffleId", "type": "uint256"}, + {"internalType": "address[]", "name": "_participants", "type": "address[]"}, + {"internalType": "uint256[]", "name": "_multipliers", "type": "uint256[]"}, ], "name": "addParticipants", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], "name": "claimPrize", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "uint256", - "name": "maxParticipants", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxMultiplier", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "endTime", - "type": "uint256" - }, - { - "internalType": "uint32", - "name": "winnersCount", - "type": "uint32" - }, - { - "internalType": "bytes32", - "name": "requirementsHash", - "type": "bytes32" - } + {"internalType": "uint256", "name": "maxParticipants", "type": "uint256"}, + {"internalType": "uint256", "name": "maxMultiplier", "type": "uint256"}, + {"internalType": "uint256", "name": "startTime", "type": "uint256"}, + {"internalType": "uint256", "name": "endTime", "type": "uint256"}, + {"internalType": "uint32", "name": "winnersCount", "type": "uint32"}, + {"internalType": "bytes32", "name": "requirementsHash", "type": "bytes32"}, ], "name": "createRaffle", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expirationTime", - "type": "uint256" - }, - { - "internalType": "uint256[]", - "name": "randomNumbers", - "type": "uint256[]" - }, - { - "internalType": "bytes", - "name": "reqId", - "type": "bytes" - }, + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "expirationTime", "type": "uint256"}, + {"internalType": "uint256[]", "name": "randomNumbers", "type": "uint256[]"}, + {"internalType": "bytes", "name": "reqId", "type": "bytes"}, { "components": [ - { - "internalType": "uint256", - "name": "signature", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "nonce", - "type": "address" - } + {"internalType": "uint256", "name": "signature", "type": "uint256"}, + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "nonce", "type": "address"}, ], "internalType": "struct IMuonClient.SchnorrSign", "name": "signature", - "type": "tuple" + "type": "tuple", }, - { - "internalType": "bytes", - "name": "gatewaySignature", - "type": "bytes" - } + {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, ], "name": "drawRaffle", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], "name": "getParticipants", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], + "outputs": [{"internalType": "address[]", "name": "", "type": "address[]"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - } - ], + "inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32"}], "name": "getRoleAdmin", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], + "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], "name": "getWinners", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], + "outputs": [{"internalType": "address[]", "name": "", "type": "address[]"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], "name": "grantRole", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], "name": "hasRole", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } + {"internalType": "address", "name": "", "type": "address"}, + {"internalType": "uint256", "name": "", "type": "uint256"}, ], "name": "isParticipated", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "address", "name": "", "type": "address"}, ], "name": "isWinner", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "address", "name": "", "type": "address"}, ], "name": "isWinnerClaimed", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "lastRaffleId", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "muon", - "outputs": [ - { - "internalType": "contract IMuonClient", - "name": "", - "type": "address" - } - ], + "outputs": [{"internalType": "contract IMuonClient", "name": "", "type": "address"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "muonAppId", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "muonPublicKey", "outputs": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "parity", - "type": "uint8" - } + {"internalType": "uint256", "name": "x", "type": "uint256"}, + {"internalType": "uint8", "name": "parity", "type": "uint8"}, ], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [], "name": "muonValidGateway", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], + "outputs": [{"internalType": "address", "name": "", "type": "address"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } + {"internalType": "address", "name": "", "type": "address"}, + {"internalType": "address", "name": "", "type": "address"}, + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "bytes", "name": "", "type": "bytes"}, ], "name": "onERC721Received", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], + "outputs": [{"internalType": "bytes4", "name": "", "type": "bytes4"}], "stateMutability": "pure", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } + {"internalType": "uint256", "name": "", "type": "uint256"}, + {"internalType": "address", "name": "", "type": "address"}, + {"internalType": "uint256", "name": "", "type": "uint256"}, ], "name": "participantPositions", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "multiplier", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "reqId", - "type": "bytes" - }, + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "multiplier", "type": "uint256"}, + {"internalType": "bytes", "name": "reqId", "type": "bytes"}, { "components": [ - { - "internalType": "uint256", - "name": "signature", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "nonce", - "type": "address" - } + {"internalType": "uint256", "name": "signature", "type": "uint256"}, + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "nonce", "type": "address"}, ], "internalType": "struct IMuonClient.SchnorrSign", "name": "signature", - "type": "tuple" + "type": "tuple", }, - { - "internalType": "bytes", - "name": "gatewaySignature", - "type": "bytes" - } + {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, ], "name": "participateInRaffle", "outputs": [], "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, + {"inputs": [], "name": "pause", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, { "inputs": [], "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "name": "raffles", "outputs": [ - { - "internalType": "address", - "name": "initiator", - "type": "address" - }, - { - "internalType": "uint256", - "name": "maxParticipants", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxMultiplier", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "startTime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "endTime", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "participantsCount", - "type": "uint256" - }, - { - "internalType": "uint32", - "name": "winnersCount", - "type": "uint32" - }, - { - "internalType": "bool", - "name": "exists", - "type": "bool" - }, - { - "internalType": "enum AbstractPrizetapRaffle.Status", - "name": "status", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "requirementsHash", - "type": "bytes32" - } + {"internalType": "address", "name": "initiator", "type": "address"}, + {"internalType": "uint256", "name": "maxParticipants", "type": "uint256"}, + {"internalType": "uint256", "name": "maxMultiplier", "type": "uint256"}, + {"internalType": "uint256", "name": "startTime", "type": "uint256"}, + {"internalType": "uint256", "name": "endTime", "type": "uint256"}, + {"internalType": "uint256", "name": "participantsCount", "type": "uint256"}, + {"internalType": "uint32", "name": "winnersCount", "type": "uint32"}, + {"internalType": "bool", "name": "exists", "type": "bool"}, + {"internalType": "enum AbstractPrizetapRaffle.Status", "name": "status", "type": "uint8"}, + {"internalType": "bytes32", "name": "requirementsHash", "type": "bytes32"}, ], "stateMutability": "view", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], "name": "refundPrize", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], "name": "rejectRaffle", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], "name": "renounceRole", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "bytes32", - "name": "role", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "account", - "type": "address" - } + {"internalType": "bytes32", "name": "role", "type": "bytes32"}, + {"internalType": "address", "name": "account", "type": "address"}, ], "name": "revokeRole", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "address", - "name": "_muonAddress", - "type": "address" - } - ], + "inputs": [{"internalType": "address", "name": "_muonAddress", "type": "address"}], "name": "setMuonAddress", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "_muonAppId", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "_muonAppId", "type": "uint256"}], "name": "setMuonAppId", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "address", - "name": "_gatewayAddress", - "type": "address" - } - ], + "inputs": [{"internalType": "address", "name": "_gatewayAddress", "type": "address"}], "name": "setMuonGateway", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ { "components": [ - { - "internalType": "uint256", - "name": "x", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "parity", - "type": "uint8" - } + {"internalType": "uint256", "name": "x", "type": "uint256"}, + {"internalType": "uint8", "name": "parity", "type": "uint8"}, ], "internalType": "struct IMuonClient.PublicKey", "name": "_muonPublicKey", - "type": "tuple" + "type": "tuple", } ], "name": "setMuonPublicKey", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "uint256", - "name": "periodSeconds", - "type": "uint256" - } - ], + "inputs": [{"internalType": "uint256", "name": "periodSeconds", "type": "uint256"}], "name": "setValidationPeriod", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], + "inputs": [{"internalType": "bytes4", "name": "interfaceId", "type": "bytes4"}], "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], + "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, + {"inputs": [], "name": "unpause", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, { "inputs": [], "name": "validationPeriod", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], + "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "stateMutability": "view", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "uint256", - "name": "raffleId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "multiplier", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "reqId", - "type": "bytes" - }, + {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, + {"internalType": "uint256", "name": "multiplier", "type": "uint256"}, + {"internalType": "bytes", "name": "reqId", "type": "bytes"}, { "components": [ - { - "internalType": "uint256", - "name": "signature", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "nonce", - "type": "address" - } + {"internalType": "uint256", "name": "signature", "type": "uint256"}, + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "nonce", "type": "address"}, ], "internalType": "struct IMuonClient.SchnorrSign", "name": "sign", - "type": "tuple" + "type": "tuple", }, - { - "internalType": "bytes", - "name": "gatewaySignature", - "type": "bytes" - } + {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, ], "name": "verifyParticipationSig", "outputs": [], "stateMutability": "nonpayable", - "type": "function" + "type": "function", }, { "inputs": [ - { - "internalType": "uint256", - "name": "expirationTime", - "type": "uint256" - }, - { - "internalType": "uint256[]", - "name": "randomNumbers", - "type": "uint256[]" - }, - { - "internalType": "bytes", - "name": "reqId", - "type": "bytes" - }, + {"internalType": "uint256", "name": "expirationTime", "type": "uint256"}, + {"internalType": "uint256[]", "name": "randomNumbers", "type": "uint256[]"}, + {"internalType": "bytes", "name": "reqId", "type": "bytes"}, { "components": [ - { - "internalType": "uint256", - "name": "signature", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "nonce", - "type": "address" - } + {"internalType": "uint256", "name": "signature", "type": "uint256"}, + {"internalType": "address", "name": "owner", "type": "address"}, + {"internalType": "address", "name": "nonce", "type": "address"}, ], "internalType": "struct IMuonClient.SchnorrSign", "name": "sign", - "type": "tuple" + "type": "tuple", }, - { - "internalType": "bytes", - "name": "gatewaySignature", - "type": "bytes" - } + {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, ], "name": "verifyRandomNumberSig", "outputs": [], "stateMutability": "nonpayable", - "type": "function" - } + "type": "function", + }, ] VRF_CLIENT_POLYGON_ADDRESS = "0xD1E7877A1C3F782dec76FB58C2B926365433d46F" CONTRACT_ADDRESSES = { - '137': { - 'erc20_prizetap_addr': "0xB521C36F76d28Edb287346C9D649Fa1A60754f04", - "erc721_prizetap_addr": "0xb68D3f2946Bf477978c68b509FD9f85E9e20F869" - }, - '80001': { - 'erc20_prizetap_addr': "0x5AD9BAf388E6E4F7c40652e21545F700C2104FF0", - "erc721_prizetap_addr": "0x9E5c0d8a54D93956f26935447BBADd629f13a0dE" - } -} \ No newline at end of file + "137": { + "erc20_prizetap_addr": "0xB521C36F76d28Edb287346C9D649Fa1A60754f04", + "erc721_prizetap_addr": "0xb68D3f2946Bf477978c68b509FD9f85E9e20F869", + }, + "80001": { + "erc20_prizetap_addr": "0x5AD9BAf388E6E4F7c40652e21545F700C2104FF0", + "erc721_prizetap_addr": "0x9E5c0d8a54D93956f26935447BBADd629f13a0dE", + }, +} diff --git a/prizetap/migrations/0036_raffle_winners_count.py b/prizetap/migrations/0036_raffle_winners_count.py new file mode 100644 index 00000000..e767d53b --- /dev/null +++ b/prizetap/migrations/0036_raffle_winners_count.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2023-10-26 08:13 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('prizetap', '0035_alter_raffle_status'), + ] + + operations = [ + migrations.AddField( + model_name='raffle', + name='winners_count', + field=models.IntegerField(default=1), + ), + ] diff --git a/prizetap/migrations/0037_alter_raffle_status.py b/prizetap/migrations/0037_alter_raffle_status.py new file mode 100644 index 00000000..e644addc --- /dev/null +++ b/prizetap/migrations/0037_alter_raffle_status.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2023-10-26 13:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('prizetap', '0036_raffle_winners_count'), + ] + + operations = [ + migrations.AlterField( + model_name='raffle', + name='status', + field=models.CharField(choices=[('PENDING', 'Pending'), ('REJECTED', 'Rejected'), ('VERIFIED', 'Verified'), ('RWS', 'Random words are set'), ('WS', 'Winners are set'), ('CLOSED', 'Closed')], default='PENDING', max_length=10), + ), + ] diff --git a/prizetap/models.py b/prizetap/models.py index 3082e0e4..3b8cc83a 100644 --- a/prizetap/models.py +++ b/prizetap/models.py @@ -1,21 +1,23 @@ from django.db import models -from faucet.models import Chain -from faucet.constraints import OptimismDonationConstraint, OptimismClaimingGasConstraint from django.utils import timezone from django.utils.translation import gettext_lazy as _ + from authentication.models import NetworkTypes, UserProfile from core.models import BigNumField, UserConstraint -from .constraints import * +from faucet.constraints import OptimismClaimingGasConstraint, OptimismDonationConstraint +from faucet.models import Chain + +from .constraints import HaveUnitapPass, NotHaveUnitapPass # Create your models here. class Constraint(UserConstraint): constraints = UserConstraint.constraints + [ - HaveUnitapPass, + HaveUnitapPass, NotHaveUnitapPass, OptimismDonationConstraint, - OptimismClaimingGasConstraint + OptimismClaimingGasConstraint, ] name = UserConstraint.create_name_field(constraints) @@ -25,14 +27,12 @@ class Status(models.TextChoices): PENDING = "PENDING", _("Pending") REJECTED = "REJECTED", _("Rejected") VERIFIED = "VERIFIED", _("Verified") - HELD = "HELD", _("Held") + RANDOM_WORDS_SET = "RWS", _("Random words are set") + WINNERS_SET = "WS", _("Winners are set") CLOSED = "CLOSED", _("Closed") - WINNER_SET = "WS", _("Winner is set") class Meta: - models.UniqueConstraint( - fields=["chain", "contract", "raffleId"], name="unique_raffle" - ) + models.UniqueConstraint(fields=["chain", "contract", "raffleId"], name="unique_raffle") name = models.CharField(max_length=256) description = models.TextField(null=True, blank=True) @@ -66,10 +66,9 @@ class Meta: deadline = models.DateTimeField() max_number_of_entries = models.IntegerField() max_multiplier = models.IntegerField(default=1) + winners_count = models.IntegerField(default=1) - status = models.CharField( - max_length=10, choices=Status.choices, default=Status.PENDING - ) + status = models.CharField(max_length=10, choices=Status.choices, default=Status.PENDING) rejection_reason = models.TextField(null=True, blank=True) tx_hash = models.CharField(max_length=255, blank=True, null=True) vrf_tx_hash = models.CharField(max_length=255, blank=True, null=True) @@ -124,10 +123,9 @@ def winner_entry(self): def __str__(self): return f"{self.name}" - + def save(self, *args, **kwargs): - if self.status == self.Status.VERIFIED \ - and not self.raffleId: + if self.status == self.Status.VERIFIED and not self.raffleId: raise Exception("The raffleId of a verified raffle can't be empty") super().save(*args, **kwargs) @@ -139,9 +137,7 @@ class Meta: verbose_name_plural = "raffle entries" raffle = models.ForeignKey(Raffle, on_delete=models.CASCADE, related_name="entries") - user_profile = models.ForeignKey( - UserProfile, on_delete=models.CASCADE, related_name="raffle_entries" - ) + user_profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name="raffle_entries") created_at = models.DateTimeField(auto_now_add=True, editable=True) @@ -161,16 +157,6 @@ def user(self): def age(self): return timezone.now() - self.created_at - def save(self, *args, **kwargs): - if self.is_winner: - try: - entry = RaffleEntry.objects.get(is_winner=True, raffle=self.raffle) - assert entry.pk == self.pk, "The raffle already has a winner" - except RaffleEntry.DoesNotExist: - pass - - super().save(*args, **kwargs) - class LineaRaffleEntries(models.Model): wallet_address = models.CharField(max_length=255) @@ -179,4 +165,4 @@ class LineaRaffleEntries(models.Model): claim_tx = models.CharField(max_length=255, blank=True, null=True) def __str__(self): - return str(self.wallet_address) \ No newline at end of file + return str(self.wallet_address) diff --git a/prizetap/tasks.py b/prizetap/tasks.py index fcba9fcb..0dff777a 100644 --- a/prizetap/tasks.py +++ b/prizetap/tasks.py @@ -1,18 +1,78 @@ +import time + import requests from celery import shared_task from django.utils import timezone + from core.helpers import memcache_lock -from .models import Raffle, Chain + +from .models import Chain, Raffle from .utils import ( - PrizetapContractClient, + LineaPrizetapContractClient, + PrizetapContractClient, VRFClientContractClient, - LineaPrizetapContractClient ) @shared_task(bind=True) -def draw_the_expired_raffles(self): +def set_raffle_random_words(self): + id = f"{self.name}-LOCK" + with memcache_lock(id, self.app.oid) as acquired: + if not acquired: + print(f"Could not acquire process lock at {self.name}") + return + + raffle = ( + Raffle.objects.filter(deadline__lt=timezone.now()) + .filter(status=Raffle.Status.VERIFIED) + .filter(vrf_tx_hash__isnull=False) + .first() + ) + + if raffle: + print(f"Setting the raffle {raffle.name} random words") + vrf_client = VRFClientContractClient(raffle.chain) + last_request = vrf_client.get_last_request() + expiration_time = last_request[0] + now = int(time.time()) + if now < expiration_time: + set_random_words(raffle) + else: + print("Random words have expired") + raffle.vrf_tx_hash = None + raffle.save() + + +def set_random_words(raffle: Raffle): + muon_response = requests.get( + f"https://shield.unitap.app/v1/?app=stage_unitap&method=random-words&\ + params[chainId]={raffle.chain.chain_id}¶ms[prizetapRaffle]={raffle.contract}&\ + params[raffleId]={raffle.raffleId}" + ) + muon_response = muon_response.json() + if muon_response["success"]: + muon_response = muon_response["result"] + muon_data = muon_response["data"]["result"] + raffle_client = PrizetapContractClient(raffle) + random_words = [int(r) for r in muon_data["randomWords"]] + raffle_client.set_raffle_random_words( + int(muon_data["expirationTime"]), + random_words, + muon_response["reqId"], + ( + int(muon_response["signatures"][0]["signature"], 16), + muon_response["signatures"][0]["owner"], + muon_response["data"]["init"]["nonceAddress"], + ), + muon_response["shieldSignature"], + ) + raffle.status = Raffle.Status.RANDOM_WORDS_SET + raffle.save() + + +@shared_task(bind=True) +def set_raffle_winners(self): id = f"{self.name}-LOCK" with memcache_lock(id, self.app.oid) as acquired: @@ -20,27 +80,21 @@ def draw_the_expired_raffles(self): print(f"Could not acquire process lock at {self.name}") return - raffles_queryset = ( - Raffle.objects - .filter(deadline__lt=timezone.now()) - .filter(status=Raffle.Status.PENDING) + raffles_queryset = Raffle.objects.filter(deadline__lt=timezone.now()).filter( + status=Raffle.Status.RANDOM_WORDS_SET ) if raffles_queryset.count() > 0: for raffle in raffles_queryset: - if raffle.number_of_onchain_entries > 0 and not raffle.winner_entry: - print(f"Drawing the raffle {raffle.name}") - raffle_client = PrizetapContractClient(raffle) - tx_hash = raffle_client.draw_raffle() - receipt = raffle_client.wait_for_transaction_receipt( - tx_hash) - if receipt['status'] == 1: - raffle.status = Raffle.Status.HELD - raffle.save() + print(f"Setting the raffle {raffle.name} winners") + raffle_client = PrizetapContractClient(raffle) + tx_hash = raffle_client.set_winners() + if tx_hash: + raffle.status = Raffle.Status.WINNERS_SET + raffle.save() @shared_task(bind=True) -def set_the_winner_of_raffles(self): - +def get_raffle_winners(self): id = f"{self.name}-LOCK" with memcache_lock(id, self.app.oid) as acquired: @@ -48,31 +102,55 @@ def set_the_winner_of_raffles(self): print(f"Could not acquire process lock at {self.name}") return - raffles_queryset = ( - Raffle.objects - .filter(deadline__lt=timezone.now()) - .filter(status=Raffle.Status.HELD) - ) + raffles_queryset = Raffle.objects.filter(deadline__lt=timezone.now()).filter(status=Raffle.Status.WINNERS_SET) if raffles_queryset.count() > 0: for raffle in raffles_queryset: - print(f"Setting the winner of raffle {raffle.name}") + print(f"Getting the winner of raffle {raffle.name}") raffle_client = PrizetapContractClient(raffle) - winner_address = raffle_client.get_raffle_winner() - if winner_address and winner_address != "0x0000000000000000000000000000000000000000": - try: - winner_entry = raffle.entries.filter( - user_profile__wallets__address__iexact=winner_address).get() + winner_addresses = raffle_client.get_raffle_winners() + for addr in winner_addresses: + if addr and addr != "0x0000000000000000000000000000000000000000": + winner_entry = raffle.entries.filter(user_profile__wallets__address__iexact=addr).get() winner_entry.is_winner = True winner_entry.save() - raffle.status = Raffle.Status.WINNER_SET + raffle.status = Raffle.Status.CLOSED raffle.save() - except Exception as e: - print(e) - pass + @shared_task(bind=True) -def request_random_words_for_expired_linea_raffles(self): +def request_random_words_for_expired_raffles(self): + id = f"{self.name}-LOCK" + + with memcache_lock(id, self.app.oid) as acquired: + if not acquired: + print(f"Could not acquire process lock at {self.name}") + return + + raffles_queryset = ( + Raffle.objects.filter(deadline__lt=timezone.now()) + .filter(status=Raffle.Status.VERIFIED) + .filter(vrf_tx_hash__isnull=True) + ) + if raffles_queryset.count() > 0: + for raffle in raffles_queryset: + if raffle.number_of_onchain_entries > 0: + print(f"Request random words for the raffle {raffle.name}") + request_random_words(raffle) + break + +def request_random_words(raffle: Raffle): + vrf_client = VRFClientContractClient(raffle.chain) + raffle_client = PrizetapContractClient(raffle) + winners_count = raffle_client.get_raffle_winners_count() + tx_hash = vrf_client.request_random_words(winners_count) + if tx_hash: + raffle.vrf_tx_hash = tx_hash + raffle.save() + + +@shared_task(bind=True) +def request_random_words_for_expired_linea_raffles(self): id = f"{self.name}-LOCK" with memcache_lock(id, self.app.oid) as acquired: @@ -81,8 +159,7 @@ def request_random_words_for_expired_linea_raffles(self): return raffles_queryset = ( - Raffle.objects - .filter(deadline__lt=timezone.now()) + Raffle.objects.filter(deadline__lt=timezone.now()) .filter(chain__chain_id=59140) .filter(status=Raffle.Status.PENDING) .filter(vrf_tx_hash__isnull=True) @@ -93,6 +170,7 @@ def request_random_words_for_expired_linea_raffles(self): print(f"Request a random number for the Linea raffle {raffle.name}") request_random_words_for_linea_raffle(raffle) + def request_random_words_for_linea_raffle(raffle: Raffle): chain = Chain.objects.get(chain_id=80001) vrf_client = VRFClientContractClient(chain) @@ -102,9 +180,9 @@ def request_random_words_for_linea_raffle(raffle: Raffle): raffle.vrf_tx_hash = tx_hash raffle.save() + @shared_task(bind=True) def draw_expired_linea_raffles(self): - id = f"{self.name}-LOCK" with memcache_lock(id, self.app.oid) as acquired: @@ -113,8 +191,7 @@ def draw_expired_linea_raffles(self): return raffles_queryset = ( - Raffle.objects - .filter(deadline__lt=timezone.now()) + Raffle.objects.filter(deadline__lt=timezone.now()) .filter(chain__chain_id=59140) .filter(status=Raffle.Status.PENDING) .filter(vrf_tx_hash__isnull=False) @@ -128,24 +205,26 @@ def draw_expired_linea_raffles(self): def draw_linea_raffle(raffle: Raffle): muon_response = requests.get( - f"https://shield.unitap.app/v1/?app=stage_unitap&method=random-words¶ms[chainId]={raffle.chain.chain_id}¶ms[prizetapRaffle]={raffle.contract}¶ms[raffleId]={raffle.raffleId}" + f"https://shield.unitap.app/v1/?app=stage_unitap&method=random-words&\ + params[chainId]={raffle.chain.chain_id}¶ms[prizetapRaffle]={raffle.contract}&\ + params[raffleId]={raffle.raffleId}" ) muon_response = muon_response.json() - if muon_response['success']: - muon_response = muon_response['result'] - muon_data = muon_response['data']['result'] + if muon_response["success"]: + muon_response = muon_response["result"] + muon_data = muon_response["data"]["result"] raffle_client = LineaPrizetapContractClient(raffle) - random_words = [int(r) for r in muon_data['randomWords']] + random_words = [int(r) for r in muon_data["randomWords"]] tx_hash = raffle_client.draw_raffle( - int(muon_data['expirationTime']), + int(muon_data["expirationTime"]), random_words, - muon_response['reqId'], + muon_response["reqId"], { - "signature": muon_response['signatures'][0]['signature'], - "owner": muon_response['signatures'][0]['owner'], - "nonce": muon_response['data']['init']['nonceAddress'] + "signature": muon_response["signatures"][0]["signature"], + "owner": muon_response["signatures"][0]["owner"], + "nonce": muon_response["data"]["init"]["nonceAddress"], }, - muon_response['shieldSignature'] + muon_response["shieldSignature"], ) print(tx_hash) raffle.status = Raffle.Status.CLOSED @@ -154,7 +233,6 @@ def draw_linea_raffle(raffle: Raffle): @shared_task(bind=True) def set_the_winner_of_linea_raffles(self): - id = f"{self.name}-LOCK" with memcache_lock(id, self.app.oid) as acquired: @@ -163,8 +241,7 @@ def set_the_winner_of_linea_raffles(self): return raffles_queryset = ( - Raffle.objects - .filter(deadline__lt=timezone.now()) + Raffle.objects.filter(deadline__lt=timezone.now()) .filter(chain__chain_id=59140) .filter(status=Raffle.Status.CLOSED) ) @@ -172,7 +249,7 @@ def set_the_winner_of_linea_raffles(self): for raffle in raffles_queryset: print(f"Setting the winners of Linea raffle {raffle.name}") set_the_winners_of_linea_raffle(raffle) - + def set_the_winners_of_linea_raffle(raffle: Raffle): raffle_client = LineaPrizetapContractClient(raffle) @@ -186,4 +263,4 @@ def set_the_winners_of_linea_raffle(raffle: Raffle): print(e) pass raffle.status = Raffle.Status.WINNER_SET - raffle.save() \ No newline at end of file + raffle.save() diff --git a/prizetap/utils.py b/prizetap/utils.py index ca0c7bb1..50856ea3 100644 --- a/prizetap/utils.py +++ b/prizetap/utils.py @@ -1,12 +1,15 @@ +import time + from core.utils import Web3Utils from faucet.models import Chain + from .constants import ( + LINEA_PRIZETAP_ABI, PRIZETAP_ERC20_ABI, PRIZETAP_ERC721_ABI, UNITAP_PASS_ABI, VRF_CLIENT_ABI, VRF_CLIENT_POLYGON_ADDRESS, - LINEA_PRIZETAP_ABI ) @@ -18,15 +21,44 @@ def __init__(self, raffle) -> None: self.set_contract(self.raffle.contract, abi) self.set_account(self.raffle.chain.wallet.private_key) - def draw_raffle(self): - func = self.contract.functions.heldRaffle(self.raffle.raffleId) + def set_raffle_random_words(self, expiration_time, random_words, reqId, muon_sig, gateway_sig): + func = self.contract.functions.setRaffleRandomNumbers( + self.raffle.raffleId, expiration_time, random_words, reqId, muon_sig, gateway_sig + ) return self.contract_txn(func) - def get_raffle_winner(self): + def get_raffle(self): func = self.contract.functions.raffles(self.raffle.raffleId) - raffle = self.contract_call(func) - return raffle[8] - + return self.contract_call(func) + + def get_last_winner_index(self): + raffle = self.get_raffle() + last_index = raffle[8] if not self.raffle.is_prize_nft else raffle[7] + return last_index + + def set_winners(self): + winners_count = self.raffle.winners_count + last_winner_index = self.get_last_winner_index() + while last_winner_index < winners_count: + to_id = last_winner_index + 25 + if to_id > winners_count: + to_id = winners_count + func = self.contract.functions.setWinners(self.raffle.raffleId, to_id) + last_winner_index = to_id + tx_hash = self.contract_txn(func) + self.wait_for_transaction_receipt(tx_hash) + + return tx_hash + + def get_raffle_winners(self): + func = self.contract.functions.getWinners(self.raffle.raffleId, 1, self.raffle.winners_count) + return self.contract_call(func) + + def get_raffle_winners_count(self): + func = self.contract.functions.getWinnersCount(self.raffle.raffleId) + return self.contract_call(func) + + class LineaPrizetapContractClient(PrizetapContractClient): def __init__(self, raffle) -> None: super().__init__(raffle) @@ -35,12 +67,7 @@ def __init__(self, raffle) -> None: def draw_raffle(self, expiration_time, random_words, reqId, muon_sig, gateway_sig): func = self.contract.functions.drawRaffle( - self.raffle.raffleId, - expiration_time, - random_words, - reqId, - muon_sig, - gateway_sig + self.raffle.raffleId, expiration_time, random_words, reqId, muon_sig, gateway_sig ) return self.contract_txn(func) @@ -53,22 +80,39 @@ def get_raffle_winners_count(self): raffle = self.contract_call(func) return raffle[6] + class VRFClientContractClient(Web3Utils): def __init__(self, chain) -> None: super().__init__(chain.rpc_url_private, chain.poa) self.set_contract(VRF_CLIENT_POLYGON_ADDRESS, VRF_CLIENT_ABI) self.set_account(chain.wallet.private_key) + def get_last_request_id(self): + func = self.contract.functions.lastRequestId() + return self.contract_call(func) + + def get_last_request(self): + last_id = self.get_last_request_id() + func = self.contract.functions.vrfRequests(last_id) + return self.contract_call(func) + + def get_validity_period(self): + func = self.contract.functions.validityPeriod() + return self.contract_call(func) + def request_random_words(self, num_words): - func = self.contract.functions.requestRandomWords(num_words) - return self.contract_txn(func) + last_request = self.get_last_request() + expiration_time = last_request[0] + now = int(time.time()) + if expiration_time < now: + func = self.contract.functions.requestRandomWords(num_words) + return self.contract_txn(func) class UnitapPassClient(Web3Utils): def __init__(self, chain: Chain) -> None: super().__init__(chain.rpc_url_private, chain.poa) - self.set_contract( - "0x23826Fd930916718a98A21FF170088FBb4C30803", UNITAP_PASS_ABI) + self.set_contract("0x23826Fd930916718a98A21FF170088FBb4C30803", UNITAP_PASS_ABI) def is_holder(self, address: str): func = self.contract.functions.balanceOf(address) From a089d517d4a6bc5bd784c42e8838b6a22a31c1f8 Mon Sep 17 00:00:00 2001 From: Shayan Shiravani Date: Thu, 26 Oct 2023 17:50:27 +0330 Subject: [PATCH 03/13] Remove linea contract auto tasks --- brightIDfaucet/celery.py | 5 - prizetap/constants.py | 518 --------------------------------------- prizetap/tasks.py | 125 +--------- prizetap/utils.py | 23 -- 4 files changed, 2 insertions(+), 669 deletions(-) diff --git a/brightIDfaucet/celery.py b/brightIDfaucet/celery.py index 29f4112c..7f23cd70 100644 --- a/brightIDfaucet/celery.py +++ b/brightIDfaucet/celery.py @@ -53,11 +53,6 @@ "set-raffle-random-words": {"task": "prizetap.tasks.set_raffle_random_words", "schedule": 120}, "set-raffle-winners": {"task": "prizetap.tasks.set_raffle_winners", "schedule": 300}, "get-raffle-winners": {"task": "prizetap.tasks.get_raffle_winners", "schedule": 300}, - "request-random-words-for-linea-raffles": { - "task": "prizetap.tasks.request_random_words_for_expired_linea_raffles", - "schedule": 150, - }, - "set-linea-raffle-winners": {"task": "prizetap.tasks.set_the_winner_of_linea_raffles", "schedule": 60}, } # Load task modules from all registered Django apps. diff --git a/prizetap/constants.py b/prizetap/constants.py index bf271bb0..e1cb393a 100644 --- a/prizetap/constants.py +++ b/prizetap/constants.py @@ -1629,524 +1629,6 @@ }, ] -LINEA_PRIZETAP_ABI = [ - { - "inputs": [ - {"internalType": "uint256", "name": "_muonAppId", "type": "uint256"}, - { - "components": [ - {"internalType": "uint256", "name": "x", "type": "uint256"}, - {"internalType": "uint8", "name": "parity", "type": "uint8"}, - ], - "internalType": "struct IMuonClient.PublicKey", - "name": "_muonPublicKey", - "type": "tuple", - }, - {"internalType": "address", "name": "_muon", "type": "address"}, - {"internalType": "address", "name": "_muonValidGateway", "type": "address"}, - {"internalType": "address", "name": "_admin", "type": "address"}, - {"internalType": "address", "name": "_operator", "type": "address"}, - ], - "stateMutability": "nonpayable", - "type": "constructor", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "address", "name": "user", "type": "address"}, - {"indexed": False, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, - {"indexed": False, "internalType": "uint256", "name": "multiplier", "type": "uint256"}, - ], - "name": "Participate", - "type": "event", - }, - { - "anonymous": False, - "inputs": [{"indexed": False, "internalType": "address", "name": "account", "type": "address"}], - "name": "Paused", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, - {"indexed": True, "internalType": "address", "name": "winner", "type": "address"}, - ], - "name": "PrizeClaimed", - "type": "event", - }, - { - "anonymous": False, - "inputs": [{"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}], - "name": "PrizeRefunded", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "address", "name": "initiator", "type": "address"}, - {"indexed": False, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, - ], - "name": "RaffleCreated", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, - {"indexed": True, "internalType": "address", "name": "rejector", "type": "address"}, - ], - "name": "RaffleRejected", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, - {"indexed": True, "internalType": "bytes32", "name": "previousAdminRole", "type": "bytes32"}, - {"indexed": True, "internalType": "bytes32", "name": "newAdminRole", "type": "bytes32"}, - ], - "name": "RoleAdminChanged", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, - {"indexed": True, "internalType": "address", "name": "account", "type": "address"}, - {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, - ], - "name": "RoleGranted", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "bytes32", "name": "role", "type": "bytes32"}, - {"indexed": True, "internalType": "address", "name": "account", "type": "address"}, - {"indexed": True, "internalType": "address", "name": "sender", "type": "address"}, - ], - "name": "RoleRevoked", - "type": "event", - }, - { - "anonymous": False, - "inputs": [{"indexed": False, "internalType": "address", "name": "account", "type": "address"}], - "name": "Unpaused", - "type": "event", - }, - { - "anonymous": False, - "inputs": [ - {"indexed": True, "internalType": "uint256", "name": "raffleId", "type": "uint256"}, - {"indexed": True, "internalType": "address[]", "name": "winner", "type": "address[]"}, - ], - "name": "WinnersSpecified", - "type": "event", - }, - { - "inputs": [], - "name": "DEFAULT_ADMIN_ROLE", - "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "MAX_NUM_WINNERS", - "outputs": [{"internalType": "uint32", "name": "", "type": "uint32"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "OPERATOR_ROLE", - "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "_ERC721_RECEIVED", - "outputs": [{"internalType": "bytes4", "name": "", "type": "bytes4"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "uint256", "name": "_raffleId", "type": "uint256"}, - {"internalType": "address[]", "name": "_participants", "type": "address[]"}, - {"internalType": "uint256[]", "name": "_multipliers", "type": "uint256[]"}, - ], - "name": "addParticipants", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], - "name": "claimPrize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "uint256", "name": "maxParticipants", "type": "uint256"}, - {"internalType": "uint256", "name": "maxMultiplier", "type": "uint256"}, - {"internalType": "uint256", "name": "startTime", "type": "uint256"}, - {"internalType": "uint256", "name": "endTime", "type": "uint256"}, - {"internalType": "uint32", "name": "winnersCount", "type": "uint32"}, - {"internalType": "bytes32", "name": "requirementsHash", "type": "bytes32"}, - ], - "name": "createRaffle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, - {"internalType": "uint256", "name": "expirationTime", "type": "uint256"}, - {"internalType": "uint256[]", "name": "randomNumbers", "type": "uint256[]"}, - {"internalType": "bytes", "name": "reqId", "type": "bytes"}, - { - "components": [ - {"internalType": "uint256", "name": "signature", "type": "uint256"}, - {"internalType": "address", "name": "owner", "type": "address"}, - {"internalType": "address", "name": "nonce", "type": "address"}, - ], - "internalType": "struct IMuonClient.SchnorrSign", - "name": "signature", - "type": "tuple", - }, - {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, - ], - "name": "drawRaffle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], - "name": "getParticipants", - "outputs": [{"internalType": "address[]", "name": "", "type": "address[]"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [{"internalType": "bytes32", "name": "role", "type": "bytes32"}], - "name": "getRoleAdmin", - "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], - "name": "getWinners", - "outputs": [{"internalType": "address[]", "name": "", "type": "address[]"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "bytes32", "name": "role", "type": "bytes32"}, - {"internalType": "address", "name": "account", "type": "address"}, - ], - "name": "grantRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "bytes32", "name": "role", "type": "bytes32"}, - {"internalType": "address", "name": "account", "type": "address"}, - ], - "name": "hasRole", - "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "uint256", "name": "", "type": "uint256"}, - ], - "name": "isParticipated", - "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "uint256", "name": "", "type": "uint256"}, - {"internalType": "address", "name": "", "type": "address"}, - ], - "name": "isWinner", - "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "uint256", "name": "", "type": "uint256"}, - {"internalType": "address", "name": "", "type": "address"}, - ], - "name": "isWinnerClaimed", - "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "lastRaffleId", - "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "muon", - "outputs": [{"internalType": "contract IMuonClient", "name": "", "type": "address"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "muonAppId", - "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "muonPublicKey", - "outputs": [ - {"internalType": "uint256", "name": "x", "type": "uint256"}, - {"internalType": "uint8", "name": "parity", "type": "uint8"}, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [], - "name": "muonValidGateway", - "outputs": [{"internalType": "address", "name": "", "type": "address"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "uint256", "name": "", "type": "uint256"}, - {"internalType": "bytes", "name": "", "type": "bytes"}, - ], - "name": "onERC721Received", - "outputs": [{"internalType": "bytes4", "name": "", "type": "bytes4"}], - "stateMutability": "pure", - "type": "function", - }, - { - "inputs": [ - {"internalType": "uint256", "name": "", "type": "uint256"}, - {"internalType": "address", "name": "", "type": "address"}, - {"internalType": "uint256", "name": "", "type": "uint256"}, - ], - "name": "participantPositions", - "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, - {"internalType": "uint256", "name": "multiplier", "type": "uint256"}, - {"internalType": "bytes", "name": "reqId", "type": "bytes"}, - { - "components": [ - {"internalType": "uint256", "name": "signature", "type": "uint256"}, - {"internalType": "address", "name": "owner", "type": "address"}, - {"internalType": "address", "name": "nonce", "type": "address"}, - ], - "internalType": "struct IMuonClient.SchnorrSign", - "name": "signature", - "type": "tuple", - }, - {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, - ], - "name": "participateInRaffle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - {"inputs": [], "name": "pause", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, - { - "inputs": [], - "name": "paused", - "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], - "name": "raffles", - "outputs": [ - {"internalType": "address", "name": "initiator", "type": "address"}, - {"internalType": "uint256", "name": "maxParticipants", "type": "uint256"}, - {"internalType": "uint256", "name": "maxMultiplier", "type": "uint256"}, - {"internalType": "uint256", "name": "startTime", "type": "uint256"}, - {"internalType": "uint256", "name": "endTime", "type": "uint256"}, - {"internalType": "uint256", "name": "participantsCount", "type": "uint256"}, - {"internalType": "uint32", "name": "winnersCount", "type": "uint32"}, - {"internalType": "bool", "name": "exists", "type": "bool"}, - {"internalType": "enum AbstractPrizetapRaffle.Status", "name": "status", "type": "uint8"}, - {"internalType": "bytes32", "name": "requirementsHash", "type": "bytes32"}, - ], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], - "name": "refundPrize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "uint256", "name": "raffleId", "type": "uint256"}], - "name": "rejectRaffle", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "bytes32", "name": "role", "type": "bytes32"}, - {"internalType": "address", "name": "account", "type": "address"}, - ], - "name": "renounceRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "bytes32", "name": "role", "type": "bytes32"}, - {"internalType": "address", "name": "account", "type": "address"}, - ], - "name": "revokeRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "address", "name": "_muonAddress", "type": "address"}], - "name": "setMuonAddress", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "uint256", "name": "_muonAppId", "type": "uint256"}], - "name": "setMuonAppId", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "address", "name": "_gatewayAddress", "type": "address"}], - "name": "setMuonGateway", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - { - "components": [ - {"internalType": "uint256", "name": "x", "type": "uint256"}, - {"internalType": "uint8", "name": "parity", "type": "uint8"}, - ], - "internalType": "struct IMuonClient.PublicKey", - "name": "_muonPublicKey", - "type": "tuple", - } - ], - "name": "setMuonPublicKey", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "uint256", "name": "periodSeconds", "type": "uint256"}], - "name": "setValidationPeriod", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [{"internalType": "bytes4", "name": "interfaceId", "type": "bytes4"}], - "name": "supportsInterface", - "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], - "stateMutability": "view", - "type": "function", - }, - {"inputs": [], "name": "unpause", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, - { - "inputs": [], - "name": "validationPeriod", - "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], - "stateMutability": "view", - "type": "function", - }, - { - "inputs": [ - {"internalType": "uint256", "name": "raffleId", "type": "uint256"}, - {"internalType": "uint256", "name": "multiplier", "type": "uint256"}, - {"internalType": "bytes", "name": "reqId", "type": "bytes"}, - { - "components": [ - {"internalType": "uint256", "name": "signature", "type": "uint256"}, - {"internalType": "address", "name": "owner", "type": "address"}, - {"internalType": "address", "name": "nonce", "type": "address"}, - ], - "internalType": "struct IMuonClient.SchnorrSign", - "name": "sign", - "type": "tuple", - }, - {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, - ], - "name": "verifyParticipationSig", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, - { - "inputs": [ - {"internalType": "uint256", "name": "expirationTime", "type": "uint256"}, - {"internalType": "uint256[]", "name": "randomNumbers", "type": "uint256[]"}, - {"internalType": "bytes", "name": "reqId", "type": "bytes"}, - { - "components": [ - {"internalType": "uint256", "name": "signature", "type": "uint256"}, - {"internalType": "address", "name": "owner", "type": "address"}, - {"internalType": "address", "name": "nonce", "type": "address"}, - ], - "internalType": "struct IMuonClient.SchnorrSign", - "name": "sign", - "type": "tuple", - }, - {"internalType": "bytes", "name": "gatewaySignature", "type": "bytes"}, - ], - "name": "verifyRandomNumberSig", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function", - }, -] - VRF_CLIENT_POLYGON_ADDRESS = "0xD1E7877A1C3F782dec76FB58C2B926365433d46F" CONTRACT_ADDRESSES = { diff --git a/prizetap/tasks.py b/prizetap/tasks.py index 0dff777a..9a1ebb09 100644 --- a/prizetap/tasks.py +++ b/prizetap/tasks.py @@ -6,12 +6,8 @@ from core.helpers import memcache_lock -from .models import Chain, Raffle -from .utils import ( - LineaPrizetapContractClient, - PrizetapContractClient, - VRFClientContractClient, -) +from .models import Raffle +from .utils import PrizetapContractClient, VRFClientContractClient @shared_task(bind=True) @@ -147,120 +143,3 @@ def request_random_words(raffle: Raffle): if tx_hash: raffle.vrf_tx_hash = tx_hash raffle.save() - - -@shared_task(bind=True) -def request_random_words_for_expired_linea_raffles(self): - id = f"{self.name}-LOCK" - - with memcache_lock(id, self.app.oid) as acquired: - if not acquired: - print(f"Could not acquire process lock at {self.name}") - return - - raffles_queryset = ( - Raffle.objects.filter(deadline__lt=timezone.now()) - .filter(chain__chain_id=59140) - .filter(status=Raffle.Status.PENDING) - .filter(vrf_tx_hash__isnull=True) - ) - if raffles_queryset.count() > 0: - for raffle in raffles_queryset: - if raffle.linea_entries.count() > 0: - print(f"Request a random number for the Linea raffle {raffle.name}") - request_random_words_for_linea_raffle(raffle) - - -def request_random_words_for_linea_raffle(raffle: Raffle): - chain = Chain.objects.get(chain_id=80001) - vrf_client = VRFClientContractClient(chain) - raffle_client = LineaPrizetapContractClient(raffle) - winners_count = raffle_client.get_raffle_winners_count() - tx_hash = vrf_client.request_random_words(winners_count) - raffle.vrf_tx_hash = tx_hash - raffle.save() - - -@shared_task(bind=True) -def draw_expired_linea_raffles(self): - id = f"{self.name}-LOCK" - - with memcache_lock(id, self.app.oid) as acquired: - if not acquired: - print(f"Could not acquire process lock at {self.name}") - return - - raffles_queryset = ( - Raffle.objects.filter(deadline__lt=timezone.now()) - .filter(chain__chain_id=59140) - .filter(status=Raffle.Status.PENDING) - .filter(vrf_tx_hash__isnull=False) - ) - if raffles_queryset.count() > 0: - for raffle in raffles_queryset: - if raffle.linea_entries.count() > 0: - print(f"Drawing the Linea raffle {raffle.name}") - draw_linea_raffle(raffle) - - -def draw_linea_raffle(raffle: Raffle): - muon_response = requests.get( - f"https://shield.unitap.app/v1/?app=stage_unitap&method=random-words&\ - params[chainId]={raffle.chain.chain_id}¶ms[prizetapRaffle]={raffle.contract}&\ - params[raffleId]={raffle.raffleId}" - ) - muon_response = muon_response.json() - if muon_response["success"]: - muon_response = muon_response["result"] - muon_data = muon_response["data"]["result"] - raffle_client = LineaPrizetapContractClient(raffle) - random_words = [int(r) for r in muon_data["randomWords"]] - tx_hash = raffle_client.draw_raffle( - int(muon_data["expirationTime"]), - random_words, - muon_response["reqId"], - { - "signature": muon_response["signatures"][0]["signature"], - "owner": muon_response["signatures"][0]["owner"], - "nonce": muon_response["data"]["init"]["nonceAddress"], - }, - muon_response["shieldSignature"], - ) - print(tx_hash) - raffle.status = Raffle.Status.CLOSED - raffle.save() - - -@shared_task(bind=True) -def set_the_winner_of_linea_raffles(self): - id = f"{self.name}-LOCK" - - with memcache_lock(id, self.app.oid) as acquired: - if not acquired: - print(f"Could not acquire process lock at {self.name}") - return - - raffles_queryset = ( - Raffle.objects.filter(deadline__lt=timezone.now()) - .filter(chain__chain_id=59140) - .filter(status=Raffle.Status.CLOSED) - ) - if raffles_queryset.count() > 0: - for raffle in raffles_queryset: - print(f"Setting the winners of Linea raffle {raffle.name}") - set_the_winners_of_linea_raffle(raffle) - - -def set_the_winners_of_linea_raffle(raffle: Raffle): - raffle_client = LineaPrizetapContractClient(raffle) - winner_addresses = raffle_client.get_raffle_winners() - for address in winner_addresses: - try: - winner_entry = raffle.linea_entries.filter(wallet_address=address).get() - winner_entry.is_winner = True - winner_entry.save() - except Exception as e: - print(e) - pass - raffle.status = Raffle.Status.WINNER_SET - raffle.save() diff --git a/prizetap/utils.py b/prizetap/utils.py index 50856ea3..4faa1adb 100644 --- a/prizetap/utils.py +++ b/prizetap/utils.py @@ -4,7 +4,6 @@ from faucet.models import Chain from .constants import ( - LINEA_PRIZETAP_ABI, PRIZETAP_ERC20_ABI, PRIZETAP_ERC721_ABI, UNITAP_PASS_ABI, @@ -59,28 +58,6 @@ def get_raffle_winners_count(self): return self.contract_call(func) -class LineaPrizetapContractClient(PrizetapContractClient): - def __init__(self, raffle) -> None: - super().__init__(raffle) - abi = LINEA_PRIZETAP_ABI - self.set_contract(self.raffle.contract, abi) - - def draw_raffle(self, expiration_time, random_words, reqId, muon_sig, gateway_sig): - func = self.contract.functions.drawRaffle( - self.raffle.raffleId, expiration_time, random_words, reqId, muon_sig, gateway_sig - ) - return self.contract_txn(func) - - def get_raffle_winners(self): - func = self.contract.functions.getWinners(self.raffle.raffleId) - return self.contract_call(func) - - def get_raffle_winners_count(self): - func = self.contract.functions.raffles(self.raffle.raffleId) - raffle = self.contract_call(func) - return raffle[6] - - class VRFClientContractClient(Web3Utils): def __init__(self, chain) -> None: super().__init__(chain.rpc_url_private, chain.poa) From 432f0f9d0912b71f1ab36a3f8e549a17424fb341 Mon Sep 17 00:00:00 2001 From: Pooya Fekri Date: Fri, 27 Oct 2023 11:41:59 +0330 Subject: [PATCH 04/13] price_url in TokenPrice can be blank --- .../0003_alter_tokenprice_price_url.py | 18 ++++ core/models.py | 13 +-- faucet/tasks.py | 99 ++++++++----------- 3 files changed, 66 insertions(+), 64 deletions(-) create mode 100644 core/migrations/0003_alter_tokenprice_price_url.py diff --git a/core/migrations/0003_alter_tokenprice_price_url.py b/core/migrations/0003_alter_tokenprice_price_url.py new file mode 100644 index 00000000..45d1607c --- /dev/null +++ b/core/migrations/0003_alter_tokenprice_price_url.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2023-10-27 08:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0002_alter_tokenprice_price_url'), + ] + + operations = [ + migrations.AlterField( + model_name='tokenprice', + name='price_url', + field=models.URLField(blank=True, max_length=255, null=True), + ), + ] diff --git a/core/models.py b/core/models.py index 7dcca52e..09a38cec 100644 --- a/core/models.py +++ b/core/models.py @@ -1,6 +1,7 @@ from django.db import models from django.utils.translation import gettext_lazy as _ -from .constraints import * + +from .constraints import BrightIDAuraVerification, BrightIDMeetVerification class UserConstraint(models.Model): @@ -19,9 +20,7 @@ class Type(models.TextChoices): choices=[(c.__name__, c.__name__) for c in constraints], ) title = models.CharField(max_length=255) - type = models.CharField( - max_length=10, choices=Type.choices, default=Type.VERIFICATION - ) + type = models.CharField(max_length=10, choices=Type.choices, default=Type.VERIFICATION) description = models.TextField(null=True, blank=True) response = models.TextField(null=True, blank=True) icon_url = models.CharField(max_length=255, null=True, blank=True) @@ -42,10 +41,8 @@ class TokenPrice(models.Model): usd_price = models.CharField(max_length=255, null=False) datetime = models.DateTimeField(auto_now_add=True) last_updated = models.DateTimeField(auto_now=True, null=True, blank=True) - price_url = models.URLField(max_length=255, null=True) - symbol = models.CharField( - max_length=255, db_index=True, unique=True, null=False, blank=False - ) + price_url = models.URLField(max_length=255, null=True, blank=True) + symbol = models.CharField(max_length=255, db_index=True, unique=True, null=False, blank=False) class BigNumField(models.Field): diff --git a/faucet/tasks.py b/faucet/tasks.py index 9ae55e37..f8515cf5 100644 --- a/faucet/tasks.py +++ b/faucet/tasks.py @@ -1,26 +1,29 @@ -import time -import logging import decimal +import logging +import time from contextlib import contextmanager -import web3.exceptions + import requests +import web3.exceptions from celery import shared_task +from django.conf import settings as django_settings from django.core.cache import cache from django.db import transaction from django.db.models import F, Func from django.utils import timezone from sentry_sdk import capture_exception + from authentication.models import NetworkTypes, Wallet +from core.models import TokenPrice from tokenTap.models import TokenDistributionClaim -from django.conf import settings as django_settings + from .faucet_manager.fund_manager import ( EVMFundManager, - SolanaFundManager, - LightningFundManager, FundMangerException, + LightningFundManager, + SolanaFundManager, ) -from core.models import TokenPrice -from .models import Chain, ClaimReceipt, TransactionBatch, DonationReceipt +from .models import Chain, ClaimReceipt, DonationReceipt, TransactionBatch @contextmanager @@ -42,9 +45,7 @@ def memcache_lock(lock_id, oid, lock_expire=60): def has_pending_batch(chain): - return TransactionBatch.objects.filter( - chain=chain, _status=ClaimReceipt.PENDING - ).exists() + return TransactionBatch.objects.filter(chain=chain, _status=ClaimReceipt.PENDING).exists() def passive_address_is_not_none(address): @@ -99,15 +100,10 @@ def process_batch(self, batch_pk): manager = SolanaFundManager(batch.chain) elif batch.chain.chain_type == NetworkTypes.LIGHTNING: manager = LightningFundManager(batch.chain) - elif ( - batch.chain.chain_type == NetworkTypes.EVM - or batch.chain.chain_type == NetworkTypes.NONEVMXDC - ): + elif batch.chain.chain_type == NetworkTypes.EVM or batch.chain.chain_type == NetworkTypes.NONEVMXDC: manager = EVMFundManager(batch.chain) else: - raise Exception( - f"Invalid chain type to process batch, chain type {batch.chain.chain_type}" - ) + raise Exception(f"Invalid chain type to process batch, chain type {batch.chain.chain_type}") tx_hash = manager.multi_transfer(data) batch.tx_hash = tx_hash batch.save() @@ -126,9 +122,7 @@ def process_batch(self, batch_pk): @shared_task def process_pending_batches(): - batches = TransactionBatch.objects.filter( - _status=ClaimReceipt.PENDING, tx_hash=None - ) + batches = TransactionBatch.objects.filter(_status=ClaimReceipt.PENDING, tx_hash=None) for _batch in batches: process_batch.delay(_batch.pk) @@ -153,15 +147,10 @@ def update_pending_batch_with_tx_hash(self, batch_pk): manager = SolanaFundManager(batch.chain) elif batch.chain.chain_type == NetworkTypes.LIGHTNING: manager = LightningFundManager(batch.chain) - elif ( - batch.chain.chain_type == NetworkTypes.EVM - or batch.chain.chain_type == NetworkTypes.NONEVMXDC - ): + elif batch.chain.chain_type == NetworkTypes.EVM or batch.chain.chain_type == NetworkTypes.NONEVMXDC: manager = EVMFundManager(batch.chain) else: - raise Exception( - f"Invalid chain type to update pending batch, chain type {batch.chain.chain_type}" - ) + raise Exception(f"Invalid chain type to update pending batch, chain type {batch.chain.chain_type}") if manager.is_tx_verified(batch.tx_hash): batch._status = ClaimReceipt.VERIFIED @@ -184,17 +173,14 @@ def reject_expired_pending_claims(): ClaimReceipt.objects.filter( batch=None, _status=ClaimReceipt.PENDING, - datetime__lte=timezone.now() - - timezone.timedelta(minutes=ClaimReceipt.MAX_PENDING_DURATION), + datetime__lte=timezone.now() - timezone.timedelta(minutes=ClaimReceipt.MAX_PENDING_DURATION), ).update(_status=ClaimReceipt.REJECTED) @shared_task def update_pending_batches_with_tx_hash_status(): batches_queryset = ( - TransactionBatch.objects.filter(_status=ClaimReceipt.PENDING) - .exclude(tx_hash=None) - .exclude(updating=True) + TransactionBatch.objects.filter(_status=ClaimReceipt.PENDING).exclude(tx_hash=None).exclude(updating=True) ) for _batch in batches_queryset: update_pending_batch_with_tx_hash.delay(_batch.pk) @@ -203,9 +189,7 @@ def update_pending_batches_with_tx_hash_status(): @shared_task def process_chain_pending_claims(chain_id): # locks chain with transaction.atomic(): - chain = Chain.objects.select_for_update().get( - pk=chain_id - ) # lock based on chain + chain = Chain.objects.select_for_update().get(pk=chain_id) # lock based on chain # all pending batches must be resolved before new transactions can be made if has_pending_batch(chain): @@ -213,9 +197,7 @@ def process_chain_pending_claims(chain_id): # locks chain # get all pending receipts for this chain # pending receipts are receipts that have not been batched yet - receipts = ClaimReceipt.objects.filter( - chain=chain, _status=ClaimReceipt.PENDING, batch=None - ) + receipts = ClaimReceipt.objects.filter(chain=chain, _status=ClaimReceipt.PENDING, batch=None) if receipts.count() == 0: return @@ -253,7 +235,7 @@ def update_needs_funding_status_chain(chain_id): chain.needs_funding = False chain.save() - except: + except Exception: capture_exception() @@ -336,7 +318,6 @@ def update_tokentap_claim_for_verified_lightning_claims(): process_rejected_lighning_claim.apply((_claim.pk,)) else: if _claim._status == ClaimReceipt.VERIFIED: - process_verified_lighning_claim.delay( _claim.pk, ) @@ -353,35 +334,37 @@ def update_tokens_price(): """ # TODO: we can make this function performance better by using aiohttp and asyncio or Threads - tokens = TokenPrice.objects.exclude(price_url__isnull=True) + tokens = TokenPrice.objects.exclude(price_url__isnull=True).exclude(price_url="") res_gen = map(lambda token: (token, requests.get(token.price_url, timeout=5)), tokens) def parse_request(token: TokenPrice, request_res: requests.Response): try: request_res.raise_for_status() json_data = request_res.json() - token.usd_price = json_data['data']['rates']['USD'] + token.usd_price = json_data["data"]["rates"]["USD"] # TODO: save all change when this function ended for all url done for better performance token.save() except requests.HTTPError as e: logging.exception( - f'requests for url: {request_res.url} can not fetched with status_code: {request_res.status_code}. \ - {str(e)}') + f"requests for url: {request_res.url} can not fetched with status_code: {request_res.status_code}. \ + {str(e)}" + ) except KeyError as e: logging.exception( - f'requests for url: {request_res.url} data do not have property keys for loading data. {str(e)}') + f"requests for url: {request_res.url} data do not have property keys for loading data. {str(e)}" + ) except Exception as e: - logging.exception(f'requests for url: {request_res.url} got error {type(e).__name__}. {str(e)}') + logging.exception(f"requests for url: {request_res.url} got error {type(e).__name__}. {str(e)}") [parse_request(*res) for res in res_gen] @shared_task(bind=True) def process_donation_receipt(self, donation_receipt_pk): - lock_name = f'{self.name}-LOCK-{donation_receipt_pk}' - logging.info(f'lock name is: {lock_name}') + lock_name = f"{self.name}-LOCK-{donation_receipt_pk}" + logging.info(f"lock name is: {lock_name}") with memcache_lock(lock_name, self.app.oid) as acquired: donation_receipt = DonationReceipt.objects.get(pk=donation_receipt_pk) if not acquired: @@ -394,22 +377,26 @@ def process_donation_receipt(self, donation_receipt_pk): return user = donation_receipt.user_profile tx = evm_fund_manager.get_tx(donation_receipt.tx_hash) - if tx.get('from').lower() not in user.wallets.annotate( - lower_address=Func(F('address'), function='LOWER')).values_list('lower_address', flat=True): + if tx.get("from").lower() not in user.wallets.annotate( + lower_address=Func(F("address"), function="LOWER") + ).values_list("lower_address", flat=True): donation_receipt.delete() return - if evm_fund_manager.to_checksum_address( - tx.get('to')) != evm_fund_manager.get_fund_manager_checksum_address(): + if ( + evm_fund_manager.to_checksum_address(tx.get("to")) + != evm_fund_manager.get_fund_manager_checksum_address() + ): donation_receipt.delete() return - donation_receipt.value = str(evm_fund_manager.from_wei(tx.get('value'))) + donation_receipt.value = str(evm_fund_manager.from_wei(tx.get("value"))) if donation_receipt.chain.is_testnet is False: try: token_price = TokenPrice.objects.get(symbol=donation_receipt.chain.symbol) donation_receipt.total_price = str( - decimal.Decimal(donation_receipt.value) * decimal.Decimal(token_price.usd_price)) + decimal.Decimal(donation_receipt.value) * decimal.Decimal(token_price.usd_price) + ) except TokenPrice.DoesNotExist: - logging.error(f'TokenPrice for Chain: {donation_receipt.chain.chain_name} did not defined') + logging.error(f"TokenPrice for Chain: {donation_receipt.chain.chain_name} did not defined") donation_receipt.status = ClaimReceipt.PROCESSED_FOR_TOKENTAP_REJECT donation_receipt.save() return From f8e8752a30ca115ec6d0a084e17823a8e66710b1 Mon Sep 17 00:00:00 2001 From: Mohamad Bastin Date: Fri, 27 Oct 2023 12:13:31 +0200 Subject: [PATCH 05/13] change gastap claimstrategy | change global settings fields --- core/utils.py | 90 ++++++------ faucet/constraints.py | 35 +++-- .../faucet_manager/brightid_user_registry.py | 68 ++++----- faucet/faucet_manager/claim_manager.py | 44 +++--- faucet/faucet_manager/credit_strategy.py | 138 ++++++++++-------- faucet/faucet_manager/fund_manager.py | 61 +++----- faucet/models.py | 48 ++---- faucet/serializers.py | 132 +++++++---------- faucet/test.py | 81 +++++----- faucet/urls.py | 23 ++- faucet/views.py | 123 ++++++++-------- permissions/admin.py | 36 ++--- ...eetverification_permission_ptr_and_more.py | 51 +++++++ permissions/migrations/0007_initial.py | 63 ++++++++ permissions/models.py | 41 +++--- permissions/serializers.py | 50 +++---- permissions/tests.py | 43 +++--- .../migrations/0003_raffle_permissions.py | 1 - tokenTap/constraints.py | 18 +-- tokenTap/helpers.py | 20 +-- .../0002_tokendistribution_permissions.py | 1 - tokenTap/models.py | 36 ++--- tokenTap/serializers.py | 21 ++- tokenTap/tests.py | 60 ++++---- tokenTap/views.py | 84 +++++------ 25 files changed, 719 insertions(+), 649 deletions(-) create mode 100644 permissions/migrations/0006_remove_brightidmeetverification_permission_ptr_and_more.py create mode 100644 permissions/migrations/0007_initial.py diff --git a/core/utils.py b/core/utils.py index 21879d7e..98916608 100644 --- a/core/utils.py +++ b/core/utils.py @@ -1,47 +1,46 @@ import datetime + import pytz -from time import time from web3 import Web3 -from web3.middleware import geth_poa_middleware from web3.contract.contract import Contract, ContractFunction -from web3.types import Type, TxParams -from django.utils import timezone +from web3.middleware import geth_poa_middleware +from web3.types import TxParams, Type class TimeUtils: - @staticmethod - def get_last_monday(): - now = int(time()) - day = 86400 # seconds in a day - week = 7 * day - weeks = now // week # number of weeks since epoch - monday = 345600 # first monday midnight - last_monday_midnight = monday + (weeks * week) - - # last monday could be off by one week - if last_monday_midnight > now: - last_monday_midnight -= week - - return timezone.make_aware( - datetime.datetime.fromtimestamp(last_monday_midnight) - ) - - @staticmethod - def get_second_last_monday(): - now = int(time()) - day = 86400 # seconds in a day - week = 7 * day - weeks = now // week # number of weeks since epoch - monday = 345600 # first monday midnight - last_monday_midnight = monday + (weeks * week) - - # last monday could be off by one week - if last_monday_midnight > now: - last_monday_midnight -= week - - return timezone.make_aware( - datetime.datetime.fromtimestamp(last_monday_midnight - week) - ) + # @staticmethod + # def get_last_monday(): + # now = int(time()) + # day = 86400 # seconds in a day + # week = 7 * day + # weeks = now // week # number of weeks since epoch + # monday = 345600 # first monday midnight + # last_monday_midnight = monday + (weeks * week) + + # # last monday could be off by one week + # if last_monday_midnight > now: + # last_monday_midnight -= week + + # return timezone.make_aware( + # datetime.datetime.fromtimestamp(last_monday_midnight) + # ) + + # @staticmethod + # def get_second_last_monday(): + # now = int(time()) + # day = 86400 # seconds in a day + # week = 7 * day + # weeks = now // week # number of weeks since epoch + # monday = 345600 # first monday midnight + # last_monday_midnight = monday + (weeks * week) + + # # last monday could be off by one week + # if last_monday_midnight > now: + # last_monday_midnight -= week + + # return timezone.make_aware( + # datetime.datetime.fromtimestamp(last_monday_midnight - week) + # ) @staticmethod def get_first_day_of_the_month(): @@ -49,9 +48,17 @@ def get_first_day_of_the_month(): first_day = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0) return first_day + @staticmethod + def get_first_day_of_last_month(): + now = datetime.datetime.now(pytz.timezone("UTC")) + first_day = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0) + last_month = first_day - datetime.timedelta(days=1) + first_day_of_last_month = last_month.replace(day=1, hour=0, minute=0, second=0, microsecond=0) + return first_day_of_last_month + class Web3Utils: - def __init__(self, rpc_url, poa = False) -> None: + def __init__(self, rpc_url, poa=False) -> None: self._rpc_url = rpc_url self._w3 = None self._account = None @@ -71,7 +78,7 @@ def w3(self) -> Web3: return self._w3 raise Exception(f"RPC provider is not connected ({self._rpc_url})") - + @property def poa(self): return self._poa @@ -102,8 +109,7 @@ def contract_call(self, func: Type[ContractFunction], from_address=None): def build_contract_txn(self, func: Type[ContractFunction]): nonce = self.w3.eth.get_transaction_count(self.account.address) - tx_data = func.build_transaction( - {"from": self.account.address, "nonce": nonce}) + tx_data = func.build_transaction({"from": self.account.address, "nonce": nonce}) return self.sign_tx(tx_data) def sign_tx(self, tx_data: TxParams): @@ -117,6 +123,6 @@ def wait_for_transaction_receipt(self, tx_hash): def current_block(self): return self.w3.eth.block_number - + def get_transaction_by_hash(self, hash): return self.w3.eth.get_transaction(hash) diff --git a/faucet/constraints.py b/faucet/constraints.py index b21c75d2..6164305d 100644 --- a/faucet/constraints.py +++ b/faucet/constraints.py @@ -1,8 +1,12 @@ +import logging + import requests -from core.constraints import * + +from core.constraints import ConstraintParam, ConstraintVerification from core.utils import Web3Utils -from faucet.faucet_manager.credit_strategy import WeeklyCreditStrategy -from .models import DonationReceipt, Chain, ClaimReceipt +from faucet.faucet_manager.credit_strategy import RoundCreditStrategy + +from .models import Chain, ClaimReceipt, DonationReceipt class DonationConstraint(ConstraintVerification): @@ -24,7 +28,8 @@ class OptimismDonationConstraint(DonationConstraint): def is_observed(self, *args, **kwargs): try: chain = Chain.objects.get(chain_id=10) - except: + except Exception as e: + logging.error(e) return False self._param_values[ConstraintParam.CHAIN] = chain.pk return super().is_observed(*args, **kwargs) @@ -38,12 +43,11 @@ def is_observed(self, *args, **kwargs): chain = Chain.objects.get(pk=chain_pk) w3 = Web3Utils(chain.rpc_url_private, chain.poa) current_block = w3.current_block() - user_address = self.user_profile.wallets.get( - wallet_type=chain.chain_type - ).address + user_address = self.user_profile.wallets.get(wallet_type=chain.chain_type).address first_internal_tx = requests.get( - f"{chain.explorer_api_url}/api?module=account&action=txlistinternal&address={user_address}&startblock=0&endblock={current_block}&page=1&offset=1&sort=asc&apikey={chain.explorer_api_key}" + f"{chain.explorer_api_url}/api?module=account&action=txlistinternal&address={user_address}&start" + f"block=0&endblock={current_block}&page=1&offset=1&sort=asc&apikey={chain.explorer_api_key}" ) first_internal_tx = first_internal_tx.json() if first_internal_tx and first_internal_tx["status"] == "1": @@ -54,16 +58,15 @@ def is_observed(self, *args, **kwargs): and first_internal_tx["isError"] == "0" ): first_tx = requests.get( - f"{chain.explorer_api_url}/api?module=account&action=txlist&address={user_address}&startblock=0&endblock={current_block}&page=1&offset=1&sort=asc&apikey={chain.explorer_api_key}" + f"{chain.explorer_api_url}/api?module=account&action=txlist&address={user_address}&startblock=0&" + f"endblock={current_block}&page=1&offset=1&sort=asc&apikey={chain.explorer_api_key}" ) first_tx = first_tx.json() if first_tx: if not first_tx["result"]: return True first_tx = first_tx["result"][0] - claiming_gas_tx = w3.get_transaction_by_hash( - first_internal_tx["hash"] - ) + claiming_gas_tx = w3.get_transaction_by_hash(first_internal_tx["hash"]) web3_first_tx = w3.get_transaction_by_hash(first_tx["hash"]) return web3_first_tx["blockNumber"] > claiming_gas_tx["blockNumber"] return False @@ -75,7 +78,8 @@ class OptimismClaimingGasConstraint(EvmClaimingGasConstraint): def is_observed(self, *args, **kwargs): try: chain = Chain.objects.get(chain_id=10) - except: + except Exception as e: + logging.error(e) return False self._param_values[ConstraintParam.CHAIN] = chain.pk return super().is_observed(*args, **kwargs) @@ -91,7 +95,7 @@ def is_observed(self, *args, **kwargs): user_profile=self.user_profile, chain=chain, _status=ClaimReceipt.VERIFIED, - datetime__gte=WeeklyCreditStrategy.get_last_monday(), + datetime__gte=RoundCreditStrategy.get_start_of_the_round(), ).exists() @@ -101,7 +105,8 @@ class OptimismHasClaimedGasInThisRound(HasClaimedGasInThisRound): def is_observed(self, *args, **kwargs): try: chain = Chain.objects.get(chain_id=10) - except: + except Exception as e: + logging.error(e) return False self._param_values[ConstraintParam.CHAIN] = chain.pk return super().is_observed(*args, **kwargs) diff --git a/faucet/faucet_manager/brightid_user_registry.py b/faucet/faucet_manager/brightid_user_registry.py index 50fb9c35..d89c14c8 100644 --- a/faucet/faucet_manager/brightid_user_registry.py +++ b/faucet/faucet_manager/brightid_user_registry.py @@ -1,40 +1,40 @@ -from eth_account.signers.local import LocalAccount -from web3 import Web3 -from web3.exceptions import TimeExhausted -from web3.gas_strategies.rpc import rpc_gas_price_strategy -from web3.middleware import geth_poa_middleware -from faucet.faucet_manager.brightid_user_registry_abi import bright_id_user_registry_abi -from faucet.models import Chain, BrightUser +# from eth_account.signers.local import LocalAccount +# from web3 import Web3 +# from web3.exceptions import TimeExhausted +# from web3.gas_strategies.rpc import rpc_gas_price_strategy +# from web3.middleware import geth_poa_middleware +# from faucet.faucet_manager.brightid_user_registry_abi import bright_id_user_registry_abi +# from faucet.models import Chain, BrightUser -class BrightIdUserRegistry: - def __init__(self, chain: Chain, bright_id_user_registry_address: str): - self.chain = chain - self.abi = bright_id_user_registry_abi - self.bright_id_user_registry_address = bright_id_user_registry_address +# class BrightIdUserRegistry: +# def __init__(self, chain: Chain, bright_id_user_registry_address: str): +# self.chain = chain +# self.abi = bright_id_user_registry_abi +# self.bright_id_user_registry_address = bright_id_user_registry_address - @property - def w3(self) -> Web3: - assert self.chain.rpc_url_private is not None - _w3 = Web3(Web3.HTTPProvider(self.chain.rpc_url_private)) - if self.chain.poa: - _w3.middleware_onion.inject(geth_poa_middleware, layer=0) - if _w3.isConnected(): - _w3.eth.set_gas_price_strategy(rpc_gas_price_strategy) - return _w3 - raise Exception(f"Could not connect to rpc {self.chain.rpc_url_private}") +# @property +# def w3(self) -> Web3: +# assert self.chain.rpc_url_private is not None +# _w3 = Web3(Web3.HTTPProvider(self.chain.rpc_url_private)) +# if self.chain.poa: +# _w3.middleware_onion.inject(geth_poa_middleware, layer=0) +# if _w3.isConnected(): +# _w3.eth.set_gas_price_strategy(rpc_gas_price_strategy) +# return _w3 +# raise Exception(f"Could not connect to rpc {self.chain.rpc_url_private}") - @property - def contract(self): - return self.w3.eth.contract( - address=self.get_checksum_address(self.bright_id_user_registry_address), - abi=self.abi, - ) +# @property +# def contract(self): +# return self.w3.eth.contract( +# address=self.get_checksum_address(self.bright_id_user_registry_address), +# abi=self.abi, +# ) - def get_checksum_address(self, address): - return Web3.toChecksumAddress(address.lower()) +# def get_checksum_address(self, address): +# return Web3.toChecksumAddress(address.lower()) - def is_verified_user(self, address): - return self.contract.functions.isVerifiedUser( - self.get_checksum_address(address) - ).call() +# def is_verified_user(self, address): +# return self.contract.functions.isVerifiedUser( +# self.get_checksum_address(address) +# ).call() diff --git a/faucet/faucet_manager/claim_manager.py b/faucet/faucet_manager/claim_manager.py index 75ca3951..d445dc07 100644 --- a/faucet/faucet_manager/claim_manager.py +++ b/faucet/faucet_manager/claim_manager.py @@ -1,19 +1,19 @@ -import logging import abc +import logging from abc import ABC + +from django.db import transaction from django.utils import timezone -from authentication.models import UserProfile -from authentication.models import NetworkTypes -from faucet.faucet_manager.lnpay_client import LNPayClient +from authentication.models import NetworkTypes, UserProfile from faucet.faucet_manager.credit_strategy import ( CreditStrategy, CreditStrategyFactory, - WeeklyCreditStrategy, + RoundCreditStrategy, ) from faucet.faucet_manager.fund_manager import EVMFundManager -from faucet.models import ClaimReceipt, BrightUser, GlobalSettings -from django.db import transaction +from faucet.faucet_manager.lnpay_client import LNPayClient +from faucet.models import BrightUser, ClaimReceipt, GlobalSettings class ClaimManager(ABC): @@ -36,9 +36,7 @@ def fund_manager(self): def claim(self, amount, passive_address=None): with transaction.atomic(): - user_profile = UserProfile.objects.select_for_update().get( - pk=self.credit_strategy.user_profile.pk - ) + user_profile = UserProfile.objects.select_for_update().get(pk=self.credit_strategy.user_profile.pk) self.assert_pre_claim_conditions(amount, user_profile) return self.create_pending_claim_receipt( amount, passive_address @@ -46,8 +44,7 @@ def claim(self, amount, passive_address=None): def assert_pre_claim_conditions(self, amount, user_profile): assert amount <= self.credit_strategy.get_unclaimed() - # TODO: uncomment this - assert self.user_is_meet_verified() == True + assert self.user_is_meet_verified() is True assert not ClaimReceipt.objects.filter( chain=self.credit_strategy.chain, user_profile=user_profile, @@ -72,13 +69,13 @@ def user_is_meet_verified(self) -> bool: class LimitedChainClaimManager(SimpleClaimManager): - def get_weekly_limit(self): - limit = GlobalSettings.objects.first().weekly_chain_claim_limit + def get_round_limit(self): + limit = GlobalSettings.objects.first().gastap_round_claim_limit return limit @staticmethod - def get_total_weekly_claims(user_profile): - last_monday = WeeklyCreditStrategy.get_last_monday() + def get_total_round_claims(user_profile): + start_of_the_round = RoundCreditStrategy.get_start_of_the_round() return ClaimReceipt.objects.filter( user_profile=user_profile, _status__in=[ @@ -87,27 +84,28 @@ def get_total_weekly_claims(user_profile): BrightUser.PENDING, BrightUser.VERIFIED, ], - datetime__gte=last_monday, + datetime__gte=start_of_the_round, ).count() def assert_pre_claim_conditions(self, amount, user_profile): super().assert_pre_claim_conditions(amount, user_profile) - total_claims = self.get_total_weekly_claims(user_profile) - assert total_claims < self.get_weekly_limit() + total_claims = self.get_total_round_claims(user_profile) + assert total_claims < self.get_round_limit() + class LightningClaimManger(LimitedChainClaimManager): def claim(self, amount, passive_address): try: lnpay_client = LNPayClient( - self.credit_strategy.chain.rpc_url_private, - self.credit_strategy.chain.wallet.main_key, - self.credit_strategy.chain.fund_manager_address + self.credit_strategy.chain.rpc_url_private, + self.credit_strategy.chain.wallet.main_key, + self.credit_strategy.chain.fund_manager_address, ) decoded_invoice = lnpay_client.decode_invoice(passive_address) except Exception as e: logging.error(e) raise AssertionError("Could not decode the invoice") - assert int(decoded_invoice['num_satoshis']) == amount, "Invalid amount" + assert int(decoded_invoice["num_satoshis"]) == amount, "Invalid amount" return super().claim(amount, passive_address) diff --git a/faucet/faucet_manager/credit_strategy.py b/faucet/faucet_manager/credit_strategy.py index 1fb51ecd..261c9548 100644 --- a/faucet/faucet_manager/credit_strategy.py +++ b/faucet/faucet_manager/credit_strategy.py @@ -1,16 +1,12 @@ import abc -from abc import ABC -from time import time import datetime +from abc import ABC -from django.db.models import Sum -from django.utils import timezone import pytz -from authentication.models import UserProfile +from django.db.models import Sum -from brightIDfaucet import settings -from faucet.faucet_manager.brightid_user_registry import BrightIdUserRegistry -from faucet.models import ClaimReceipt, BrightUser, Chain +from authentication.models import UserProfile +from faucet.models import Chain, ClaimReceipt class CreditStrategy(ABC): @@ -51,12 +47,68 @@ def get_claimed(self): return _sum def get_unclaimed(self): - # print("max_claim_amount", self.chain.max_claim_amount) - # print("get_claimed", self.get_claimed()) return int(self.chain.max_claim_amount) - int(self.get_claimed()) -class WeeklyCreditStrategy(SimpleCreditStrategy): +# class WeeklyCreditStrategy(SimpleCreditStrategy): +# def __int__(self, chain: Chain, user_profile: UserProfile): +# self.chain = chain +# self.user_profile = user_profile + +# def get_claim_receipts(self): +# return ClaimReceipt.objects.filter( +# chain=self.chain, +# user_profile=self.user_profile, +# _status=ClaimReceipt.VERIFIED, +# datetime__gte=self.get_last_monday(), +# ) + +# @staticmethod +# def get_last_monday(): +# now = int(time()) +# day = 86400 # seconds in a day +# week = 7 * day +# weeks = now // week # number of weeks since epoch +# monday = 345600 # first monday midnight +# last_monday_midnight = monday + (weeks * week) + +# # last monday could be off by one week +# if last_monday_midnight > now: +# last_monday_midnight -= week + +# return timezone.make_aware(datetime.datetime.fromtimestamp(last_monday_midnight)) + +# @staticmethod +# def get_second_last_monday(): +# now = int(time()) +# day = 86400 # seconds in a day +# week = 7 * day +# weeks = now // week # number of weeks since epoch +# monday = 345600 # first monday midnight +# last_monday_midnight = monday + (weeks * week) + +# # last monday could be off by one week +# if last_monday_midnight > now: +# last_monday_midnight -= week + +# return timezone.make_aware(datetime.datetime.fromtimestamp(last_monday_midnight - week)) + + +# class ArbitrumCreditStrategy(WeeklyCreditStrategy): +# def get_unclaimed(self): +# contract_address = "0x631a12430F94207De980D9b6A744AEB4093DCeC1" +# max_claim_amount = self.chain.max_claim_amount +# is_verified_user = BrightIdUserRegistry(self.chain, contract_address).is_verified_user( +# self.user_profile.initial_context_id +# ) + +# if is_verified_user: +# max_claim_amount = 5000000000000000 + +# return max_claim_amount - self.get_claimed() + + +class RoundCreditStrategy(SimpleCreditStrategy): def __int__(self, chain: Chain, user_profile: UserProfile): self.chain = chain self.user_profile = user_profile @@ -66,62 +118,30 @@ def get_claim_receipts(self): chain=self.chain, user_profile=self.user_profile, _status=ClaimReceipt.VERIFIED, - datetime__gte=self.get_last_monday(), + datetime__gte=self._get_first_day_of_the_month(), ) @staticmethod - def get_last_monday(): - now = int(time()) - day = 86400 # seconds in a day - week = 7 * day - weeks = now // week # number of weeks since epoch - monday = 345600 # first monday midnight - last_monday_midnight = monday + (weeks * week) - - # last monday could be off by one week - if last_monday_midnight > now: - last_monday_midnight -= week - - return timezone.make_aware( - datetime.datetime.fromtimestamp(last_monday_midnight) - ) + def get_start_of_the_round(): + return RoundCreditStrategy._get_first_day_of_the_month() @staticmethod - def get_second_last_monday(): - now = int(time()) - day = 86400 # seconds in a day - week = 7 * day - weeks = now // week # number of weeks since epoch - monday = 345600 # first monday midnight - last_monday_midnight = monday + (weeks * week) - - # last monday could be off by one week - if last_monday_midnight > now: - last_monday_midnight -= week - - return timezone.make_aware( - datetime.datetime.fromtimestamp(last_monday_midnight - week) - ) + def get_start_of_previous_round(): + return RoundCreditStrategy._get_first_day_of_last_month() - @staticmethod - def get_first_day_of_the_month(): + @classmethod + def _get_first_day_of_the_month(cls): now = datetime.datetime.now(pytz.timezone("UTC")) first_day = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0) return first_day - -class ArbitrumCreditStrategy(WeeklyCreditStrategy): - def get_unclaimed(self): - contract_address = "0x631a12430F94207De980D9b6A744AEB4093DCeC1" - max_claim_amount = self.chain.max_claim_amount - is_verified_user = BrightIdUserRegistry( - self.chain, contract_address - ).is_verified_user(self.user_profile.initial_context_id) - - if is_verified_user: - max_claim_amount = 5000000000000000 - - return max_claim_amount - self.get_claimed() + @classmethod + def _get_first_day_of_last_month(cls): + now = datetime.datetime.now(pytz.timezone("UTC")) + first_day = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0) + last_month = first_day - datetime.timedelta(days=1) + first_day_of_last_month = last_month.replace(day=1, hour=0, minute=0, second=0, microsecond=0) + return first_day_of_last_month class CreditStrategyFactory: @@ -130,9 +150,7 @@ def __init__(self, chain, user_profile): self.user_profile = user_profile def get_strategy_class(self): - return WeeklyCreditStrategy - if self.chain.chain_id == "42161": - return ArbitrumCreditStrategy + return RoundCreditStrategy def get_strategy(self) -> CreditStrategy: _Strategy = self.get_strategy_class() diff --git a/faucet/faucet_manager/fund_manager.py b/faucet/faucet_manager/fund_manager.py index 5df163ad..e35e9909 100644 --- a/faucet/faucet_manager/fund_manager.py +++ b/faucet/faucet_manager/fund_manager.py @@ -1,15 +1,9 @@ -import time -import os import logging +import os +import time + from django.core.cache import cache from eth_account.signers.local import LocalAccount -from web3 import Web3 -from web3.gas_strategies.rpc import rpc_gas_price_strategy -from web3.middleware import geth_poa_middleware -from faucet.faucet_manager.fund_manager_abi import manager_abi -from faucet.models import Chain, BrightUser, LightningConfig -from faucet.helpers import memcache_lock -from faucet.constants import * from solana.rpc.api import Client from solana.rpc.core import RPCException, RPCNoResultException from solana.transaction import Transaction @@ -17,10 +11,19 @@ from solders.pubkey import Pubkey from solders.signature import Signature from solders.transaction_status import TransactionConfirmationStatus -from .anchor_client.accounts.lock_account import LockAccount +from web3 import Web3 +from web3.gas_strategies.rpc import rpc_gas_price_strategy +from web3.middleware import geth_poa_middleware + +from faucet.constants import MEMCACHE_LIGHTNING_LOCK_KEY +from faucet.faucet_manager.fund_manager_abi import manager_abi +from faucet.helpers import memcache_lock +from faucet.models import BrightUser, Chain, LightningConfig + from .anchor_client import instructions -from .solana_client import SolanaClient +from .anchor_client.accounts.lock_account import LockAccount from .lnpay_client import LNPayClient +from .solana_client import SolanaClient class FundMangerException: @@ -48,9 +51,7 @@ def w3(self) -> Web3: return _w3 except Exception as e: logging.error(e) - raise FundMangerException.RPCError( - f"Could not connect to rpc {self.chain.rpc_url_private}" - ) + raise FundMangerException.RPCError(f"Could not connect to rpc {self.chain.rpc_url_private}") @property def is_gas_price_too_high(self): @@ -77,9 +78,7 @@ def get_fund_manager_checksum_address(self): @property def contract(self): - return self.w3.eth.contract( - address=self.get_fund_manager_checksum_address(), abi=self.abi - ) + return self.w3.eth.contract(address=self.get_fund_manager_checksum_address(), abi=self.abi) def transfer(self, bright_user: BrightUser, amount: int): tx = self.single_eth_transfer_signed_tx(amount, bright_user.address) @@ -153,9 +152,7 @@ def w3(self) -> Client: return _w3 except Exception as e: logging.error(e) - raise FundMangerException.RPCError( - f"Could not connect to rpc {self.chain.rpc_url_private}" - ) + raise FundMangerException.RPCError(f"Could not connect to rpc {self.chain.rpc_url_private}") @property def account(self) -> Keypair: @@ -171,9 +168,7 @@ def lock_account_seed(self) -> bytes: @property def lock_account_address(self) -> Pubkey: - lock_account_address, nonce = Pubkey.find_program_address( - [self.lock_account_seed], self.program_id - ) + lock_account_address, nonce = Pubkey.find_program_address([self.lock_account_seed], self.program_id) return lock_account_address @property @@ -247,23 +242,17 @@ def multi_transfer(self, data): def is_tx_verified(self, tx_hash): try: confirmation_status = ( - self.w3.get_signature_statuses([Signature.from_string(tx_hash)]) - .value[0] - .confirmation_status + self.w3.get_signature_statuses([Signature.from_string(tx_hash)]).value[0].confirmation_status ) return confirmation_status in [ TransactionConfirmationStatus.Confirmed, TransactionConfirmationStatus.Finalized, ] except RPCException: - logging.warning( - "Solana raised the RPCException at get_signature_statuses()" - ) + logging.warning("Solana raised the RPCException at get_signature_statuses()") return False except RPCNoResultException: - logging.warning( - "Solana raised the RPCNoResultException at get_signature_statuses()" - ) + logging.warning("Solana raised the RPCNoResultException at get_signature_statuses()") return False except Exception: raise @@ -285,9 +274,7 @@ def api_key(self): @property def lnpay_client(self): - return LNPayClient( - self.chain.rpc_url_private, self.api_key, self.chain.fund_manager_address - ) + return LNPayClient(self.chain.rpc_url_private, self.api_key, self.chain.fund_manager_address) def __check_max_cap_exceeds(self, amount) -> bool: try: @@ -309,9 +296,7 @@ def multi_transfer(self, data): assert acquired, "Could not acquire Lightning multi-transfer lock" item = data[0] - assert not self.__check_max_cap_exceeds( - item["amount"] - ), "Lightning periodic max cap exceeded" + assert not self.__check_max_cap_exceeds(item["amount"]), "Lightning periodic max cap exceeded" try: pay_result = client.pay_invoice(item["to"]) diff --git a/faucet/models.py b/faucet/models.py index 6e6a8e6e..affaa022 100644 --- a/faucet/models.py +++ b/faucet/models.py @@ -361,55 +361,35 @@ def total_claims(self): return total_claims @property - def total_claims_since_last_monday(self): - cached_total_claims_since_last_monday = cache.get(f"gas_tap_chain_total_claims_since_last_monday_{self.pk}") - if cached_total_claims_since_last_monday: - return cached_total_claims_since_last_monday - from faucet.faucet_manager.claim_manager import WeeklyCreditStrategy + def total_claims_this_round(self): + cached_total_claims_this_round = cache.get(f"gas_tap_chain_total_claims_this_round_{self.pk}") + if cached_total_claims_this_round: + return cached_total_claims_this_round + from faucet.faucet_manager.claim_manager import RoundCreditStrategy - total_claims_since_last_monday = ClaimReceipt.objects.filter( + total_claims_this_round = ClaimReceipt.objects.filter( chain=self, - datetime__gte=WeeklyCreditStrategy.get_last_monday(), - _status__in=[ClaimReceipt.VERIFIED, BrightUser.VERIFIED], + datetime__gte=RoundCreditStrategy.get_start_of_the_round(), + _status__in=[ClaimReceipt.VERIFIED], ).count() cache.set( - f"gas_tap_chain_total_claims_since_last_monday_{self.pk}", - total_claims_since_last_monday, + f"gas_tap_chain_total_claims_this_round_{self.pk}", + total_claims_this_round, get_cache_time(self.pk), ) - return total_claims_since_last_monday - - @property - def total_claims_for_last_round(self): - cached_total_claims_for_last_round = cache.get(f"gas_tap_chain_total_claims_for_last_round_{self.pk}") - if cached_total_claims_for_last_round: - return cached_total_claims_for_last_round - from faucet.faucet_manager.claim_manager import WeeklyCreditStrategy - - total_claims_for_last_round = ClaimReceipt.objects.filter( - chain=self, - datetime__gte=WeeklyCreditStrategy.get_second_last_monday(), - datetime__lte=WeeklyCreditStrategy.get_last_monday(), - _status__in=[ClaimReceipt.VERIFIED, BrightUser.VERIFIED], - ).count() - cache.set( - f"gas_tap_chain_total_claims_for_last_round_{self.pk}", - total_claims_for_last_round, - get_cache_time(self.pk), - ) - return total_claims_for_last_round + return total_claims_this_round @property def total_claims_since_last_round(self): cached_total_claims_since_last_round = cache.get(f"gas_tap_chain_total_claims_since_last_round_{self.pk}") if cached_total_claims_since_last_round: return cached_total_claims_since_last_round - from faucet.faucet_manager.claim_manager import WeeklyCreditStrategy + from faucet.faucet_manager.claim_manager import RoundCreditStrategy total_claims_since_last_round = ClaimReceipt.objects.filter( chain=self, - datetime__gte=WeeklyCreditStrategy.get_second_last_monday(), - _status__in=[ClaimReceipt.VERIFIED, BrightUser.VERIFIED], + datetime__gte=RoundCreditStrategy.get_start_of_previous_round(), + _status__in=[ClaimReceipt.VERIFIED], ).count() cache.set( f"gas_tap_chain_total_claims_since_last_round_{self.pk}", diff --git a/faucet/serializers.py b/faucet/serializers.py index 1fb19b25..5c42a209 100644 --- a/faucet/serializers.py +++ b/faucet/serializers.py @@ -1,46 +1,43 @@ from rest_framework import serializers -from faucet.faucet_manager.claim_manager import LimitedChainClaimManager -from faucet.faucet_manager.credit_strategy import CreditStrategyFactory -from faucet.models import BrightUser, Chain, ClaimReceipt, GlobalSettings, DonationReceipt - - -class UserSerializer(serializers.ModelSerializer): - total_weekly_claims_remaining = serializers.SerializerMethodField() - - class Meta: - model = BrightUser - fields = [ - "pk", - "context_id", - "address", - "verification_url", - "verification_status", - "total_weekly_claims_remaining", - ] - read_only_fields = ["context_id"] - - def get_total_weekly_claims_remaining(self, instance): - gs = GlobalSettings.objects.first() - if gs is not None: - return ( - gs.weekly_chain_claim_limit - - LimitedChainClaimManager.get_total_weekly_claims(instance) - ) - - def create(self, validated_data): - address = validated_data["address"] - bright_user = BrightUser.objects.get_or_create(address) - return bright_user +from faucet.models import Chain, ClaimReceipt, DonationReceipt, GlobalSettings + +# class UserSerializer(serializers.ModelSerializer): +# total_weekly_claims_remaining = serializers.SerializerMethodField() + +# class Meta: +# model = BrightUser +# fields = [ +# "pk", +# "context_id", +# "address", +# "verification_url", +# "verification_status", +# "total_weekly_claims_remaining", +# ] +# read_only_fields = ["context_id"] + +# def get_total_weekly_claims_remaining(self, instance): +# gs = GlobalSettings.objects.first() +# if gs is not None: +# return ( +# gs.weekly_chain_claim_limit +# - LimitedChainClaimManager.get_total_weekly_claims(instance) +# ) + +# def create(self, validated_data): +# address = validated_data["address"] +# bright_user = BrightUser.objects.get_or_create(address) +# return bright_user class GlobalSettingsSerializer(serializers.ModelSerializer): class Meta: model = GlobalSettings fields = [ - "weekly_chain_claim_limit", - "tokentap_weekly_claim_limit", - "prizetap_weekly_claim_limit", + "gastap_round_claim_limit", + "tokentap_round_claim_limit", + "prizetap_round_claim_limit", "is_gas_tap_available", ] @@ -104,8 +101,8 @@ class Meta: class ChainSerializer(serializers.ModelSerializer): - claimed = serializers.SerializerMethodField() - unclaimed = serializers.SerializerMethodField() + # claimed = serializers.SerializerMethodField() + # unclaimed = serializers.SerializerMethodField() class Meta: model = Chain @@ -123,11 +120,10 @@ class Meta: "modal_url", "gas_image_url", "max_claim_amount", - "claimed", - "unclaimed", - # "order", + # "claimed", + # "unclaimed", "total_claims", - "total_claims_since_last_monday", + "total_claims_this_round", "tokentap_contract_address", "needs_funding", "is_testnet", @@ -135,21 +131,21 @@ class Meta: "block_scan_address", ] - def get_claimed(self, chain) -> int: - user = self.context["request"].user + # def get_claimed(self, chain) -> int: + # user = self.context["request"].user - if not user.is_authenticated: - return "N/A" - user_profile = user.profile - return CreditStrategyFactory(chain, user_profile).get_strategy().get_claimed() + # if not user.is_authenticated: + # return "N/A" + # user_profile = user.profile + # return CreditStrategyFactory(chain, user_profile).get_strategy().get_claimed() - def get_unclaimed(self, chain) -> int: - user = self.context["request"].user + # def get_unclaimed(self, chain) -> int: + # user = self.context["request"].user - if not user.is_authenticated: - return "N/A" - user_profile = user.profile - return CreditStrategyFactory(chain, user_profile).get_strategy().get_unclaimed() + # if not user.is_authenticated: + # return "N/A" + # user_profile = user.profile + # return CreditStrategyFactory(chain, user_profile).get_strategy().get_unclaimed() class ReceiptSerializer(serializers.ModelSerializer): @@ -173,39 +169,23 @@ class DonationReceiptSerializer(serializers.ModelSerializer): chain = SmallChainSerializer(read_only=True) def validate(self, attrs): - chain = self._validate_chain(attrs.pop('chain_pk')) - attrs['user_profile'] = self.context.get('user') - attrs['chain'] = chain + chain = self._validate_chain(attrs.pop("chain_pk")) + attrs["user_profile"] = self.context.get("user") + attrs["chain"] = chain return attrs def _validate_chain(self, pk: str): try: - chain: Chain = Chain.objects.get(pk=pk, chain_type='EVM') + chain: Chain = Chain.objects.get(pk=pk, chain_type="EVM") except Chain.DoesNotExist: - raise serializers.ValidationError({'chain': 'chain is not EVM or does not exist.'}) + raise serializers.ValidationError({"chain": "chain is not EVM or does not exist."}) return chain class Meta: model = DonationReceipt depth = 1 - fields = [ - "tx_hash", - "chain", - "datetime", - "total_price", - "value", - "chain_pk", - "status", - "user_profile" - ] - read_only_fields = [ - 'value', - 'datetime', - 'total_price', - 'chain', - 'status', - "user_profile" - ] + fields = ["tx_hash", "chain", "datetime", "total_price", "value", "chain_pk", "status", "user_profile"] + read_only_fields = ["value", "datetime", "total_price", "chain", "status", "user_profile"] class LeaderboardSerializer(serializers.Serializer): diff --git a/faucet/test.py b/faucet/test.py index e8321f01..d7a651ef 100644 --- a/faucet/test.py +++ b/faucet/test.py @@ -9,14 +9,14 @@ from django.utils import timezone from rest_framework.test import APITestCase -from authentication.models import UserProfile +from authentication.models import UserProfile, Wallet from brightIDfaucet.settings import DEBUG from faucet.constants import MEMCACHE_LIGHTNING_LOCK_KEY from faucet.constraints import OptimismClaimingGasConstraint, OptimismDonationConstraint from faucet.faucet_manager.claim_manager import ClaimManagerFactory, SimpleClaimManager from faucet.faucet_manager.credit_strategy import ( + RoundCreditStrategy, SimpleCreditStrategy, - WeeklyCreditStrategy, ) from faucet.faucet_manager.fund_manager import LightningFundManager from faucet.helpers import memcache_lock @@ -28,7 +28,6 @@ LightningConfig, NetworkTypes, TransactionBatch, - Wallet, WalletAccount, ) from faucet.views import CustomException @@ -198,36 +197,36 @@ def test_list_chains(self): response = self.request_chain_list() self.assertEqual(response.status_code, 200) - def test_list_chain_should_show_NA_if_no_addresses_provided(self): - chains = self.request_chain_list() - chains_list = json.loads(chains.content) + # def test_list_chain_should_show_NA_if_no_addresses_provided(self): + # chains = self.request_chain_list() + # chains_list = json.loads(chains.content) - for chain_data in chains_list: - self.assertEqual(chain_data["claimed"], "N/A") - self.assertEqual(chain_data["unclaimed"], "N/A") - if chain_data["symbol"] == "XDAI": - self.assertEqual(chain_data["maxClaimAmount"], x_dai_max_claim) - elif chain_data["symbol"] == "eidi": - self.assertEqual(chain_data["maxClaimAmount"], eidi_max_claim) + # for chain_data in chains_list: + # self.assertEqual(chain_data["claimed"], "N/A") + # self.assertEqual(chain_data["unclaimed"], "N/A") + # if chain_data["symbol"] == "XDAI": + # self.assertEqual(chain_data["maxClaimAmount"], x_dai_max_claim) + # elif chain_data["symbol"] == "eidi": + # self.assertEqual(chain_data["maxClaimAmount"], eidi_max_claim) - def test_chain_list_without_token(self): - endpoint = reverse("FAUCET:chain-list") - chain_list_response = self.client.get(endpoint) - chain_list = json.loads(chain_list_response.content) + # def test_chain_list_without_token(self): + # endpoint = reverse("FAUCET:chain-list") + # chain_list_response = self.client.get(endpoint) + # chain_list = json.loads(chain_list_response.content) - for chain_data in chain_list: - self.assertEqual(chain_data["claimed"], "N/A") - self.assertEqual(chain_data["unclaimed"], "N/A") + # for chain_data in chain_list: + # self.assertEqual(chain_data["claimed"], "N/A") + # self.assertEqual(chain_data["unclaimed"], "N/A") - def test_chain_list_with_token(self): - endpoint = reverse("FAUCET:chain-list") - self.client.force_authenticate(user=self.new_user.user) - chain_list_response = self.client.get(endpoint) - chain_list = json.loads(chain_list_response.content) + # def test_chain_list_with_token(self): + # endpoint = reverse("FAUCET:chain-list") + # self.client.force_authenticate(user=self.new_user.user) + # chain_list_response = self.client.get(endpoint) + # chain_list = json.loads(chain_list_response.content) - for chain_data in chain_list: - self.assertEqual(chain_data["claimed"], 0) - self.assertEqual(chain_data["unclaimed"], chain_data["maxClaimAmount"]) + # for chain_data in chain_list: + # self.assertEqual(chain_data["claimed"], 0) + # self.assertEqual(chain_data["unclaimed"], chain_data["maxClaimAmount"]) class TestClaim(APITestCase): @@ -238,11 +237,11 @@ def setUp(self) -> None: self.x_dai = create_xDai_chain(self.wallet) self.idChain = create_idChain_chain(self.wallet) self.test_chain = create_test_chain(self.wallet) - GlobalSettings.objects.create(weekly_chain_claim_limit=2) + GlobalSettings.objects.create(gastap_round_claim_limit=2) def test_get_claimed_should_be_zero(self): - credit_strategy_xdai = WeeklyCreditStrategy(self.x_dai, self.new_user) - credit_strategy_id_chain = WeeklyCreditStrategy(self.idChain, self.new_user) + credit_strategy_xdai = RoundCreditStrategy(self.x_dai, self.new_user) + credit_strategy_id_chain = RoundCreditStrategy(self.idChain, self.new_user) self.assertEqual(credit_strategy_xdai.get_claimed(), 0) self.assertEqual(credit_strategy_id_chain.get_claimed(), 0) @@ -259,8 +258,8 @@ def test_x_dai_claimed_be_zero_eth_be_100(self): amount=claim_amount, ) - credit_strategy_xdai = WeeklyCreditStrategy(self.x_dai, self.new_user) - credit_strategy_id_chain = WeeklyCreditStrategy(self.idChain, self.new_user) + credit_strategy_xdai = RoundCreditStrategy(self.x_dai, self.new_user) + credit_strategy_id_chain = RoundCreditStrategy(self.idChain, self.new_user) self.assertEqual(credit_strategy_xdai.get_claimed(), 0) self.assertEqual(credit_strategy_id_chain.get_claimed(), claim_amount) @@ -268,7 +267,7 @@ def test_x_dai_claimed_be_zero_eth_be_100(self): self.assertEqual(credit_strategy_id_chain.get_unclaimed(), eidi_max_claim - claim_amount) def test_claim_manager_fail_if_claim_amount_exceeds_unclaimed(self): - claim_manager_x_dai = SimpleClaimManager(WeeklyCreditStrategy(self.x_dai, self.new_user)) + claim_manager_x_dai = SimpleClaimManager(RoundCreditStrategy(self.x_dai, self.new_user)) try: claim_manager_x_dai.claim(x_dai_max_claim + 10) @@ -282,7 +281,7 @@ def test_claim_manager_fail_if_claim_amount_exceeds_unclaimed(self): ) def test_claim_unverified_user_should_fail(self): claim_amount = 100 - claim_manager_x_dai = SimpleClaimManager(WeeklyCreditStrategy(self.x_dai, self.new_user)) + claim_manager_x_dai = SimpleClaimManager(RoundCreditStrategy(self.x_dai, self.new_user)) try: claim_manager_x_dai.claim(claim_amount) @@ -396,7 +395,7 @@ def setUp(self) -> None: self.password = "test" self._address = "0x3E5e9111Ae8eB78Fe1CC3bb8915d5D461F3Ef9A9" - GlobalSettings.objects.create(weekly_chain_claim_limit=2) + GlobalSettings.objects.create(gastap_round_claim_limit=2) LightningConfig.objects.create( period=86800, period_max_cap=100, current_round=int(int(time.time()) / 86800) * 86800 ) @@ -566,15 +565,15 @@ def setUp(self) -> None: self.password = "test" self._address = "0x3E5e9111Ae8eB78Fe1CC3bb8915d5D461F3Ef9A9" - GlobalSettings.objects.create(weekly_chain_claim_limit=2) + GlobalSettings.objects.create(gastap_round_claim_limit=2) self.user_profile = create_new_user(self._address) self.client.force_authenticate(user=self.user_profile.user) - self.strategy = WeeklyCreditStrategy(self.test_chain, self.user_profile) + self.strategy = RoundCreditStrategy(self.test_chain, self.user_profile) def test_last_monday(self): now = timezone.now() - last_monday = WeeklyCreditStrategy.get_last_monday() + last_monday = RoundCreditStrategy.get_start_of_the_round() self.assertGreaterEqual(now, last_monday) def create_claim_receipt(self, date, amount=10): @@ -591,7 +590,7 @@ def create_claim_receipt(self, date, amount=10): ) def test_last_week_claims(self): - last_monday = WeeklyCreditStrategy.get_last_monday() + last_monday = RoundCreditStrategy.get_start_of_the_round() last_sunday = last_monday - datetime.timedelta(days=1) tuesday = last_monday + datetime.timedelta(days=1) wednesday = last_monday + datetime.timedelta(days=2) @@ -606,7 +605,7 @@ def test_last_week_claims(self): self.assertEqual(total_claimed, 30) def test_unclaimed(self): - last_monday = WeeklyCreditStrategy.get_last_monday() + last_monday = RoundCreditStrategy.get_start_of_the_round() last_sunday = last_monday - datetime.timedelta(days=1) tuesday = last_monday + datetime.timedelta(days=1) diff --git a/faucet/urls.py b/faucet/urls.py index d4d2449e..a58a80e2 100644 --- a/faucet/urls.py +++ b/faucet/urls.py @@ -1,25 +1,24 @@ from django.urls import path +from drf_yasg import openapi +from drf_yasg.views import get_schema_view from faucet.views import ( + ChainBalanceView, ChainListView, ClaimCountView, ClaimMaxView, + DonationReceiptView, + GetTotalWeeklyClaimsRemainingView, GlobalSettingsView, LastClaimView, + LeaderboardView, ListClaims, - GetTotalWeeklyClaimsRemainingView, + SmallChainListView, + UserLeaderboardView, artwork_video, error500, - ChainBalanceView, - SmallChainListView, - DonationReceiptView, - LeaderboardView, - UserLeaderboardView ) -from drf_yasg.views import get_schema_view -from drf_yasg import openapi - schema_view = get_schema_view( openapi.Info( title="BrightID Gas Faucet API", @@ -42,9 +41,7 @@ path("user/last-claim/", LastClaimView.as_view(), name="last-claim"), path("user/claims/", ListClaims.as_view(), name="claims"), path("claims/count/", ClaimCountView.as_view(), name="claims-count"), - path( - "chain/list/", ChainListView.as_view(), name="chain-list" - ), # can have auth token for more user specific info + path("chain/list/", ChainListView.as_view(), name="chain-list"), # can have auth token for more user specific info path("chain/small-list/", SmallChainListView.as_view(), name="small-chain-list"), path( "chain//claim-max/", @@ -67,5 +64,5 @@ ), path("user/donation/", DonationReceiptView.as_view(), name="donation-receipt"), path("gas-tap/leaderboard/", LeaderboardView.as_view(), name="gas-tap-leaderboard"), - path("user/gas-tap/leaderboard/", UserLeaderboardView.as_view(), name="user-gas-tap-leaderboard") + path("user/gas-tap/leaderboard/", UserLeaderboardView.as_view(), name="user-gas-tap-leaderboard"), ] diff --git a/faucet/views.py b/faucet/views.py index 8548dc7a..0d91a139 100644 --- a/faucet/views.py +++ b/faucet/views.py @@ -1,41 +1,42 @@ import json -from django.http import FileResponse +import logging import os + import rest_framework.exceptions -from django.http import Http404 +from django.conf import settings +from django.contrib.postgres.expressions import ArraySubquery +from django.db.models import FloatField, OuterRef, Subquery, Sum +from django.db.models.functions import Cast +from django.http import FileResponse, Http404, HttpResponse +from django.urls import reverse from rest_framework.generics import ( - RetrieveAPIView, ListAPIView, - ListCreateAPIView, get_object_or_404, + ListCreateAPIView, + RetrieveAPIView, + get_object_or_404, ) +from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView -from django.http import HttpResponse -from rest_framework.permissions import IsAuthenticated -from django.urls import reverse from authentication.models import UserProfile, Wallet +from core.filters import ChainFilterBackend, IsOwnerFilterBackend +from core.paginations import StandardResultsSetPagination from faucet.faucet_manager.claim_manager import ( ClaimManagerFactory, LimitedChainClaimManager, ) -from faucet.faucet_manager.claim_manager import WeeklyCreditStrategy -from faucet.models import Chain, ClaimReceipt, GlobalSettings, DonationReceipt +from faucet.faucet_manager.credit_strategy import RoundCreditStrategy +from faucet.models import Chain, ClaimReceipt, DonationReceipt, GlobalSettings from faucet.serializers import ( ChainBalanceSerializer, + ChainSerializer, + DonationReceiptSerializer, GlobalSettingsSerializer, + LeaderboardSerializer, ReceiptSerializer, - ChainSerializer, SmallChainSerializer, - DonationReceiptSerializer, LeaderboardSerializer, ) -from core.paginations import StandardResultsSetPagination -from core.filters import ChainFilterBackend, IsOwnerFilterBackend -# import BASE_DIR from django settings -from django.conf import settings -from django.db.models import FloatField, Sum, OuterRef, Subquery, Window, F, Count -from django.db.models.functions import Cast -from django.contrib.postgres.expressions import ArraySubquery class CustomException(Exception): @@ -55,11 +56,7 @@ class LastClaimView(RetrieveAPIView): def get_object(self): user_profile = self.request.user.profile try: - return ( - ClaimReceipt.objects.filter(user_profile=user_profile) - .order_by("pk") - .last() - ) + return ClaimReceipt.objects.filter(user_profile=user_profile).order_by("pk").last() except ClaimReceipt.DoesNotExist: raise Http404("Claim Receipt for this user does not exist") @@ -83,7 +80,7 @@ def get_queryset(self): ClaimReceipt.PENDING, ClaimReceipt.REJECTED, ], - datetime__gte=WeeklyCreditStrategy.get_last_monday(), + datetime__gte=RoundCreditStrategy.get_start_of_the_round(), ).order_by("-pk") @@ -98,10 +95,7 @@ def get(self, request, *args, **kwargs): user_profile = request.user.profile gs = GlobalSettings.objects.first() if gs is not None: - result = ( - gs.weekly_chain_claim_limit - - LimitedChainClaimManager.get_total_weekly_claims(user_profile) - ) + result = gs.weekly_chain_claim_limit - LimitedChainClaimManager.get_total_weekly_claims(user_profile) return Response({"total_weekly_claims_remaining": result}, status=200) else: raise Http404("Global Settings Not Found") @@ -119,9 +113,7 @@ class ChainListView(ListAPIView): def get_queryset(self): queryset = Chain.objects.filter(is_active=True, show_in_gastap=True) - sorted_queryset = sorted( - queryset, key=lambda obj: obj.total_claims_since_last_round, reverse=True - ) + sorted_queryset = sorted(queryset, key=lambda obj: obj.total_claims_since_last_round, reverse=True) return sorted_queryset @@ -169,13 +161,11 @@ def wallet_address_is_set(self): chain = self.get_chain() try: - _wallet = Wallet.objects.get( - user_profile=self.get_user(), wallet_type=chain.chain_type - ) + Wallet.objects.get(user_profile=self.get_user(), wallet_type=chain.chain_type) return True, None except Exception as e: + logging.error("wallet address not set", e) raise CustomException("wallet address not set") - # return Response({"message": "wallet address not set"}, status=403) def get_chain(self) -> Chain: chain_pk = self.kwargs.get("chain_pk", None) @@ -194,7 +184,7 @@ def claim_max(self, passive_address) -> ClaimReceipt: assert max_credit > 0 return manager.claim(max_credit, passive_address=passive_address) except AssertionError as e: - # return Response({"message": "no credit left"}, status=403) + logging.error("no credit left for user", e) raise CustomException("no credit left") except ValueError as e: raise rest_framework.exceptions.APIException(e) @@ -228,7 +218,7 @@ class DonationReceiptView(ListCreateAPIView): def get_serializer_context(self): context = super().get_serializer_context() - context.update({'user': self.get_user()}) + context.update({"user": self.get_user()}) return context def get_queryset(self): @@ -249,20 +239,24 @@ def get_user(self) -> UserProfile: def get_object(self): queryset = self.filter_queryset(self.get_queryset()) - queryset = queryset.filter(status=ClaimReceipt.VERIFIED) \ - .annotate( - total_price_float=Cast('total_price', FloatField())).values('user_profile') \ - .annotate( - sum_total_price=Sum('total_price_float')) + queryset = ( + queryset.filter(status=ClaimReceipt.VERIFIED) + .annotate(total_price_float=Cast("total_price", FloatField())) + .values("user_profile") + .annotate(sum_total_price=Sum("total_price_float")) + ) user_obj = get_object_or_404(queryset, user_profile=self.get_user().pk) - user_rank = queryset.filter(sum_total_price__gt=user_obj.get('sum_total_price')).count() + 1 - user_obj['rank'] = user_rank - user_obj['username'] = self.get_user().username - user_obj['wallet'] = self.get_user().wallets.all()[0].address - interacted_chains = list(DonationReceipt.objects.filter( - user_profile=self.get_user()).filter(status=ClaimReceipt.VERIFIED).values_list( - 'chain', flat=True).distinct()) - user_obj['interacted_chains'] = interacted_chains + user_rank = queryset.filter(sum_total_price__gt=user_obj.get("sum_total_price")).count() + 1 + user_obj["rank"] = user_rank + user_obj["username"] = self.get_user().username + user_obj["wallet"] = self.get_user().wallets.all()[0].address + interacted_chains = list( + DonationReceipt.objects.filter(user_profile=self.get_user()) + .filter(status=ClaimReceipt.VERIFIED) + .values_list("chain", flat=True) + .distinct() + ) + user_obj["interacted_chains"] = interacted_chains return user_obj @@ -275,15 +269,22 @@ class LeaderboardView(ListAPIView): def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) - donation_receipt = queryset.filter(status=ClaimReceipt.VERIFIED).annotate( - total_price_float=Cast('total_price', FloatField())).values('user_profile').annotate( - sum_total_price=Sum('total_price_float')).order_by('-sum_total_price') - subquery_interacted_chains = DonationReceipt.objects.filter( - user_profile=OuterRef('user_profile')).filter(status=ClaimReceipt.VERIFIED).values_list( - 'chain', flat=True).distinct() + donation_receipt = ( + queryset.filter(status=ClaimReceipt.VERIFIED) + .annotate(total_price_float=Cast("total_price", FloatField())) + .values("user_profile") + .annotate(sum_total_price=Sum("total_price_float")) + .order_by("-sum_total_price") + ) + subquery_interacted_chains = ( + DonationReceipt.objects.filter(user_profile=OuterRef("user_profile")) + .filter(status=ClaimReceipt.VERIFIED) + .values_list("chain", flat=True) + .distinct() + ) queryset = donation_receipt.annotate(interacted_chains=ArraySubquery(subquery_interacted_chains)) - subquery_username = UserProfile.objects.filter(pk=OuterRef('user_profile')).values('username') - subquery_wallet = Wallet.objects.filter(user_profile=OuterRef('user_profile')).values('address') + subquery_username = UserProfile.objects.filter(pk=OuterRef("user_profile")).values("username") + subquery_wallet = Wallet.objects.filter(user_profile=OuterRef("user_profile")).values("address") queryset = queryset.annotate(username=Subquery(subquery_username), wallet=Subquery(subquery_wallet)) page = self.paginate_queryset(queryset) if page is not None: @@ -295,7 +296,7 @@ def list(self, request, *args, **kwargs): def artwork_video(request): - video_file = os.path.join(settings.BASE_DIR, f"faucet/artwork.mp4") + video_file = os.path.join(settings.BASE_DIR, "faucet/artwork.mp4") return FileResponse(open(video_file, "rb"), content_type="video/mp4") @@ -305,7 +306,9 @@ def artwork_view(request, token_id): response = { "name": "Unitap Pass", - "description": "Unitap is an onboarding tool for networks and communities and a gateway for users to web3. https://unitap.app . Unitap Pass is a VIP pass for Unitap. Holders will enjoy various benefits as Unitap grows.", + "description": "Unitap is an onboarding tool for networks and communities and a gateway for users to web3." + " https://unitap.app . Unitap Pass is a VIP pass for Unitap. Holders" + " will enjoy various benefits as Unitap grows.", "image": artwork_video_url, "animation_url": artwork_video_url, } diff --git a/permissions/admin.py b/permissions/admin.py index 7933cfe0..030a68e4 100644 --- a/permissions/admin.py +++ b/permissions/admin.py @@ -1,31 +1,31 @@ -from django.contrib import admin -from .models import * +# from django.contrib import admin +# from .models import * -# Register your models here. +# # Register your models here. -class BrightIDMeetVerificationAdmin(admin.ModelAdmin): - list_display = ["pk", "name"] +# class BrightIDMeetVerificationAdmin(admin.ModelAdmin): +# list_display = ["pk", "name"] -class BrightIDAuraVerificationAdmin(admin.ModelAdmin): - list_display = ["pk", "name"] +# class BrightIDAuraVerificationAdmin(admin.ModelAdmin): +# list_display = ["pk", "name"] -class OncePerWeekVerificationAdmin(admin.ModelAdmin): - list_display = ["pk", "name"] +# class OncePerWeekVerificationAdmin(admin.ModelAdmin): +# list_display = ["pk", "name"] -class OncePerMonthVerificationAdmin(admin.ModelAdmin): - list_display = ["pk", "name"] +# class OncePerMonthVerificationAdmin(admin.ModelAdmin): +# list_display = ["pk", "name"] -class OnceInALifeTimeVerificationAdmin(admin.ModelAdmin): - list_display = ["pk", "name"] +# class OnceInALifeTimeVerificationAdmin(admin.ModelAdmin): +# list_display = ["pk", "name"] -admin.site.register(BrightIDMeetVerification, BrightIDMeetVerificationAdmin) -admin.site.register(BrightIDAuraVerification, BrightIDAuraVerificationAdmin) -admin.site.register(OncePerWeekVerification, OncePerWeekVerificationAdmin) -admin.site.register(OncePerMonthVerification, OncePerMonthVerificationAdmin) -admin.site.register(OnceInALifeTimeVerification, OnceInALifeTimeVerificationAdmin) +# admin.site.register(BrightIDMeetVerification, BrightIDMeetVerificationAdmin) +# admin.site.register(BrightIDAuraVerification, BrightIDAuraVerificationAdmin) +# admin.site.register(OncePerWeekVerification, OncePerWeekVerificationAdmin) +# admin.site.register(OncePerMonthVerification, OncePerMonthVerificationAdmin) +# admin.site.register(OnceInALifeTimeVerification, OnceInALifeTimeVerificationAdmin) diff --git a/permissions/migrations/0006_remove_brightidmeetverification_permission_ptr_and_more.py b/permissions/migrations/0006_remove_brightidmeetverification_permission_ptr_and_more.py new file mode 100644 index 00000000..0ae46b1b --- /dev/null +++ b/permissions/migrations/0006_remove_brightidmeetverification_permission_ptr_and_more.py @@ -0,0 +1,51 @@ +# Generated by Django 4.0.4 on 2023-10-26 21:20 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('permissions', '0005_onceinalifetimeverification'), + ] + + operations = [ + migrations.RemoveField( + model_name='brightidmeetverification', + name='permission_ptr', + ), + migrations.RemoveField( + model_name='onceinalifetimeverification', + name='permission_ptr', + ), + migrations.RemoveField( + model_name='oncepermonthverification', + name='permission_ptr', + ), + migrations.RemoveField( + model_name='onceperweekverification', + name='permission_ptr', + ), + migrations.RemoveField( + model_name='permission', + name='polymorphic_ctype', + ), + migrations.DeleteModel( + name='BrightIDAuraVerification', + ), + migrations.DeleteModel( + name='BrightIDMeetVerification', + ), + migrations.DeleteModel( + name='OnceInALifeTimeVerification', + ), + migrations.DeleteModel( + name='OncePerMonthVerification', + ), + migrations.DeleteModel( + name='OncePerWeekVerification', + ), + migrations.DeleteModel( + name='Permission', + ), + ] diff --git a/permissions/migrations/0007_initial.py b/permissions/migrations/0007_initial.py new file mode 100644 index 00000000..44aafc09 --- /dev/null +++ b/permissions/migrations/0007_initial.py @@ -0,0 +1,63 @@ +# Generated by Django 4.0.4 on 2023-10-26 21:41 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('permissions', '0006_remove_brightidmeetverification_permission_ptr_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='Permission', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('description', models.TextField(blank=True, null=True)), + ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + ), + migrations.CreateModel( + name='BrightIDAuraVerification', + fields=[ + ('permission_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='permissions.permission')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('permissions.permission',), + ), + migrations.CreateModel( + name='BrightIDMeetVerification', + fields=[ + ('permission_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='permissions.permission')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('permissions.permission',), + ), + migrations.CreateModel( + name='OnceInALifeTimeVerification', + fields=[ + ('permission_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='permissions.permission')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('permissions.permission',), + ), + ] diff --git a/permissions/models.py b/permissions/models.py index 61ffc1fb..1a80cc56 100644 --- a/permissions/models.py +++ b/permissions/models.py @@ -1,11 +1,8 @@ from django.db import models from polymorphic.models import PolymorphicModel -from faucet.faucet_manager.credit_strategy import WeeklyCreditStrategy - class Permission(PolymorphicModel): - name = models.CharField(max_length=200) description = models.TextField(null=True, blank=True) @@ -33,28 +30,28 @@ def response(self): return "You must be Aura verified on BrightID to claim this token." -class OncePerWeekVerification(Permission): - def is_valid(self, user_profile, *args, **kwargs): - token_distribution = kwargs.get("token_distribution") - return not token_distribution.claims.filter( - user_profile=user_profile, - created_at__gte=WeeklyCreditStrategy.get_last_monday(), - ).exists() - - def response(self): - return "You have already claimed this token this week" +# class OncePerWeekVerification(Permission): +# def is_valid(self, user_profile, *args, **kwargs): +# token_distribution = kwargs.get("token_distribution") +# return not token_distribution.claims.filter( +# user_profile=user_profile, +# created_at__gte=WeeklyCreditStrategy.get_last_monday(), +# ).exists() +# def response(self): +# return "You have already claimed this token this week" -class OncePerMonthVerification(Permission): - def is_valid(self, user_profile, *args, **kwargs): - token_distribution = kwargs.get("token_distribution") - return not token_distribution.claims.filter( - user_profile=user_profile, - created_at__gte=WeeklyCreditStrategy.get_first_day_of_the_month(), - ).exists() - def response(self): - return "You have already claimed this token this month" +# class OncePerMonthVerification(Permission): +# def is_valid(self, user_profile, *args, **kwargs): +# token_distribution = kwargs.get("token_distribution") +# return not token_distribution.claims.filter( +# user_profile=user_profile, +# created_at__gte=WeeklyCreditStrategy.get_first_day_of_the_month(), +# ).exists() + +# def response(self): +# return "You have already claimed this token this month" class OnceInALifeTimeVerification(Permission): diff --git a/permissions/serializers.py b/permissions/serializers.py index e815efb4..1e89ca06 100644 --- a/permissions/serializers.py +++ b/permissions/serializers.py @@ -1,35 +1,35 @@ -from rest_framework import serializers -from rest_polymorphic.serializers import PolymorphicSerializer +# from rest_framework import serializers +# from rest_polymorphic.serializers import PolymorphicSerializer -from permissions.models import ( - Permission, - BrightIDMeetVerification, - BrightIDAuraVerification, -) +# from permissions.models import ( +# Permission, +# BrightIDMeetVerification, +# BrightIDAuraVerification, +# ) -class PermissionBaseSerializer(serializers.ModelSerializer): - class Meta: - model = Permission - fields = ["id", "name", "description"] +# class PermissionBaseSerializer(serializers.ModelSerializer): +# class Meta: +# model = Permission +# fields = ["id", "name", "description"] -class BrightIDMeetVerificationSerializer(PermissionBaseSerializer): - class Meta: - model = BrightIDMeetVerification - fields = ["id", "name", "description"] +# class BrightIDMeetVerificationSerializer(PermissionBaseSerializer): +# class Meta: +# model = BrightIDMeetVerification +# fields = ["id", "name", "description"] -class BrightIDAuraVerificationSerializer(PermissionBaseSerializer): - class Meta: - model = BrightIDAuraVerification - fields = ["id", "name", "description"] +# class BrightIDAuraVerificationSerializer(PermissionBaseSerializer): +# class Meta: +# model = BrightIDAuraVerification +# fields = ["id", "name", "description"] -class PermissionSerializer(PolymorphicSerializer): - model_serializer_mapping = { - Permission: PermissionBaseSerializer, - BrightIDMeetVerification: BrightIDMeetVerificationSerializer, - BrightIDAuraVerification: BrightIDAuraVerificationSerializer, - } +# class PermissionSerializer(PolymorphicSerializer): +# model_serializer_mapping = { +# Permission: PermissionBaseSerializer, +# BrightIDMeetVerification: BrightIDMeetVerificationSerializer, +# BrightIDAuraVerification: BrightIDAuraVerificationSerializer, +# } diff --git a/permissions/tests.py b/permissions/tests.py index 23086d7d..3487ab0b 100644 --- a/permissions/tests.py +++ b/permissions/tests.py @@ -1,29 +1,28 @@ -from rest_framework.test import APITestCase -from .models import * +# from rest_framework.test import APITestCase +# from .models import * -class PermissionsTestCase(APITestCase): - def setUp(self) -> None: - pass +# class PermissionsTestCase(APITestCase): +# def setUp(self) -> None: +# pass - def test_permissions_creation(self): - p = BrightIDMeetVerification.objects.create(name="BrightID Meet Verification") - self.assertEqual(Permission.objects.count(), 1) - self.assertEqual(Permission.objects.first(), p) +# def test_permissions_creation(self): +# p = BrightIDMeetVerification.objects.create(name="BrightID Meet Verification") +# self.assertEqual(Permission.objects.count(), 1) +# self.assertEqual(Permission.objects.first(), p) - p2 = BrightIDAuraVerification.objects.create(name="BrightID Aura Verification") - self.assertEqual(Permission.objects.count(), 2) - self.assertEqual(Permission.objects.last(), p2) +# p2 = BrightIDAuraVerification.objects.create(name="BrightID Aura Verification") +# self.assertEqual(Permission.objects.count(), 2) +# self.assertEqual(Permission.objects.last(), p2) - p3 = OncePerWeekVerification.objects.create(name="Once Per Week Verification") - self.assertEqual(Permission.objects.count(), 3) - self.assertEqual(Permission.objects.last(), p3) +# p3 = OncePerWeekVerification.objects.create(name="Once Per Week Verification") +# self.assertEqual(Permission.objects.count(), 3) +# self.assertEqual(Permission.objects.last(), p3) - p4 = OncePerMonthVerification.objects.create(name="Once Per Month Verification") - self.assertEqual(Permission.objects.count(), 4) - self.assertEqual(Permission.objects.last(), p4) +# p4 = OncePerMonthVerification.objects.create(name="Once Per Month Verification") +# self.assertEqual(Permission.objects.count(), 4) +# self.assertEqual(Permission.objects.last(), p4) - p5 = OnceInALifeTimeVerification.objects.create(name="Once In A Life Time Verification") - self.assertEqual(Permission.objects.count(), 5) - self.assertEqual(Permission.objects.last(), p5) - +# p5 = OnceInALifeTimeVerification.objects.create(name="Once In A Life Time Verification") +# self.assertEqual(Permission.objects.count(), 5) +# self.assertEqual(Permission.objects.last(), p5) diff --git a/prizetap/migrations/0003_raffle_permissions.py b/prizetap/migrations/0003_raffle_permissions.py index 201b70e2..9461baf4 100644 --- a/prizetap/migrations/0003_raffle_permissions.py +++ b/prizetap/migrations/0003_raffle_permissions.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): dependencies = [ - ('permissions', '0004_oncepermonthverification'), ('prizetap', '0002_raffle_is_prize_nft'), ] diff --git a/tokenTap/constraints.py b/tokenTap/constraints.py index 5e76522f..626ab7c1 100644 --- a/tokenTap/constraints.py +++ b/tokenTap/constraints.py @@ -1,16 +1,14 @@ -from core.constraints import * +from core.constraints import ConstraintVerification from core.utils import TimeUtils -from faucet.constraints import OptimismHasClaimedGasInThisRound from faucet.models import ClaimReceipt - -class OncePerWeekVerification(ConstraintVerification): - def is_observed(self, *args, **kwargs): - token_distribution = kwargs["token_distribution"] - return not token_distribution.claims.filter( - user_profile=self.user_profile, - created_at__gte=TimeUtils.get_last_monday(), - ).exists() +# class OncePerWeekVerification(ConstraintVerification): +# def is_observed(self, *args, **kwargs): +# token_distribution = kwargs["token_distribution"] +# return not token_distribution.claims.filter( +# user_profile=self.user_profile, +# created_at__gte=TimeUtils.get_first_day_of_the_month(), +# ).exists() class OncePerMonthVerification(ConstraintVerification): diff --git a/tokenTap/helpers.py b/tokenTap/helpers.py index b7d0f254..eb6fe373 100644 --- a/tokenTap/helpers.py +++ b/tokenTap/helpers.py @@ -1,11 +1,13 @@ import random -from web3 import Web3, Account -from faucet.faucet_manager.credit_strategy import WeeklyCreditStrategy -from faucet.models import GlobalSettings -from .models import TokenDistributionClaim -from authentication.models import NetworkTypes -from faucet.models import WalletAccount + from eth_account.messages import encode_defunct +from web3 import Account, Web3 + +from authentication.models import NetworkTypes +from faucet.faucet_manager.credit_strategy import RoundCreditStrategy +from faucet.models import GlobalSettings, WalletAccount + +from .models import TokenDistributionClaim def create_uint32_random_nonce(): @@ -19,7 +21,6 @@ def create_uint32_random_nonce(): def hash_message(user, token, amount, nonce): - message_hash = Web3().solidity_keccak( ["address", "address", "uint256", "uint32"], [Web3.to_checksum_address(user), Web3.to_checksum_address(token), amount, nonce], @@ -30,7 +31,6 @@ def hash_message(user, token, amount, nonce): def sign_hashed_message(hashed_message): - private_key = WalletAccount.objects.get(network_type=NetworkTypes.EVM).private_key account = Account.from_key(private_key) @@ -43,7 +43,7 @@ def has_weekly_credit_left(user_profile): return ( TokenDistributionClaim.objects.filter( user_profile=user_profile, - created_at__gte=WeeklyCreditStrategy.get_last_monday(), + created_at__gte=RoundCreditStrategy.get_start_of_the_round(), ).count() - < GlobalSettings.objects.first().tokentap_weekly_claim_limit + < GlobalSettings.objects.first().tokentap_round_claim_limit ) diff --git a/tokenTap/migrations/0002_tokendistribution_permissions.py b/tokenTap/migrations/0002_tokendistribution_permissions.py index 3666fc02..a1698c55 100644 --- a/tokenTap/migrations/0002_tokendistribution_permissions.py +++ b/tokenTap/migrations/0002_tokendistribution_permissions.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): dependencies = [ - ('permissions', '0001_initial'), ('tokenTap', '0001_initial'), ] diff --git a/tokenTap/models.py b/tokenTap/models.py index 57b3dbd5..310fedf6 100644 --- a/tokenTap/models.py +++ b/tokenTap/models.py @@ -1,16 +1,21 @@ -from django.utils import timezone +from django.core.cache import cache from django.db import models +from django.utils import timezone + from authentication.models import NetworkTypes, UserProfile -from faucet.models import Chain, ClaimReceipt -from faucet.constraints import OptimismHasClaimedGasInThisRound from core.models import UserConstraint -from .constraints import * -from django.core.cache import cache +from faucet.constraints import OptimismHasClaimedGasInThisRound +from faucet.models import Chain, ClaimReceipt + +from .constraints import ( + OnceInALifeTimeVerification, + OncePerMonthVerification, + TimeUtils, +) class Constraint(UserConstraint): constraints = UserConstraint.constraints + [ - OncePerWeekVerification, OncePerMonthVerification, OnceInALifeTimeVerification, OptimismHasClaimedGasInThisRound, @@ -31,9 +36,7 @@ class TokenDistribution(models.Model): token = models.CharField(max_length=100) token_address = models.CharField(max_length=255) amount = models.BigIntegerField() - chain = models.ForeignKey( - Chain, on_delete=models.CASCADE, related_name="token_distribution" - ) + chain = models.ForeignKey(Chain, on_delete=models.CASCADE, related_name="token_distribution") permissions = models.ManyToManyField(Constraint, blank=True) @@ -73,11 +76,10 @@ def total_claims_since_last_round(self): ) if cached_total_claims_since_last_round: return cached_total_claims_since_last_round - from faucet.faucet_manager.claim_manager import WeeklyCreditStrategy total_claims_since_last_round = TokenDistributionClaim.objects.filter( token_distribution=self, - created_at__gte=TimeUtils.get_second_last_monday(), + created_at__gte=TimeUtils.get_first_day_of_last_month(), status__in=[ClaimReceipt.VERIFIED, ClaimReceipt.PENDING], ).count() cache.set( @@ -92,12 +94,8 @@ def __str__(self): class TokenDistributionClaim(models.Model): - token_distribution = models.ForeignKey( - TokenDistribution, on_delete=models.CASCADE, related_name="claims" - ) - user_profile = models.ForeignKey( - UserProfile, on_delete=models.CASCADE, related_name="tokentap_claims" - ) + token_distribution = models.ForeignKey(TokenDistribution, on_delete=models.CASCADE, related_name="claims") + user_profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name="tokentap_claims") created_at = models.DateTimeField(auto_now_add=True, editable=True) notes = models.TextField(null=True, blank=True) @@ -105,9 +103,7 @@ class TokenDistributionClaim(models.Model): signature = models.CharField(max_length=1024, blank=True, null=True) nonce = models.BigIntegerField(null=True, blank=True) - status = models.CharField( - max_length=30, choices=ClaimReceipt.states, default=ClaimReceipt.PENDING - ) + status = models.CharField(max_length=30, choices=ClaimReceipt.states, default=ClaimReceipt.PENDING) tx_hash = models.CharField(max_length=255, null=True, blank=True) diff --git a/tokenTap/serializers.py b/tokenTap/serializers.py index e772d17f..06ae3fe8 100644 --- a/tokenTap/serializers.py +++ b/tokenTap/serializers.py @@ -1,8 +1,23 @@ -from faucet.serializers import SmallChainSerializer from rest_framework import serializers + +from core.constraints import ( # noqa: F401 + BrightIDAuraVerification, + BrightIDMeetVerification, +) from core.serializers import UserConstraintBaseSerializer -from tokenTap.models import * -from .constraints import * +from faucet.serializers import SmallChainSerializer +from tokenTap.models import ( + Constraint, + TokenDistribution, + TokenDistributionClaim, + UserConstraint, +) + +from .constraints import ( # noqa: F401 + ConstraintVerification, + OnceInALifeTimeVerification, + OncePerMonthVerification, +) class ConstraintSerializer(UserConstraintBaseSerializer, serializers.ModelSerializer): diff --git a/tokenTap/tests.py b/tokenTap/tests.py index 23265e63..0b5bd35a 100644 --- a/tokenTap/tests.py +++ b/tokenTap/tests.py @@ -4,18 +4,9 @@ from django.contrib.auth.models import User from django.urls import reverse from django.utils import timezone - -# from permissions.models import ( -# BrightIDAuraVerification, -# BrightIDMeetVerification, -# OncePerWeekVerification, -# OncePerMonthVerification, -# OnceInALifeTimeVerification, -# ) from rest_framework.test import APITestCase, override_settings from authentication.models import NetworkTypes, UserProfile, Wallet -from faucet.faucet_manager.credit_strategy import WeeklyCreditStrategy from faucet.models import ( Chain, ClaimReceipt, @@ -217,7 +208,6 @@ def setUp(self) -> None: ) self.permission1 = Constraint.objects.create(name="BrightIDMeetVerification", title="BrightID Meet", type="VER") self.permission2 = Constraint.objects.create(name="BrightIDAuraVerification", title="BrightID Aura", type="VER") - self.permission3 = Constraint.objects.create(name="OncePerWeekVerification", title="Once per Week", type="TIME") self.permission4 = Constraint.objects.create( name="OncePerMonthVerification", title="Once per Month", type="TIME" ) @@ -225,7 +215,7 @@ def setUp(self) -> None: name="OnceInALifeTimeVerification", title="Once per Lifetime", type="TIME" ) - self.td.permissions.set([self.permission1, self.permission2, self.permission3, self.permission4]) + self.td.permissions.set([self.permission1, self.permission2, self.permission4]) self.btc_td = TokenDistribution.objects.create( name="Test Distribution", @@ -322,29 +312,29 @@ def test_token_distribution_not_claimable_already_claimed(self): # response.data["detail"], "You have already claimed this token this week" # ) - @patch( - "authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", - lambda a, b, c: (True, None), - ) - def test_token_distribution_not_claimable_already_claimed_month(self): - tdc = TokenDistributionClaim.objects.create( - user_profile=self.user_profile, - token_distribution=self.td, - # Claimed 2 weeks ago - created_at=WeeklyCreditStrategy.get_first_day_of_the_month(), - ) - tdc.created_at = WeeklyCreditStrategy.get_first_day_of_the_month() - tdc.save() - - self.client.force_authenticate(user=self.user_profile.user) - response = self.client.post( - reverse("token-distribution-claim", kwargs={"pk": self.td.pk}), - ) - - self.assertEqual(response.status_code, 403) - # self.assertEqual( - # response.data["detail"], "You have already claimed this token this month" - # ) + # @patch( + # "authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", + # lambda a, b, c: (True, None), + # ) + # def test_token_distribution_not_claimable_already_claimed_month(self): + # tdc = TokenDistributionClaim.objects.create( + # user_profile=self.user_profile, + # token_distribution=self.td, + # # Claimed 2 weeks ago + # created_at=WeeklyCreditStrategy.get_first_day_of_the_month(), + # ) + # tdc.created_at = WeeklyCreditStrategy.get_first_day_of_the_month() + # tdc.save() + + # self.client.force_authenticate(user=self.user_profile.user) + # response = self.client.post( + # reverse("token-distribution-claim", kwargs={"pk": self.td.pk}), + # ) + + # self.assertEqual(response.status_code, 403) + # # self.assertEqual( + # # response.data["detail"], "You have already claimed this token this month" + # # ) @patch( "authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", @@ -357,7 +347,7 @@ def test_token_distribution_not_claimable_false_permissions(self): self.assertEqual(response.status_code, 403) def test_token_distribution_not_claimable_weekly_credit_limit_reached(self): - self.global_settings.tokentap_weekly_claim_limit = 0 + self.global_settings.tokentap_round_claim_limit = 0 self.global_settings.save() self.client.force_authenticate(user=self.user_profile.user) diff --git a/tokenTap/views.py b/tokenTap/views.py index 0d6c8a95..20100018 100644 --- a/tokenTap/views.py +++ b/tokenTap/views.py @@ -1,16 +1,23 @@ import json -from django.shortcuts import get_object_or_404 +import logging + import rest_framework.exceptions -from rest_framework.generics import CreateAPIView, RetrieveAPIView, ListAPIView -from rest_framework.response import Response -from rest_framework.permissions import IsAuthenticated +from django.shortcuts import get_object_or_404 +from django.utils import timezone +from drf_yasg import openapi +from drf_yasg.utils import swagger_auto_schema from rest_framework.exceptions import PermissionDenied -from django.urls import reverse -from authentication.models import NetworkTypes, UserProfile, Wallet -from authentication.serializers import MessageResponseSerializer -from faucet.models import Chain, ClaimReceipt, GlobalSettings -from permissions.models import Permission +from rest_framework.generics import CreateAPIView, ListAPIView, RetrieveAPIView +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response from rest_framework.views import APIView + +from authentication.models import NetworkTypes +from core.constraints import ( # noqa: F401 + BrightIDAuraVerification, + BrightIDMeetVerification, +) +from faucet.models import ClaimReceipt from tokenTap.models import TokenDistribution, TokenDistributionClaim from tokenTap.serializers import ( ConstraintSerializer, @@ -19,16 +26,18 @@ TokenDistributionClaimSerializer, TokenDistributionSerializer, ) -from django.utils import timezone -from drf_yasg.utils import swagger_auto_schema -from drf_yasg import openapi + +from .constraints import ( # noqa: F401 + ConstraintVerification, + OnceInALifeTimeVerification, + OncePerMonthVerification, +) from .helpers import ( create_uint32_random_nonce, + has_weekly_credit_left, hash_message, sign_hashed_message, - has_weekly_credit_left, ) -from .constraints import * class TokenDistributionListView(ListAPIView): @@ -38,9 +47,7 @@ class TokenDistributionListView(ListAPIView): def get_queryset(self): q = TokenDistribution.objects.filter(is_active=True) - sorted_queryset = sorted( - q, key=lambda obj: obj.total_claims_since_last_round, reverse=True - ) + sorted_queryset = sorted(q, key=lambda obj: obj.total_claims_since_last_round, reverse=True) return sorted_queryset @@ -50,9 +57,7 @@ class TokenDistributionClaimView(CreateAPIView): def check_token_distribution_is_claimable(self, token_distribution): if not token_distribution.is_claimable: - raise rest_framework.exceptions.PermissionDenied( - "This token is not claimable" - ) + raise rest_framework.exceptions.PermissionDenied("This token is not claimable") def check_user_permissions(self, token_distribution, user_profile): for c in token_distribution.permissions.all(): @@ -63,15 +68,11 @@ def check_user_permissions(self, token_distribution, user_profile): def check_user_weekly_credit(self, user_profile): if not has_weekly_credit_left(user_profile): - raise rest_framework.exceptions.PermissionDenied( - "You have reached your weekly claim limit" - ) + raise rest_framework.exceptions.PermissionDenied("You have reached your weekly claim limit") def check_user_has_wallet(self, user_profile): if not user_profile.wallets.filter(wallet_type=NetworkTypes.EVM).exists(): - raise rest_framework.exceptions.PermissionDenied( - "You have not connected an EVM wallet to your account" - ) + raise rest_framework.exceptions.PermissionDenied("You have not connected an EVM wallet to your account") @swagger_auto_schema( responses={ @@ -150,7 +151,7 @@ def post(self, request, *args, **kwargs): signature=lightning_invoice, token_distribution=token_distribution, ) - gas_tap_claim = ClaimReceipt.objects.create( + ClaimReceipt.objects.create( chain=token_distribution.chain, user_profile=user_profile, datetime=timezone.now(), @@ -172,11 +173,14 @@ class GetTokenDistributionConstraintsView(APIView): permission_classes = [IsAuthenticated] def get(self, request, td_id): + # from .constraints import + user_profile = request.user.profile td = get_object_or_404(TokenDistribution, pk=td_id) try: param_values = json.loads(td.constraint_params) - except: + except Exception as e: + logging.error("Error parsing constraint params", e) param_values = {} response_constraints = [] @@ -191,13 +195,9 @@ def get(self, request, td_id): is_verified = False if constraint.is_observed(token_distribution=td): is_verified = True - response_constraints.append( - {**ConstraintSerializer(c).data, "is_verified": is_verified} - ) + response_constraints.append({**ConstraintSerializer(c).data, "is_verified": is_verified}) - return Response( - {"success": True, "constraints": response_constraints}, status=200 - ) + return Response({"success": True, "constraints": response_constraints}, status=200) class TokenDistributionClaimStatusUpdateView(CreateAPIView): @@ -210,18 +210,12 @@ def post(self, request, *args, **kwargs): ) tx_hash = request.data.get("tx_hash", None) if tx_hash is None: - raise rest_framework.exceptions.ValidationError( - "tx_hash is a required field" - ) + raise rest_framework.exceptions.ValidationError("tx_hash is a required field") if token_distribution_claim.user_profile != user_profile: - raise rest_framework.exceptions.PermissionDenied( - "You do not have permission to update this claim" - ) + raise rest_framework.exceptions.PermissionDenied("You do not have permission to update this claim") if token_distribution_claim.status != ClaimReceipt.PENDING: - raise rest_framework.exceptions.PermissionDenied( - "This claim has already been updated" - ) + raise rest_framework.exceptions.PermissionDenied("This claim has already been updated") token_distribution_claim.tx_hash = tx_hash token_distribution_claim.status = ClaimReceipt.VERIFIED token_distribution_claim.save() @@ -247,6 +241,4 @@ class TokenDistributionClaimRetrieveView(RetrieveAPIView): def get_object(self): user_profile = self.request.user.profile - return TokenDistributionClaim.objects.get( - pk=self.kwargs["pk"], user_profile=user_profile - ) + return TokenDistributionClaim.objects.get(pk=self.kwargs["pk"], user_profile=user_profile) From 23817922d36d7d840a797c31892bb298dbc1de73 Mon Sep 17 00:00:00 2001 From: Mohamad Bastin Date: Fri, 27 Oct 2023 20:32:16 +0200 Subject: [PATCH 06/13] db error permissions --- ...eetverification_permission_ptr_and_more.py | 51 --------------- ...eekverification_permission_ptr_and_more.py | 23 +++++++ permissions/migrations/0007_initial.py | 63 ------------------- permissions/serializers.py | 51 ++++++++------- .../migrations/0003_raffle_permissions.py | 1 + .../0002_tokendistribution_permissions.py | 1 + .../migrations/0020_alter_constraint_name.py | 18 ++++++ 7 files changed, 68 insertions(+), 140 deletions(-) delete mode 100644 permissions/migrations/0006_remove_brightidmeetverification_permission_ptr_and_more.py create mode 100644 permissions/migrations/0006_remove_onceperweekverification_permission_ptr_and_more.py delete mode 100644 permissions/migrations/0007_initial.py create mode 100644 tokenTap/migrations/0020_alter_constraint_name.py diff --git a/permissions/migrations/0006_remove_brightidmeetverification_permission_ptr_and_more.py b/permissions/migrations/0006_remove_brightidmeetverification_permission_ptr_and_more.py deleted file mode 100644 index 0ae46b1b..00000000 --- a/permissions/migrations/0006_remove_brightidmeetverification_permission_ptr_and_more.py +++ /dev/null @@ -1,51 +0,0 @@ -# Generated by Django 4.0.4 on 2023-10-26 21:20 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('permissions', '0005_onceinalifetimeverification'), - ] - - operations = [ - migrations.RemoveField( - model_name='brightidmeetverification', - name='permission_ptr', - ), - migrations.RemoveField( - model_name='onceinalifetimeverification', - name='permission_ptr', - ), - migrations.RemoveField( - model_name='oncepermonthverification', - name='permission_ptr', - ), - migrations.RemoveField( - model_name='onceperweekverification', - name='permission_ptr', - ), - migrations.RemoveField( - model_name='permission', - name='polymorphic_ctype', - ), - migrations.DeleteModel( - name='BrightIDAuraVerification', - ), - migrations.DeleteModel( - name='BrightIDMeetVerification', - ), - migrations.DeleteModel( - name='OnceInALifeTimeVerification', - ), - migrations.DeleteModel( - name='OncePerMonthVerification', - ), - migrations.DeleteModel( - name='OncePerWeekVerification', - ), - migrations.DeleteModel( - name='Permission', - ), - ] diff --git a/permissions/migrations/0006_remove_onceperweekverification_permission_ptr_and_more.py b/permissions/migrations/0006_remove_onceperweekverification_permission_ptr_and_more.py new file mode 100644 index 00000000..f5edd017 --- /dev/null +++ b/permissions/migrations/0006_remove_onceperweekverification_permission_ptr_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0.4 on 2023-10-27 18:29 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('permissions', '0005_onceinalifetimeverification'), + ] + + operations = [ + migrations.RemoveField( + model_name='onceperweekverification', + name='permission_ptr', + ), + migrations.DeleteModel( + name='OncePerMonthVerification', + ), + migrations.DeleteModel( + name='OncePerWeekVerification', + ), + ] diff --git a/permissions/migrations/0007_initial.py b/permissions/migrations/0007_initial.py deleted file mode 100644 index 44aafc09..00000000 --- a/permissions/migrations/0007_initial.py +++ /dev/null @@ -1,63 +0,0 @@ -# Generated by Django 4.0.4 on 2023-10-26 21:41 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), - ('permissions', '0006_remove_brightidmeetverification_permission_ptr_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='Permission', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=200)), - ('description', models.TextField(blank=True, null=True)), - ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype')), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - ), - migrations.CreateModel( - name='BrightIDAuraVerification', - fields=[ - ('permission_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='permissions.permission')), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('permissions.permission',), - ), - migrations.CreateModel( - name='BrightIDMeetVerification', - fields=[ - ('permission_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='permissions.permission')), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('permissions.permission',), - ), - migrations.CreateModel( - name='OnceInALifeTimeVerification', - fields=[ - ('permission_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='permissions.permission')), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('permissions.permission',), - ), - ] diff --git a/permissions/serializers.py b/permissions/serializers.py index 1e89ca06..42d21590 100644 --- a/permissions/serializers.py +++ b/permissions/serializers.py @@ -1,35 +1,34 @@ -# from rest_framework import serializers -# from rest_polymorphic.serializers import PolymorphicSerializer +from rest_framework import serializers +from rest_polymorphic.serializers import PolymorphicSerializer +from permissions.models import ( + BrightIDAuraVerification, + BrightIDMeetVerification, + Permission, +) -# from permissions.models import ( -# Permission, -# BrightIDMeetVerification, -# BrightIDAuraVerification, -# ) +class PermissionBaseSerializer(serializers.ModelSerializer): + class Meta: + model = Permission + fields = ["id", "name", "description"] -# class PermissionBaseSerializer(serializers.ModelSerializer): -# class Meta: -# model = Permission -# fields = ["id", "name", "description"] +class BrightIDMeetVerificationSerializer(PermissionBaseSerializer): + class Meta: + model = BrightIDMeetVerification + fields = ["id", "name", "description"] -# class BrightIDMeetVerificationSerializer(PermissionBaseSerializer): -# class Meta: -# model = BrightIDMeetVerification -# fields = ["id", "name", "description"] +class BrightIDAuraVerificationSerializer(PermissionBaseSerializer): + class Meta: + model = BrightIDAuraVerification + fields = ["id", "name", "description"] -# class BrightIDAuraVerificationSerializer(PermissionBaseSerializer): -# class Meta: -# model = BrightIDAuraVerification -# fields = ["id", "name", "description"] - -# class PermissionSerializer(PolymorphicSerializer): -# model_serializer_mapping = { -# Permission: PermissionBaseSerializer, -# BrightIDMeetVerification: BrightIDMeetVerificationSerializer, -# BrightIDAuraVerification: BrightIDAuraVerificationSerializer, -# } +class PermissionSerializer(PolymorphicSerializer): + model_serializer_mapping = { + Permission: PermissionBaseSerializer, + BrightIDMeetVerification: BrightIDMeetVerificationSerializer, + BrightIDAuraVerification: BrightIDAuraVerificationSerializer, + } diff --git a/prizetap/migrations/0003_raffle_permissions.py b/prizetap/migrations/0003_raffle_permissions.py index 9461baf4..201b70e2 100644 --- a/prizetap/migrations/0003_raffle_permissions.py +++ b/prizetap/migrations/0003_raffle_permissions.py @@ -6,6 +6,7 @@ class Migration(migrations.Migration): dependencies = [ + ('permissions', '0004_oncepermonthverification'), ('prizetap', '0002_raffle_is_prize_nft'), ] diff --git a/tokenTap/migrations/0002_tokendistribution_permissions.py b/tokenTap/migrations/0002_tokendistribution_permissions.py index a1698c55..3666fc02 100644 --- a/tokenTap/migrations/0002_tokendistribution_permissions.py +++ b/tokenTap/migrations/0002_tokendistribution_permissions.py @@ -6,6 +6,7 @@ class Migration(migrations.Migration): dependencies = [ + ('permissions', '0001_initial'), ('tokenTap', '0001_initial'), ] diff --git a/tokenTap/migrations/0020_alter_constraint_name.py b/tokenTap/migrations/0020_alter_constraint_name.py new file mode 100644 index 00000000..7093dbb3 --- /dev/null +++ b/tokenTap/migrations/0020_alter_constraint_name.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2023-10-27 18:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tokenTap', '0019_alter_constraint_name'), + ] + + operations = [ + migrations.AlterField( + model_name='constraint', + name='name', + field=models.CharField(choices=[('BrightIDMeetVerification', 'BrightIDMeetVerification'), ('BrightIDAuraVerification', 'BrightIDAuraVerification'), ('OncePerMonthVerification', 'OncePerMonthVerification'), ('OnceInALifeTimeVerification', 'OnceInALifeTimeVerification'), ('OptimismHasClaimedGasInThisRound', 'OptimismHasClaimedGasInThisRound')], max_length=255, unique=True), + ), + ] From 9149c884b572c837dc9a13d45de91a414a86af7f Mon Sep 17 00:00:00 2001 From: Mohamad Bastin Date: Fri, 27 Oct 2023 20:37:40 +0200 Subject: [PATCH 07/13] db error permissions --- ...ove_onceperweekverification_permission_ptr_and_more.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/permissions/migrations/0006_remove_onceperweekverification_permission_ptr_and_more.py b/permissions/migrations/0006_remove_onceperweekverification_permission_ptr_and_more.py index f5edd017..57417c8c 100644 --- a/permissions/migrations/0006_remove_onceperweekverification_permission_ptr_and_more.py +++ b/permissions/migrations/0006_remove_onceperweekverification_permission_ptr_and_more.py @@ -10,10 +10,10 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RemoveField( - model_name='onceperweekverification', - name='permission_ptr', - ), + # migrations.RemoveField( + # model_name='onceperweekverification', + # name='permission_ptr', + # ), migrations.DeleteModel( name='OncePerMonthVerification', ), From 82346ecba2f3cba284e291aa305a48a63ada739f Mon Sep 17 00:00:00 2001 From: Mohamad Bastin Date: Fri, 27 Oct 2023 20:45:15 +0200 Subject: [PATCH 08/13] db error permissions --- .../0007_oncepermonthverification.py | 25 ++++++++++++ .../0008_onceperweekverification.py | 25 ++++++++++++ permissions/models.py | 40 ++++++++++--------- 3 files changed, 71 insertions(+), 19 deletions(-) create mode 100644 permissions/migrations/0007_oncepermonthverification.py create mode 100644 permissions/migrations/0008_onceperweekverification.py diff --git a/permissions/migrations/0007_oncepermonthverification.py b/permissions/migrations/0007_oncepermonthverification.py new file mode 100644 index 00000000..da275fbd --- /dev/null +++ b/permissions/migrations/0007_oncepermonthverification.py @@ -0,0 +1,25 @@ +# Generated by Django 4.0.4 on 2023-10-27 18:43 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('permissions', '0006_remove_onceperweekverification_permission_ptr_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='OncePerMonthVerification', + fields=[ + ('permission_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='permissions.permission')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('permissions.permission',), + ), + ] diff --git a/permissions/migrations/0008_onceperweekverification.py b/permissions/migrations/0008_onceperweekverification.py new file mode 100644 index 00000000..054ec0ed --- /dev/null +++ b/permissions/migrations/0008_onceperweekverification.py @@ -0,0 +1,25 @@ +# Generated by Django 4.0.4 on 2023-10-27 18:43 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('permissions', '0007_oncepermonthverification'), + ] + + operations = [ + migrations.CreateModel( + name='OncePerWeekVerification', + fields=[ + ('permission_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='permissions.permission')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('permissions.permission',), + ), + ] diff --git a/permissions/models.py b/permissions/models.py index 1a80cc56..c1d5e0a7 100644 --- a/permissions/models.py +++ b/permissions/models.py @@ -1,6 +1,8 @@ from django.db import models from polymorphic.models import PolymorphicModel +from faucet.faucet_manager.credit_strategy import RoundCreditStrategy + class Permission(PolymorphicModel): name = models.CharField(max_length=200) @@ -30,28 +32,28 @@ def response(self): return "You must be Aura verified on BrightID to claim this token." -# class OncePerWeekVerification(Permission): -# def is_valid(self, user_profile, *args, **kwargs): -# token_distribution = kwargs.get("token_distribution") -# return not token_distribution.claims.filter( -# user_profile=user_profile, -# created_at__gte=WeeklyCreditStrategy.get_last_monday(), -# ).exists() +class OncePerWeekVerification(Permission): + def is_valid(self, user_profile, *args, **kwargs): + token_distribution = kwargs.get("token_distribution") + return not token_distribution.claims.filter( + user_profile=user_profile, + created_at__gte=RoundCreditStrategy.get_start_of_the_round(), + ).exists() + + def response(self): + return "You have already claimed this token this week" -# def response(self): -# return "You have already claimed this token this week" +class OncePerMonthVerification(Permission): + def is_valid(self, user_profile, *args, **kwargs): + token_distribution = kwargs.get("token_distribution") + return not token_distribution.claims.filter( + user_profile=user_profile, + created_at__gte=RoundCreditStrategy.get_start_of_the_round(), + ).exists() -# class OncePerMonthVerification(Permission): -# def is_valid(self, user_profile, *args, **kwargs): -# token_distribution = kwargs.get("token_distribution") -# return not token_distribution.claims.filter( -# user_profile=user_profile, -# created_at__gte=WeeklyCreditStrategy.get_first_day_of_the_month(), -# ).exists() - -# def response(self): -# return "You have already claimed this token this month" + def response(self): + return "You have already claimed this token this month" class OnceInALifeTimeVerification(Permission): From e6289d4b53e1adf89b86df7a6304cd42ee51d2aa Mon Sep 17 00:00:00 2001 From: Mohamad Bastin Date: Fri, 27 Oct 2023 20:58:04 +0200 Subject: [PATCH 09/13] db error permissions --- permissions/admin.py | 43 +++++++++++-------- ...eekverification_permission_ptr_and_more.py | 23 ---------- .../0007_oncepermonthverification.py | 25 ----------- .../0008_onceperweekverification.py | 25 ----------- 4 files changed, 25 insertions(+), 91 deletions(-) delete mode 100644 permissions/migrations/0006_remove_onceperweekverification_permission_ptr_and_more.py delete mode 100644 permissions/migrations/0007_oncepermonthverification.py delete mode 100644 permissions/migrations/0008_onceperweekverification.py diff --git a/permissions/admin.py b/permissions/admin.py index 030a68e4..018dd20c 100644 --- a/permissions/admin.py +++ b/permissions/admin.py @@ -1,31 +1,38 @@ -# from django.contrib import admin -# from .models import * +from django.contrib import admin -# # Register your models here. +from .models import ( + BrightIDAuraVerification, + BrightIDMeetVerification, + OnceInALifeTimeVerification, + OncePerMonthVerification, + OncePerWeekVerification, +) +# Register your models here. -# class BrightIDMeetVerificationAdmin(admin.ModelAdmin): -# list_display = ["pk", "name"] +class BrightIDMeetVerificationAdmin(admin.ModelAdmin): + list_display = ["pk", "name"] -# class BrightIDAuraVerificationAdmin(admin.ModelAdmin): -# list_display = ["pk", "name"] +class BrightIDAuraVerificationAdmin(admin.ModelAdmin): + list_display = ["pk", "name"] -# class OncePerWeekVerificationAdmin(admin.ModelAdmin): -# list_display = ["pk", "name"] +class OncePerWeekVerificationAdmin(admin.ModelAdmin): + list_display = ["pk", "name"] -# class OncePerMonthVerificationAdmin(admin.ModelAdmin): -# list_display = ["pk", "name"] +class OncePerMonthVerificationAdmin(admin.ModelAdmin): + list_display = ["pk", "name"] -# class OnceInALifeTimeVerificationAdmin(admin.ModelAdmin): -# list_display = ["pk", "name"] +class OnceInALifeTimeVerificationAdmin(admin.ModelAdmin): + list_display = ["pk", "name"] -# admin.site.register(BrightIDMeetVerification, BrightIDMeetVerificationAdmin) -# admin.site.register(BrightIDAuraVerification, BrightIDAuraVerificationAdmin) -# admin.site.register(OncePerWeekVerification, OncePerWeekVerificationAdmin) -# admin.site.register(OncePerMonthVerification, OncePerMonthVerificationAdmin) -# admin.site.register(OnceInALifeTimeVerification, OnceInALifeTimeVerificationAdmin) + +admin.site.register(BrightIDMeetVerification, BrightIDMeetVerificationAdmin) +admin.site.register(BrightIDAuraVerification, BrightIDAuraVerificationAdmin) +admin.site.register(OncePerWeekVerification, OncePerWeekVerificationAdmin) +admin.site.register(OncePerMonthVerification, OncePerMonthVerificationAdmin) +admin.site.register(OnceInALifeTimeVerification, OnceInALifeTimeVerificationAdmin) diff --git a/permissions/migrations/0006_remove_onceperweekverification_permission_ptr_and_more.py b/permissions/migrations/0006_remove_onceperweekverification_permission_ptr_and_more.py deleted file mode 100644 index 57417c8c..00000000 --- a/permissions/migrations/0006_remove_onceperweekverification_permission_ptr_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.0.4 on 2023-10-27 18:29 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('permissions', '0005_onceinalifetimeverification'), - ] - - operations = [ - # migrations.RemoveField( - # model_name='onceperweekverification', - # name='permission_ptr', - # ), - migrations.DeleteModel( - name='OncePerMonthVerification', - ), - migrations.DeleteModel( - name='OncePerWeekVerification', - ), - ] diff --git a/permissions/migrations/0007_oncepermonthverification.py b/permissions/migrations/0007_oncepermonthverification.py deleted file mode 100644 index da275fbd..00000000 --- a/permissions/migrations/0007_oncepermonthverification.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.0.4 on 2023-10-27 18:43 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('permissions', '0006_remove_onceperweekverification_permission_ptr_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='OncePerMonthVerification', - fields=[ - ('permission_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='permissions.permission')), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('permissions.permission',), - ), - ] diff --git a/permissions/migrations/0008_onceperweekverification.py b/permissions/migrations/0008_onceperweekverification.py deleted file mode 100644 index 054ec0ed..00000000 --- a/permissions/migrations/0008_onceperweekverification.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.0.4 on 2023-10-27 18:43 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('permissions', '0007_oncepermonthverification'), - ] - - operations = [ - migrations.CreateModel( - name='OncePerWeekVerification', - fields=[ - ('permission_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='permissions.permission')), - ], - options={ - 'abstract': False, - 'base_manager_name': 'objects', - }, - bases=('permissions.permission',), - ), - ] From 7a0de66f354fb42196e58284300ae5b865be4680 Mon Sep 17 00:00:00 2001 From: Mohamad Bastin Date: Fri, 27 Oct 2023 21:05:01 +0200 Subject: [PATCH 10/13] fix user info error --- authentication/serializers.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/authentication/serializers.py b/authentication/serializers.py index b3359f37..6aa38b5e 100644 --- a/authentication/serializers.py +++ b/authentication/serializers.py @@ -1,12 +1,8 @@ -from django.db import IntegrityError -from authentication.models import ( - UserProfile, - Wallet, -) -from rest_framework.authtoken.models import Token from rest_framework import serializers -from faucet.faucet_manager.claim_manager import LimitedChainClaimManager +from rest_framework.authtoken.models import Token +from authentication.models import UserProfile, Wallet +from faucet.faucet_manager.claim_manager import LimitedChainClaimManager from faucet.models import GlobalSettings @@ -80,11 +76,9 @@ def get_token(self, instance): def get_total_weekly_claims_remaining(self, instance): gs = GlobalSettings.objects.first() if gs is not None: - return ( - gs.weekly_chain_claim_limit - - LimitedChainClaimManager.get_total_weekly_claims(instance) - ) - + return gs.gastap_round_claim_limit - LimitedChainClaimManager.get_total_round_claims(instance) + + class SimpleProfilerSerializer(serializers.ModelSerializer): wallets = WalletSerializer(many=True, read_only=True) username = serializers.SerializerMethodField() @@ -102,4 +96,4 @@ class Meta: def get_username(self, user_profile: UserProfile): if not user_profile.username: return f"User{user_profile.pk}" - return user_profile.username \ No newline at end of file + return user_profile.username From 8654374a070a14cd59c700c708dad842b3ce30b4 Mon Sep 17 00:00:00 2001 From: Mohamad Bastin Date: Fri, 27 Oct 2023 21:11:19 +0200 Subject: [PATCH 11/13] fix remaining claims error --- faucet/urls.py | 4 ++-- faucet/views.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/faucet/urls.py b/faucet/urls.py index a58a80e2..ee488a5d 100644 --- a/faucet/urls.py +++ b/faucet/urls.py @@ -8,7 +8,7 @@ ClaimCountView, ClaimMaxView, DonationReceiptView, - GetTotalWeeklyClaimsRemainingView, + GetTotalRoundClaimsRemainingView, GlobalSettingsView, LastClaimView, LeaderboardView, @@ -35,7 +35,7 @@ urlpatterns = [ path( "user/remainig-claims/", - GetTotalWeeklyClaimsRemainingView.as_view(), + GetTotalRoundClaimsRemainingView.as_view(), name="remaining-claims", ), path("user/last-claim/", LastClaimView.as_view(), name="last-claim"), diff --git a/faucet/views.py b/faucet/views.py index 0d91a139..8d7b828d 100644 --- a/faucet/views.py +++ b/faucet/views.py @@ -84,7 +84,7 @@ def get_queryset(self): ).order_by("-pk") -class GetTotalWeeklyClaimsRemainingView(RetrieveAPIView): +class GetTotalRoundClaimsRemainingView(RetrieveAPIView): """ Return the total weekly claims remaining for the given user """ @@ -95,8 +95,8 @@ def get(self, request, *args, **kwargs): user_profile = request.user.profile gs = GlobalSettings.objects.first() if gs is not None: - result = gs.weekly_chain_claim_limit - LimitedChainClaimManager.get_total_weekly_claims(user_profile) - return Response({"total_weekly_claims_remaining": result}, status=200) + result = gs.gastap_round_claim_limit - LimitedChainClaimManager.get_total_round_claims(user_profile) + return Response({"total_round_claims_remaining": result}, status=200) else: raise Http404("Global Settings Not Found") From d75610ca9eca56a2d7f75d296ca0bfa4302adcb7 Mon Sep 17 00:00:00 2001 From: Mohamad Bastin Date: Fri, 27 Oct 2023 21:16:00 +0200 Subject: [PATCH 12/13] fix remaining claims error --- authentication/serializers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/authentication/serializers.py b/authentication/serializers.py index 6aa38b5e..0772ddda 100644 --- a/authentication/serializers.py +++ b/authentication/serializers.py @@ -53,7 +53,7 @@ class Meta: class ProfileSerializer(serializers.ModelSerializer): wallets = WalletSerializer(many=True, read_only=True) - total_weekly_claims_remaining = serializers.SerializerMethodField() + total_round_claims_remaining = serializers.SerializerMethodField() token = serializers.SerializerMethodField() class Meta: @@ -65,7 +65,7 @@ class Meta: "initial_context_id", "is_meet_verified", "is_aura_verified", - "total_weekly_claims_remaining", + "total_round_claims_remaining", "wallets", ] @@ -73,7 +73,7 @@ def get_token(self, instance): token, bol = Token.objects.get_or_create(user=instance.user) return token.key - def get_total_weekly_claims_remaining(self, instance): + def get_total_round_claims_remaining(self, instance): gs = GlobalSettings.objects.first() if gs is not None: return gs.gastap_round_claim_limit - LimitedChainClaimManager.get_total_round_claims(instance) From ea00242d4b43cb9759bf283506e93651c84236d5 Mon Sep 17 00:00:00 2001 From: Shayan Shiravani Date: Sat, 28 Oct 2023 09:57:14 +0330 Subject: [PATCH 13/13] Prizetap: fix tests --- prizetap/serializers.py | 66 +++++++------ prizetap/tests.py | 200 ++++++++++++---------------------------- 2 files changed, 91 insertions(+), 175 deletions(-) diff --git a/prizetap/serializers.py b/prizetap/serializers.py index 897136ca..6136eb61 100644 --- a/prizetap/serializers.py +++ b/prizetap/serializers.py @@ -1,11 +1,16 @@ -import json +# flake8: noqa import base64 +import json + from rest_framework import serializers -from core.serializers import UserConstraintBaseSerializer + from authentication.serializers import SimpleProfilerSerializer +from core.serializers import UserConstraintBaseSerializer from faucet.serializers import SmallChainSerializer + +from .constraints import * from .models import * -from .constants import * + class ConstraintSerializer(UserConstraintBaseSerializer, serializers.ModelSerializer): class Meta(UserConstraintBaseSerializer.Meta): @@ -16,6 +21,7 @@ def get_params(self, constraint: UserConstraint): c_class: ConstraintVerification = eval(constraint.name) return [p.name for p in c_class.param_keys()] + class SimpleRaffleSerializer(serializers.ModelSerializer): class Meta: model = Raffle @@ -32,11 +38,13 @@ class Meta: "raffleId", ] + class RaffleEntrySerializer(serializers.ModelSerializer): raffle = SimpleRaffleSerializer() user_profile = SimpleProfilerSerializer() chain = serializers.SerializerMethodField() wallet = serializers.SerializerMethodField() + class Meta: model = RaffleEntry fields = [ @@ -48,7 +56,7 @@ class Meta: "created_at", "multiplier", "tx_hash", - "claiming_prize_tx" + "claiming_prize_tx", ] read_only_fields = [ "pk", @@ -62,25 +70,18 @@ class Meta: def get_chain(self, entry: RaffleEntry): return entry.raffle.chain.chain_id - + def get_wallet(self, entry: RaffleEntry): - return entry.user_profile.wallets.get( - wallet_type=entry.raffle.chain.chain_type).address + return entry.user_profile.wallets.get(wallet_type=entry.raffle.chain.chain_type).address + class WinnerEntrySerializer(serializers.ModelSerializer): user_profile = SimpleProfilerSerializer() wallet = serializers.SerializerMethodField() + class Meta: model = RaffleEntry - fields = [ - "pk", - "user_profile", - "wallet", - "created_at", - "multiplier", - "tx_hash", - "claiming_prize_tx" - ] + fields = ["pk", "user_profile", "wallet", "created_at", "multiplier", "tx_hash", "claiming_prize_tx"] read_only_fields = [ "pk", "user_profile", @@ -90,13 +91,13 @@ class Meta: ] def get_wallet(self, entry: RaffleEntry): - return entry.user_profile.wallets.get( - wallet_type=entry.raffle.chain.chain_type).address + return entry.user_profile.wallets.get(wallet_type=entry.raffle.chain.chain_type).address + class CreateRaffleSerializer(serializers.ModelSerializer): class Meta: model = Raffle - fields = '__all__' + fields = "__all__" read_only_fields = [ "pk", @@ -105,13 +106,13 @@ class Meta: "created_at", "status", "rejection_reason", - "is_active" + "is_active", ] def validate(self, data): - constraints = data['constraints'] - constraint_params = json.loads(base64.b64decode(data['constraint_params'])) - data['constraint_params'] = base64.b64decode(data['constraint_params']).decode("utf-8") + constraints = data["constraints"] + constraint_params = json.loads(base64.b64decode(data["constraint_params"])) + data["constraint_params"] = base64.b64decode(data["constraint_params"]).decode("utf-8") if len(constraints) != 0: for c in constraints: constraint_class: ConstraintVerification = eval(c.name) @@ -119,14 +120,11 @@ def validate(self, data): if len(constraint_class.param_keys()) != 0: constraint_class.is_valid_param_keys(constraint_params[c.name]) except KeyError as e: - raise serializers.ValidationError({ - "constraint_params": [{ - f"{c.name}": str(e) - }] - }) - data['creator_profile'] = self.context['user_profile'] + raise serializers.ValidationError({"constraint_params": [{f"{c.name}": str(e)}]}) + data["creator_profile"] = self.context["user_profile"] return data + class RaffleSerializer(serializers.ModelSerializer): chain = SmallChainSerializer() winner_entry = WinnerEntrySerializer() @@ -174,14 +172,12 @@ class Meta: "user_entry", "number_of_entries", "number_of_onchain_entries", - "max_multiplier" + "max_multiplier", ] - + def get_user_entry(self, raffle: Raffle): try: - return RaffleEntrySerializer( - raffle.entries.get(user_profile=self.context['user']) - ).data + return RaffleEntrySerializer(raffle.entries.get(user_profile=self.context["user"])).data except RaffleEntry.DoesNotExist: return None @@ -189,4 +185,4 @@ def get_user_entry(self, raffle: Raffle): class LineaRaffleEntrySerializer(serializers.ModelSerializer): class Meta: model = LineaRaffleEntries - fields = "__all__" \ No newline at end of file + fields = "__all__" diff --git a/prizetap/tests.py b/prizetap/tests.py index b516bd1e..c8846783 100644 --- a/prizetap/tests.py +++ b/prizetap/tests.py @@ -1,14 +1,18 @@ -from unittest.mock import patch, PropertyMock +# flake8: noqa +from unittest.mock import PropertyMock, patch + +from django.contrib.auth.models import User from django.urls import reverse from django.utils import timezone -from django.contrib.auth.models import User from rest_framework.test import APITestCase + from authentication.models import NetworkTypes, UserProfile, Wallet from faucet.models import Chain, WalletAccount -from .models import * + from .constraints import * -from .utils import PrizetapContractClient +from .models import * +# from .utils import PrizetapContractClient test_wallet_key = "f57fecd11c6034fd2665d622e866f05f9b07f35f253ebd5563e3d7e76ae66809" test_rpc_url_private = "https://rpc.ankr.com/eth_sepolia" @@ -19,13 +23,11 @@ # # Create your tests here. + class BaseTestCase(APITestCase): def setUp(self): self.user_profile = UserProfile.objects.create( - user=User.objects.create_user( - username="test", - password="1234" - ), + user=User.objects.create_user(username="test", password="1234"), initial_context_id="test", username="test", ) @@ -48,12 +50,12 @@ def setUp(self): native_currency_name="ETH", symbol="ETH", chain_id="11155111", - max_claim_amount=1e11 + max_claim_amount=1e11, ) self.meet_constraint = Constraint.objects.create( name=BrightIDMeetVerification.__name__, title="BrightID meet", - description="You have to be BrightID verified." + description="You have to be BrightID verified.", ) @@ -74,7 +76,7 @@ def setUp(self): chain=self.chain, deadline=timezone.now() + timezone.timedelta(days=1), max_number_of_entries=2, - status=Raffle.Status.VERIFIED + status=Raffle.Status.VERIFIED, ) self.raffle.constraints.set([self.meet_constraint]) @@ -82,8 +84,7 @@ def test_raffle_creation(self): self.assertEqual(Raffle.objects.count(), 1) self.assertEqual(Raffle.objects.first(), self.raffle) self.assertEqual(Raffle.objects.first().constraints.count(), 1) - self.assertEqual(Raffle.objects.first( - ).constraints.first(), self.meet_constraint) + self.assertEqual(Raffle.objects.first().constraints.first(), self.meet_constraint) def test_raffle_claimable(self): self.assertTrue(self.raffle.is_claimable) @@ -103,7 +104,7 @@ def test_raffle_is_active(self): self.assertFalse(self.raffle.is_active) self.assertFalse(self.raffle.is_claimable) - @patch('prizetap.models.Raffle.is_maxed_out') + @patch("prizetap.models.Raffle.is_maxed_out") def test_raffle_claimable_if_maxed_out(self, mock_method): mock_method.return_value = True self.assertTrue(self.raffle.is_maxed_out) @@ -111,13 +112,7 @@ def test_raffle_claimable_if_maxed_out(self, mock_method): def test_raffle_maxed_out(self): self.raffle.entries.set( - [ - RaffleEntry.objects.create( - raffle=self.raffle, - user_profile=self.user_profile, - multiplier=2 - ) - ] + [RaffleEntry.objects.create(raffle=self.raffle, user_profile=self.user_profile, multiplier=2)] ) self.assertFalse(self.raffle.is_maxed_out) entry: RaffleEntry = self.raffle.entries.first() @@ -130,14 +125,11 @@ def test_raffle_maxed_out(self): RaffleEntry.objects.create( raffle=self.raffle, user_profile=UserProfile.objects.create( - user=User.objects.create_user( - username="test_2", - password="1234" - ), + user=User.objects.create_user(username="test_2", password="1234"), initial_context_id="test_2", username="test_2", ), - multiplier=1 + multiplier=1, ) self.assertTrue(self.raffle.is_maxed_out) @@ -148,36 +140,27 @@ class RaffleAPITestCase(RaffleTestCase): def setUp(self) -> None: super().setUp() - @patch( - "authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", - lambda a, b, c: (True, None) - ) + @patch("authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", lambda a, b, c: (True, None)) def test_raffle_list(self): self.raffle.constraints.add( Constraint.objects.create( name=BrightIDAuraVerification.__name__, title="BrightID aura", - description="You have to be Aura verified." + description="You have to be Aura verified.", ) ) - response = self.client.get( - reverse("raffle-list") - ) + response = self.client.get(reverse("raffle-list")) raffle = response.data[0] self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 1) self.assertEqual(len(raffle["constraints"]), 2) - self.assertEqual( - raffle["constraints"][1]["name"], BrightIDAuraVerification.__name__ - ) - self.assertEqual(raffle['number_of_entries'], 0) - self.assertEqual(raffle['user_entry'], None) - self.assertEqual(raffle['winner_entry'], None) + self.assertEqual(raffle["constraints"][1]["name"], BrightIDAuraVerification.__name__) + self.assertEqual(raffle["number_of_entries"], 0) + self.assertEqual(raffle["user_entry"], None) + self.assertEqual(raffle["winner_entry"], None) def test_raffle_enrollment_authentication(self): - response = self.client.post( - reverse("raflle-enrollment", kwargs={"pk": self.raffle.pk}) - ) + response = self.client.post(reverse("raflle-enrollment", kwargs={"pk": self.raffle.pk})) self.assertEqual(response.status_code, 401) @patch( @@ -186,9 +169,7 @@ def test_raffle_enrollment_authentication(self): ) def test_raffle_enrollment_validation(self): self.client.force_authenticate(user=self.user_profile.user) - response = self.client.post( - reverse("raflle-enrollment", kwargs={"pk": self.raffle.pk}) - ) + response = self.client.post(reverse("raflle-enrollment", kwargs={"pk": self.raffle.pk})) self.assertEqual(response.status_code, 403) @@ -207,9 +188,7 @@ def setUp(self): ) def test_raffle_enrollment(self): self.client.force_authenticate(user=self.user_profile.user) - response = self.client.post( - reverse("raflle-enrollment", kwargs={"pk": self.raffle.pk}) - ) + response = self.client.post(reverse("raflle-enrollment", kwargs={"pk": self.raffle.pk})) self.assertEqual(response.status_code, 200) self.assertEqual(self.raffle.entries.count(), 1) entry: RaffleEntry = self.raffle.entries.first() @@ -217,151 +196,92 @@ def test_raffle_enrollment(self): self.assertEqual(entry.is_winner, False) self.assertEqual(self.raffle.number_of_entries, 1) - @patch('prizetap.models.Raffle.is_claimable', new_callable=PropertyMock) - @patch( - "authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", - lambda a, b, c: (True, None) - ) + @patch("prizetap.models.Raffle.is_claimable", new_callable=PropertyMock) + @patch("authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", lambda a, b, c: (True, None)) def test_not_claimable_raffle_enrollment(self, is_claimable_mock: PropertyMock): is_claimable_mock.return_value = False self.client.force_authenticate(user=self.user_profile.user) - response = self.client.post( - reverse("raflle-enrollment", kwargs={"pk": self.raffle.pk}) - ) + response = self.client.post(reverse("raflle-enrollment", kwargs={"pk": self.raffle.pk})) self.assertEqual(response.status_code, 403) - @patch( - "authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", - lambda a, b, c: (True, None) - ) + @patch("authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", lambda a, b, c: (True, None)) def test_set_raffle_enrollment_tx(self): - entry = RaffleEntry.objects.create( - raffle=self.raffle, - user_profile=self.user_profile - ) + entry = RaffleEntry.objects.create(raffle=self.raffle, user_profile=self.user_profile) self.client.force_authenticate(user=self.user_profile.user) tx_hash = "0xc9f4401d848bf61bd8e225fa800ab259018a917b55b0aa6aa1beefb2747d4af5" - response = self.client.post( - reverse("set-enrollment-tx", kwargs={"pk": entry.pk}), - data={"tx_hash": tx_hash} - ) + response = self.client.post(reverse("set-enrollment-tx", kwargs={"pk": entry.pk}), data={"tx_hash": tx_hash}) self.assertEqual(response.status_code, 200) entry.refresh_from_db() self.assertEqual(entry.tx_hash, tx_hash) - self.assertEqual(response.data['entry']['tx_hash'], tx_hash) + self.assertEqual(response.data["entry"]["tx_hash"], tx_hash) self.assertEqual(self.raffle.number_of_entries, 1) - @patch( - "authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", - lambda a, b, c: (True, None) - ) + @patch("authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", lambda a, b, c: (True, None)) def test_set_not_owned_raffle_enrollment_tx_failure(self): entry = RaffleEntry.objects.create( raffle=self.raffle, user_profile=UserProfile.objects.create( - user=User.objects.create_user( - username="test_2", - password="1234" - ), + user=User.objects.create_user(username="test_2", password="1234"), initial_context_id="test_2", username="test_2", - ) + ), ) self.client.force_authenticate(user=self.user_profile.user) tx_hash = "0xc9f4401d848bf61bd8e225fa800ab259018a917b55b0aa6aa1beefb2747d4af5" - response = self.client.post( - reverse("set-enrollment-tx", kwargs={"pk": entry.pk}), - data={"tx_hash": tx_hash} - ) + response = self.client.post(reverse("set-enrollment-tx", kwargs={"pk": entry.pk}), data={"tx_hash": tx_hash}) self.assertEqual(response.status_code, 403) entry.refresh_from_db() self.assertEqual(entry.tx_hash, None) - @patch( - "authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", - lambda a, b, c: (True, None) - ) + @patch("authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", lambda a, b, c: (True, None)) def test_duplicate_set_raffle_enrollment_tx_failure(self): tx_hash = "0xc9f4401d848bf61bd8e225fa800ab259018a917b55b0aa6aa1beefb2747d4af5" - entry = RaffleEntry.objects.create( - raffle=self.raffle, - user_profile=self.user_profile, - tx_hash=tx_hash - ) + entry = RaffleEntry.objects.create(raffle=self.raffle, user_profile=self.user_profile, tx_hash=tx_hash) self.client.force_authenticate(user=self.user_profile.user) - response = self.client.post( - reverse("set-enrollment-tx", kwargs={"pk": entry.pk}), - data={"tx_hash": tx_hash} - ) + response = self.client.post(reverse("set-enrollment-tx", kwargs={"pk": entry.pk}), data={"tx_hash": tx_hash}) self.assertEqual(response.status_code, 403) - @patch( - "authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", - lambda a, b, c: (True, None) - ) + @patch("authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", lambda a, b, c: (True, None)) def test_set_claiming_prize_tx(self): - entry = RaffleEntry.objects.create( - raffle=self.raffle, - user_profile=self.user_profile, - is_winner=True - ) + entry = RaffleEntry.objects.create(raffle=self.raffle, user_profile=self.user_profile, is_winner=True) self.client.force_authenticate(user=self.user_profile.user) tx_hash = "0xc9f4401d848bf61bd8e225fa800ab259018a917b55b0aa6aa1beefb2747d4af5" response = self.client.post( - reverse("set-claiming-prize-tx", kwargs={"pk": self.raffle.pk}), - data={"tx_hash": tx_hash} + reverse("set-claiming-prize-tx", kwargs={"pk": self.raffle.pk}), data={"tx_hash": tx_hash} ) self.assertEqual(response.status_code, 200) entry.refresh_from_db() self.assertEqual(entry.claiming_prize_tx, tx_hash) - self.assertEqual(response.data['entry']['claiming_prize_tx'], tx_hash) + self.assertEqual(response.data["entry"]["claiming_prize_tx"], tx_hash) - @patch( - "authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", - lambda a, b, c: (True, None) - ) + @patch("authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", lambda a, b, c: (True, None)) def test_set_not_owned_claim_prize_failure(self): - RaffleEntry.objects.create( - raffle=self.raffle, - user_profile=self.user_profile - ) + RaffleEntry.objects.create(raffle=self.raffle, user_profile=self.user_profile) entry = RaffleEntry.objects.create( raffle=self.raffle, user_profile=UserProfile.objects.create( - user=User.objects.create_user( - username="test_2", - password="1234" - ), + user=User.objects.create_user(username="test_2", password="1234"), initial_context_id="test_2", username="test_2", ), - is_winner=True + is_winner=True, ) self.client.force_authenticate(user=self.user_profile.user) tx_hash = "0xc9f4401d848bf61bd8e225fa800ab259018a917b55b0aa6aa1beefb2747d4af5" response = self.client.post( - reverse("set-claiming-prize-tx", kwargs={"pk": self.raffle.pk}), - data={"tx_hash": tx_hash} + reverse("set-claiming-prize-tx", kwargs={"pk": self.raffle.pk}), data={"tx_hash": tx_hash} ) self.assertEqual(response.status_code, 403) entry.refresh_from_db() self.assertEqual(entry.claiming_prize_tx, None) - @patch( - "authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", - lambda a, b, c: (True, None) - ) + @patch("authentication.helpers.BrightIDSoulboundAPIInterface.get_verification_status", lambda a, b, c: (True, None)) def test_duplicate_claiming_prize_tx_failure(self): tx_hash = "0xc9f4401d848bf61bd8e225fa800ab259018a917b55b0aa6aa1beefb2747d4af5" - RaffleEntry.objects.create( - raffle=self.raffle, - user_profile=self.user_profile, - claiming_prize_tx=tx_hash - ) + RaffleEntry.objects.create(raffle=self.raffle, user_profile=self.user_profile, claiming_prize_tx=tx_hash) self.client.force_authenticate(user=self.user_profile.user) response = self.client.post( - reverse("set-claiming-prize-tx", kwargs={"pk": self.raffle.pk}), - data={"tx_hash": tx_hash} + reverse("set-claiming-prize-tx", kwargs={"pk": self.raffle.pk}), data={"tx_hash": tx_hash} ) self.assertEqual(response.status_code, 403) @@ -378,15 +298,15 @@ def setUp(self): native_currency_name="ETH", symbol="ETH", chain_id="1", - max_claim_amount=1e11 + max_claim_amount=1e11, ) def test_unitappass_contraint(self): constraint = NotHaveUnitapPass(self.user_profile) self.assertTrue(constraint.is_observed()) - def test_set_winner(self): - self.raffle.raffleId = 2 - client = PrizetapContractClient(self.raffle) - winner = client.get_raffle_winner() - self.assertEqual(winner, "0x59351584417882EE549eE3B9BF398485ddB5B7E9") + # def test_set_winner(self): + # self.raffle.raffleId = 2 + # client = PrizetapContractClient(self.raffle) + # winner = client.get_raffle_winner() + # self.assertEqual(winner, "0x59351584417882EE549eE3B9BF398485ddB5B7E9")