Skip to content

Commit

Permalink
Merge pull request #110 from HyperLink-Technology/contracts
Browse files Browse the repository at this point in the history
Updates to network.contract and network.account
  • Loading branch information
iamdefinitelyahuman authored May 7, 2019
2 parents 7c83000 + dc10f1b commit 3fcfa0e
Show file tree
Hide file tree
Showing 15 changed files with 173 additions and 170 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
1.0.0b4
-------

- Add broadcast_reverting_tx flag
- Use py-solc-x 0.4.0
- Detect and attach to an already active RPC client, better verbosity on RPC exceptions
- introduce Singleton metaclass and refactor code to take advantage
Expand Down
18 changes: 12 additions & 6 deletions brownie/_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
_Singleton
)

IGNORE_MISSING = ['active_network', 'folders', 'logging']
REPLACE_IN_UPDATE = ['active_network', 'networks']
IGNORE_IF_MISSING = ['folders', 'logging']


def _load_default_config():
'''Loads the default configuration settings from brownie/data/config.json'''
Expand All @@ -32,6 +34,7 @@ def _load_default_config():
config['logging'] = {"tx": 1, "exc": 1}
return config


def load_project_config():
'''Loads configuration settings from a project's brownie-config.json'''
CONFIG._unlock()
Expand All @@ -45,9 +48,10 @@ def load_project_config():
str(path)
)
print("WARNING: No config file found for this project. A new one has been created.")
CONFIG.setdefault('active_network',{'name': None})
CONFIG.setdefault('active_network', {'name': None})

def modify_network_config(network = None):

