mirror of https://github.com/nucypher/nucypher.git
UserEscrow dual-agency and mini-interface
parent
ff0e952595
commit
b6fef220ad
|
@ -2,12 +2,13 @@ import random
|
|||
from abc import ABC
|
||||
from logging import getLogger
|
||||
|
||||
from constant_sorrow.constants import NO_CONTRACT_AVAILABLE, NO_BENEFICIARY
|
||||
from constant_sorrow.constants import NO_CONTRACT_AVAILABLE, NO_BENEFICIARY, CONTRACT_NOT_DEPLOYED
|
||||
from typing import Generator, List, Tuple, Union
|
||||
from web3.contract import Contract
|
||||
|
||||
from nucypher.blockchain.eth import constants
|
||||
from nucypher.blockchain.eth.chains import Blockchain
|
||||
from nucypher.blockchain.eth.registry import AllocationRegistry
|
||||
|
||||
|
||||
class EthereumContractAgent(ABC):
|
||||
|
@ -16,7 +17,7 @@ class EthereumContractAgent(ABC):
|
|||
"""
|
||||
|
||||
registry_contract_name = NotImplemented
|
||||
_upgradeable = NotImplemented
|
||||
_forward_address = True
|
||||
_proxy_name = None
|
||||
|
||||
class ContractNotDeployed(Exception):
|
||||
|
@ -32,7 +33,8 @@ class EthereumContractAgent(ABC):
|
|||
|
||||
if contract is None: # Fetch the contract
|
||||
contract = self.blockchain.interface.get_contract_by_name(name=self.registry_contract_name,
|
||||
proxy_name=self._proxy_name)
|
||||
proxy_name=self._proxy_name,
|
||||
use_proxy_address=self._forward_address)
|
||||
self.__contract = contract
|
||||
super().__init__()
|
||||
self.log.info("Initialized new {} for {} with {} and {}".format(self.__class__.__name__,
|
||||
|
@ -64,7 +66,6 @@ class EthereumContractAgent(ABC):
|
|||
class NucypherTokenAgent(EthereumContractAgent):
|
||||
|
||||
registry_contract_name = "NuCypherToken"
|
||||
_upgradeable = False
|
||||
|
||||
def get_balance(self, address: str=None) -> int:
|
||||
"""Get the balance of a token address, or of this contract address"""
|
||||
|
@ -93,16 +94,11 @@ class NucypherTokenAgent(EthereumContractAgent):
|
|||
class MinerAgent(EthereumContractAgent):
|
||||
|
||||
registry_contract_name = "MinersEscrow"
|
||||
_upgradeable = True
|
||||
_proxy_name = "Dispatcher"
|
||||
|
||||
class NotEnoughMiners(Exception):
|
||||
pass
|
||||
|
||||
def __init__(self, token_agent: NucypherTokenAgent, *args, **kwargs) -> None:
|
||||
super().__init__(blockchain=token_agent.blockchain, *args, **kwargs)
|
||||
self.token_agent = token_agent
|
||||
|
||||
#
|
||||
# Miner Network Status
|
||||
#
|
||||
|
@ -228,14 +224,8 @@ class MinerAgent(EthereumContractAgent):
|
|||
class PolicyAgent(EthereumContractAgent):
|
||||
|
||||
registry_contract_name = "PolicyManager"
|
||||
_upgradeable = True
|
||||
_proxy_name = "Dispatcher"
|
||||
|
||||
def __init__(self, miner_agent: MinerAgent, *args, **kwargs) -> None:
|
||||
super().__init__(blockchain=miner_agent.blockchain, *args, **kwargs)
|
||||
self.miner_agent = miner_agent
|
||||
self.token_agent = miner_agent.token_agent
|
||||
|
||||
def create_policy(self,
|
||||
policy_id: str,
|
||||
author_address: str,
|
||||
|
@ -291,59 +281,132 @@ class PolicyAgent(EthereumContractAgent):
|
|||
return txhash
|
||||
|
||||
|
||||
class UserEscrowAgent(MinerAgent):
|
||||
class UserEscrowAgent(EthereumContractAgent):
|
||||
|
||||
registry_contract_name = "UserEscrow"
|
||||
_upgradeable = True
|
||||
_proxy_name = "UserEscrowProxy"
|
||||
_proxy_name = NotImplemented
|
||||
_forward_address = False
|
||||
__allocation_registry = AllocationRegistry
|
||||
|
||||
class UserEscrowProxyAgent(EthereumContractAgent):
|
||||
registry_contract_name = "UserEscrowProxy"
|
||||
_proxy_name = "UserEscrowLibraryLinker"
|
||||
_forward_address = False
|
||||
|
||||
def _generate_beneficiary_agency(self, principal_address: str):
|
||||
contract = self.blockchain.interface.w3.eth.contract(address=principal_address, abi=self.contract.abi)
|
||||
return contract
|
||||
|
||||
def __init__(self,
|
||||
policy_agent: PolicyAgent,
|
||||
beneficiary: str = None,
|
||||
*args, **kwargs):
|
||||
beneficiary: str,
|
||||
blockchain: Blockchain = None,
|
||||
allocation_registry: AllocationRegistry = None,
|
||||
*args, **kwargs) -> None:
|
||||
|
||||
self.__beneficiary = beneficiary or NO_BENEFICIARY
|
||||
self.policy_agent = policy_agent
|
||||
self.miner_agent = self.policy_agent.miner_agent
|
||||
self.token_agent = self.miner_agent.token_agent
|
||||
super().__init__(token_agent=self.token_agent, *args, **kwargs)
|
||||
self.__read_beneficiary()
|
||||
self.blockchain = blockchain or Blockchain.connect()
|
||||
|
||||
def __read_beneficiary(self) -> None:
|
||||
self.__beneficiary = self.contract.functions.owner.call()
|
||||
self.__allocation_registry = allocation_registry or self.__allocation_registry()
|
||||
self.__beneficiary = beneficiary
|
||||
self.__principal_contract = NO_CONTRACT_AVAILABLE
|
||||
self.__proxy_contract = NO_CONTRACT_AVAILABLE
|
||||
|
||||
# Sets the above
|
||||
self.__read_principal()
|
||||
self.__read_proxy()
|
||||
super().__init__(blockchain=self.blockchain, contract=self.principal_contract, *args, **kwargs)
|
||||
|
||||
self.token_agent = NucypherTokenAgent(blockchain=self.blockchain)
|
||||
|
||||
def __read_proxy(self):
|
||||
self.__proxy_agent = self.UserEscrowProxyAgent(blockchain=self.blockchain)
|
||||
contract = self.__proxy_agent._generate_beneficiary_agency(principal_address=self.principal_contract.address)
|
||||
self.__proxy_contract = contract
|
||||
|
||||
def __fetch_principal_contract(self, contract_address: str = None) -> None:
|
||||
"""Fetch the UserEscrow deployment directly from the AllocationRegistry."""
|
||||
if contract_address is not None:
|
||||
contract_data = self.__allocation_registry.search(contract_address=contract_address)
|
||||
else:
|
||||
contract_data = self.__allocation_registry.search(beneficiary_address=self.beneficiary)
|
||||
address, abi = contract_data
|
||||
principal_contract = self.blockchain.interface.w3.eth.contract(abi=abi,
|
||||
address=address,
|
||||
ContractFactoryClass=Contract)
|
||||
self.__principal_contract = principal_contract
|
||||
|
||||
def __set_owner(self) -> None:
|
||||
owner = self.owner
|
||||
self.__beneficiary = owner
|
||||
|
||||
def __read_principal(self, contract_address: str = None) -> None:
|
||||
self.__fetch_principal_contract(contract_address=contract_address)
|
||||
self.__set_owner()
|
||||
|
||||
@property
|
||||
def owner(self):
|
||||
owner = self.principal_contract.functions.owner().call()
|
||||
return owner
|
||||
|
||||
@property
|
||||
def beneficiary(self):
|
||||
return self.contract.functions.owner().call()
|
||||
return self.__beneficiary
|
||||
|
||||
@property
|
||||
def end_timestamp(self):
|
||||
return self.contract.functions.endLockTimeStamp().call()
|
||||
def proxy_contract(self):
|
||||
"""Directly reference the beneficiary's deployed contract instead of the proxy contracts's interface"""
|
||||
if self.__proxy_contract is NO_CONTRACT_AVAILABLE:
|
||||
raise RuntimeError("{} not available".format(self.registry_contract_name))
|
||||
return self.__proxy_contract
|
||||
|
||||
@property
|
||||
def principal_contract(self):
|
||||
"""Directly reference the beneficiary's deployed contract instead of the proxy contracts's interface"""
|
||||
if self.__principal_contract is NO_CONTRACT_AVAILABLE:
|
||||
raise RuntimeError("{} not available".format(self.registry_contract_name))
|
||||
return self.__principal_contract
|
||||
|
||||
@property
|
||||
def allocation(self):
|
||||
return self.contract.functions.lockedValue().call()
|
||||
return self.principal_contract.functions.lockedValue().call()
|
||||
|
||||
def get_locked_tokens(self) -> int:
|
||||
@property
|
||||
def end_timestamp(self):
|
||||
return self.principal_contract.functions.endLockTimestamp().call()
|
||||
|
||||
@property
|
||||
def locked_tokens(self) -> int:
|
||||
"""Returns the amount of tokens this miner has locked for the beneficiary."""
|
||||
return self.contract.functions.getLockedTokens().call()
|
||||
return self.principal_contract.functions.getLockedTokens().call()
|
||||
|
||||
def lock(self, amount: int, periods: int) -> str:
|
||||
txhash = self.__proxy_contract.functions.lock(amount, periods).transact({'from': self.__beneficiary})
|
||||
self.blockchain.wait_for_receipt(txhash)
|
||||
return txhash
|
||||
|
||||
def deposit_tokens(self, amount: int, sender_address: str):
|
||||
"""Deposit without locking"""
|
||||
txhash = self.token_agent.transfer(amount=amount,
|
||||
sender_address=sender_address,
|
||||
target_address=self.principal_contract.address)
|
||||
self.blockchain.wait_for_receipt(txhash)
|
||||
return txhash
|
||||
|
||||
def withdraw_tokens(self, value: int) -> str:
|
||||
txhash = self.contract.functions.withdrawTokens(value).transact({'from': self.__beneficiary})
|
||||
txhash = self.principal_contract.functions.withdrawTokens(value).transact({'from': self.__beneficiary})
|
||||
self.blockchain.wait_for_receipt(txhash)
|
||||
return txhash
|
||||
|
||||
def withdraw_eth(self) -> str:
|
||||
txhash = self.contract.functions.withdrawETH().transact({'from': self.__beneficiary})
|
||||
txhash = self.principal_contract.functions.withdrawETH().transact({'from': self.__beneficiary})
|
||||
self.blockchain.wait_for_receipt(txhash)
|
||||
return txhash
|
||||
|
||||
def deposit_as_miner(self, value:int, periods: int) -> str:
|
||||
txhash = self.contract.functions.depositAsMiner(value, periods).transact({'from': self.__beneficiary})
|
||||
def deposit_as_miner(self, value: int, periods: int) -> str:
|
||||
txhash = self.__proxy_contract.functions.depositAsMiner(value, periods).transact({'from': self.__beneficiary})
|
||||
self.blockchain.wait_for_receipt(txhash)
|
||||
return txhash
|
||||
|
||||
def withdraw_as_miner(self, value: int) -> str:
|
||||
txhash = self.contract.functions.withdrawAsMiner(value).transact({'from': self.__beneficiary})
|
||||
txhash = self.__proxy_contract.functions.withdrawAsMiner(value).transact({'from': self.__beneficiary})
|
||||
self.blockchain.wait_for_receipt(txhash)
|
||||
return txhash
|
||||
|
|
Loading…
Reference in New Issue