Skip to content

Commit

Permalink
Merge pull request #122 from UnitapApp/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Mohamad Bastin authored Sep 16, 2023
2 parents 03946b2 + 303df80 commit 3924713
Show file tree
Hide file tree
Showing 23 changed files with 1,683 additions and 142 deletions.
25 changes: 25 additions & 0 deletions core/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from rest_framework import filters
from rest_framework.generics import get_object_or_404

from faucet.models import Chain


class IsOwnerFilterBackend(filters.BaseFilterBackend):
"""
Filter that only allows users to see their own objects.
"""

def filter_queryset(self, request, queryset, view):
return queryset.filter(user_profile=request.user.profile)


class ChainFilterBackend(filters.BaseFilterBackend):
"""
Filter that filter nested chains
"""

def filter_queryset(self, request, queryset, view):
chain_pk = request.query_params.get('chain_pk')
if chain_pk is None:
return queryset
return queryset.filter(chain=get_object_or_404(Chain, pk=chain_pk))
18 changes: 18 additions & 0 deletions core/migrations/0002_alter_tokenprice_price_url.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.0.4 on 2023-09-15 10:34

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('core', '0001_initial'),
]

operations = [
migrations.AlterField(
model_name='tokenprice',
name='price_url',
field=models.URLField(max_length=255, null=True),
),
]
52 changes: 39 additions & 13 deletions core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,16 @@ class Type(models.TextChoices):
VERIFICATION = "VER", _("Verification")
TIME = "TIME", _("Time")

constraints = [
BrightIDMeetVerification,
BrightIDAuraVerification
]
constraints = [BrightIDMeetVerification, BrightIDAuraVerification]

name = models.CharField(max_length=255, unique=True,
choices=[(c.__name__, c.__name__) for c in constraints])
name = models.CharField(
max_length=255,
unique=True,
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
max_length=10, choices=Type.choices, default=Type.VERIFICATION
)
description = models.TextField(null=True, blank=True)
response = models.TextField(null=True, blank=True)
Expand All @@ -32,13 +30,41 @@ def __str__(self) -> str:

@classmethod
def create_name_field(cls, constraints):
return models.CharField(max_length=255, unique=True,
choices=[(c.__name__, c.__name__) for c in constraints])
return models.CharField(
max_length=255,
unique=True,
choices=[(c.__name__, c.__name__) for c in constraints],
)


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, blank=True, null=False)
symbol = models.CharField(max_length=255, db_index=True, unique=True, null=False, blank=False)
price_url = models.URLField(max_length=255, null=True)
symbol = models.CharField(
max_length=255, db_index=True, unique=True, null=False, blank=False
)


class BigNumField(models.Field):
empty_strings_allowed = False

def __init__(self, *args, **kwargs):
kwargs["max_length"] = 200 # or some other number
super().__init__(*args, **kwargs)

def db_type(self, connection):
return "numeric"

def get_internal_type(self):
return "BigNumField"

def to_python(self, value):
if isinstance(value, str):
return int(value)

return value

def get_prep_value(self, value):
return str(value)
7 changes: 7 additions & 0 deletions core/paginations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from rest_framework.pagination import PageNumberPagination


class StandardResultsSetPagination(PageNumberPagination):
page_size = 100
page_size_query_param = 'page_size'
max_page_size = 1000
63 changes: 60 additions & 3 deletions core/utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import datetime
import pytz
from time import time
from web3 import Web3
from web3.contract.contract import Contract, ContractFunction
from web3.types import Type, TxParams
from django.utils import timezone

class TimeUtils:

class TimeUtils:
@staticmethod
def get_last_monday():
now = int(time())
Expand All @@ -21,7 +24,7 @@ def get_last_monday():
return timezone.make_aware(
datetime.datetime.fromtimestamp(last_monday_midnight)
)

@staticmethod
def get_second_last_monday():
now = int(time())
Expand All @@ -43,4 +46,58 @@ def get_second_last_monday():
def get_first_day_of_the_month():
now = datetime.datetime.now(pytz.timezone("UTC"))
first_day = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
return first_day
return first_day


class Web3Utils:
def __init__(self, rpc_url) -> None:
self._rpc_url = rpc_url
self._w3 = None
self._account = None
self._contract = None

@property
def w3(self) -> Web3:
if self._w3 and self._w3.is_connected():
return self._w3

self._w3 = Web3(Web3.HTTPProvider(self._rpc_url))

if self._w3.is_connected():
return self._w3

raise Exception(f"RPC provider is not connected ({self._rpc_url})")

@property
def account(self):
return self._account

def set_account(self, private_key):
self._account = self.w3.eth.account.from_key(private_key)

@property
def contract(self) -> Type[Contract]:
return self._contract

def set_contract(self, address, abi):
self._contract = self.w3.eth.contract(address=address, abi=abi)

def contract_txn(self, func: Type[ContractFunction]):
signed_tx = self.build_contract_call(func)
txn_hash = self.send_raw_tx(signed_tx)
return txn_hash.hex()

def contract_call(self, func: Type[ContractFunction], from_address=None):
if from_address:
return func.call({"from": from_address})
return func.call()