def modify_network_config(network=None):
'''Modifies the 'active_network' configuration settings'''
CONFIG._unlock()
try:
Expand All @@ -67,11 +71,13 @@ def modify_network_config(network = None):
# merges project .json with brownie .json
def _recursive_update(original, new, base):
for k in new:
if type(new[k]) is dict and k in original:
if type(new[k]) is dict and k in REPLACE_IN_UPDATE:
original[k] = new[k]
elif type(new[k]) is dict and k in original:
_recursive_update(original[k], new[k], base+[k])
else:
original[k] = new[k]
for k in [i for i in original if i not in new and not set(base+[i]).intersection(IGNORE_MISSING)]:
for k in [i for i in original if i not in new and not set(base+[i]).intersection(IGNORE_IF_MISSING)]:
print(
"WARNING: Value '{}' not found in the config file for this project."
" The default setting has been used.".format(".".join(base+[k]))
Expand All @@ -91,4 +97,4 @@ def _recursive_update(original, new, base):
ARGV['cli'] = sys.argv[1]

# load config
CONFIG = _load_default_config()
CONFIG = _load_default_config()
2 changes: 1 addition & 1 deletion brownie/cli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from brownie.cli.utils import color
import brownie.project as project

__version__ = "1.0.0b3" # did you change this in docs/conf.py as well?
__version__ = "1.0.0b4" # did you change this in docs/conf.py as well?

__doc__ = """Usage: brownie <command> [<args>...] [options <args>]
Expand Down
6 changes: 4 additions & 2 deletions brownie/data/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
"networks": {
"development": {
"test-rpc": "ganache-cli",
"host": "http://127.0.0.1:8545"
"host": "http://127.0.0.1:8545",
"broadcast_reverting_tx": true
},
"ropsten": {
"host": "https://ropsten.infura.io/"
"host": "https://ropsten.infura.io/",
"broadcast_reverting_tx": false
}
},
"test":{
Expand Down
164 changes: 77 additions & 87 deletions brownie/network/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def load(self, filename=None):
Returns:
Account instance.'''
path = Path(CONFIG['folders']['brownie']).joinpath("data/accounts")
if not module:
if not filename:
return [i.stem for i in path.glob('*.json')]
json_file = path.joinpath("{}.json".format(filename))
if not json_file.exists():
Expand Down Expand Up @@ -155,22 +155,68 @@ def __eq__(self, other):
return False
return super().__eq__(other)

def _gas_limit(self, to, amount, data=""):
if type(CONFIG['active_network']['gas_limit']) is int:
return CONFIG['active_network']['gas_limit']
return self.estimate_gas(to, amount, data)

def _gas_price(self):
return CONFIG['active_network']['gas_price'] or web3.eth.gasPrice

def _check_for_revert(self, tx):
if (
'broadcast_reverting_tx' not in CONFIG['active_network'] or
CONFIG['active_network']['broadcast_reverting_tx']
):
return
try:
web3.eth.call(dict((k, v) for k, v in tx.items() if v))
except ValueError as e:
raise VirtualMachineError(e)

def balance(self):
'''Returns the current balance at the address, in wei.'''
return web3.eth.getBalance(self.address)

def deploy(self, contract, *args):
def deploy(self, contract, *args, amount=None, gas_limit=None, gas_price=None, callback=None):
'''Deploys a contract.
Args:
contract: ContractContainer instance.
*args: Constructor arguments. The last argument may optionally be
a dictionary of transaction values.
Kwargs:
amount: Amount of ether to send with transaction, in wei.
gas_limit: Gas limit of the transaction.
gas_price: Gas price of the transaction.
callback: Callback function to attach to TransactionReceipt.
Returns:
* Contract instance if the transaction confirms
* TransactionReceipt if the transaction is pending or reverts'''
return contract.deploy(self, *args)
data = contract.deploy.encode_abi(*args)
try:
txid = self._transact({
'from': self.address,
'value': wei(amount),
'gasPrice': wei(gas_price) or self._gas_price(),
'gas': wei(gas_limit) or self._gas_limit(amount, data),
'data': HexBytes(data)
})
except ValueError as e:
txid = _raise_or_return_tx(e)
self.nonce += 1
tx = TransactionReceipt(
txid,
self,
name=contract._name+".constructor",
callback=callback
)
if tx.status != 1:
return tx
tx.contract_address = contract.at(tx.contract_address, self, tx)
return tx.contract_address

def estimate_gas(self, to, amount, data=""):
'''Estimates the gas cost for a transaction. Raises VirtualMachineError
Expand All @@ -190,64 +236,50 @@ def estimate_gas(self, to, amount, data=""):
'value': wei(amount)
})

def _gas_limit(self, to, amount, data=""):
if type(CONFIG['active_network']['gas_limit']) is int:
return CONFIG['active_network']['gas_limit']
return self.estimate_gas(to, amount, data)

def _gas_price(self):
return CONFIG['active_network']['gas_price'] or web3.eth.gasPrice


class Account(_AccountBase):

'''Class for interacting with an Ethereum account.
Attributes:
address: Public address of the account.
nonce: Current nonce of the account.'''

def _console_repr(self):
return "<Account object '{0[string]}{1}{0}'>".format(color, self.address)

def transfer(self, to, amount, gas_limit=None, gas_price=None, data=""):
'''Broadcasts a transaction from this account.
'''Transfers ether from this account.
Args:
to: Account instance or address string to transfer to.
amount: Amount of ether to send, in wei.
Kwargs:
gas_limit: Gas limit of the transaction.
gas_price: Gas price of the transaction.
data: Transaction data hexstring.
data: Hexstring of data to include in transaction.
Returns:
TransactionReceipt instance'''
TransactionReceipt object'''
try:
txid = web3.eth.sendTransaction({
txid = self._transact({
'from': self.address,
'to': str(to),
'value': wei(amount),
'nonce': self.nonce,
'gasPrice': wei(gas_price) or self._gas_price(),
'gas': wei(gas_limit) or self._gas_limit(to, amount, data),
'to': str(to),
'value': wei(amount),
'data': HexBytes(data)
})
except ValueError as e:
txid = _raise_or_return_tx(e)
self.nonce += 1
return TransactionReceipt(txid, self)

def _contract_tx(self, fn, args, tx, name, callback=None):
tx['from'] = self.address
if type(CONFIG['active_network']['gas_price']) is int:
tx['gasPrice'] = CONFIG['active_network']['gas_price']
if type(CONFIG['active_network']['gas_limit']) is int:
tx['gas'] = CONFIG['active_network']['gas_limit']
try:
txid = fn(*args).transact(tx)
except ValueError as e:
txid = _raise_or_return_tx(e)
self.nonce += 1
return TransactionReceipt(txid, self, name=name, callback=callback)

class Account(_AccountBase):

'''Class for interacting with an Ethereum account.
Attributes:
address: Public address of the account.
nonce: Current nonce of the account.'''

def _console_repr(self):
return "<Account object '{0[string]}{1}{0}'>".format(color, self.address)

def _transact(self, tx):
self._check_for_revert(tx)
return web3.eth.sendTransaction(tx)


class LocalAccount(_AccountBase):
Expand Down Expand Up @@ -282,52 +314,10 @@ def save(self, identifier, overwrite=False):
json.dump(encrypted, json_file.open('w'))
print("Saved to {}".format(json_file))

def transfer(self, to, amount, gas_limit=None, gas_price=None, data=''):
'''Transfers ether from this account.
Args:
to: Account instance or address string to transfer to.
amount: Amount of ether to send, in wei.
gas_limit: Gas limit of the transaction.
gas_price: Gas price of the transaction.
Returns:
TransactionReceipt instance'''
try:
signed_tx = self._acct.signTransaction({
'from': self.address,
'nonce': self.nonce,
'gasPrice': wei(gas_price) or self._gas_price(),
'gas': wei(gas_limit) or self._gas_limit(to, amount, data),
'to': str(to),
'value': wei(amount),
'data': HexBytes(data)
}).rawTransaction
txid = web3.eth.sendRawTransaction(signed_tx)
except ValueError as e:
txid = _raise_or_return_tx(e)
self.nonce += 1
return TransactionReceipt(txid, self)

def _contract_tx(self, fn, args, tx, name, callback=None):
try:
tx.update({
'from': self.address,
'nonce': self.nonce,
'gasPrice': self._gas_price(),
'gas': (
CONFIG['active_network']['gas_limit'] or
fn(*args).estimateGas({'from': self.address})
)
})
raw = fn(*args).buildTransaction(tx)
txid = web3.eth.sendRawTransaction(
self._acct.signTransaction(raw).rawTransaction
)
except ValueError as e:
txid = _raise_or_return_tx(e)
self.nonce += 1
return TransactionReceipt(txid, self, name=name, callback=callback)
def _transact(self, tx):
self._check_for_revert(tx)
signed_tx = self._acct.signTransaction(tx).rawTransaction
return web3.eth.sendRawTransaction(signed_tx)


def _raise_or_return_tx(exc):
Expand Down
Loading

0 comments on commit 3fcfa0e

Please sign in to comment.