(Almost) Completes UserEscrow Agency Methods

pull/484/head
Kieran R. Prasch 2018-10-25 15:01:04 -07:00 committed by jMyles
parent 46c0e96d81
commit c5c8a6f9cb
5 changed files with 68 additions and 53 deletions

View File

@ -178,19 +178,19 @@ class Deployer(NucypherTokenActor):
self.deploy_miner_contract(secret=miner_secret)
self.deploy_policy_contract(secret=policy_secret)
def deploy_beneficiary_contracts(self, allocations: List[Dict[str, Union[str, int]]]):
def deploy_beneficiary_contracts(self, allocations: List[Dict[str, Union[str, int]]]) -> None:
"""
Example allocation dataset:
Example allocation dataset (one year is 31540000 seconds):
data = [{'address': '0xdeadbeef', 'amount': 100, 'periods': 100},
{'address': '0xabced120', 'amount': 133432, 'periods': 1},
{'address': '0xf7aefec2', 'amount': 999, 'periods': 30}]
data = [{'address': '0xdeadbeef', 'amount': 100, 'duration': 31540000},
{'address': '0xabced120', 'amount': 133432, 'duration': 31540000*2},
{'address': '0xf7aefec2', 'amount': 999, 'duration': 31540000*3}]
"""
for allocation in allocations:
deployer = self.deploy_user_escrow()
deployer.deliver(value=allocation['amount'],
duration=allocation['periods'],
duration=allocation['duration'],
beneficiary_address=allocation['address'])
@staticmethod
@ -330,9 +330,9 @@ class Miner(NucypherTokenActor):
return bool(self.locked_tokens > 0)
@property
def locked_tokens(self, ):
def locked_tokens(self):
"""Returns the amount of tokens this miner has locked."""
return self.miner_agent.get_locked_tokens(node_address=self.checksum_public_address)
return self.miner_agent.get_locked_tokens(miner_address=self.checksum_public_address)
@property
def stakes(self) -> Tuple[list]:

View File