def build_contract_call(self, func: Type[ContractFunction]):
tx_data = func.build_transaction({"from": self.account.address})
return self.sign_tx(tx_data)

def sign_tx(self, tx_data: TxParams):
return self.w3.eth.account.sign_transaction(tx_data, self.account.key)

def send_raw_tx(self, signed_tx):
return self.w3.eth.send_raw_transaction(signed_tx.rawTransaction)
14 changes: 8 additions & 6 deletions faucet/faucet_manager/fund_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from django.core.cache import cache
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.fund_manager_abi import manager_abi
Expand Down Expand Up @@ -44,7 +43,7 @@ def w3(self) -> Web3:
_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():
if _w3.is_connected():
_w3.eth.set_gas_price_strategy(rpc_gas_price_strategy)
return _w3
except Exception as e:
Expand All @@ -67,11 +66,11 @@ def is_gas_price_too_high(self):

@property
def account(self) -> LocalAccount:
return self.w3.eth.account.privateKeyToAccount(self.chain.wallet.main_key)
return self.w3.eth.account.from_key(self.chain.wallet.main_key)

@staticmethod
def to_checksum_address(address: str):
return Web3.toChecksumAddress(address.lower())
return Web3.to_checksum_address(address.lower())

def get_fund_manager_checksum_address(self):
return self.to_checksum_address(self.chain.fund_manager_address)
Expand Down Expand Up @@ -106,14 +105,14 @@ def multi_eth_transfer_signed_tx(self, data):

def prepare_tx_for_broadcast(self, tx_function):
nonce = self.w3.eth.get_transaction_count(self.account.address)
gas_estimation = tx_function.estimateGas({"from": self.account.address})
gas_estimation = tx_function.estimate_gas({"from": self.account.address})
if self.chain.chain_id == "997":
gas_estimation = 100000

if self.is_gas_price_too_high:
raise FundMangerException.GasPriceTooHigh("Gas price is too high")

tx_data = tx_function.buildTransaction(
tx_data = tx_function.build_transaction(
{
"nonce": nonce,
"from": self.account.address,
Expand All @@ -134,6 +133,9 @@ def get_tx(self, tx_hash):
tx = self.w3.eth.get_transaction(tx_hash)
return tx

def from_wei(self, value: int, unit: str = 'ether'):
return self.w3.from_wei(value, unit)


class SolanaFundManager:
def __init__(self, chain: Chain):
Expand Down
45 changes: 15 additions & 30 deletions faucet/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
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 brightIDfaucet.settings import BRIGHT_ID_INTERFACE

Expand All @@ -25,29 +26,6 @@ def get_cache_time(id):
return int((float(int(id) % 25) / 25.0) * 180.0) + 180


class BigNumField(models.Field):
empty_strings_allowed = False

def __init__(self, *args, **kwargs):
kwargs["max_length"] = 200 # or some other number
super().__init__(*args, **kwargs)

def db_type(self, connection):
return "numeric"

def get_internal_type(self):
return "BigNumField"

def to_python(self, value):
if isinstance(value, str):
return int(value)

return value

def get_prep_value(self, value):
return str(value)


class WalletAccount(models.Model):
name = models.CharField(max_length=255, blank=True, null=True)
private_key = EncryptedCharField(max_length=100)
Expand Down Expand Up @@ -296,7 +274,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.getBalance(
funds = EVMFundManager(self).w3.eth.get_balance(
self.fund_manager_address
)
return funds
Expand Down Expand Up @@ -335,7 +313,7 @@ def get_wallet_balance(self):
)

if self.chain_type == NetworkTypes.EVM or int(self.chain_id) == 500:
return EVMFundManager(self).w3.eth.getBalance(self.wallet.address)
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(
Expand Down Expand Up @@ -475,12 +453,17 @@ class GlobalSettings(models.Model):


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)

_status = models.CharField(
max_length=30, choices=ClaimReceipt.states, default=ClaimReceipt.PENDING, db_index=True
max_length=30,
choices=ClaimReceipt.states,
default=ClaimReceipt.PENDING,
db_index=True,
)

updating = models.BooleanField(default=False)
Expand Down Expand Up @@ -537,7 +520,7 @@ class DonationReceipt(models.Model):
related_name="donations",
on_delete=models.PROTECT,
null=False,
blank=False
blank=False,
)
tx_hash = models.CharField(max_length=255, blank=False, null=False)
chain = models.ForeignKey(
Expand All @@ -551,8 +534,10 @@ class DonationReceipt(models.Model):
total_price = models.CharField(max_length=255, null=True, blank=True)
datetime = models.DateTimeField(auto_now_add=True)
status = models.CharField(
max_length=30, choices=ClaimReceipt.states, default=ClaimReceipt.PROCESSED_FOR_TOKENTAP
max_length=30,
choices=ClaimReceipt.states,
default=ClaimReceipt.PROCESSED_FOR_TOKENTAP,
)

class Meta:
unique_together = ('chain', 'tx_hash')
unique_together = ("chain", "tx_hash")
Loading

0 comments on commit 3924713

Please sign in to comment.