From 7e2ec9d21c2c6ba3b45340c699095614909f636d Mon Sep 17 00:00:00 2001 From: Patricio Kumagae <pkumagae@boletinoficial.gob.ar> Date: Tue, 23 Apr 2019 11:24:30 -0300 Subject: [PATCH] =?UTF-8?q?Actualizaci=C3=B3n=20desde=20gitlab.bora.local?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Poppins/local_settings_dev.py | 2 +- Poppins/local_settings_preprod.py | 3 +- Poppins/local_settings_prod.py | 107 +++++++++++++----- Poppins/local_settings_tst.py | 14 +-- README.md | 24 +++- api/admin.py | 23 +++- api/models.py | 1 + dapp/gateway.py | 58 ++++++---- dapp/managers.py | 10 +- dapp/models.py | 1 - dapp/services.py | 55 +++++---- dapp/tests.py | 84 +++++++++++--- frontend/templates/dapp/account_list.html | 2 +- .../registration_form.html | 42 ++++++- frontend/templates/header.html | 9 ++ logica_cuentas/admin.py | 16 +++ logica_cuentas/apps.py | 1 + .../agregar_estados_cuenta_usuario.py | 22 ++-- logica_cuentas/managers.py | 16 ++- logica_cuentas/models.py | 11 ++ logica_cuentas/services.py | 71 +++++++++++- logica_cuentas/tests.py | 91 ++++++++++++--- requirements.txt | 1 - scripts_utiles/PoAdeploy.py | 4 +- scripts_utiles/cambiarCantidad.py | 23 ++-- scripts_utiles/cargarDistribuidor.py | 15 ++- 26 files changed, 546 insertions(+), 160 deletions(-) diff --git a/Poppins/local_settings_dev.py b/Poppins/local_settings_dev.py index 8625b09..9830555 100644 --- a/Poppins/local_settings_dev.py +++ b/Poppins/local_settings_dev.py @@ -96,4 +96,4 @@ DISTILLERY_ABI = '[ { "anonymous": false, "inputs": [ { "indexed": false, "name" RAVEN_CONFIG = { 'dsn': 'http://5c7db71f422f4f6c90f0e424691ac8c5:6d461c37c9ee4335817f42406a8ef34a@172.17.30.21:9000/63', -} \ No newline at end of file +} diff --git a/Poppins/local_settings_preprod.py b/Poppins/local_settings_preprod.py index fa1aeab..e311bfc 100644 --- a/Poppins/local_settings_preprod.py +++ b/Poppins/local_settings_preprod.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """ Copyright 2019 de la Dirección General de Sistemas Informáticos – SecretarÃa Legal y Técnica - Nación. @@ -10,7 +11,7 @@ You should have received a copy of the GNU General Public License along with thi # DEBUG DEBUG = False -APP_ROOT = '/var/www/poppins.bc.local/app/Poppins/' +APP_ROOT = '/var/www/poppins.bc.local/' STATIC_ROOT = '/var/www/poppins.bc.local/html' # MAIL DATA diff --git a/Poppins/local_settings_prod.py b/Poppins/local_settings_prod.py index 4f360b9..58488d5 100644 --- a/Poppins/local_settings_prod.py +++ b/Poppins/local_settings_prod.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """ Copyright 2019 de la Dirección General de Sistemas Informáticos – SecretarÃa Legal y Técnica - Nación. @@ -10,12 +11,26 @@ You should have received a copy of the GNU General Public License along with thi #DEBUG DEBUG = False -APP_ROOT = '/var/www/poppins.bc.local/app/Poppins/' +import os +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +APP_ROOT = BASE_DIR+'/../../' STATIC_ROOT = '/var/www/poppins.bc.local/html' +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'poppins', + 'USER': 'poppinsuser', + 'PASSWORD': '1234', + 'HOST': '127.0.0.1', + 'PORT': '5432', + } +} + #MAIL DATA EMAIL_USE_TLS = False -EMAIL_HOST = '172.16.1.106' +EMAIL_HOST = 'localhost' EMAIL_PORT = 25 EMAIL_HOST_USER = '' EMAIL_HOST_PASSWORD = '' @@ -24,40 +39,80 @@ DEFAULT_FROM_EMAIL = 'no-reply@bfa.ar' ADMIN_EMAIL = 'no-reply@bfa.ar' #NODO DE BLOACJAJEICHAIN -NODE_URL = 'http://10.23.10.71:54450' # salberchain +NODE_URL = 'http://10.24.10.14:8545' # mainnet (bootnode) #CFG BLOCKCHANGE -DISTILLERY_ADDRESS = '0x67d6e2887638cb6F4D55FCe4f4122635E4B27531' # distillery -DISTRIBUTOR_ACCOUNT = '0x25c185DcaeD065BAC30a0a1cd0688A7aA02896d7' # cuenta con mucho ether -DISTILLERY_ABI = '[ { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "limit", ' \ - '"type": "uint256" } ], "name": "addBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], ' \ - '"payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, ' \ - '"inputs": [ { "name": "acc", "type": "address" }, { "name": "top", "type": "uint256" } ], ' \ - '"name": "addDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, ' \ +DISTILLERY_ADDRESS = '0xc3cF96aF51d3c41DfBE428dE75a8E5597d4D7A7B' # distillery +DISTRIBUTOR_ACCOUNT = '0xBF1ce9Cca7dedea3FDB22d169B49643664602eE1' # cuenta con mucho ether +DISTILLERY_ABI = '[ { "anonymous": false, "inputs": [ { "indexed": false, "name": "amount", "type": "uint256" } ], ' \ + '"name": "proofOfControlWeiAmountChanged", "type": "event" }, { "constant": false, "inputs": [ { ' \ + '"name": "acc", "type": "address" }, { "name": "limit", "type": "uint256" } ], ' \ + '"name": "addBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, ' \ '"stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": ' \ - '"acc", "type": "address" }, { "name": "limit", "type": "uint256" } ], "name": "changeLimit", ' \ + '"add", "type": "address" }, { "name": "password", "type": "bytes32" } ], "name": "addSuitor", ' \ + '"outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", ' \ + '"type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, ' \ + '{ "name": "limit", "type": "uint256" } ], "name": "changeLimit", "outputs": [ { "name": "", ' \ + '"type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, ' \ + '{ "constant": false, "inputs": [ { "name": "acc", "type": "address" } ], "name": "kickBeneficiary", ' \ '"outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", ' \ '"type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" } ], ' \ - '"name": "kickBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, ' \ + '"name": "kickDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, ' \ + '"stateMutability": "nonpayable", "type": "function" }, { "anonymous": false, "inputs": [ { ' \ + '"indexed": true, "name": "distr", "type": "address" }, { "indexed": true, "name": "ben", ' \ + '"type": "address" }, { "indexed": false, "name": "newLimit", "type": "uint256" } ], ' \ + '"name": "limitChanged", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, ' \ + '"name": "suitor", "type": "address" } ], "name": "suitorApproved", "type": "event" }, ' \ + '{ "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" } ], ' \ + '"name": "suitorNotApproved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": ' \ + 'true, "name": "kicked", "type": "address" } ], "name": "kickedDistributor", "type": "event" }, ' \ + '{ "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" }, ' \ + '{ "indexed": true, "name": "distr", "type": "address" } ], "name": "suitorAdded", "type": "event" ' \ + '}, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, ' \ + '{ "indexed": true, "name": "added", "type": "address" }, { "indexed": false, "name": "limit", ' \ + '"type": "uint256" } ], "name": "addedBeneficiary", "type": "event" }, { "anonymous": false, ' \ + '"inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": true, ' \ + '"name": "kicked", "type": "address" } ], "name": "kickedBeneficiary", "type": "event" }, ' \ + '{ "anonymous": false, "inputs": [ { "indexed": true, "name": "added", "type": "address" }, ' \ + '{ "indexed": false, "name": "top", "type": "uint256" } ], "name": "addedDistributor", ' \ + '"type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", ' \ + '"type": "address" }, { "indexed": false, "name": "amount", "type": "uint256" } ], ' \ + '"name": "replenished", "type": "event" }, { "constant": false, "inputs": [ { "name": "acc", ' \ + '"type": "address" }, { "name": "top", "type": "uint256" } ], "name": "addDistributor", "outputs": [ ' \ + '{ "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", ' \ + '"type": "function" }, { "constant": false, "inputs": [ { "name": "key", "type": "string" } ], ' \ + '"name": "proveControl", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, ' \ '"stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": ' \ - '"acc", "type": "address" } ], "name": "kickDistributor", "outputs": [ { "name": "", "type": "bool" ' \ - '} ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, ' \ - '"inputs": [ { "name": "acc", "type": "address" }, { "name": "amount", "type": "uint256" } ], ' \ - '"name": "replenish", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, ' \ - '"stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [], ' \ - '"name": "replenishAll", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, ' \ + '"acc", "type": "address" }, { "name": "amount", "type": "uint256" } ], "name": "replenish", ' \ + '"outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", ' \ + '"type": "function" }, { "constant": false, "inputs": [], "name": "replenishAll", "outputs": [ { ' \ + '"name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", "type": "function" ' \ + '}, { "constant": false, "inputs": [ { "name": "accs", "type": "address[]" }, { "name": "amounts", ' \ + '"type": "uint256[]" } ], "name": "replenishList", "outputs": [], "payable": true, ' \ '"stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": ' \ - '"accs", "type": "address[]" }, { "name": "amounts", "type": "uint256[]" } ], ' \ - '"name": "replenishList", "outputs": [], "payable": true, "stateMutability": "payable", ' \ - '"type": "function" }, { "inputs": [], "payable": true, "stateMutability": "payable", ' \ - '"type": "constructor" }, { "constant": true, "inputs": [], "name": "getBeneficiariesCount", ' \ - '"outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", ' \ - '"type": "function" }, { "constant": true, "inputs": [ { "name": "acc", "type": "address" } ], ' \ + '"amount", "type": "uint256" } ], "name": "setProofOfControlWeiAmount", "outputs": [ { "name": "", ' \ + '"type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, ' \ + '{ "inputs": [], "payable": true, "stateMutability": "payable", "type": "constructor" }, ' \ + '{ "constant": true, "inputs": [], "name": "getBeneficiariesCount", "outputs": [ { "name": "", ' \ + '"type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, ' \ + '{ "constant": true, "inputs": [ { "name": "acc", "type": "address" } ], ' \ '"name": "getBeneficiaryLimit", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, ' \ '"stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "acc", ' \ '"type": "address" } ], "name": "getDistributorLimit", "outputs": [ { "name": "", "type": "uint256" ' \ - '} ], "payable": false, "stateMutability": "view", "type": "function" } ] ' + '} ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, ' \ + '"inputs": [], "name": "getProofOfControlWeiAmount", "outputs": [ { "name": "", "type": "uint256" } ' \ + '], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, ' \ + '"inputs": [ { "name": "key", "type": "string" } ], "name": "hash", "outputs": [ { "name": "", ' \ + '"type": "bytes32" } ], "payable": false, "stateMutability": "pure", "type": "function" }, ' \ + '{ "constant": true, "inputs": [ { "name": "add", "type": "address" } ], "name": "isBeneficiary", ' \ + '"outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", ' \ + '"type": "function" }, { "constant": true, "inputs": [ { "name": "add", "type": "address" } ], ' \ + '"name": "isDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, ' \ + '"stateMutability": "view", "type": "function" } ] ' + +GOOGLE_RECAPTCHA_SECRET_KEY = '6LdIsXoUAAAAAM2CK9KUohWWFZTjpwo-Z2CP_Ndp' +DATA_SITEKEY = '6LdIsXoUAAAAAFQfkzQWPpJ5ERGdxmY8YT4bFLmt' RAVEN_CONFIG = { - 'dsn': 'http://5c7db71f422f4f6c90f0e424691ac8c5:6d461c37c9ee4335817f42406a8ef34a@172.17.30.21:9000/63', + 'dsn': 'http://0f6b7e857c31436badd6f5a33b6795e4:21003d12f52b4e2cb4efba1f27fd1780@10.1.100.118:9000/81', } \ No newline at end of file diff --git a/Poppins/local_settings_tst.py b/Poppins/local_settings_tst.py index 42d3f1e..946fb50 100644 --- a/Poppins/local_settings_tst.py +++ b/Poppins/local_settings_tst.py @@ -1,8 +1,9 @@ # DEBUG -DEBUG = False +DEBUG = True +import os +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -APP_ROOT = '/var/www/poppins.bc.local/app/Poppins/' -STATIC_ROOT = '/var/www/poppins.bc.local/html' +APP_ROOT = BASE_DIR+'/' DATABASES = { 'default': { @@ -10,7 +11,7 @@ DATABASES = { 'NAME': 'poppins', 'USER': 'poppinsuser', 'PASSWORD': '1234', - 'HOST': 'localhost', + 'HOST': '10.14.2.198', 'PORT': '5432', } } @@ -26,7 +27,7 @@ DEFAULT_FROM_EMAIL = 'no-reply@bfa.ar' ADMIN_EMAIL = 'no-reply@bfa.ar' # NODO DE BLOACJAJEICHAIN -NODE_URL = 'http://10.23.10.73:54450' # salberchain +NODE_URL = 'http://10.23.10.71:54450' # salberchain # CFG BLOCKCHANGE DISTILLERY_ADDRESS = '0x822c2b518dCfEE69d435E0C5F2e6d196FcC8320E' # distillery @@ -102,9 +103,6 @@ DISTILLERY_ABI = '[ { "anonymous": false, "inputs": [ { "indexed": false, "name" '"name": "isDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, ' \ '"stateMutability": "view", "type": "function" } ] ' -GOOGLE_RECAPTCHA_SECRET_KEY = '6LdIsXoUAAAAAM2CK9KUohWWFZTjpwo-Z2CP_Ndp' -DATA_SITEKEY = '6LdIsXoUAAAAAFQfkzQWPpJ5ERGdxmY8YT4bFLmt' - RAVEN_CONFIG = { 'dsn': 'http://af8a61a068af431eb80d8ee277f84364:887b38e0b1594fabb844b75309bdaab7@10.1.100.118:9000/79', } diff --git a/README.md b/README.md index 597db7d..698b829 100644 --- a/README.md +++ b/README.md @@ -22,5 +22,27 @@ Ejecutar dentro del virtual environment - python manage.py agregar_estados_cuenta_usuario - service apache2 restart -- Cronear el comando pyhton manage.py pedir_ether cada 1 minuto +- Cronear el comando pyhton manage.py pedir_ether cada 1 minuto o menos +- Cronear el comando pyhton manage.py actualizar_estado cada 1 minuto o menos +### Comandos + +Existen varios comandos para ayudar con el deploy, el estado, o la verificación de consistencia de la aplicación + +- python manage.py deployar_smart_contract : deploya smart contract + +- python manage.py verificar_admin_distribuidor : verifica que el distribuidor en los settings está cargado en el smart contract y el tope que tiene + +- python manage.py verificar_balance_distribuidor: devuelve el balance de la cuenta del distribuidor en los settings + +- python manage.py cargar_distribuidor: carga en el smart contract el distribuidor en los settings con el tope en los settings + +- python manage.py ver_bytecode_contrato : devuelve el bytecode del smart contract, para verificar que está bien deployado + +- python manage.py settear_cantidad_prueba_control : settea en el smart contract la cantidad de saldo para hacer la verificación de control + +- python manage.py cantidad_prueba_control : getter de la cantidad de saldo en el smart contract para verificacion de control + +- python manage.py sincronizar_cuentas_beneficiario : levanta los beneficiarios cargados en el smart contract y los carga en base + +- python manage.py verificar_consistencia : verifica las cuentas que no estan relacionadas con usuarios y si están en smart contract y las borra o desvincula diff --git a/api/admin.py b/api/admin.py index 5d0fd82..a411bfd 100644 --- a/api/admin.py +++ b/api/admin.py @@ -8,8 +8,29 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/ """ from django.contrib import admin -from api.models import CustomUser, Institution, Section +from api.models import CustomUser, Institution, Section, Service +from dapp.models import Account + + +class ServiceAdmin(admin.ModelAdmin): + list_display = ('name', 'address', 'status', ) + + def address(self, service): + qs = Account.objects.filter(service=service) + if qs.exists(): + return qs.first().address + else: + return "" + + def status(self, service): + qs = Account.objects.filter(service=service) + if qs.exists(): + return qs.first().status + else: + return "" + admin.site.register(CustomUser) admin.site.register(Institution) admin.site.register(Section) +admin.site.register(Service, ServiceAdmin) diff --git a/api/models.py b/api/models.py index 0e37c5e..4741ced 100644 --- a/api/models.py +++ b/api/models.py @@ -61,6 +61,7 @@ class CustomUser(models.Model): cuit = models.CharField(max_length=20, null=True, blank=True) user = models.ForeignKey(User, on_delete=models.PROTECT, ) enabled_institutions = models.ManyToManyField(Institution, verbose_name='Instituciones habilitadas', blank=True) + accepted_terms = models.BooleanField(default=True) class Meta: db_table = 'custom_user' diff --git a/dapp/gateway.py b/dapp/gateway.py index b9719c5..8bc37c8 100644 --- a/dapp/gateway.py +++ b/dapp/gateway.py @@ -55,9 +55,6 @@ class EthereumGateway: event_filter = event.createFilter(**params) return event_filter.get_all_entries() - def calcular_gas(self, action): - return action.estimateGas() - class InvalidTransactionException(Exception): pass @@ -68,7 +65,7 @@ class Distillery: def execute_transaction(self, contract, transaction_data, exception_message=""): es_valido = contract.call(transaction_data) - gas_estimate = self.gateway.calcular_gas(contract) + if es_valido: # transaction_data['gasLimit'] = 1000000000000 tx_hash = contract.transact(transaction_data) @@ -91,19 +88,18 @@ class Distillery: abi = settings.DISTILLERY_ABI return self.gateway.get_contract_events(abi, self.contract_account) - def beneficiarios(self): - cant_cuentas = self.contrato.numberOfBeneficiaries().call() + def beneficiarios(self, from_block_number): + event_ben = self.eventos.addedBeneficiary + event_filter_ben = event_ben.createFilter(fromBlock=int(from_block_number), toBlock='latest') + results = event_filter_ben.get_all_entries() - cuentas = [] + bens = [] - if cant_cuentas > 0: - i = 0 - while i < cant_cuentas: - par = self.contrato.atPosition(i).call() - cuentas.append(par[0]) - i += 1 + for r in results: + if self.es_beneficiario(r['args']['added']): + bens.append((r['args']['added'], r['args']['limit'])) - return cuentas + return bens def distribuir(self, from_account): distribute = self.contrato.replenishAll() @@ -111,11 +107,12 @@ class Distillery: return tx_hash def agregar_beneficiario(self, from_account, address, tope): - agregar = self.contrato.addBeneficiary(self.gateway.to_checksum_address(address), tope) - tx_hash = self.execute_transaction(agregar, {'from': self.gateway.to_checksum_address(from_account)}, - "Transaction is invalid, " + from_account + " has no permissions or top " - + str(tope) + "is higher than allowed") - return tx_hash + if not self.es_beneficiario(address): + agregar = self.contrato.addBeneficiary(self.gateway.to_checksum_address(address), tope) + tx_hash = self.execute_transaction(agregar, {'from': self.gateway.to_checksum_address(from_account)}, + "Transaction is invalid, " + from_account + " has no permissions or top " + + str(tope) + " is higher than allowed") + return tx_hash def agregar_distribuidor(self, from_account, address, tope): agregar = self.contrato.addDistributor(self.gateway.to_checksum_address(address), tope) @@ -131,7 +128,9 @@ class Distillery: def abastecer(self, from_account, cuenta, cantidad): abastecer = self.contrato.replenish(self.gateway.to_checksum_address(cuenta), int(cantidad)) - tx_hash = self.execute_transaction(abastecer, {'from': self.gateway.to_checksum_address(from_account)}, + tx_hash = self.execute_transaction(abastecer, { + 'from': self.gateway.to_checksum_address(from_account), + 'value': int(cantidad) + 1}, # para pasar validacion "Transaction is invalid " + from_account + " is not allowed or amount is too high, contract balance: " + str(self.gateway.get_balance(self.contract_account)) + " amount " @@ -143,7 +142,9 @@ class Distillery: for c in cuentas: checksumed.append(self.gateway.to_checksum_address(c)) abastecer = self.contrato.replenish(checksumed, cantidades) - tx_hash = self.execute_transaction(abastecer, {'from': self.gateway.to_checksum_address(from_account)}, + tx_hash = self.execute_transaction(abastecer, { + 'from': self.gateway.to_checksum_address(from_account), + 'value': sum(cantidades)}, "Transaction is invalid" + from_account + " is not allowed or amount is too high") return tx_hash @@ -152,10 +153,11 @@ class Distillery: return self.contrato.getBeneficiaryLimit(self.gateway.to_checksum_address(cuenta)).call() def sacar_beneficiario(self, from_account, address): - patear = self.contrato.kickBeneficiary(self.gateway.to_checksum_address(address)) - tx_hash = self.execute_transaction(patear, {'from': self.gateway.to_checksum_address(from_account)}, - 'Transaction is invalid ' + from_account + " has no permissions") - return tx_hash + if self.es_beneficiario(address): + patear = self.contrato.kickBeneficiary(self.gateway.to_checksum_address(address)) + tx_hash = self.execute_transaction(patear, {'from': self.gateway.to_checksum_address(from_account)}, + 'Transaction is invalid ' + from_account + " has no permissions") + return tx_hash def ya_fue_eliminado(self, from_account, address): args = { @@ -170,6 +172,9 @@ class Distillery: entradas = self.gateway.buscar_entradas(evento, args) return len(entradas) > 0 + def es_beneficiario(self, address): + return self.contrato.isBeneficiary(self.gateway.to_checksum_address(address)).call() + def es_distribuidor(self, address): return self.contrato.isDistributor(self.gateway.to_checksum_address(address)).call() @@ -216,3 +221,6 @@ class Distillery: } entradas = self.gateway.buscar_entradas(suitor_approved_evento, params) return len(entradas) > 0 + + def tope_distribuidor(self, address): + return self.contrato.getDistributorLimit(self.gateway.to_checksum_address(address)).call() diff --git a/dapp/managers.py b/dapp/managers.py index 4b8c012..0f7b893 100644 --- a/dapp/managers.py +++ b/dapp/managers.py @@ -23,7 +23,7 @@ class StatusManager(models.Manager): def get_esperando_transaccion(self): try: - return self.filter(descripcion="Esperando transaccion").first() + return self.filter(descripcion="Esperando transaccion de alta beneficiario").first() except Exception as e: pass except OperationalError as oe: @@ -61,6 +61,14 @@ class StatusManager(models.Manager): except OperationalError as oe: return None + def get_esperando_transaccion_abastecimiento(self): + try: + return self.filter(descripcion="Esperando transaccion de abastecimiento").first() + except Exception as e: + pass + except OperationalError as oe: + return None + class AccountManager(models.Manager): gateway = EthereumGateway() diff --git a/dapp/models.py b/dapp/models.py index eb7e4da..997a8fb 100644 --- a/dapp/models.py +++ b/dapp/models.py @@ -33,7 +33,6 @@ class Account(models.Model): institution = models.ForeignKey(Institution, on_delete=models.PROTECT, null=True, blank=True) service = models.ForeignKey(Service, on_delete=models.PROTECT, null=True) clave = models.CharField(max_length=255, null=True, default='', blank=True) - owner = models.ForeignKey(CustomUser, on_delete=models.PROTECT, null=False) objects = AccountManager() def __str__(self): diff --git a/dapp/services.py b/dapp/services.py index 894cea5..8da2611 100644 --- a/dapp/services.py +++ b/dapp/services.py @@ -10,6 +10,7 @@ You should have received a copy of the GNU General Public License along with thi import logging from Poppins import settings +from api.models import Service from dapp.gateway import Distillery, EthereumGateway from dapp.models import Account, Status, TopeEsperado from django.db import transaction @@ -27,15 +28,15 @@ class AccountBeingKicked(Exception): class PetitorioEtherCuenta: logger = logging.getLogger('logger') - pendiente = Status.objects.get_pendiente_distribucion() - desvinculando = Status.objects.get_esperando_desvinculado() + pendiente = Status.objects.get_pendiente_distribucion + desvinculando = Status.objects.get_esperando_desvinculado def pedir_ether(self, account): """ :type account: Account """ - if account.status != self.desvinculando: - account.status = self.pendiente + if account.status is not self.desvinculando(): + account.status = self.pendiente() self.logger.info('Pedido de ether para cuenta :' + str(account)) account.save() else: @@ -120,7 +121,7 @@ class Abastecimiento: account = settings.DISTRIBUTOR_ACCOUNT logger = logging.getLogger('logger') account_manager = Account.objects - esperando_transaccion = Status.objects.get_esperando_transaccion() + esperando_transaccion = Status.objects.get_esperando_transaccion_abastecimiento() def abastecer(self, account, cantidad): self.logger.info("Abasteciendo {} con {} wei".format(account.address, cantidad)) @@ -143,9 +144,11 @@ class ActualizacionEstados: pendiente_distribucion = Status.objects.get_pendiente_distribucion esperando_desvinculacion = Status.objects.get_esperando_desvinculado esperando_transaccion = Status.objects.get_esperando_transaccion + esperando_transaccion_abastecimiento = Status.objects.get_esperando_transaccion_abastecimiento lista_para_gestion = Status.objects.get_lista_para_gestion distillery = Distillery() asociacion_beneficiario = AsociacionCuenta() + servicios_manager = Service.objects def actualizar_cuentas(self, cuentas): # no me odies pato, cuando vuelva corrijo esta bola de nieve, mi peor codigo cuentas_a_actualizar = [] @@ -153,44 +156,48 @@ class ActualizacionEstados: cuentas_a_eliminar = [] cuentas_a_listo = [] topes_a_eliminar = [] - satisfecho = self.satisfecho() - verificado = self.verificado() - sin_verificar = self.sin_verificar() - pendiente_distribucion = self.pendiente_distribucion() - esperando_desvinculacion = self.esperando_desvinculacion() - esperando_transaccion = self.esperando_transaccion() - lista_para_gestion = self.lista_para_gestion() + servicios_a_eliminar = [] for i in cuentas: - if i.status == pendiente_distribucion and i.balance() >= i.tope(): + if (i.status == self.pendiente_distribucion() or i.status == self.esperando_transaccion_abastecimiento())\ + and i.balance() >= i.tope(): cuentas_a_actualizar.append(i.pk) - elif i.status == esperando_desvinculacion and\ + elif i.status == self.esperando_desvinculacion() and\ self.distillery.ya_fue_eliminado(settings.DISTRIBUTOR_ACCOUNT, i.address): cuentas_a_eliminar.append(i.pk) - elif i.status == sin_verificar and self.distillery.ya_fue_verificado(i.address): + servicios_a_eliminar.append(i.service.id) + elif i.status == self.sin_verificar() and self.distillery.ya_fue_verificado(i.address): cuentas_a_verificar.append(i.pk) - elif i.status == verificado: + elif i.status == self.verificado(): tope_esperado = self.tope_manager.get(account=i) try: self.asociacion_beneficiario.asociar_cuenta(i, tope_esperado.valor) except Exception as e: self.logger.error(e) - elif i.status == esperando_transaccion and self.distillery.ya_fue_agregado(i.address): + elif i.status == self.esperando_transaccion() and self.distillery.ya_fue_agregado(i.address): cuentas_a_listo.append(i.pk) topes_a_eliminar.append(i.pk) - self.account_manager.filter(pk__in=cuentas_a_actualizar).update(status=satisfecho) - self.account_manager.filter(pk__in=cuentas_a_verificar).update(status=verificado) - self.account_manager.filter(pk__in=cuentas_a_listo).update(status=lista_para_gestion) + self.account_manager.filter(pk__in=cuentas_a_actualizar).update(status=self.satisfecho()) + self.account_manager.filter(pk__in=cuentas_a_verificar).update(status=self.verificado()) + self.account_manager.filter(pk__in=cuentas_a_listo).update(status=self.lista_para_gestion()) self.account_manager.filter(pk__in=cuentas_a_eliminar).delete() self.tope_manager.filter(account__id__in=topes_a_eliminar).delete() + self.servicios_manager.filter(pk__in=servicios_a_eliminar).delete() class DesvinculacionCuenta: distillery = Distillery() account_manager = Account.objects - desvinculando = Status.objects.get_esperando_desvinculado() + desvinculando = Status.objects.get_esperando_desvinculado + sin_verificar = Status.objects.get_sin_verificar def desvincular_cuenta(self, account): - self.distillery.sacar_beneficiario(settings.DISTRIBUTOR_ACCOUNT, account.address) - account.status = self.desvinculando - account.save() + if account.status != self.sin_verificar(): + self.distillery.sacar_beneficiario(settings.DISTRIBUTOR_ACCOUNT, account.address) + account.status = self.desvinculando() + account.save() + else: + service = account.service + account.delete() + service.delete() + diff --git a/dapp/tests.py b/dapp/tests.py index 33efbc5..0e312c4 100644 --- a/dapp/tests.py +++ b/dapp/tests.py @@ -9,9 +9,10 @@ You should have received a copy of the GNU General Public License along with thi """ from django.test import TestCase -from api.models import CustomUser, Institution, Service +from api.models import CustomUser, Institution, Service, Section from dapp.services import PetitorioEtherCuenta, AsociacionCuenta, \ - NotValidAddressException, DesvinculacionCuenta, VerificacionCuenta, NotVerifiedAccountException + NotValidAddressException, DesvinculacionCuenta, VerificacionCuenta, NotVerifiedAccountException, \ + ActualizacionEstados from dapp.models import Account, Status, TopeEsperado from django.contrib.auth.models import User @@ -19,30 +20,38 @@ from django.contrib.auth.models import User class GeneradorPruebas: def generar_pruebas(self): - Account.objects.create(address="address") - self.account = Account.objects.filter(address="address").first() - user = User.objects.create(first_name="Algun", last_name="Usuario", ) - self.user = CustomUser.objects.create(user=user, cuit="123456789", section=1) + Section.objects.create(name="Seccion") + self.seccion = Section.objects.filter(name='Seccion').first() + user = User.objects.create(first_name="Algun", last_name="Usuario", username="username") + self.user = CustomUser.objects.create(user=user, cuit="123456789", section=self.seccion) Status.objects.create(descripcion="Pendiente de distribucion") self.pendiente_status = Status.objects.filter(descripcion="Pendiente de distribucion").first() - Status.objects.create(descripcion="Esperando transaccion") - self.esperando_transaccion = Status.objects.filter(descripcion="Esperando transaccion").first() + Status.objects.create(descripcion="Esperando transaccion de alta beneficiario") + self.esperando_transaccion = Status.objects.filter( + descripcion="Esperando transaccion de alta beneficiario").first() Status.objects.create(descripcion="Esperando desvinculacion") self.esperando_desvinculador = Status.objects.filter(descripcion="Esperando desvinculacion").first() Status.objects.create(descripcion="Sin verificar") self.sin_verificar = Status.objects.filter(descripcion="Sin verificar").first() Status.objects.create(descripcion="Verificada") self.verificada = Status.objects.filter(descripcion="Verificada").first() + Status.objects.create(descripcion="Satisfecho") + self.satisfecho = Status.objects.filter(descripcion="Satisfecho").first() + Status.objects.create(descripcion="Esperando transaccion de abastecimiento") + self.esperando_transaccion_abastecimiento = Status.objects.filter( + descripcion="Esperando transaccion de abastecimiento").first() Institution.objects.create(name="Institucion loca") self.institucion = Institution.objects.filter(name='Institucion loca').first() Service.objects.create(name="Servicio loco") self.service = Service.objects.filter(name="Servicio loco").first() + Account.objects.create(address="address", status=self.sin_verificar) + self.account = Account.objects.filter(address="address").first() def generar_cuentas(self): - Account.objects.create(address="address1") - Account.objects.create(address="address2") - Account.objects.create(address="address3") - Account.objects.create(address="address4") + Account.objects.create(address="address1", status=self.sin_verificar) + Account.objects.create(address="address2", status=self.sin_verificar) + Account.objects.create(address="address3", status=self.sin_verificar) + Account.objects.create(address="address4", status=self.sin_verificar) self.accounts = Account.objects.filter(address__in=["address1", "address2", "address3", @@ -92,6 +101,9 @@ class DistilleryMock: def iniciar_verificacion(self, from_account, address, password): pass + def ya_fue_eliminado(self, dist, target): + return True + class TestAsociacionCuenta(TestCase, GeneradorPruebas): class ValidadorSiempreTrueMock: @@ -127,8 +139,7 @@ class TestAsociacionCuenta(TestCase, GeneradorPruebas): self.asociador.gateway = self.ValidadorSiempreTrueMock() Account.objects.create(address="cuenta no verificada", status=self.sin_verificar) cuenta = Account.objects.filter(address="cuenta no verificada").first() - self.assertRaises(NotVerifiedAccountException, self.asociador.asociar_cuenta, account=cuenta, - tope=10) + self.assertRaises(NotVerifiedAccountException, self.asociador.asociar_cuenta, account=cuenta, tope=10) class TestDesvincularCuenta(TestCase, GeneradorPruebas): @@ -139,13 +150,22 @@ class TestDesvincularCuenta(TestCase, GeneradorPruebas): self.desvinculador.distillery = DistilleryMock() def test_desvincular_cuenta(self): - self.desvinculador.desvincular_cuenta(self.account) - self.assertEqual(self.esperando_desvinculador.descripcion, self.account.status.descripcion, + account_desvinculando = Account.objects.create(address='address_desvincular', status=self.satisfecho, + institution=self.institucion, service=self.service) + self.desvinculador.desvincular_cuenta(account_desvinculando) + self.assertEqual(self.esperando_desvinculador, + Account.objects.get(address=account_desvinculando.address).status, "Deberia estar esperando desvinculado") + def test_borrar_cuenta(self): + account_a_borrar = Account.objects.create(address='address_borrar', status=self.sin_verificar, + institution=self.institucion, service=self.service) + self.assertEqual(Account.objects.filter(address='address_borrar').count(), 1) + self.desvinculador.desvincular_cuenta(account_a_borrar) + self.assertEqual(Account.objects.filter(address='address_borrar').count(), 0) -class TestVerificacionCuenta(TestCase, GeneradorPruebas): +class TestVerificacionCuenta(TestCase, GeneradorPruebas): class GeneradorClaveMock: def generar_clave(self): return "clave mock" @@ -181,3 +201,33 @@ class TestVerificacionCuenta(TestCase, GeneradorPruebas): def test_verificar_cuenta_invalida(self): self.verificacion.gateway = self.ValidadorSiempreFalseMock() self.assertRaises(NotValidAddressException, self.verificacion.iniciar_verificacion, account=self.account, ) + + +class TestActualizarEstados(TestCase, GeneradorPruebas): + + def setUp(self): + self.actualizador = ActualizacionEstados() + self.generar_pruebas() + + def test_actualizar_desvinculacion(self): + self.actualizador.distillery = DistilleryMock() + Account.objects.distillery = DistilleryMock() + Account.objects.gateway = MockGateway() + account = Account.objects.create(address="address_random", status=self.esperando_desvinculador, + service=self.service, institution=self.institucion) + self.assertEqual(Account.objects.filter(address="address_random").count(), 1) + self.actualizador.actualizar_cuentas([account]) + self.assertEqual(Account.objects.filter(address="address_random").count(), 0) + + def test_ya_esta_satisfecho(self): + Account.objects.gateway = MockGateway() + Account.objects.distillery = DistilleryMock() + account_pendiente = Account.objects.create(address="address_random", status=self.pendiente_status, + service=self.service, institution=self.institucion) + + account_esperando = Account.objects.create(address="address_random_2", status=self.esperando_transaccion_abastecimiento, + service=self.service, institution=self.institucion) + self.actualizador.actualizar_cuentas([account_pendiente, account_esperando]) + self.assertEqual(self.satisfecho, Account.objects.get(address="address_random").status) + self.assertEqual(self.satisfecho, Account.objects.get(address="address_random_2").status) + diff --git a/frontend/templates/dapp/account_list.html b/frontend/templates/dapp/account_list.html index 014e266..4def325 100644 --- a/frontend/templates/dapp/account_list.html +++ b/frontend/templates/dapp/account_list.html @@ -128,7 +128,7 @@ <pre>var estimate = contractInstance.proveControl.estimateGas("<label id="label-clave1"></label>")</pre> </li> <li>Generá una transacción - <pre>var tx = contractInstance.proveControl.sendTransaction("<label id="label-clave2"></label>", {gas:estimate, gasPrice:1})</pre> + <pre>var tx = contractInstance.proveControl.sendTransaction("<label id="label-clave2"></label>", {gas:estimate, gasPrice:eth.gasPrice})</pre> </li> <li>Obtené el recibo. Esto puede devolver <i>undefined</i> porque depende de si se selló el bloque con la transacción <pre>eth.getTransactionReceipt(tx)</pre> diff --git a/frontend/templates/django_registration/registration_form.html b/frontend/templates/django_registration/registration_form.html index 8e49617..a38b61b 100644 --- a/frontend/templates/django_registration/registration_form.html +++ b/frontend/templates/django_registration/registration_form.html @@ -72,6 +72,16 @@ You should have received a copy of the GNU General Public License along with thi <p>Utilizá ocho caracteres como mÃnimo con una combinación de letras, números y sÃmbolos.</p> </div> + <div class="form-group form-group-lg col-sm-12"> + <div> + <label class="control-label" for="terms">PolÃtica de Uso</label> + </div> + <div> + <input type="checkbox" name="terms" id="terms" placeholder="PolÃtica de Uso" required style="float: left; margin-top: 8px;"> + <label class="font_small" for="terms" style="font-weight: 100">He leÃdo y acepto la <a style="cursor: pointer" data-toggle="modal" data-target="#terms-modal">polÃtica de uso</a></label> + </div> + </div> + <script src='https://www.google.com/recaptcha/api.js'></script> <div class="g-recaptcha col-sm-12" data-sitekey="{{ data_sitekey }}"></div> @@ -84,6 +94,34 @@ You should have received a copy of the GNU General Public License along with thi </form> </section> </div> + <div class="modal" tabindex="-1" role="dialog" id="terms-modal"> + <div class="modal-dialog" role="document" style="width: 80%;"> + <div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title">PolÃtica de uso</h4> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"> + <span aria-hidden="true">×</span> + </button> + </div> + <div class="modal-body"> + <p>What is Lorem Ipsum? +Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. + +Why do we use it? +It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like). + + +Where does it come from? +Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32. + + </p> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-primary" data-dismiss="modal" >Cerrar</button> + </div> + </div> + </div> + </div> </main> {% include 'footer.html' %} @@ -139,13 +177,15 @@ You should have received a copy of the GNU General Public License along with thi password: { required: "Ingresá una contraseña", minlength: "La contraseña debe tener al menos 8 caracteres" - } + }, + terms: "Debes aceptar la polÃtica de uso" }, rules:{ first_name: "required", last_name: "required", username: "required", + terms: "required", password: { required: true, atLeastOneLowercaseLetter: true, diff --git a/frontend/templates/header.html b/frontend/templates/header.html index dd8ffc6..c9c9194 100644 --- a/frontend/templates/header.html +++ b/frontend/templates/header.html @@ -28,4 +28,13 @@ You should have received a copy of the GNU General Public License along with thi <body> {% block content %}{% endblock %} </body> + <script> + $(window).unload(function() { + $.ajax({ + url: '/accounts/logout/', + method: 'GET', + + }); + }); + </script> </html> \ No newline at end of file diff --git a/logica_cuentas/admin.py b/logica_cuentas/admin.py index 540903a..c48ca11 100644 --- a/logica_cuentas/admin.py +++ b/logica_cuentas/admin.py @@ -10,3 +10,19 @@ You should have received a copy of the GNU General Public License along with thi from django.contrib import admin # Register your models here. +from logica_cuentas.forms import RelacionUsuarioAccountForm +from logica_cuentas.models import RelacionUsuarioAccountStatus, RelacionUsuarioAccount + + +class RelacionUsuarioAccountAdmin(admin.ModelAdmin): + form = RelacionUsuarioAccountForm + list_filter = ('status',) + # actions = [pedir_ether, abastecer_inmediatamente, desvincular] + + +class RelacionUsuarioAccountStatusAdmin(admin.ModelAdmin): + exclude = ('id',) + + +admin.site.register(RelacionUsuarioAccount, RelacionUsuarioAccountAdmin) +admin.site.register(RelacionUsuarioAccountStatus, RelacionUsuarioAccountStatusAdmin) diff --git a/logica_cuentas/apps.py b/logica_cuentas/apps.py index b36ee85..c558f2d 100644 --- a/logica_cuentas/apps.py +++ b/logica_cuentas/apps.py @@ -12,3 +12,4 @@ from django.apps import AppConfig class LogicaCuentasConfig(AppConfig): name = 'logica_cuentas' + verbose_name = 'Relacion Cuenta BFA - EOAs' diff --git a/logica_cuentas/management/commands/agregar_estados_cuenta_usuario.py b/logica_cuentas/management/commands/agregar_estados_cuenta_usuario.py index 615ad1e..499816c 100644 --- a/logica_cuentas/management/commands/agregar_estados_cuenta_usuario.py +++ b/logica_cuentas/management/commands/agregar_estados_cuenta_usuario.py @@ -10,21 +10,25 @@ You should have received a copy of the GNU General Public License along with thi from django.core.management.base import BaseCommand from logica_cuentas.models import RelacionUsuarioAccountStatus import logging + logger = logging.getLogger('logger') class Command(BaseCommand): def handle(self, *args, **options): try: - logger.info("Estado 'Sin verificar' no existe, creandose") - res = RelacionUsuarioAccountStatus.objects.create(descripcion="Sin verificar") - logger.info("Hecho " + str(res)) - - - logger.info("Estado 'Verificada' no existe, creandose") - res = RelacionUsuarioAccountStatus.objects.create(descripcion="Verificada") - logger.info("Hecho " + str(res)) - + sin_verificar = RelacionUsuarioAccountStatus.objects.filter(descripcion="Sin verificar") + verificada = RelacionUsuarioAccountStatus.objects.filter(descripcion="Verificada") + + if not sin_verificar.exists(): + logger.info("Estado 'Sin verificar' no existe, creandose") + res = RelacionUsuarioAccountStatus.objects.create(descripcion="Sin verificar") + logger.info("Hecho " + str(res)) + + if not verificada.exists(): + logger.info("Estado 'Verificada' no existe, creandose") + res = RelacionUsuarioAccountStatus.objects.create(descripcion="Verificada") + logger.info("Hecho " + str(res)) except Exception as e: logger.exception(e) diff --git a/logica_cuentas/managers.py b/logica_cuentas/managers.py index fe359c8..5a48b77 100644 --- a/logica_cuentas/managers.py +++ b/logica_cuentas/managers.py @@ -27,7 +27,6 @@ class RelacionUsuarioAccountStatusManager(models.Manager): class RelacionUsuarioAccountManager(models.Manager): - account_status_manager = Status.objects account_manager = Account.objects @@ -40,8 +39,23 @@ class RelacionUsuarioAccountManager(models.Manager): def cant_cuentas_sin_verificar_por_user(self, user): return self.get_accounts_sin_verificar_por_user(user).count() + def get_users_por_account(self, account): + users = [] + for u in self.filter(account=account): + users.append(u.user) + return users + def get_accounts_por_user(self, user): accounts = [] for a in self.filter(user=user): accounts.append(a.account) return accounts + + def existe_relacion(self, user, account): + return self.filter(user=user, account=account).exists() + + def tiene_owner(self, account): + return self.filter(account=account, is_owner=True).exists() + + def owner(self, account): + return self.filter(account=account, is_owner=True).first().user.user \ No newline at end of file diff --git a/logica_cuentas/models.py b/logica_cuentas/models.py index f01ed2e..123831a 100644 --- a/logica_cuentas/models.py +++ b/logica_cuentas/models.py @@ -18,16 +18,27 @@ class RelacionUsuarioAccountStatus(models.Model): descripcion = models.CharField(max_length=60) objects = RelacionUsuarioAccountStatusManager() + def __str__(self): + return self.descripcion + class Meta: db_table = 'customuser_account_status' + verbose_name = 'Estado de la relacion usuario - EOA' + verbose_name_plural = 'Estados de la relacion usuario - EOA' class RelacionUsuarioAccount(models.Model): account = models.ForeignKey(Account, on_delete=models.PROTECT) user = models.ForeignKey(CustomUser, on_delete=models.PROTECT) status = models.ForeignKey(RelacionUsuarioAccountStatus, on_delete=models.PROTECT, ) + is_owner = models.BooleanField(default=False) objects = RelacionUsuarioAccountManager() + def __str__(self): + return "Account: {} ; user : {}".format(self.account, self.user) + class Meta: db_table = 'customuser_account' unique_together = (("account", "user"),) + verbose_name = 'Relacion usuario BFA - EOA' + verbose_name_plural = 'Relaciones usuario BFA - EOA' diff --git a/logica_cuentas/services.py b/logica_cuentas/services.py index 8855c2a..a4e1a66 100644 --- a/logica_cuentas/services.py +++ b/logica_cuentas/services.py @@ -11,8 +11,8 @@ import logging from django.db import transaction -from dapp.models import Account, TopeEsperado -from dapp.services import VerificacionCuenta, PetitorioEtherCuenta, AccountBeingKicked +from dapp.models import Account, TopeEsperado, Status +from dapp.services import VerificacionCuenta, PetitorioEtherCuenta, AccountBeingKicked, DesvinculacionCuenta from logica_cuentas.models import RelacionUsuarioAccount, RelacionUsuarioAccountStatus @@ -27,19 +27,21 @@ class AltaCuentaEthereum: verificador_cuenta = VerificacionCuenta() relacion_sin_verificar = RelacionUsuarioAccountStatus.objects.get_sin_verificar_relacion relacion_verificada = RelacionUsuarioAccountStatus.objects.get_relacion_verificada + sin_verificar = Status.objects.get_sin_verificar def alta_cuenta_ethereum(self, address, institution, service, user, tope=0): if self.relacion_manager.cant_cuentas_sin_verificar_por_user(user) > 4: raise TooMuchUnverifiedAccountsException with transaction.atomic(): - self.account_manager.create(address=address, institution=institution, - service=service, owner=user) + funcion_status = self.sin_verificar + self.account_manager.create(address=address, institution=institution, service=service, + status=funcion_status()) account = self.account_manager.filter(address=address).first() self.tope_manager.create(valor=tope, account=account) clave = self.verificador_cuenta.iniciar_verificacion(account) funcion = self.relacion_verificada - self.relacion_manager.create(user=user, account=account, status=funcion()) + self.relacion_manager.create(user=user, account=account, status=funcion(), is_owner=True) return account, clave @@ -58,3 +60,62 @@ class PetitorioEtherUsuario: self.petitorio_ether.pedir_ether(c) except AccountBeingKicked as ack: self.logger.info(ack.msg) + + +class NoOwnerException(Exception): + pass + + +class AlreadyBoundException(Exception): + pass + + +class CreacionRelacionCuentaUsuario: + manager = RelacionUsuarioAccount.objects + sin_verificar = RelacionUsuarioAccountStatus.objects.get_sin_verificar_relacion + + def vincular(self, user, account): + if self.manager.existe_relacion(user, account): + raise AlreadyBoundException("Account {} ya esta relacionada a user {}".format(str(account), str(user))) + if not self.manager.tiene_owner(account): + raise NoOwnerException("Account {} no tiene dueño".format(str(account))) + sin_verificar_funcion = self.sin_verificar + relacion = self.manager.create(user=user, account=account, is_owner=False, status=sin_verificar_funcion()) + return relacion + + +class DesvinculacionDefinitiva: + desvinculador = DesvinculacionCuenta() + relacion_manager = RelacionUsuarioAccount.objects + + def desvincular(self, relacion): + with transaction.atomic(): + + if relacion.is_owner: + + accounts = self.relacion_manager.get_users_por_account(relacion.account) + + if accounts.count() > 1: + error_message = 'Los siguientes usuarios tienen vinculada la cuenta, deben desvincularla para poder ser borrada: <br/><ul>' + for a in accounts: + if a.user.user.id != relacion.user.user.id: + error_message = error_message + '<li>' + a.user.user.username + ' - ' + a.user.user.email + '</li>' + + error_message = error_message + '</ul>' + + messages.error(request, error_message, extra_tags='danger') + else: + account = Account.objects.get(pk=relacion.account_id) + + account_address = relacion.account.address + + relacion.delete() + account.delete() + service = Service.objects.get(pk=account.service_id) + service.delete() + + messages.success(request, _('cuenta_borrada') % account_address) + + else: + relacion.delete() + messages.success(request, _('cuenta_desvinculada') % relacion.account.address) diff --git a/logica_cuentas/tests.py b/logica_cuentas/tests.py index 21097c7..731504c 100644 --- a/logica_cuentas/tests.py +++ b/logica_cuentas/tests.py @@ -11,12 +11,15 @@ from django.test import TestCase # Create your tests here. import dapp +from api.models import CustomUser from dapp.models import Account, Status, TopeEsperado from dapp.services import Distribucion, NotValidAddressException from dapp.tests import DistilleryMock from logica_cuentas.models import RelacionUsuarioAccountStatus, RelacionUsuarioAccount -from logica_cuentas.services import PetitorioEtherUsuario, AltaCuentaEthereum, TooMuchUnverifiedAccountsException +from logica_cuentas.services import PetitorioEtherUsuario, AltaCuentaEthereum, TooMuchUnverifiedAccountsException, \ + NoOwnerException, AlreadyBoundException, CreacionRelacionCuentaUsuario from django.db import models +from django.contrib.auth.models import User class GeneradorPruebas: @@ -26,6 +29,28 @@ class GeneradorPruebas: RelacionUsuarioAccountStatus.objects.create(descripcion="Verificada") self.relacion_verificada = RelacionUsuarioAccountStatus.objects.filter(descripcion="Verificada").first() + class ValidadorSiempreTrueMock: + def is_valid_address(self, address): + return True + + class ValidadorSiempreFalseMock: + def is_valid_address(self, address): + return False + + class ManagerMock(models.Manager): + def cant_cuentas_sin_verificar_por_user(self, user): + return 4 + + def tiene_owner(self, account): + return True + + class ManagerMockCuentasSinVerificar(models.Manager): + def cant_cuentas_sin_verificar_por_user(self, user): + return 10 + + def tiene_owner(self, account): + return False + class TestDistribucion(TestCase, dapp.tests.GeneradorPruebas): @@ -69,21 +94,6 @@ class VerificacionInvalidaMock(object): class TestAltaCuentaEthereum(TestCase, GeneradorPruebas, dapp.tests.GeneradorPruebas): - class ValidadorSiempreTrueMock: - def is_valid_address(self, address): - return True - - class ValidadorSiempreFalseMock: - def is_valid_address(self, address): - return False - - class ManagerMock(models.Manager): - def cant_cuentas_sin_verificar_por_user(self, user): - return 4 - - class ManagerMockCuentasSinVerificar(models.Manager): - def cant_cuentas_sin_verificar_por_user(self, user): - return 10 def setUp(self): self.alta_cuenta = AltaCuentaEthereum() @@ -99,12 +109,14 @@ class TestAltaCuentaEthereum(TestCase, GeneradorPruebas, dapp.tests.GeneradorPru self.managerMock.cant_cuentas_sin_verificar_por_user (cuenta, clave) = self.alta_cuenta.alta_cuenta_ethereum("cuenta poronga", self.institucion, self.service, self.user, 1000) + relacion = RelacionUsuarioAccount.objects.filter(user=self.user, account=cuenta).first() self.assertEqual("cuenta poronga", cuenta.address, "DeberÃan ser iguales las direcciones") self.assertEqual(self.institucion, cuenta.institution, "DeberÃan ser las mismas instituciones") self.assertEqual("clave mock", clave, "Las claves deberÃan ser iguales") tope_esperado = TopeEsperado.objects.filter(account=cuenta).first().valor self.assertEqual(1000, tope_esperado, "Los montos deberÃan ser iguales") self.assertEqual(self.sin_verificar.descripcion, cuenta.status.descripcion, "DeberÃa estar sin verificar") + self.assertTrue(relacion.is_owner, "El usuario deberÃa ser owner de esta cuenta") def test_verificar_cuenta_invalida(self): self.alta_cuenta.verificador_cuenta = VerificacionInvalidaMock() @@ -121,3 +133,50 @@ class TestAltaCuentaEthereum(TestCase, GeneradorPruebas, dapp.tests.GeneradorPru self.assertRaises(TooMuchUnverifiedAccountsException, self.alta_cuenta.alta_cuenta_ethereum, address="cuenta poronga", user=self.user, institution=self.institucion, service=self.service) self.assertFalse(Account.objects.filter(address="cuenta poronga").exists()) + + +class TestCreacionRelacionCuentaUsuario(TestCase, GeneradorPruebas, dapp.tests.GeneradorPruebas): + + def setUp(self): + self.creador = CreacionRelacionCuentaUsuario() + self.generar_estados() + self.generar_pruebas() + self.generar_cuentas() + user = User.objects.create(first_name="Otro", last_name="Usuarito", username="sarlanga") + self.otro_user = CustomUser.objects.create(user=user, cuit="12345678910", section=self.seccion) + self.managerMock = self.ManagerMock() + self.managerMockInvalido = self.ManagerMockCuentasSinVerificar() + pass + + def test_creacion_vinculacion(self): + manager_original = self.creador.manager + self.creador.manager.tiene_owner = self.managerMock.tiene_owner + self.assertEqual(RelacionUsuarioAccount.objects.filter(user=self.user, account=self.account).count(), 0) + relacion = self.creador.vincular(self.user, self.account) + self.assertEqual(RelacionUsuarioAccount.objects.filter(user=self.user, account=self.account).count(), 1) + self.assertFalse(relacion.is_owner) + self.assertEqual(self.sin_verificar_relacion, relacion.status) + self.creador.manager = manager_original + + def test_creacion_vinculacion_ya_existia(self): + self.creador.vincular(self.user, self.account) + self.assertRaises(AlreadyBoundException, self.creador.vincular, + user=self.user, account=self.account) + + def test_alta_y_vinculacion(self): + alta_cuenta = AltaCuentaEthereum() + alta_cuenta.verificador_cuenta = VerificacionValidaMock() + alta_cuenta.relacion_manager.cant_cuentas_sin_verificar_por_user = \ + self.managerMock.cant_cuentas_sin_verificar_por_user + (cuenta, clave) = alta_cuenta.alta_cuenta_ethereum("cuenta poronga", self.institucion, self.service, + self.user, 1000) + relacion = self.creador.vincular(self.otro_user, cuenta) + self.assertFalse(relacion.is_owner) + self.assertEqual(RelacionUsuarioAccount.objects.filter(account=cuenta).count(), 2) + self.assertEqual(self.sin_verificar_relacion, relacion.status) + + def test_vinculacion_sin_owner(self): + manager_original = self.creador.manager + self.creador.manager.tiene_owner = self.managerMockInvalido.tiene_owner + self.assertRaises(NoOwnerException, self.creador.vincular, user=self.user, account=self.account) + self.creador.manager = manager_original diff --git a/requirements.txt b/requirements.txt index d504a15..697def6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,7 +19,6 @@ hexbytes==0.1.0 idna==2.7 lru-dict==1.1.6 parsimonious==0.8.0 -pkg-resources==0.0.0 psycopg2==2.7.6.1 psycopg2-binary==2.7.6.1 pycryptodome==3.6.6 diff --git a/scripts_utiles/PoAdeploy.py b/scripts_utiles/PoAdeploy.py index 6462f5a..99dca83 100644 --- a/scripts_utiles/PoAdeploy.py +++ b/scripts_utiles/PoAdeploy.py @@ -19,9 +19,9 @@ from web3.middleware import geth_poa_middleware w3 = Web3(Web3.HTTPProvider('http://10.23.10.71:8501')) w3.middleware_stack.inject(geth_poa_middleware, layer=0) -abi = '[ { "anonymous": false, "inputs": [ { "indexed": false, "name": "amount", "type": "uint256" } ], "name": "proofOfControlWeiAmountChanged", "type": "event" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "limit", "type": "uint256" } ], "name": "addBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "add", "type": "address" }, { "name": "password", "type": "bytes32" } ], "name": "addSuitor", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "limit", "type": "uint256" } ], "name": "changeLimit", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" } ], "name": "kickBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" } ], "name": "kickDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": true, "name": "ben", "type": "address" }, { "indexed": false, "name": "newLimit", "type": "uint256" } ], "name": "limitChanged", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" } ], "name": "suitorApproved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" } ], "name": "suitorNotApproved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "kicked", "type": "address" } ], "name": "kickedDistributor", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" }, { "indexed": true, "name": "distr", "type": "address" } ], "name": "suitorAdded", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": true, "name": "added", "type": "address" }, { "indexed": false, "name": "limit", "type": "uint256" } ], "name": "addedBeneficiary", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": true, "name": "kicked", "type": "address" } ], "name": "kickedBeneficiary", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "added", "type": "address" }, { "indexed": false, "name": "top", "type": "uint256" } ], "name": "addedDistributor", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": false, "name": "amount", "type": "uint256" } ], "name": "replenished", "type": "event" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "top", "type": "uint256" } ], "name": "addDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "key", "type": "string" } ], "name": "proveControl", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "amount", "type": "uint256" } ], "name": "replenish", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [], "name": "replenishAll", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "accs", "type": "address[]" }, { "name": "amounts", "type": "uint256[]" } ], "name": "replenishList", "outputs": [], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "amount", "type": "uint256" } ], "name": "setProofOfControlWeiAmount", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "payable": true, "stateMutability": "payable", "type": "constructor" }, { "constant": true, "inputs": [], "name": "getBeneficiariesCount", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "acc", "type": "address" } ], "name": "getBeneficiaryLimit", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "acc", "type": "address" } ], "name": "getDistributorLimit", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "getProofOfControlWeiAmount", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "key", "type": "string" } ], "name": "hash", "outputs": [ { "name": "", "type": "bytes32" } ], "payable": false, "stateMutability": "pure", "type": "function" }, { "constant": true, "inputs": [ { "name": "add", "type": "address" } ], "name": "isBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "add", "type": "address" } ], "name": "isDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" } ]' +abi = '[ { "constant": true, "inputs": [ { "name": "acc", "type": "address" } ], "name": "getBeneficiaryLimit", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "name": "accs", "type": "address[]" }, { "name": "amounts", "type": "uint256[]" } ], "name": "replenishList", "outputs": [], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "key", "type": "string" } ], "name": "proveControl", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [], "name": "getProofOfControlWeiAmount", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "name": "amount", "type": "uint256" } ], "name": "setProofOfControlWeiAmount", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "amount", "type": "uint256" } ], "name": "replenish", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": true, "inputs": [], "name": "getBeneficiariesCount", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" } ], "name": "kickBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [ { "name": "add", "type": "address" } ], "name": "isDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "limit", "type": "uint256" } ], "name": "addBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "add", "type": "address" }, { "name": "password", "type": "bytes32" } ], "name": "addSuitor", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": true, "inputs": [ { "name": "add", "type": "address" } ], "name": "isBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "top", "type": "uint256" } ], "name": "addDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "limit", "type": "uint256" } ], "name": "changeLimit", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": true, "inputs": [ { "name": "key", "type": "string" } ], "name": "hash", "outputs": [ { "name": "", "type": "bytes32" } ], "payable": false, "stateMutability": "pure", "type": "function" }, { "constant": true, "inputs": [ { "name": "acc", "type": "address" } ], "name": "getDistributorLimit", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": false, "inputs": [], "name": "replenishAll", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" } ], "name": "kickDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "payable": true, "stateMutability": "payable", "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": true, "name": "added", "type": "address" }, { "indexed": false, "name": "limit", "type": "uint256" } ], "name": "addedBeneficiary", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "added", "type": "address" }, { "indexed": false, "name": "top", "type": "uint256" } ], "name": "addedDistributor", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": true, "name": "kicked", "type": "address" } ], "name": "kickedBeneficiary", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "kicked", "type": "address" } ], "name": "kickedDistributor", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": true, "name": "ben", "type": "address" }, { "indexed": false, "name": "newLimit", "type": "uint256" } ], "name": "limitChanged", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": false, "name": "amount", "type": "uint256" } ], "name": "replenished", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" }, { "indexed": true, "name": "distr", "type": "address" } ], "name": "suitorAdded", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" } ], "name": "suitorApproved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" } ], "name": "suitorNotApproved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "name": "amount", "type": "uint256" } ], "name": "proofOfControlWeiAmountChanged", "type": "event" } ]' -bytecode = "6080604052336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611ce0806100536000396000f3006080604052600436106100fc576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630146dfef14610101578063118b43d41461015857806312777df8146101f4578063141ff2a11461027557806352417497146102a057806356407455146102e5578063669be7011461033d5780637bde190c146103685780638f0c86fa146103c357806396074e701461041e5780639b5dca5a146104835780639d19b226146104df578063a7ade36f1461053a578063b20f3f371461059f578063b411ee9414610604578063cf1eb1c214610689578063d2030a37146106e0578063d9ec42f814610702575b600080fd5b34801561010d57600080fd5b50610142600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061075d565b6040518082815260200191505060405180910390f35b6101f26004803603810190808035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290505050610771565b005b34801561020057600080fd5b5061025b600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610861565b604051808215151515815260200191505060405180910390f35b34801561028157600080fd5b5061028a610aa9565b6040518082815260200191505060405180910390f35b3480156102ac57600080fd5b506102cb60048036038101908080359060200190929190505050610ab3565b604051808215151515815260200191505060405180910390f35b610323600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b53565b604051808215151515815260200191505060405180910390f35b34801561034957600080fd5b50610352610cc9565b6040518082815260200191505060405180910390f35b34801561037457600080fd5b506103a9600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610cd6565b604051808215151515815260200191505060405180910390f35b3480156103cf57600080fd5b50610404600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610db9565b604051808215151515815260200191505060405180910390f35b34801561042a57600080fd5b50610469600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610dcd565b604051808215151515815260200191505060405180910390f35b6104c5600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190505050610ee6565b604051808215151515815260200191505060405180910390f35b3480156104eb57600080fd5b50610520600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611076565b604051808215151515815260200191505060405180910390f35b34801561054657600080fd5b50610585600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061108a565b604051808215151515815260200191505060405180910390f35b3480156105ab57600080fd5b506105ea600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611165565b604051808215151515815260200191505060405180910390f35b34801561061057600080fd5b5061066b600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061127f565b60405180826000191660001916815260200191505060405180910390f35b34801561069557600080fd5b506106ca600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611357565b6040518082815260200191505060405180910390f35b6106e861136b565b604051808215151515815260200191505060405180910390f35b34801561070e57600080fd5b50610743600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506114bd565b604051808215151515815260200191505060405180910390f35b600061076a600183611589565b9050919050565b60008151835114151561078357600080fd5b60009050610790836115d8565b1561085c575b825181101561085b5782818151811015156107ad57fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff166108fc84838151811015156107de57fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff16316108216001878681518110151561081257fe5b90602001906020020151611589565b039081150290604051600060405180830381858888f1935050505015801561084d573d6000803e3d6000fd5b508080600101915050610796565b5b505050565b6000806008541180156109c85750600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600019163073ffffffffffffffffffffffffffffffffffffffff1663b411ee94846040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561093b578082015181840152602081019050610920565b50505050905090810190601f1680156109685780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561098757600080fd5b505af115801561099b573d6000803e3d6000fd5b505050506040513d60208110156109b157600080fd5b810190808051906020019092919050505060001916145b15610a5c573373ffffffffffffffffffffffffffffffffffffffff167f27331d2f70895590002d07861712460d31f950e1b18f7658f3a40441149d54b260405160405180910390a2600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000905560019050610aa4565b3373ffffffffffffffffffffffffffffffffffffffff167f0bd7a7206a3474c66723618e72cc804f3b3db8c5440ad272f4032a517b663ce060405160405180910390a2600090505b919050565b6000600854905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610b1057600080fd5b816008819055507fb922369845d41aae76bb07b70450bc5603d4a0959b47db440c0c8491165a10e9826040518082815260200191505060405180910390a1919050565b6000610b606004336116b1565b80610bb757506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b1515610bc257600080fd5b610bcd6001846116b1565b8015610bf95750610bdf600184611589565b8373ffffffffffffffffffffffffffffffffffffffff1631105b8015610c1b5750813073ffffffffffffffffffffffffffffffffffffffff1631115b15610cbe578273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050158015610c66573d6000803e3d6000fd5b503373ffffffffffffffffffffffffffffffffffffffff167f67aa7cb8cf4d3427fea2605f3073936075334185ea817ad4a3e3ffe6612ef830836040518082815260200191505060405180910390a260019050610cc3565b600090505b92915050565b6000600160020154905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610d3357600080fd5b610d3e6004836116b1565b15610daf578173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fee9dbfa1f0856d9dc7e726f2a84489bf9ceb44e65761440471e0cf07024ec2fb60405160405180910390a3610da8600483611702565b9050610db4565b600090505b919050565b6000610dc66004836116b1565b9050919050565b6000610dda6004336116b1565b80610e3157506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b1515610e3c57600080fd5b610e476004846116b1565b158015610e5d5750610e5a600433611589565b82105b15610edb578273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167facb9534d8c7cff5af1fe1ee56d258412e52005019c12a868daf35fcf6ebfdd9c846040518082815260200191505060405180910390a3610ed36001848461180d565b159050610ee0565b600090505b92915050565b6000610ef36004336116b1565b80610f4a57506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b1515610f5557600080fd5b6008543073ffffffffffffffffffffffffffffffffffffffff163110151561106b5781600760008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081600019169055503373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fbfdc4f9f1c1e9c255c4aa6abd73a2a2cb4f599e3fc15f8b58d55483cb4ada82460405160405180910390a38273ffffffffffffffffffffffffffffffffffffffff166108fc6008549081150290604051600060405180830381858888f19350505050158015611061573d6000803e3d6000fd5b5060019050611070565b600090505b92915050565b60006110836001836116b1565b9050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156110e757600080fd5b6110f26001846116b1565b151561115a578273ffffffffffffffffffffffffffffffffffffffff167f0644aa13d0ac1766bc91d62a757486dc5f7f5dec6e40d3fec281ece9d2d3de2d836040518082815260200191505060405180910390a26111526004848461180d565b15905061115f565b600090505b92915050565b60006111726004336116b1565b806111c957506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156111d457600080fd5b6111df6001846116b1565b80156111f45750816111f2600433611589565b115b156112745761120560018484611994565b508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f861f6b2bc31fb94186e291e6e9b393d17d621075c758cb77330d8be25f57c6ee846040518082815260200191505060405180910390a360019050611279565b600090505b92915050565b6000816040516020018082805190602001908083835b6020831015156112ba5780518252602082019150602081019050602083039250611295565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b60208310151561132357805182526020820191506020810190506020830392506112fe565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209050919050565b6000611364600483611589565b9050919050565b60008060008061137c6004336116b1565b806113d357506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156113de57600080fd5b6113e6611a46565b156114b2576113f56001611af1565b92505b611403600184611b24565b156114a957611413600184611b38565b915091508173ffffffffffffffffffffffffffffffffffffffff1631811115611497578173ffffffffffffffffffffffffffffffffffffffff166108fc8373ffffffffffffffffffffffffffffffffffffffff163183039081150290604051600060405180830381858888f19350505050158015611495573d6000803e3d6000fd5b505b6114a2600184611bca565b92506113f8565b600193506114b7565b600093505b50505090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561151a57600080fd5b6115256004836116b1565b1561157f578173ffffffffffffffffffffffffffffffffffffffff167f53ae61629b1cf76adc0f9eb0b6e7fcdf1271040d7a0df25ac23671ed6ecc191760405160405180910390a2611578600483611702565b9050611584565b600090505b919050565b60008260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010154905092915050565b60008060008060009250600091505b845183101561168d576116126001868581518110151561160357fe5b90602001906020020151611589565b9050848381518110151561162257fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff163181111561168057848381518110151561165857fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff16318103820191505b82806001019350506115e7565b3073ffffffffffffffffffffffffffffffffffffffff163182109350505050919050565b6000808360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000015411905092915050565b6000808360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050600081141561175e5760009150611806565b8360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008082016000905560018201600090555050600184600101600183038154811015156117c857fe5b9060005260206000200160000160146101000a81548160ff021916908315150217905550836002016000815480929190600190039190505550600191505b5092915050565b6000808460000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050828560000160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001018190555060008111156118b2576001915061198c565b8460010180548091906001016118c89190611c2e565b9050600181018560000160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000018190555083856001018281548110151561192857fe5b9060005260206000200160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508460020160008154809291906001019190505550600091505b509392505050565b6000808460000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000154905060008114156119f05760009150611a3e565b828560000160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010181905550600191505b509392505050565b6000806000806000611a586001611af1565b9350600092505b611a6a600185611b24565b15611ace57611a7a600185611b38565b915091508173ffffffffffffffffffffffffffffffffffffffff1631811115611abc578173ffffffffffffffffffffffffffffffffffffffff16318103830192505b611ac7600185611bca565b9350611a5f565b3073ffffffffffffffffffffffffffffffffffffffff1631831094505050505090565b6000611b1d827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff611bca565b9050919050565b600082600101805490508210905092915050565b6000808360010183815481101515611b4c57fe5b9060005260206000200160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691508360000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015490509250929050565b600081806001019250505b826001018054905082108015611c1357508260010182815481101515611bf757fe5b9060005260206000200160000160149054906101000a900460ff165b15611c25578180600101925050611bd5565b81905092915050565b815481835581811115611c5557818360005260206000209182019101611c549190611c5a565b5b505050565b611cb191905b80821115611cad57600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a81549060ff021916905550600101611c60565b5090565b905600a165627a7a72305820682a03d4645be868cf5284f41444500a7c502d082820e40ed844358bc8ec69c40029" +bytecode = "6080604052336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611ce0806100536000396000f3006080604052600436106100fc576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630146dfef14610101578063118b43d41461015857806312777df8146101f4578063141ff2a11461027557806352417497146102a057806356407455146102e5578063669be7011461033d5780637bde190c146103685780638f0c86fa146103c357806396074e701461041e5780639b5dca5a146104835780639d19b226146104df578063a7ade36f1461053a578063b20f3f371461059f578063b411ee9414610604578063cf1eb1c214610689578063d2030a37146106e0578063d9ec42f814610702575b600080fd5b34801561010d57600080fd5b50610142600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061075d565b6040518082815260200191505060405180910390f35b6101f26004803603810190808035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919291929080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509192919290505050610771565b005b34801561020057600080fd5b5061025b600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610861565b604051808215151515815260200191505060405180910390f35b34801561028157600080fd5b5061028a610aa9565b6040518082815260200191505060405180910390f35b3480156102ac57600080fd5b506102cb60048036038101908080359060200190929190505050610ab3565b604051808215151515815260200191505060405180910390f35b610323600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b53565b604051808215151515815260200191505060405180910390f35b34801561034957600080fd5b50610352610cc9565b6040518082815260200191505060405180910390f35b34801561037457600080fd5b506103a9600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610cd6565b604051808215151515815260200191505060405180910390f35b3480156103cf57600080fd5b50610404600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610db9565b604051808215151515815260200191505060405180910390f35b34801561042a57600080fd5b50610469600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610dcd565b604051808215151515815260200191505060405180910390f35b6104c5600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190505050610ee6565b604051808215151515815260200191505060405180910390f35b3480156104eb57600080fd5b50610520600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611076565b604051808215151515815260200191505060405180910390f35b34801561054657600080fd5b50610585600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061108a565b604051808215151515815260200191505060405180910390f35b3480156105ab57600080fd5b506105ea600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611165565b604051808215151515815260200191505060405180910390f35b34801561061057600080fd5b5061066b600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061127f565b60405180826000191660001916815260200191505060405180910390f35b34801561069557600080fd5b506106ca600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611357565b6040518082815260200191505060405180910390f35b6106e861136b565b604051808215151515815260200191505060405180910390f35b34801561070e57600080fd5b50610743600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506114bd565b604051808215151515815260200191505060405180910390f35b600061076a600183611589565b9050919050565b60008151835114151561078357600080fd5b60009050610790836115d8565b1561085c575b825181101561085b5782818151811015156107ad57fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff166108fc84838151811015156107de57fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff16316108216001878681518110151561081257fe5b90602001906020020151611589565b039081150290604051600060405180830381858888f1935050505015801561084d573d6000803e3d6000fd5b508080600101915050610796565b5b505050565b6000806008541180156109c85750600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600019163073ffffffffffffffffffffffffffffffffffffffff1663b411ee94846040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561093b578082015181840152602081019050610920565b50505050905090810190601f1680156109685780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b15801561098757600080fd5b505af115801561099b573d6000803e3d6000fd5b505050506040513d60208110156109b157600080fd5b810190808051906020019092919050505060001916145b15610a5c573373ffffffffffffffffffffffffffffffffffffffff167f27331d2f70895590002d07861712460d31f950e1b18f7658f3a40441149d54b260405160405180910390a2600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000905560019050610aa4565b3373ffffffffffffffffffffffffffffffffffffffff167f0bd7a7206a3474c66723618e72cc804f3b3db8c5440ad272f4032a517b663ce060405160405180910390a2600090505b919050565b6000600854905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610b1057600080fd5b816008819055507fb922369845d41aae76bb07b70450bc5603d4a0959b47db440c0c8491165a10e9826040518082815260200191505060405180910390a1919050565b6000610b606004336116b1565b80610bb757506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b1515610bc257600080fd5b610bcd6001846116b1565b8015610bf95750610bdf600184611589565b8373ffffffffffffffffffffffffffffffffffffffff1631105b8015610c1b5750813073ffffffffffffffffffffffffffffffffffffffff1631115b15610cbe578273ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050158015610c66573d6000803e3d6000fd5b503373ffffffffffffffffffffffffffffffffffffffff167f67aa7cb8cf4d3427fea2605f3073936075334185ea817ad4a3e3ffe6612ef830836040518082815260200191505060405180910390a260019050610cc3565b600090505b92915050565b6000600160020154905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610d3357600080fd5b610d3e6004836116b1565b15610daf578173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fee9dbfa1f0856d9dc7e726f2a84489bf9ceb44e65761440471e0cf07024ec2fb60405160405180910390a3610da8600483611702565b9050610db4565b600090505b919050565b6000610dc66004836116b1565b9050919050565b6000610dda6004336116b1565b80610e3157506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b1515610e3c57600080fd5b610e476004846116b1565b158015610e5d5750610e5a600433611589565b82105b15610edb578273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167facb9534d8c7cff5af1fe1ee56d258412e52005019c12a868daf35fcf6ebfdd9c846040518082815260200191505060405180910390a3610ed36001848461180d565b159050610ee0565b600090505b92915050565b6000610ef36004336116b1565b80610f4a57506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b1515610f5557600080fd5b6008543073ffffffffffffffffffffffffffffffffffffffff163110151561106b5781600760008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081600019169055503373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fbfdc4f9f1c1e9c255c4aa6abd73a2a2cb4f599e3fc15f8b58d55483cb4ada82460405160405180910390a38273ffffffffffffffffffffffffffffffffffffffff166108fc6008549081150290604051600060405180830381858888f19350505050158015611061573d6000803e3d6000fd5b5060019050611070565b600090505b92915050565b60006110836001836116b1565b9050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156110e757600080fd5b6110f26001846116b1565b151561115a578273ffffffffffffffffffffffffffffffffffffffff167f0644aa13d0ac1766bc91d62a757486dc5f7f5dec6e40d3fec281ece9d2d3de2d836040518082815260200191505060405180910390a26111526004848461180d565b15905061115f565b600090505b92915050565b60006111726004336116b1565b806111c957506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156111d457600080fd5b6111df6001846116b1565b80156111f45750816111f2600433611589565b115b156112745761120560018484611994565b508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f861f6b2bc31fb94186e291e6e9b393d17d621075c758cb77330d8be25f57c6ee846040518082815260200191505060405180910390a360019050611279565b600090505b92915050565b6000816040516020018082805190602001908083835b6020831015156112ba5780518252602082019150602081019050602083039250611295565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b60208310151561132357805182526020820191506020810190506020830392506112fe565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209050919050565b6000611364600483611589565b9050919050565b60008060008061137c6004336116b1565b806113d357506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156113de57600080fd5b6113e6611a46565b156114b2576113f56001611af1565b92505b611403600184611b24565b156114a957611413600184611b38565b915091508173ffffffffffffffffffffffffffffffffffffffff1631811115611497578173ffffffffffffffffffffffffffffffffffffffff166108fc8373ffffffffffffffffffffffffffffffffffffffff163183039081150290604051600060405180830381858888f19350505050158015611495573d6000803e3d6000fd5b505b6114a2600184611bca565b92506113f8565b600193506114b7565b600093505b50505090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561151a57600080fd5b6115256004836116b1565b1561157f578173ffffffffffffffffffffffffffffffffffffffff167f53ae61629b1cf76adc0f9eb0b6e7fcdf1271040d7a0df25ac23671ed6ecc191760405160405180910390a2611578600483611702565b9050611584565b600090505b919050565b60008260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010154905092915050565b60008060008060009250600091505b845183101561168d576116126001868581518110151561160357fe5b90602001906020020151611589565b9050848381518110151561162257fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff163181111561168057848381518110151561165857fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff16318103820191505b82806001019350506115e7565b3073ffffffffffffffffffffffffffffffffffffffff163182109350505050919050565b6000808360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000015411905092915050565b6000808360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050600081141561175e5760009150611806565b8360000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008082016000905560018201600090555050600184600101600183038154811015156117c857fe5b9060005260206000200160000160146101000a81548160ff021916908315150217905550836002016000815480929190600190039190505550600191505b5092915050565b6000808460000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050828560000160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001018190555060008111156118b2576001915061198c565b8460010180548091906001016118c89190611c2e565b9050600181018560000160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000018190555083856001018281548110151561192857fe5b9060005260206000200160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508460020160008154809291906001019190505550600091505b509392505050565b6000808460000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000154905060008114156119f05760009150611a3e565b828560000160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010181905550600191505b509392505050565b6000806000806000611a586001611af1565b9350600092505b611a6a600185611b24565b15611ace57611a7a600185611b38565b915091508173ffffffffffffffffffffffffffffffffffffffff1631811115611abc578173ffffffffffffffffffffffffffffffffffffffff16318103830192505b611ac7600185611bca565b9350611a5f565b3073ffffffffffffffffffffffffffffffffffffffff1631831094505050505090565b6000611b1d827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff611bca565b9050919050565b600082600101805490508210905092915050565b6000808360010183815481101515611b4c57fe5b9060005260206000200160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691508360000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015490509250929050565b600081806001019250505b826001018054905082108015611c1357508260010182815481101515611bf757fe5b9060005260206000200160000160149054906101000a900460ff165b15611c25578180600101925050611bd5565b81905092915050565b815481835581811115611c5557818360005260206000209182019101611c549190611c5a565b5b505050565b611cb191905b80821115611cad57600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a81549060ff021916905550600101611c60565b5090565b905600a165627a7a72305820e32f918d7b59986f9e898dc7dbf279e11c82a273dec1b2d416b96fd919d6c8780029" print (str(w3.eth.accounts)) # set pre-funded account as sender diff --git a/scripts_utiles/cambiarCantidad.py b/scripts_utiles/cambiarCantidad.py index 8e24fe0..8341f59 100644 --- a/scripts_utiles/cambiarCantidad.py +++ b/scripts_utiles/cambiarCantidad.py @@ -10,29 +10,28 @@ You should have received a copy of the GNU General Public License along with thi from web3 import Web3 from web3.middleware import geth_poa_middleware from uuid import uuid1 +from django.conf import settings - -w3 = Web3(Web3.HTTPProvider('http://10.23.10.71:8501')) +w3 = Web3(Web3.HTTPProvider(settings.NODE_URL)) w3.middleware_stack.inject(geth_poa_middleware, layer=0) -abi = '[ { "anonymous": false, "inputs": [ { "indexed": false, "name": "amount", "type": "uint256" } ], "name": "proofOfControlWeiAmountChanged", "type": "event" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "limit", "type": "uint256" } ], "name": "addBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "add", "type": "address" }, { "name": "password", "type": "bytes32" } ], "name": "addSuitor", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "limit", "type": "uint256" } ], "name": "changeLimit", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" } ], "name": "kickBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" } ], "name": "kickDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": true, "name": "ben", "type": "address" }, { "indexed": false, "name": "newLimit", "type": "uint256" } ], "name": "limitChanged", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" } ], "name": "suitorApproved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" } ], "name": "suitorNotApproved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "kicked", "type": "address" } ], "name": "kickedDistributor", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" }, { "indexed": true, "name": "distr", "type": "address" } ], "name": "suitorAdded", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": true, "name": "added", "type": "address" }, { "indexed": false, "name": "limit", "type": "uint256" } ], "name": "addedBeneficiary", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": true, "name": "kicked", "type": "address" } ], "name": "kickedBeneficiary", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "added", "type": "address" }, { "indexed": false, "name": "top", "type": "uint256" } ], "name": "addedDistributor", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": false, "name": "amount", "type": "uint256" } ], "name": "replenished", "type": "event" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "top", "type": "uint256" } ], "name": "addDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "key", "type": "string" } ], "name": "proveControl", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "amount", "type": "uint256" } ], "name": "replenish", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [], "name": "replenishAll", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "accs", "type": "address[]" }, { "name": "amounts", "type": "uint256[]" } ], "name": "replenishList", "outputs": [], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "amount", "type": "uint256" } ], "name": "setProofOfControlWeiAmount", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "payable": true, "stateMutability": "payable", "type": "constructor" }, { "constant": true, "inputs": [], "name": "getBeneficiariesCount", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "acc", "type": "address" } ], "name": "getBeneficiaryLimit", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "acc", "type": "address" } ], "name": "getDistributorLimit", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "getProofOfControlWeiAmount", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "key", "type": "string" } ], "name": "hash", "outputs": [ { "name": "", "type": "bytes32" } ], "payable": false, "stateMutability": "pure", "type": "function" }, { "constant": true, "inputs": [ { "name": "add", "type": "address" } ], "name": "isBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "add", "type": "address" } ], "name": "isDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" } ]' -contract_address = "0xBCE634B5cd8ba22A66A5CDedFb1bC56EFFb8a525" +abi = settings.DISTILLERY_ABI +contract_address = settings.DISTILLERY_ADDRESS + +distributor_address = settings.DISTRIBUTOR_ACCOUNT contract = w3.eth.contract(abi=abi, address=contract_address) -w3.eth.defaultAccount = w3.eth.accounts[0] +w3.eth.defaultAccount = w3.eth.accounts[3] + +gasPrice = w3.eth.gasPrice clave = str(uuid1()) -estimate = contract.functions.proveControl(clave).estimateGas() +estimate = (contract.functions.proveControl(clave).estimateGas() + 10000) * gasPrice print("Gas estimado para probar control: {}".format(estimate)) tx_hash = contract.functions.setProofOfControlWeiAmount(estimate).transact() -tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) - -print("\n") -print("Block {0}".format(w3.eth.blockNumber)) -print("Data {0}".format(str(w3.eth.getBlock(w3.eth.blockNumber)))) -print("Funciono: {0}".format(str(contract.functions.getProofOfControlWeiAmount().call()))) \ No newline at end of file +tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) \ No newline at end of file diff --git a/scripts_utiles/cargarDistribuidor.py b/scripts_utiles/cargarDistribuidor.py index 7ff1477..ac20533 100644 --- a/scripts_utiles/cargarDistribuidor.py +++ b/scripts_utiles/cargarDistribuidor.py @@ -9,20 +9,23 @@ You should have received a copy of the GNU General Public License along with thi """ from web3 import Web3 from web3.middleware import geth_poa_middleware +from django.conf import settings -w3 = Web3(Web3.HTTPProvider('http://10.23.10.71:8501')) +w3 = Web3(Web3.HTTPProvider(settings.NODE_URL)) w3.middleware_stack.inject(geth_poa_middleware, layer=0) -abi = '[ { "anonymous": false, "inputs": [ { "indexed": false, "name": "amount", "type": "uint256" } ], "name": "proofOfControlWeiAmountChanged", "type": "event" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "limit", "type": "uint256" } ], "name": "addBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "add", "type": "address" }, { "name": "password", "type": "bytes32" } ], "name": "addSuitor", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "limit", "type": "uint256" } ], "name": "changeLimit", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" } ], "name": "kickBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" } ], "name": "kickDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": true, "name": "ben", "type": "address" }, { "indexed": false, "name": "newLimit", "type": "uint256" } ], "name": "limitChanged", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" } ], "name": "suitorApproved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" } ], "name": "suitorNotApproved", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "kicked", "type": "address" } ], "name": "kickedDistributor", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "suitor", "type": "address" }, { "indexed": true, "name": "distr", "type": "address" } ], "name": "suitorAdded", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": true, "name": "added", "type": "address" }, { "indexed": false, "name": "limit", "type": "uint256" } ], "name": "addedBeneficiary", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": true, "name": "kicked", "type": "address" } ], "name": "kickedBeneficiary", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "added", "type": "address" }, { "indexed": false, "name": "top", "type": "uint256" } ], "name": "addedDistributor", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "distr", "type": "address" }, { "indexed": false, "name": "amount", "type": "uint256" } ], "name": "replenished", "type": "event" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "top", "type": "uint256" } ], "name": "addDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "key", "type": "string" } ], "name": "proveControl", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "constant": false, "inputs": [ { "name": "acc", "type": "address" }, { "name": "amount", "type": "uint256" } ], "name": "replenish", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [], "name": "replenishAll", "outputs": [ { "name": "", "type": "bool" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "accs", "type": "address[]" }, { "name": "amounts", "type": "uint256[]" } ], "name": "replenishList", "outputs": [], "payable": true, "stateMutability": "payable", "type": "function" }, { "constant": false, "inputs": [ { "name": "amount", "type": "uint256" } ], "name": "setProofOfControlWeiAmount", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "payable": true, "stateMutability": "payable", "type": "constructor" }, { "constant": true, "inputs": [], "name": "getBeneficiariesCount", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "acc", "type": "address" } ], "name": "getBeneficiaryLimit", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "acc", "type": "address" } ], "name": "getDistributorLimit", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "getProofOfControlWeiAmount", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "key", "type": "string" } ], "name": "hash", "outputs": [ { "name": "", "type": "bytes32" } ], "payable": false, "stateMutability": "pure", "type": "function" }, { "constant": true, "inputs": [ { "name": "add", "type": "address" } ], "name": "isBeneficiary", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "add", "type": "address" } ], "name": "isDistributor", "outputs": [ { "name": "", "type": "bool" } ], "payable": false, "stateMutability": "view", "type": "function" } ]' -contract_address = "0xBCE634B5cd8ba22A66A5CDedFb1bC56EFFb8a525" +abi = settings.DISTILLERY_ABI +contract_address = settings.DISTILLERY_ADDRESS -distributor_address = "0x25c185DcaeD065BAC30a0a1cd0688A7aA02896d7" # salberchain distributor +distributor_address = settings.DISTRIBUTOR_ACCOUNT contract = w3.eth.contract(abi=abi, address=contract_address) -w3.eth.defaultAccount = w3.eth.accounts[0] +w3.eth.defaultAccount = "PepitaLaPistolera" # TODO Pedir por prompt (es el dueño del contrato -tx_hash = contract.functions.addDistributor(distributor_address, 100000000).transact() +w3.personal.unlockAccount(w3.eth.defaultAccount,"") # TODO Pedir por prompt + +tx_hash = contract.functions.addDistributor(distributor_address, 60000).transact({"gas":900000}) tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) -- GitLab