@ -115,9 +115,16 @@ class MinerAgent(EthereumContractAgent):
# MinersEscrow Contract API
#
def get_locked_tokens(self, node_address):
"""Returns the amount of tokens this miner has locked."""
return self.contract.functions.getLockedTokens(node_address).call()
def get_locked_tokens(self, miner_address: str, periods: int = 0) -> int:
"""
Returns the amount of tokens this miner has locked.
TODO: Validate input (periods not less then 0)
"""
return self.contract.functions.getLockedTokens(miner_address, periods).call()
def owned_tokens(self, address: str) -> int:
return self.contract.functions.minerInfo(address).call()[0]
def get_stake_info(self, miner_address: str, stake_index: int):
first_period, *others, locked_value = self.contract.functions.getStakeInfo(miner_address, stake_index).call()
@ -152,7 +159,11 @@ class MinerAgent(EthereumContractAgent):
return txhash
def mint(self, node_address) -> Tuple[str, str]:
"""Computes reward tokens for the miner's account"""
"""
Computes reward tokens for the miner's account;
This is only used to calculate the reward for the final period of a stake,
when you intend to withdraw 100% of tokens.
"""
mint_txhash = self.contract.functions.mint().transact({'from': node_address})
self.blockchain.wait_for_receipt(mint_txhash)
@ -231,12 +242,12 @@ class PolicyAgent(EthereumContractAgent):
author_address: str,
value: int,
periods: int,
reward: int,
initial_reward: int,
node_addresses: List[str]) -> str:
txhash = self.contract.functions.createPolicy(policy_id,
periods,
reward,
initial_reward,
node_addresses).transact({'from': author_address,
'value': value})
self.blockchain.wait_for_receipt(txhash)
@ -315,8 +326,6 @@ class UserEscrowAgent(EthereumContractAgent):
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)
@ -353,7 +362,6 @@ class UserEscrowAgent(EthereumContractAgent):
@property
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
@ -366,31 +374,18 @@ class UserEscrowAgent(EthereumContractAgent):
return self.__principal_contract
@property
def allocation(self):
return self.principal_contract.functions.lockedValue().call()
@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."""
def allocation(self) -> int:
return self.principal_contract.functions.getLockedTokens().call()
@property
def end_timestamp(self) -> int:
return self.principal_contract.functions.endLockTimestamp().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.principal_contract.functions.withdrawTokens(value).transact({'from': self.__beneficiary})
self.blockchain.wait_for_receipt(txhash)
@ -410,3 +405,23 @@ class UserEscrowAgent(EthereumContractAgent):
txhash = self.__proxy_contract.functions.withdrawAsMiner(value).transact({'from': self.__beneficiary})
self.blockchain.wait_for_receipt(txhash)
return txhash
def confirm_activity(self) -> str:
txhash = self.__proxy_contract.functions.confirmActivity().transact({'from': self.__beneficiary})
self.blockchain.wait_for_receipt(txhash)
return txhash
def mint(self) -> str:
txhash = self.__proxy_contract.functions.mint().transact({'from': self.__beneficiary})
self.blockchain.wait_for_receipt(txhash)
return txhash
def collect_policy_reward(self) -> str:
txhash = self.__proxy_contract.functions.withdrawPolicyReward().transact({'from': self.__beneficiary})
self.blockchain.wait_for_receipt(txhash)
return txhash
def set_min_reward_rate(self, rate: int) -> str:
txhash = self.__proxy_contract.functions.setMinRewardRate(rate).transact({'from': self.__beneficiary})
self.blockchain.wait_for_receipt(txhash)
return txhash

View File

@ -1,5 +1,6 @@
"""Nucypher Token and Miner constants."""
ONE_YEAR_IN_SECONDS = 31540000
NUCYPHER_GAS_LIMIT = 5000000 # TODO: move elsewhere?
#

View File

@ -21,7 +21,6 @@ class ContractDeployer:
agency = NotImplemented
_contract_name = NotImplemented
_interface_class = BlockchainDeployerInterface
__is_proxy = False
__upgradeable = NotImplemented
__proxy_deployer = NotImplemented
@ -40,6 +39,7 @@ class ContractDeployer:
self.__armed = False
self.__proxy_contract = NotImplemented
self.__deployer_address = deployer_address
self.__ready_to_deploy = False
@property
def contract_address(self) -> str:
@ -68,7 +68,8 @@ class ContractDeployer:
def is_armed(self) -> bool:
return bool(self.__armed is True)
def check_ready_to_deploy(self, fail=False, check_arming=False) -> Tuple[bool, list]:
@property
def ready_to_deploy(self, fail=False, check_arming=False) -> Tuple[bool, list]:
"""
Iterates through a set of rules required for an ethereum
contract deployer to be eligible for deployment returning a
@ -80,6 +81,9 @@ class ContractDeployer:
If fail is set to True, raise a configuration error, instead of returning.
"""
if self.__ready_to_deploy is True:
return True, list()
rules = [
(self.is_deployed is not True, 'Contract already deployed'),
(self.deployer_address is not None, 'No deployer address set.'),
@ -111,7 +115,7 @@ class ContractDeployer:
return True
def arm(self, abort=True) -> tuple:
def arm(self, abort=True) -> bool:
"""
Safety mechanism for ethereum contract deployment
@ -124,8 +128,8 @@ class ContractDeployer:
"""
if self.__armed is True and abort is True:
raise self.ContractDeploymentError('{} deployer is already armed.'.format(self._contract_name))
self.__armed, disqualifications = self.check_ready_to_deploy(fail=abort, check_arming=False)
return self.__armed, disqualifications
self.__armed, disqualifications = self.ready_to_deploy
return self.__armed
def deploy(self) -> dict:
"""
@ -158,7 +162,7 @@ class NucypherTokenDeployer(ContractDeployer):
The contract must be armed before it can be deployed.
Deployment can only ever be executed exactly once!
"""
self.check_ready_to_deploy(fail=True, check_arming=True)
self.ready_to_deploy
_contract, deployment_txhash = self.blockchain.interface.deploy_contract(
self._contract_name,
@ -175,7 +179,6 @@ class DispatcherDeployer(ContractDeployer):
"""
_contract_name = 'Dispatcher'
__is_proxy = True
__upgradeable = False
def __init__(self, target_contract: Contract, secret_hash: bytes, *args, **kwargs):
@ -228,7 +231,7 @@ class MinerEscrowDeployer(ContractDeployer):
"""
# Raise if not all-systems-go
self.check_ready_to_deploy(fail=True, check_arming=True)
self.ready_to_deploy
# Build deployment arguments
origin_args = {'from': self.deployer_address}
@ -307,7 +310,7 @@ class PolicyManagerDeployer(ContractDeployer):
self.secret_hash = secret_hash
def deploy(self) -> Dict[str, str]:
self.check_ready_to_deploy(fail=True, check_arming=True)
self.ready_to_deploy
# Creator deploys the policy manager
policy_manager_contract, deploy_txhash = self.blockchain.interface.deploy_contract(
@ -352,8 +355,6 @@ class PolicyManagerDeployer(ContractDeployer):
class LibraryLinkerDeployer(ContractDeployer):
_contract_name = 'UserEscrowLibraryLinker'
__is_proxy = True
__upgradeable = False
def __init__(self, target_contract: Contract, secret_hash: bytes, *args, **kwargs):
self.target_contract = target_contract
@ -370,8 +371,6 @@ class LibraryLinkerDeployer(ContractDeployer):
class UserEscrowProxyDeployer(ContractDeployer):
_contract_name = 'UserEscrowProxy'
__is_proxy = True
__upgradeable = True
__proxy_deployer = LibraryLinkerDeployer
def __init__(self, secret_hash: bytes, *args, **kwargs):
@ -418,7 +417,7 @@ class UserEscrowDeployer(ContractDeployer):
agency = UserEscrowAgent
_contract_name = agency.registry_contract_name
__proxy_deployer = UserEscrowProxyDeployer
__linker_deployer = LibraryLinkerDeployer
__allocation_registry = AllocationRegistry
def __init__(self, allocation_registry: AllocationRegistry = None, *args, **kwargs) -> None:
@ -500,12 +499,12 @@ class UserEscrowDeployer(ContractDeployer):
def deploy(self) -> dict:
"""Deploy a new instance of UserEscrow to the blockchain."""
self.check_ready_to_deploy(fail=True, check_arming=True)
self.ready_to_deploy
deployment_transactions = dict()
proxy_contract = self.__proxy_deployer.get_latest_version(blockchain=self.blockchain)
args = (self._contract_name, proxy_contract.address, self.token_agent.contract_address)
linker_contract = self.blockchain.interface.get_contract_by_name(name=self.__linker_deployer._contract_name)
args = (self._contract_name, linker_contract.address, self.token_agent.contract_address)
user_escrow_contract, deploy_txhash = self.blockchain.interface.deploy_contract(*args, enroll=False)
self.__principal_contract = user_escrow_contract
deployment_transactions['deploy_user_escrow'] = deploy_txhash

View File

@ -206,7 +206,7 @@ class BlockchainInterface:
if uri_breakdown.scheme == 'tester':
if uri_breakdown.netloc == 'pyevm':
genesis_params = PyEVMBackend._generate_genesis_params(overrides={'gas_limit': NUCYPHER_GAS_LIMIT})
genesis_params = PyEVMBackend.generate_genesis_params(overrides={'gas_limit': NUCYPHER_GAS_LIMIT})
pyevm_backend = PyEVMBackend(genesis_parameters=genesis_params)
eth_tester = EthereumTester(backend=pyevm_backend, auto_mine_transactions=True)
provider = EthereumTesterProvider(ethereum_tester=eth_tester)