diff --git a/README.md b/README.md index 24d263a..aec8cce 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Django 区块链钱包应用 # 应用 ``` +pip install Django>=4.0.4,<5 # 构建本地数据库 python manage.py migrate # 创建超级用户 diff --git a/requirements.txt b/requirements.txt index 24a2b1f..5aa7ed6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ -Django>=4.0.4,<5 - ecdsa>=0.13,<1 mnemonic>=0.19,<1 pysha3>=1.0.2,<2 -base58>=2.0.1,<3 \ No newline at end of file +base58>=2.0.1,<3 +requests>=2.27.1,<3 \ No newline at end of file diff --git a/start.bat b/start.bat new file mode 100644 index 0000000..f459841 --- /dev/null +++ b/start.bat @@ -0,0 +1 @@ +python manage.py runserver \ No newline at end of file diff --git a/wallet.json b/wallet.json index fd3ec15..6e2b8d3 100644 --- a/wallet.json +++ b/wallet.json @@ -21,6 +21,20 @@ "explorer_url":"https://etherscan.io/" } }, + { + "model":"wallet.rpc", + "fields":{ + "created_at":"2022-05-21T03:11:20.347Z", + "updated_at":"2022-05-21T03:11:20.347Z", + "chain":2, + "company":"infura", + "alias":"test", + "endpoint":"https://mainnet.infura.io/v3/8a5284b35807498aa04f95fc580a76ec", + "username":null, + "password":null, + "auth":"NORMAL" + } + }, { "model":"wallet.token", "fields":{ diff --git a/wallet/chainstate/__init__.py b/wallet/chainstate/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/wallet/chainstate/admin.py b/wallet/chainstate/admin.py new file mode 100644 index 0000000..f1ff8c4 --- /dev/null +++ b/wallet/chainstate/admin.py @@ -0,0 +1,15 @@ +from django.contrib import admin + +# Register your models here. +from wallet.chainstate.models import * + +class RPCAdmin(admin.ModelAdmin): + + list_display = ("chain","company","alias","endpoint","username","password","auth",) + +class StateAdmin(admin.ModelAdmin): + + list_display = ("address","balance","next_time","is_active","rpc","next_time") + +admin.site.register(RPC,RPCAdmin) +admin.site.register(State,StateAdmin) \ No newline at end of file diff --git a/wallet/chainstate/apps.py b/wallet/chainstate/apps.py new file mode 100644 index 0000000..56bdd44 --- /dev/null +++ b/wallet/chainstate/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ChainstateConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'wallet.chainstate' diff --git a/wallet/chainstate/constant.py b/wallet/chainstate/constant.py new file mode 100644 index 0000000..2787937 --- /dev/null +++ b/wallet/chainstate/constant.py @@ -0,0 +1,7 @@ +from django.utils.translation import gettext_lazy as _ + + +NORMAL="NORMAL" +AUTH_TYPE = ( + (NORMAL, _("normal")), +) \ No newline at end of file diff --git a/wallet/chainstate/migrations/0001_initial.py b/wallet/chainstate/migrations/0001_initial.py new file mode 100644 index 0000000..d61f957 --- /dev/null +++ b/wallet/chainstate/migrations/0001_initial.py @@ -0,0 +1,53 @@ +# Generated by Django 4.0.4 on 2022-05-21 12:27 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('wallet', '0009_remove_state_address_remove_state_rpc_delete_rpc_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='RPC', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created Time')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated Time')), + ('company', models.CharField(max_length=128, verbose_name='company')), + ('alias', models.CharField(blank=True, max_length=128, null=True, verbose_name='alias')), + ('endpoint', models.CharField(max_length=128, verbose_name='endpoint')), + ('username', models.CharField(blank=True, max_length=128, null=True, verbose_name='username')), + ('password', models.CharField(blank=True, max_length=128, null=True, verbose_name='password')), + ('auth', models.CharField(choices=[('NORMAL', 'normal')], default='NORMAL', max_length=128, verbose_name='auth')), + ('chain', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wallet_rpc', to='wallet.chain')), + ], + options={ + 'verbose_name': 'RPC', + 'verbose_name_plural': 'RPC', + }, + ), + migrations.CreateModel( + name='State', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created Time')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated Time')), + ('balance', models.JSONField(verbose_name='balance')), + ('next_time', models.DateTimeField(auto_now=True, help_text='When to run the next test', verbose_name='Created Time')), + ('is_active', models.BooleanField(default=True, help_text='Whether it is necessary to detect the operating status of the address', verbose_name='active')), + ('is_update', models.BooleanField(default=False, help_text='Status of address update', verbose_name='update')), + ('address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wallet_state', to='wallet.address')), + ('rpc', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wallet_state', to='chainstate.rpc')), + ], + options={ + 'verbose_name': 'State', + 'verbose_name_plural': 'Status', + }, + ), + ] diff --git a/wallet/chainstate/migrations/__init__.py b/wallet/chainstate/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/wallet/chainstate/models.py b/wallet/chainstate/models.py new file mode 100644 index 0000000..92218c3 --- /dev/null +++ b/wallet/chainstate/models.py @@ -0,0 +1,60 @@ +from django.db import models +from django.utils.translation import gettext_lazy as _ + +# Create your models here. +from wallet.models import Chain,CreateUpdateTracker,Address +from wallet.chainstate.constant import * + +class RPC(CreateUpdateTracker): + chain = models.ForeignKey(Chain, related_name='wallet_rpc', on_delete=models.CASCADE) + company = models.CharField(verbose_name=_("company"),max_length=128) + alias = models.CharField(verbose_name=_("alias"),max_length=128,blank=True,null=True,) + endpoint = models.CharField(verbose_name=_("endpoint"),max_length=128) + username = models.CharField(verbose_name=_("username"),max_length=128,blank=True,null=True,) + password = models.CharField(verbose_name=_("password"),max_length=128,blank=True,null=True,) + auth = models.CharField(verbose_name=_("auth"),max_length=128,choices=AUTH_TYPE,default=NORMAL) + + def __str__(self): + return f"{self.alias}-[{self.company}]" + + class Meta: + verbose_name = _('RPC') + verbose_name_plural = _('RPC') + + +class StateManager(models.Manager): + def get_queryset(self): + return super().get_queryset().filter(is_active=True) + +class State(CreateUpdateTracker): + objects = StateManager() + + address = models.ForeignKey(Address, related_name="wallet_state",on_delete=models.CASCADE) + balance = models.JSONField(verbose_name=_('balance')) + next_time = models.DateTimeField( + _("Created Time"),editable=False, + auto_now=True, + help_text=_( + "When to run the next test" + ) + ) + is_active = models.BooleanField( + verbose_name=_('active'),default=True, + help_text=_( + "Whether it is necessary to detect the operating status of the address" + ) + ) + is_update = models.BooleanField( + verbose_name=_('update'),default=False, + help_text=_( + "Status of address update" + ) + ) + rpc = models.ForeignKey(RPC, related_name="wallet_state", on_delete=models.CASCADE) + + def __str__(self): + return f"{self.is_update}" + + class Meta: + verbose_name = _('State') + verbose_name_plural = _('Status') diff --git a/wallet/chainstate/tests.py b/wallet/chainstate/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/wallet/chainstate/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/wallet/chainstate/views.py b/wallet/chainstate/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/wallet/chainstate/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/wallet/constant.py b/wallet/constant.py index 9ffc3ce..f36f7f2 100644 --- a/wallet/constant.py +++ b/wallet/constant.py @@ -6,4 +6,5 @@ ADDRESS_TYPE = ( (DEPOSIT,_("deposit")), (SYSTEM_LEASE,_("system lease")), -) \ No newline at end of file +) + diff --git a/wallet/helpers.py b/wallet/helpers.py index f9f0390..8eb6e6d 100644 --- a/wallet/helpers.py +++ b/wallet/helpers.py @@ -38,7 +38,6 @@ def generate_address(user, chain_symbol,index:int=None, type=None, new_address=T chain=chain, public_key= hdwallet.xpublic_key(), ) - # user = pubkey.user # 确认最新的地址下标 if index is None: @@ -50,7 +49,6 @@ def generate_address(user, chain_symbol,index:int=None, type=None, new_address=T if new_address: index = index + 1 except Address.DoesNotExist as e: - # index=0 pass # 若已经存在该地址则返回,没有则创建 @@ -72,4 +70,4 @@ def generate_address(user, chain_symbol,index:int=None, type=None, new_address=T address=address ) except Exception as e: - logger.error(f"wallet.generate_address:{e.args}") + logger.error(msg="Exception while generating wallet address:", exc_info=e) diff --git a/wallet/management/commands/create_deposit_address.py b/wallet/management/commands/create_deposit_address.py index cf5c56e..74315be 100644 --- a/wallet/management/commands/create_deposit_address.py +++ b/wallet/management/commands/create_deposit_address.py @@ -1,7 +1,3 @@ - -import os -# os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lender.settings') - from django.core.management.base import BaseCommand from logging import getLogger @@ -9,7 +5,11 @@ class Command(BaseCommand): - help = "Create Deposit Address" + help = """ + Create Deposit Address: + + python manage.py create_deposit_address -u [username or uid] + """ def add_arguments(self, parser): self.username_help = 'User Unique username (Required)' diff --git a/wallet/management/commands/runchainstate.py b/wallet/management/commands/runchainstate.py new file mode 100644 index 0000000..12914e6 --- /dev/null +++ b/wallet/management/commands/runchainstate.py @@ -0,0 +1,23 @@ +from django.core.management.base import BaseCommand + +from logging import getLogger +logger = getLogger(__name__) + + +class Command(BaseCommand): + help = """ + Create Deposit Address: + + python manage.py create_deposit_address -u [username or uid] + """ + + def add_arguments(self, parser): + pass + + def handle(self, *args, **options): + pass + + + + + \ No newline at end of file diff --git a/wallet/migrations/0003_rpc_state.py b/wallet/migrations/0003_rpc_state.py new file mode 100644 index 0000000..2f814b5 --- /dev/null +++ b/wallet/migrations/0003_rpc_state.py @@ -0,0 +1,51 @@ +# Generated by Django 4.0.4 on 2022-05-21 02:24 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wallet', '0002_alter_address_chain_alter_pubkey_chain_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='RPC', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created Time')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated Time')), + ('company', models.CharField(max_length=128, verbose_name='company')), + ('alias', models.CharField(blank=True, max_length=128, null=True, verbose_name='alias')), + ('endpoint', models.CharField(max_length=128, verbose_name='endpoint')), + ('username', models.CharField(blank=True, max_length=128, null=True, verbose_name='username')), + ('password', models.CharField(blank=True, max_length=128, null=True, verbose_name='password')), + ('auth', models.CharField(max_length=128, verbose_name='auth')), + ('chain', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wallet_rpc', to='wallet.chain')), + ], + options={ + 'verbose_name': 'RPC', + 'verbose_name_plural': 'RPC', + }, + ), + migrations.CreateModel( + name='State', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created Time')), + ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated Time')), + ('balance', models.JSONField(verbose_name='balance')), + ('next_time', models.DateTimeField(auto_now_add=True, verbose_name='Created Time')), + ('is_active', models.BooleanField(default=False, verbose_name='active')), + ('address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wallet_state', to='wallet.address')), + ('rpc', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wallet_state', to='wallet.rpc')), + ('token', models.ManyToManyField(related_name='wallet_state', to='wallet.token')), + ], + options={ + 'ordering': ('-created_at',), + 'abstract': False, + }, + ), + ] diff --git a/wallet/migrations/0004_alter_rpc_auth.py b/wallet/migrations/0004_alter_rpc_auth.py new file mode 100644 index 0000000..b5baacb --- /dev/null +++ b/wallet/migrations/0004_alter_rpc_auth.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2022-05-21 03:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wallet', '0003_rpc_state'), + ] + + operations = [ + migrations.AlterField( + model_name='rpc', + name='auth', + field=models.CharField(choices=[('NORMAL', 'normal')], default='NORMAL', max_length=128, verbose_name='auth'), + ), + ] diff --git a/wallet/migrations/0005_state_is_update_alter_state_is_active_and_more.py b/wallet/migrations/0005_state_is_update_alter_state_is_active_and_more.py new file mode 100644 index 0000000..4819fde --- /dev/null +++ b/wallet/migrations/0005_state_is_update_alter_state_is_active_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 4.0.4 on 2022-05-21 03:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wallet', '0004_alter_rpc_auth'), + ] + + operations = [ + migrations.AddField( + model_name='state', + name='is_update', + field=models.BooleanField(default=False, help_text='Status of address update', verbose_name='update'), + ), + migrations.AlterField( + model_name='state', + name='is_active', + field=models.BooleanField(default=True, help_text='Whether it is necessary to detect the operating status of the address', verbose_name='active'), + ), + migrations.AlterField( + model_name='state', + name='next_time', + field=models.DateTimeField(editable=False, help_text='When to run the next test', verbose_name='Created Time'), + ), + ] diff --git a/wallet/migrations/0006_remove_state_token.py b/wallet/migrations/0006_remove_state_token.py new file mode 100644 index 0000000..219f9bf --- /dev/null +++ b/wallet/migrations/0006_remove_state_token.py @@ -0,0 +1,17 @@ +# Generated by Django 4.0.4 on 2022-05-21 03:28 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('wallet', '0005_state_is_update_alter_state_is_active_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='state', + name='token', + ), + ] diff --git a/wallet/migrations/0007_alter_state_next_time.py b/wallet/migrations/0007_alter_state_next_time.py new file mode 100644 index 0000000..b4df0eb --- /dev/null +++ b/wallet/migrations/0007_alter_state_next_time.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.4 on 2022-05-21 03:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wallet', '0006_remove_state_token'), + ] + + operations = [ + migrations.AlterField( + model_name='state', + name='next_time', + field=models.DateTimeField(auto_now=True, help_text='When to run the next test', verbose_name='Created Time'), + ), + ] diff --git a/wallet/migrations/0008_alter_state_options.py b/wallet/migrations/0008_alter_state_options.py new file mode 100644 index 0000000..2c3553e --- /dev/null +++ b/wallet/migrations/0008_alter_state_options.py @@ -0,0 +1,17 @@ +# Generated by Django 4.0.4 on 2022-05-21 12:24 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('wallet', '0007_alter_state_next_time'), + ] + + operations = [ + migrations.AlterModelOptions( + name='state', + options={'verbose_name': 'State', 'verbose_name_plural': 'Status'}, + ), + ] diff --git a/wallet/migrations/0009_remove_state_address_remove_state_rpc_delete_rpc_and_more.py b/wallet/migrations/0009_remove_state_address_remove_state_rpc_delete_rpc_and_more.py new file mode 100644 index 0000000..99fcf00 --- /dev/null +++ b/wallet/migrations/0009_remove_state_address_remove_state_rpc_delete_rpc_and_more.py @@ -0,0 +1,27 @@ +# Generated by Django 4.0.4 on 2022-05-21 12:25 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('wallet', '0008_alter_state_options'), + ] + + operations = [ + migrations.RemoveField( + model_name='state', + name='address', + ), + migrations.RemoveField( + model_name='state', + name='rpc', + ), + migrations.DeleteModel( + name='RPC', + ), + migrations.DeleteModel( + name='State', + ), + ] diff --git a/wallet/models.py b/wallet/models.py index d36066b..8c0e6ed 100644 --- a/wallet/models.py +++ b/wallet/models.py @@ -37,6 +37,7 @@ class Meta: verbose_name = _('chain') verbose_name_plural = _('chain') + class Pubkey(CreateUpdateTracker): user = models.ForeignKey(get_user_model(),related_name='wallet_pubkey',blank=True,null=True,verbose_name=_("User ID"),on_delete=models.CASCADE) public_key = models.CharField(verbose_name=_("Account Extended Public Key"),max_length=128) @@ -44,7 +45,7 @@ class Pubkey(CreateUpdateTracker): chain = models.ForeignKey(Chain, on_delete=models.CASCADE) def __str__(self): - return f"{self.public_key[:6]}...{self.public_key[6:]}" + return f"{self.public_key[:8]}...{self.public_key[-8:]}" class Meta: verbose_name = _('public key') @@ -72,7 +73,7 @@ class Token(CreateUpdateTracker): ) def __str__(self) -> str: - return f"{self.token_symbol}" + return f"{self.token_name}" class Meta: verbose_name = _('Token') @@ -115,3 +116,5 @@ def __str__(self): class Meta: verbose_name = _('address') verbose_name_plural = _('addresses') + +