mirror of https://github.com/nucypher/nucypher.git
Use fine-tuned proxy-contract deployment options; Build-out UserEscrow and proxy deployers.
parent
f7e9a04f94
commit
3ef9527638
|
@ -1,6 +1,7 @@
|
||||||
from constant_sorrow.constants import CONTRACT_NOT_DEPLOYED, NO_DEPLOYER_CONFIGURED
|
from constant_sorrow.constants import CONTRACT_NOT_DEPLOYED, NO_DEPLOYER_CONFIGURED
|
||||||
from eth_utils import is_checksum_address
|
from eth_utils import is_checksum_address
|
||||||
from typing import Tuple, Dict
|
from typing import Tuple, Dict
|
||||||
|
from web3.contract import Contract
|
||||||
|
|
||||||
from nucypher.blockchain.eth import constants
|
from nucypher.blockchain.eth import constants
|
||||||
from nucypher.blockchain.eth.agents import (
|
from nucypher.blockchain.eth.agents import (
|
||||||
|
@ -17,8 +18,11 @@ from .chains import Blockchain
|
||||||
class ContractDeployer:
|
class ContractDeployer:
|
||||||
|
|
||||||
agency = NotImplemented
|
agency = NotImplemented
|
||||||
_interface_class = BlockchainDeployerInterface
|
|
||||||
_contract_name = NotImplemented
|
_contract_name = NotImplemented
|
||||||
|
_interface_class = BlockchainDeployerInterface
|
||||||
|
__is_proxy = False
|
||||||
|
__upgradeable = NotImplemented
|
||||||
|
__proxy_deployer = NotImplemented
|
||||||
|
|
||||||
class ContractDeploymentError(Exception):
|
class ContractDeploymentError(Exception):
|
||||||
pass
|
pass
|
||||||
|
@ -26,23 +30,13 @@ class ContractDeployer:
|
||||||
class ContractNotDeployed(ContractDeploymentError):
|
class ContractNotDeployed(ContractDeploymentError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self, deployer_address: str, blockchain: Blockchain = None) -> None:
|
||||||
deployer_address: str,
|
|
||||||
blockchain: Blockchain = None,
|
|
||||||
) -> None:
|
|
||||||
|
|
||||||
self.__armed = False
|
self.__armed = False
|
||||||
self._contract = CONTRACT_NOT_DEPLOYED
|
self._contract = CONTRACT_NOT_DEPLOYED
|
||||||
self.deployment_receipt = CONTRACT_NOT_DEPLOYED
|
self.deployment_receipt = CONTRACT_NOT_DEPLOYED
|
||||||
self.__proxy_contract = NotImplemented
|
self.__proxy_contract = NotImplemented
|
||||||
self.__deployer_address = deployer_address
|
self.__deployer_address = deployer_address
|
||||||
|
|
||||||
# Sanity check
|
|
||||||
if blockchain is not None:
|
|
||||||
if not isinstance(blockchain, Blockchain):
|
|
||||||
error = 'Only a Blockchain instance can be used to create a deployer; Got {}.'
|
|
||||||
raise ValueError(error.format(type(blockchain)))
|
|
||||||
|
|
||||||
self.blockchain = blockchain or Blockchain.connect()
|
self.blockchain = blockchain or Blockchain.connect()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -147,7 +141,8 @@ class ContractDeployer:
|
||||||
class NucypherTokenDeployer(ContractDeployer):
|
class NucypherTokenDeployer(ContractDeployer):
|
||||||
|
|
||||||
agency = NucypherTokenAgent
|
agency = NucypherTokenAgent
|
||||||
_contract_name = agency.principal_contract_name
|
_contract_name = agency.registry_contract_name
|
||||||
|
__upgradeable = False
|
||||||
|
|
||||||
def __init__(self, deployer_address: str, *args, **kwargs) -> None:
|
def __init__(self, deployer_address: str, *args, **kwargs) -> None:
|
||||||
super().__init__(deployer_address=deployer_address, *args, **kwargs)
|
super().__init__(deployer_address=deployer_address, *args, **kwargs)
|
||||||
|
@ -178,18 +173,17 @@ class DispatcherDeployer(ContractDeployer):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_contract_name = 'Dispatcher'
|
_contract_name = 'Dispatcher'
|
||||||
|
__is_proxy = True
|
||||||
|
__upgradeable = False
|
||||||
|
|
||||||
def __init__(self, target_contract, secret_hash: bytes, *args, **kwargs):
|
def __init__(self, target_contract: Contract, secret_hash: bytes, *args, **kwargs):
|
||||||
self.target_contract = target_contract
|
self.target_contract = target_contract
|
||||||
self.secret_hash = secret_hash
|
self.secret_hash = secret_hash
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def deploy(self) -> dict:
|
def deploy(self) -> dict:
|
||||||
|
args = (self._contract_name, self.target_contract.address, self.secret_hash)
|
||||||
dispatcher_contract, txhash = self.blockchain.interface.deploy_contract(self._contract_name,
|
dispatcher_contract, txhash = self.blockchain.interface.deploy_contract(*args)
|
||||||
self.target_contract.address,
|
|
||||||
self.secret_hash)
|
|
||||||
|
|
||||||
self._contract = dispatcher_contract
|
self._contract = dispatcher_contract
|
||||||
return {'txhash': txhash}
|
return {'txhash': txhash}
|
||||||
|
|
||||||
|
@ -200,7 +194,9 @@ class MinerEscrowDeployer(ContractDeployer):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
agency = MinerAgent
|
agency = MinerAgent
|
||||||
_contract_name = agency.principal_contract_name
|
_contract_name = agency.registry_contract_name
|
||||||
|
__upgradeable = True
|
||||||
|
__proxy_deployer = DispatcherDeployer
|
||||||
|
|
||||||
def __init__(self, token_agent, secret_hash, *args, **kwargs):
|
def __init__(self, token_agent, secret_hash, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
@ -248,7 +244,7 @@ class MinerEscrowDeployer(ContractDeployer):
|
||||||
secret_hash=self.secret_hash)
|
secret_hash=self.secret_hash)
|
||||||
|
|
||||||
dispatcher_deployer.arm()
|
dispatcher_deployer.arm()
|
||||||
dispatcher_deploy_txhash = dispatcher_deployer.deploy()
|
dispatcher_deploy_txhashes = dispatcher_deployer.deploy()
|
||||||
|
|
||||||
# Cache the dispatcher contract
|
# Cache the dispatcher contract
|
||||||
dispatcher_contract = dispatcher_deployer.contract
|
dispatcher_contract = dispatcher_deployer.contract
|
||||||
|
@ -273,7 +269,7 @@ class MinerEscrowDeployer(ContractDeployer):
|
||||||
|
|
||||||
# Gather the transaction hashes
|
# Gather the transaction hashes
|
||||||
deployment_transactions = {'deploy': deploy_txhash,
|
deployment_transactions = {'deploy': deploy_txhash,
|
||||||
'dispatcher_deploy': dispatcher_deploy_txhash,
|
'dispatcher_deploy': dispatcher_deploy_txhashes['txhash'],
|
||||||
'reward_transfer': reward_txhash,
|
'reward_transfer': reward_txhash,
|
||||||
'initialize': init_txhash}
|
'initialize': init_txhash}
|
||||||
|
|
||||||
|
@ -294,7 +290,9 @@ class PolicyManagerDeployer(ContractDeployer):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
agency = PolicyAgent
|
agency = PolicyAgent
|
||||||
_contract_name = agency.principal_contract_name
|
_contract_name = agency.registry_contract_name
|
||||||
|
__upgradeable = True
|
||||||
|
__proxy_deployer = DispatcherDeployer
|
||||||
|
|
||||||
def make_agent(self) -> EthereumContractAgent:
|
def make_agent(self) -> EthereumContractAgent:
|
||||||
agent = self.agency(miner_agent=self.miner_agent, contract=self._contract)
|
agent = self.agency(miner_agent=self.miner_agent, contract=self._contract)
|
||||||
|
@ -310,49 +308,69 @@ class PolicyManagerDeployer(ContractDeployer):
|
||||||
self.check_ready_to_deploy(fail=True, check_arming=True)
|
self.check_ready_to_deploy(fail=True, check_arming=True)
|
||||||
|
|
||||||
# Creator deploys the policy manager
|
# Creator deploys the policy manager
|
||||||
the_policy_manager_contract, deploy_txhash = self.blockchain.interface.deploy_contract(
|
policy_manager_contract, deploy_txhash = self.blockchain.interface.deploy_contract(
|
||||||
self._contract_name, self.miner_agent.contract_address)
|
self._contract_name, self.miner_agent.contract_address)
|
||||||
|
|
||||||
dispatcher_deployer = DispatcherDeployer(blockchain=self.blockchain,
|
proxy_deployer = self.__proxy_deployer(blockchain=self.blockchain,
|
||||||
target_contract=the_policy_manager_contract,
|
target_contract=policy_manager_contract,
|
||||||
deployer_address=self.deployer_address,
|
deployer_address=self.deployer_address,
|
||||||
secret_hash=self.secret_hash)
|
secret_hash=self.secret_hash)
|
||||||
|
|
||||||
dispatcher_deployer.arm()
|
proxy_deployer.arm()
|
||||||
dispatcher_deploy_txhash = dispatcher_deployer.deploy()
|
proxy_deploy_txhashes = proxy_deployer.deploy()
|
||||||
|
|
||||||
# Cache the dispatcher contract
|
# Cache the dispatcher contract
|
||||||
dispatcher_contract = dispatcher_deployer.contract
|
proxy_contract = proxy_deployer.contract
|
||||||
self.__dispatcher_contract = dispatcher_contract
|
self.__proxy_contract = proxy_contract
|
||||||
|
|
||||||
# Wrap the escrow contract
|
# Wrap the escrow contract
|
||||||
wrapped_policy_manager_contract = self.blockchain.interface._wrap_contract(dispatcher_contract,
|
wrapped_policy_manager_contract = self.blockchain.interface. \
|
||||||
target_contract=the_policy_manager_contract)
|
_wrap_contract(proxy_contract, target_contract=policy_manager_contract)
|
||||||
|
|
||||||
# Switch the contract for the wrapped one
|
# Switch the contract for the wrapped one
|
||||||
the_policy_manager_contract = wrapped_policy_manager_contract
|
policy_manager_contract = wrapped_policy_manager_contract
|
||||||
|
|
||||||
# Configure the MinerEscrow by setting the PolicyManager
|
# Configure the MinerEscrow by setting the PolicyManager
|
||||||
policy_setter_txhash = self.miner_agent.contract.functions. \
|
policy_setter_txhash = self.miner_agent.contract.functions.setPolicyManager(policy_manager_contract.address) \
|
||||||
setPolicyManager(the_policy_manager_contract.address).transact({'from': self.deployer_address})
|
.transact({'from': self.deployer_address})
|
||||||
|
|
||||||
self.blockchain.wait_for_receipt(policy_setter_txhash)
|
self.blockchain.wait_for_receipt(policy_setter_txhash)
|
||||||
|
|
||||||
# Gather the transaction hashes
|
# Gather the transaction hashes
|
||||||
deployment_transactions = {'deployment': deploy_txhash,
|
deployment_transactions = {'deployment': deploy_txhash,
|
||||||
'dispatcher_deployment': dispatcher_deploy_txhash,
|
'dispatcher_deployment': proxy_deploy_txhashes['txhash'],
|
||||||
'set_policy_manager': policy_setter_txhash}
|
'set_policy_manager': policy_setter_txhash}
|
||||||
|
|
||||||
self.deployment_transactions = deployment_transactions
|
self.deployment_transactions = deployment_transactions
|
||||||
self._contract = the_policy_manager_contract
|
self._contract = policy_manager_contract
|
||||||
|
|
||||||
return deployment_transactions
|
return deployment_transactions
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
self.secret_hash = secret_hash
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def deploy(self) -> dict:
|
||||||
|
linker_args = (self._contract_name, self.target_contract.address, self.secret_hash)
|
||||||
|
linker_contract, linker_deployment_txhash = self.blockchain.interface.deploy_contract(*linker_args)
|
||||||
|
self._contract = linker_contract
|
||||||
|
return {'txhash': linker_deployment_txhash}
|
||||||
|
|
||||||
|
|
||||||
class UserEscrowProxyDeployer(ContractDeployer):
|
class UserEscrowProxyDeployer(ContractDeployer):
|
||||||
|
|
||||||
_contract_name = 'UserEscrowProxy'
|
_contract_name = 'UserEscrowProxy'
|
||||||
_linker_name = 'UserEscrowLibraryLinker'
|
__is_proxy = True
|
||||||
|
__upgradeable = True
|
||||||
|
__proxy_deployer = LibraryLinkerDeployer
|
||||||
|
|
||||||
def __init__(self, policy_agent: PolicyAgent, secret_hash: bytes, *args, **kwargs):
|
def __init__(self, policy_agent: PolicyAgent, secret_hash: bytes, *args, **kwargs):
|
||||||
self.policy_agent = policy_agent
|
self.policy_agent = policy_agent
|
||||||
|
@ -361,6 +379,9 @@ class UserEscrowProxyDeployer(ContractDeployer):
|
||||||
self.secret_hash = secret_hash
|
self.secret_hash = secret_hash
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def __get_state_contract(self) -> str:
|
||||||
|
return self.contract.functions.getStateContract()
|
||||||
|
|
||||||
def deploy(self) -> dict:
|
def deploy(self) -> dict:
|
||||||
|
|
||||||
deployment_transactions = dict()
|
deployment_transactions = dict()
|
||||||
|
@ -370,69 +391,82 @@ class UserEscrowProxyDeployer(ContractDeployer):
|
||||||
self.token_agent.contract_address,
|
self.token_agent.contract_address,
|
||||||
self.miner_agent.contract_address,
|
self.miner_agent.contract_address,
|
||||||
self.policy_agent.contract_address)
|
self.policy_agent.contract_address)
|
||||||
proxy_contract, proxy_deployment_txhash = self.blockchain.interface.deploy_contract(*proxy_args)
|
user_escrow_proxy_contract, proxy_deployment_txhash = self.blockchain.interface.deploy_contract(*proxy_args)
|
||||||
self.__proxy = proxy_contract
|
self._contract = user_escrow_proxy_contract
|
||||||
|
deployment_transactions['deployment_txhash'] = proxy_deployment_txhash
|
||||||
|
|
||||||
|
# Proxy-Proxy
|
||||||
|
proxy_deployer = self.__proxy_deployer(deployer_address=self.deployer_address,
|
||||||
|
target_contract=user_escrow_proxy_contract,
|
||||||
|
secret_hash=self.secret_hash)
|
||||||
|
proxy_deployer.arm()
|
||||||
|
proxy_deployment_txhashes = proxy_deployer.deploy()
|
||||||
deployment_transactions['proxy_deployment'] = proxy_deployment_txhash
|
deployment_transactions['proxy_deployment'] = proxy_deployment_txhash
|
||||||
|
|
||||||
# Linker
|
|
||||||
linker_args = (self._linker_name, proxy_contract.address, self.secret_hash)
|
|
||||||
linker_contract, linker_deployment_txhash = self.blockchain.interface.deploy_contract(*linker_args)
|
|
||||||
self.__linker = linker_contract
|
|
||||||
deployment_transactions['linker_deployment'] = linker_deployment_txhash
|
|
||||||
return deployment_transactions
|
return deployment_transactions
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_latest_version(cls, blockchain) -> Contract:
|
||||||
|
contract = blockchain.interface.get_contract_by_name(name=cls._contract_name,
|
||||||
|
proxy_name=cls.__proxy_deployer._contract_name)
|
||||||
|
return contract
|
||||||
|
|
||||||
|
|
||||||
class UserEscrowDeployer(ContractDeployer):
|
class UserEscrowDeployer(ContractDeployer):
|
||||||
|
|
||||||
agency = UserEscrowAgent
|
agency = UserEscrowAgent
|
||||||
_contract_name = agency.principal_contract_name
|
_contract_name = agency.registry_contract_name
|
||||||
|
__upgradeable = True
|
||||||
__proxy_name = UserEscrowProxyDeployer._contract_name
|
__proxy_deployer = UserEscrowProxyDeployer
|
||||||
__linker_name = UserEscrowProxyDeployer._linker_name
|
|
||||||
|
|
||||||
def __init__(self,
|
|
||||||
policy_agent: PolicyAgent,
|
|
||||||
*args, **kwargs
|
|
||||||
) -> None:
|
|
||||||
|
|
||||||
|
def __init__(self, policy_agent: PolicyAgent, *args, **kwargs) -> None:
|
||||||
self.policy_agent = policy_agent
|
self.policy_agent = policy_agent
|
||||||
self.miner_agent = policy_agent.miner_agent
|
self.miner_agent = policy_agent.miner_agent
|
||||||
self.token_agent = policy_agent.token_agent
|
self.token_agent = policy_agent.token_agent
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
self.__principal_contract = CONTRACT_NOT_DEPLOYED
|
||||||
|
|
||||||
try:
|
@property
|
||||||
self.__linker_contract = self.blockchain.interface.get_contract_by_name(name=self.__linker_name)
|
def principal_contract(self):
|
||||||
self.__proxy_contract = self.blockchain.interface.get_contract_by_name(name=self.__proxy_name)
|
if self.__principal_contract is CONTRACT_NOT_DEPLOYED:
|
||||||
except self.blockchain.interface.registry.UnknownContract:
|
raise self.ContractDeploymentError("{} not deployed".format(self.__class__.__name__))
|
||||||
self.__linker_contract = CONTRACT_NOT_DEPLOYED
|
return self.__principal_contract
|
||||||
self.__proxy_contract = CONTRACT_NOT_DEPLOYED
|
|
||||||
|
|
||||||
def commit_beneficiary(self, beneficiary_address: str) -> str:
|
def assign_beneficiary(self, beneficiary_address: str) -> str:
|
||||||
if not is_checksum_address(beneficiary_address):
|
if not is_checksum_address(beneficiary_address):
|
||||||
raise self.ContractDeploymentError("{} is not a valid checksum address.".format(beneficiary_address))
|
raise self.ContractDeploymentError("{} is not a valid checksum address.".format(beneficiary_address))
|
||||||
txhash = self.contract.functions.transferOwnership(beneficiary_address).transact({'from': self.deployer_address})
|
txhash = self.contract.functions.transferOwnership(beneficiary_address).transact({'from': self.deployer_address})
|
||||||
self.blockchain.wait_for_receipt(txhash)
|
self.blockchain.wait_for_receipt(txhash)
|
||||||
return txhash
|
return txhash
|
||||||
|
|
||||||
def deploy(self, beneficiary_address: str = None) -> dict:
|
def initial_deposit(self, value: int, duration: int) -> str:
|
||||||
if beneficiary_address:
|
approve_txhash = self.token_agent.approve_transfer(amount=value,
|
||||||
if not is_checksum_address(beneficiary_address):
|
target_address=self.principal_contract.address,
|
||||||
raise self.ContractDeploymentError('{} is not a valid checksum address'.format(beneficiary_address))
|
sender_address=self.deployer_address)
|
||||||
|
|
||||||
|
txhash = self.principal_contract.functions.initialDeposit(value, duration).transact({'from': self.deployer_address})
|
||||||
|
self.blockchain.wait_for_receipt(txhash)
|
||||||
|
return txhash
|
||||||
|
|
||||||
|
def make_agent(self) -> EthereumContractAgent:
|
||||||
|
agent = self.agency(policy_agent=self.policy_agent,
|
||||||
|
contract=self._contract)
|
||||||
|
return agent
|
||||||
|
|
||||||
|
def deploy(self) -> dict:
|
||||||
|
|
||||||
self.check_ready_to_deploy(fail=True, check_arming=True)
|
self.check_ready_to_deploy(fail=True, check_arming=True)
|
||||||
|
|
||||||
deployment_transactions = dict()
|
deployment_transactions = dict()
|
||||||
|
proxy_contract = self.__proxy_deployer.get_latest_version(blockchain=self.blockchain)
|
||||||
|
|
||||||
args = ('UserEscrow', self.__linker_contract.address, self.token_agent.contract_address)
|
args = (self._contract_name, proxy_contract.address, self.token_agent.contract_address)
|
||||||
user_escrow_contract, deploy_txhash = self.blockchain.interface.deploy_contract(*args)
|
user_escrow_contract, deploy_txhash = self.blockchain.interface.deploy_contract(*args)
|
||||||
|
self.__principal_contract = user_escrow_contract
|
||||||
deployment_transactions['deploy_user_escrow'] = deploy_txhash
|
deployment_transactions['deploy_user_escrow'] = deploy_txhash
|
||||||
|
|
||||||
if beneficiary_address:
|
# Wrap the escrow contract
|
||||||
txhash = user_escrow_contract.functions.transferOwnership(beneficiary_address).transact({'from': self.deployer_address})
|
wrapped_user_escrow_contract = self.blockchain.interface._wrap_contract(wrapper_contract=proxy_contract,
|
||||||
deployment_transactions['transfer_ownership'] = txhash
|
|
||||||
|
|
||||||
# Wrap the escrow contract (Govern)
|
|
||||||
wrapped_user_escrow_contract = self.blockchain.interface._wrap_contract(wrapper_contract=self.__proxy_contract,
|
|
||||||
target_contract=user_escrow_contract)
|
target_contract=user_escrow_contract)
|
||||||
|
|
||||||
# Switch the contract for the wrapped one
|
# Switch the contract for the wrapped one
|
||||||
|
@ -440,8 +474,3 @@ class UserEscrowDeployer(ContractDeployer):
|
||||||
self._contract = user_escrow_contract
|
self._contract = user_escrow_contract
|
||||||
|
|
||||||
return deployment_transactions
|
return deployment_transactions
|
||||||
|
|
||||||
def make_agent(self) -> EthereumContractAgent:
|
|
||||||
agent = self.agency(policy_agent=self.policy_agent,
|
|
||||||
contract=self._contract)
|
|
||||||
return agent
|
|
Loading…
Reference in New Issue