Merge branch 'development' of https://github.com/0xProject/0x-monorepo into feature/what_is_0x_video_embed

This commit is contained in:
fragosti 2019-08-01 13:43:33 -07:00
commit 25ef3b8445
40 changed files with 1152 additions and 904 deletions

View File

@ -11,37 +11,18 @@ from typing import ( # pylint: disable=unused-import
Union,
)
from eth_utils import to_checksum_address
from mypy_extensions import TypedDict # pylint: disable=unused-import
from hexbytes import HexBytes
from web3 import Web3
from web3.contract import ContractFunction
from web3.datastructures import AttributeDict
from web3.providers.base import BaseProvider
from zero_ex.contract_wrappers._base_contract_wrapper import BaseContractWrapper
from zero_ex.contract_wrappers.bases import ContractMethod, Validator
from zero_ex.contract_wrappers.tx_params import TxParams
class {{contractName}}ValidatorBase:
"""Base class for validating inputs to {{contractName}} methods."""
def __init__(
self,
provider: BaseProvider,
contract_address: str,
private_key: str = None,
):
"""Initialize the instance."""
def assert_valid(
self, method_name: str, parameter_name: str, argument_value: Any
):
"""Raise an exception if method input is not valid.
:param method_name: Name of the method whose input is to be validated.
:param parameter_name: Name of the parameter whose input is to be
validated.
:param argument_value: Value of argument to parameter to be validated.
"""
# Try to import a custom validator class definition; if there isn't one,
# declare one that we can instantiate for the default argument to the
# constructor for {{contractName}} below.
@ -53,56 +34,52 @@ try:
)
except ImportError:
class {{contractName}}Validator({{contractName}}ValidatorBase): # type: ignore
class {{contractName}}Validator(Validator): # type: ignore
"""No-op input validator."""
{{tupleDefinitions ABIString}}
{{#each methods}}
{{> method_class contractName=../contractName}}
{{/each}}
# pylint: disable=too-many-public-methods
class {{contractName}}(BaseContractWrapper):
# pylint: disable=too-many-public-methods,too-many-instance-attributes
class {{contractName}}:
"""Wrapper class for {{contractName}} Solidity contract.{{docBytesIfNecessary ABIString}}"""
{{#each methods}}
{{toPythonIdentifier this.name}}: {{toPythonClassname this.name}}Method
{{/each}}
def __init__(
self,
provider: BaseProvider,
contract_address: str,
validator: {{contractName}}Validator = None,
private_key: str = None,
):
"""Get an instance of wrapper for smart contract.
:param provider: instance of :class:`web3.providers.base.BaseProvider`
:param contract_address: where the contract has been deployed
:param private_key: If specified, transactions will be signed locally,
via Web3.py's `eth.account.signTransaction()`:code:, before being
sent via `eth.sendRawTransaction()`:code:.
:param validator: for validation of method inputs.
"""
super().__init__(
provider=provider,
contract_address=contract_address,
private_key=private_key,
)
self.contract_address = contract_address
if not validator:
validator = {{contractName}}Validator(provider, contract_address, private_key)
validator = {{contractName}}Validator(provider, contract_address)
self.validator = validator
self._web3_eth = Web3( # type: ignore # pylint: disable=no-member
provider
).eth
def _get_contract_instance(self, token_address):
"""Get an instance of the smart contract at a specific address.
functions = self._web3_eth.contract(address=to_checksum_address(contract_address), abi={{contractName}}.abi()).functions
:returns: contract object
"""
return self._contract_instance(
address=token_address, abi={{contractName}}.abi()
)
{{#each methods}}
{{> call contractName=../contractName}}
self.{{toPythonIdentifier this.name}} = {{toPythonClassname this.name}}Method(provider, contract_address, functions.{{this.name}}, validator)
{{/each}}
{{#each events}}
{{> event}}
{{> event contractName=../contractName}}
{{/each}}
@staticmethod

View File

@ -1,54 +0,0 @@
def {{this.languageSpecificName}}(
self,
{{> typed_params inputs=inputs}}
tx_params: Optional[TxParams] = None,
{{^this.constant}}
view_only: bool = False,
{{/this.constant}}
) -> {{> return_type outputs=outputs~}}:
"""Execute underlying, same-named contract method.
{{sanitizeDevdocDetails this.name this.devdoc.details 8}}{{~#if this.devdoc.params~}}{{#each this.devdoc.params}}
{{makeParameterDocstringRole @key this 8}}{{/each}}{{/if}}
:param tx_params: transaction parameters
{{#if this.constant~}}
{{#if this.devdoc.return}}
{{makeReturnDocstringRole this.devdoc.return 8}}{{/if}}
{{else}}
:param view_only: whether to use transact() or call()
:returns: if param `view_only`:code: is `True`:code:, then returns the
value returned from the underlying function; else returns the
transaction hash.
{{/if}}
"""
{{#each this.inputs}}
self.validator.assert_valid(
method_name='{{../name}}',
parameter_name='{{name}}',
argument_value={{toPythonIdentifier name}},
)
{{#if (equal type 'address')}}
{{toPythonIdentifier this.name}} = self._validate_and_checksum_address({{toPythonIdentifier this.name}})
{{else if (equal type 'uint256')}}
# safeguard against fractional inputs
{{toPythonIdentifier this.name}} = int({{toPythonIdentifier this.name}})
{{else if (equal type 'bytes')}}
{{toPythonIdentifier this.name}} = bytes.fromhex({{toPythonIdentifier this.name}}.decode("utf-8"))
{{else if (equal type 'bytes[]')}}
{{toPythonIdentifier this.name}} = [
bytes.fromhex({{toPythonIdentifier this.name}}_element.decode("utf-8"))
for {{toPythonIdentifier this.name}}_element in {{toPythonIdentifier this.name}}
]
{{/if}}
{{/each}}
func = self._get_contract_instance(
self.contract_address
).functions.{{this.name}}(
{{> params}}
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only={{#if this.constant}}True{{else}}view_only{{/if}}
)

View File

@ -6,8 +6,4 @@
{{makeEventParameterDocstringRole name 8}}
"""
tx_receipt = self._web3_eth.getTransactionReceipt(tx_hash)
return (
self._get_contract_instance(self.contract_address)
.events.{{name}}()
.processReceipt(tx_receipt)
)
return self._web3_eth.contract(address=to_checksum_address(self.contract_address), abi={{contractName}}.abi()).events.{{name}}().processReceipt(tx_receipt)

View File

@ -0,0 +1,76 @@
class {{toPythonClassname this.name}}Method(ContractMethod):
"""Various interfaces to the {{this.name}} method."""
def __init__(self, provider: BaseProvider, contract_address: str, contract_function: ContractFunction, validator: Validator=None):
"""Persist instance data."""
super().__init__(provider, contract_address, validator)
self.underlying_method = contract_function
{{#if inputs}}
def validate_and_normalize_inputs(self, {{> typed_params inputs=inputs}}):
"""Validate the inputs to the {{this.name}} method."""
{{#each this.inputs}}
self.validator.assert_valid(
method_name='{{../name}}',
parameter_name='{{name}}',
argument_value={{toPythonIdentifier name}},
)
{{#if (equal type 'address')}}
{{toPythonIdentifier this.name}} = self.validate_and_checksum_address({{toPythonIdentifier this.name}})
{{else if (equal type 'uint256')}}
# safeguard against fractional inputs
{{toPythonIdentifier this.name}} = int({{toPythonIdentifier this.name}})
{{else if (equal type 'bytes')}}
{{toPythonIdentifier this.name}} = bytes.fromhex({{toPythonIdentifier this.name}}.decode("utf-8"))
{{else if (equal type 'bytes[]')}}
{{toPythonIdentifier this.name}} = [
bytes.fromhex({{toPythonIdentifier this.name}}_element.decode("utf-8"))
for {{toPythonIdentifier this.name}}_element in {{toPythonIdentifier this.name}}
]
{{/if}}
{{/each}}
return ({{> params }})
{{/if}}
def call(self, {{#if inputs}}{{> typed_params inputs=inputs}}, {{/if}}tx_params: Optional[TxParams] = None) -> {{> return_type outputs=outputs type='call'~}}:
"""Execute underlying contract method via eth_call.
{{sanitizeDevdocDetails this.name this.devdoc.details 8}}{{~#if this.devdoc.params~}}{{#each this.devdoc.params}}
{{makeParameterDocstringRole @key this 8}}{{/each}}{{/if}}
:param tx_params: transaction parameters
{{#if this.constant~}}
{{#if this.devdoc.return}}
{{makeReturnDocstringRole this.devdoc.return 8}}{{/if}}
{{else}}
:returns: the return value of the underlying method.
{{/if}}
"""
{{#if inputs}}
({{> params }}) = self.validate_and_normalize_inputs({{> params}})
{{/if}}
tx_params = super().normalize_tx_params(tx_params)
return self.underlying_method({{> params}}).call(tx_params.as_dict())
def send_transaction(self, {{#if inputs}}{{> typed_params inputs=inputs}}, {{/if}}tx_params: Optional[TxParams] = None) -> Union[HexBytes, bytes]:
"""Execute underlying contract method via eth_sendTransaction.
{{sanitizeDevdocDetails this.name this.devdoc.details 8}}{{~#if this.devdoc.params~}}{{#each this.devdoc.params}}
{{makeParameterDocstringRole @key this 8}}{{/each}}{{/if}}
:param tx_params: transaction parameters
{{#if this.constant~}}
{{#if this.devdoc.return}}
{{makeReturnDocstringRole this.devdoc.return 8}}{{/if}}
{{/if}}
"""
{{#if inputs}}
({{> params }}) = self.validate_and_normalize_inputs({{> params}})
{{/if}}
tx_params = super().normalize_tx_params(tx_params)
return self.underlying_method({{> params}}).transact(tx_params.as_dict())
def estimate_gas(self, {{#if inputs}}{{> typed_params inputs=inputs}}, {{/if}}tx_params: Optional[TxParams] = None) -> int:
"""Estimate gas consumption of method call."""
{{#if inputs}}
({{> params }}) = self.validate_and_normalize_inputs({{> params}})
{{/if}}
tx_params = super().normalize_tx_params(tx_params)
return self.underlying_method({{> params}}).estimateGas(tx_params.as_dict())

View File

@ -1,3 +1,3 @@
{{#each inputs}}
{{toPythonIdentifier name}}{{#if @last}}{{else}},{{/if}}
{{/each}}
{{toPythonIdentifier name}}{{#if @last}}{{else}}, {{/if~}}
{{/each~}}

View File

@ -1,3 +1,3 @@
{{#each inputs}}
{{toPythonIdentifier name}}: {{#parameterType type components}}{{/parameterType}},
{{/each}}
{{toPythonIdentifier name}}: {{#parameterType type components}}{{/parameterType}}{{^if @last}}, {{/if~}}
{{/each~}}

View File

@ -1,12 +1,33 @@
[
{
"timestamp": 1564604963,
"version": "4.0.0",
"changes": [
{
"note": "whitespace changes to generated Python code",
"pr": 1996
},
{
"note": "move Python Validator base class from generated code to common package",
"pr": 1996
},
{
"note": "Changed fundamental thing-to-be-wrapped from the contract to the contract method. That is, now there is a base contract method wrapper class rather than a base contract wrapper class, and individual contract methods are represented by named classes inheriting from that base, and the different operations on a method are now represented by a nested-object dot notation, ie, WrappedContract.ContractMethod.call() and WrappedContract.ContractMethod.send_transaction().",
"pr": 1996
},
{
"note": "added gas estimation functionality to contract methods",
"pr": 1996
}
]
},
{
"version": "3.1.2",
"changes": [
{
"note": "Dependencies updated"
}
]
],
"timestamp": 1564604963
},
{
"version": "3.1.1",

View File

@ -23,6 +23,7 @@
"test_cli:clean": "rm -rf test-cli/output && rm -rf test-cli/test_typescript/lib",
"test_cli:build": "tsc --project test-cli/tsconfig.json",
"test_cli:run_mocha": "mocha --require source-map-support/register --require make-promises-safe test-cli/test_typescript/lib/**/*_test.js --timeout 100000 --bail --exit",
"test_cli:test_python": "black --check test-cli/output/python/**/__init__.py; test $? -le 1 # just make sure black can parse the output",
"rebuild_and_test": "run-s build test",
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",

View File

@ -225,6 +225,10 @@ function registerPythonHelpers(): void {
}
return '';
});
Handlebars.registerHelper(
'toPythonClassname',
(sourceName: string) => new Handlebars.SafeString(changeCase.pascal(sourceName)),
);
}
if (args.language === 'TypeScript') {
registerTypeScriptHelpers();

View File

@ -11,37 +11,18 @@ from typing import ( # pylint: disable=unused-import
Union,
)
from eth_utils import to_checksum_address
from mypy_extensions import TypedDict # pylint: disable=unused-import
from hexbytes import HexBytes
from web3 import Web3
from web3.contract import ContractFunction
from web3.datastructures import AttributeDict
from web3.providers.base import BaseProvider
from zero_ex.contract_wrappers._base_contract_wrapper import BaseContractWrapper
from zero_ex.contract_wrappers.bases import ContractMethod, Validator
from zero_ex.contract_wrappers.tx_params import TxParams
class LibDummyValidatorBase:
"""Base class for validating inputs to LibDummy methods."""
def __init__(
self,
provider: BaseProvider,
contract_address: str,
private_key: str = None,
):
"""Initialize the instance."""
def assert_valid(
self, method_name: str, parameter_name: str, argument_value: Any
):
"""Raise an exception if method input is not valid.
:param method_name: Name of the method whose input is to be validated.
:param parameter_name: Name of the parameter whose input is to be
validated.
:param argument_value: Value of argument to parameter to be validated.
"""
# Try to import a custom validator class definition; if there isn't one,
# declare one that we can instantiate for the default argument to the
# constructor for LibDummy below.
@ -53,15 +34,15 @@ try:
)
except ImportError:
class LibDummyValidator(LibDummyValidatorBase): # type: ignore
class LibDummyValidator(Validator): # type: ignore
"""No-op input validator."""
# pylint: disable=too-many-public-methods
class LibDummy(BaseContractWrapper):
# pylint: disable=too-many-public-methods,too-many-instance-attributes
class LibDummy:
"""Wrapper class for LibDummy Solidity contract."""
def __init__(
@ -69,35 +50,24 @@ class LibDummy(BaseContractWrapper):
provider: BaseProvider,
contract_address: str,
validator: LibDummyValidator = None,
private_key: str = None,
):
"""Get an instance of wrapper for smart contract.
:param provider: instance of :class:`web3.providers.base.BaseProvider`
:param contract_address: where the contract has been deployed
:param private_key: If specified, transactions will be signed locally,
via Web3.py's `eth.account.signTransaction()`:code:, before being
sent via `eth.sendRawTransaction()`:code:.
:param validator: for validation of method inputs.
"""
super().__init__(
provider=provider,
contract_address=contract_address,
private_key=private_key,
)
self.contract_address = contract_address
if not validator:
validator = LibDummyValidator(provider, contract_address, private_key)
validator = LibDummyValidator(provider, contract_address)
self.validator = validator
self._web3_eth = Web3( # type: ignore # pylint: disable=no-member
provider
).eth
def _get_contract_instance(self, token_address):
"""Get an instance of the smart contract at a specific address.
functions = self._web3_eth.contract(address=to_checksum_address(contract_address), abi=LibDummy.abi()).functions
:returns: contract object
"""
return self._contract_instance(
address=token_address, abi=LibDummy.abi()
)
@staticmethod
def abi():

View File

@ -11,37 +11,18 @@ from typing import ( # pylint: disable=unused-import
Union,
)
from eth_utils import to_checksum_address
from mypy_extensions import TypedDict # pylint: disable=unused-import
from hexbytes import HexBytes
from web3 import Web3
from web3.contract import ContractFunction
from web3.datastructures import AttributeDict
from web3.providers.base import BaseProvider
from zero_ex.contract_wrappers._base_contract_wrapper import BaseContractWrapper
from zero_ex.contract_wrappers.bases import ContractMethod, Validator
from zero_ex.contract_wrappers.tx_params import TxParams
class TestLibDummyValidatorBase:
"""Base class for validating inputs to TestLibDummy methods."""
def __init__(
self,
provider: BaseProvider,
contract_address: str,
private_key: str = None,
):
"""Initialize the instance."""
def assert_valid(
self, method_name: str, parameter_name: str, argument_value: Any
):
"""Raise an exception if method input is not valid.
:param method_name: Name of the method whose input is to be validated.
:param parameter_name: Name of the parameter whose input is to be
validated.
:param argument_value: Value of argument to parameter to be validated.
"""
# Try to import a custom validator class definition; if there isn't one,
# declare one that we can instantiate for the default argument to the
# constructor for TestLibDummy below.
@ -53,62 +34,23 @@ try:
)
except ImportError:
class TestLibDummyValidator(TestLibDummyValidatorBase): # type: ignore
class TestLibDummyValidator(Validator): # type: ignore
"""No-op input validator."""
# pylint: disable=too-many-public-methods
class TestLibDummy(BaseContractWrapper):
"""Wrapper class for TestLibDummy Solidity contract."""
class PublicAddConstantMethod(ContractMethod):
"""Various interfaces to the publicAddConstant method."""
def __init__(
self,
provider: BaseProvider,
contract_address: str,
validator: TestLibDummyValidator = None,
private_key: str = None,
):
"""Get an instance of wrapper for smart contract.
def __init__(self, provider: BaseProvider, contract_address: str, contract_function: ContractFunction, validator: Validator=None):
"""Persist instance data."""
super().__init__(provider, contract_address, validator)
self.underlying_method = contract_function
:param provider: instance of :class:`web3.providers.base.BaseProvider`
:param contract_address: where the contract has been deployed
:param private_key: If specified, transactions will be signed locally,
via Web3.py's `eth.account.signTransaction()`:code:, before being
sent via `eth.sendRawTransaction()`:code:.
"""
super().__init__(
provider=provider,
contract_address=contract_address,
private_key=private_key,
)
if not validator:
validator = TestLibDummyValidator(provider, contract_address, private_key)
self.validator = validator
def _get_contract_instance(self, token_address):
"""Get an instance of the smart contract at a specific address.
:returns: contract object
"""
return self._contract_instance(
address=token_address, abi=TestLibDummy.abi()
)
def public_add_constant(
self,
x: int,
tx_params: Optional[TxParams] = None,
) -> int:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
def validate_and_normalize_inputs(self, x: int):
"""Validate the inputs to the publicAddConstant method."""
self.validator.assert_valid(
method_name='publicAddConstant',
parameter_name='x',
@ -116,27 +58,44 @@ class TestLibDummy(BaseContractWrapper):
)
# safeguard against fractional inputs
x = int(x)
func = self._get_contract_instance(
self.contract_address
).functions.publicAddConstant(
x
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
return (x)
def public_add_one(
self,
x: int,
tx_params: Optional[TxParams] = None,
) -> int:
"""Execute underlying, same-named contract method.
def call(self, x: int, tx_params: Optional[TxParams] = None) -> int:
"""Execute underlying contract method via eth_call.
:param tx_params: transaction parameters
"""
(x) = self.validate_and_normalize_inputs(x)
tx_params = super().normalize_tx_params(tx_params)
return self.underlying_method(x).call(tx_params.as_dict())
def send_transaction(self, x: int, tx_params: Optional[TxParams] = None) -> Union[HexBytes, bytes]:
"""Execute underlying contract method via eth_sendTransaction.
:param tx_params: transaction parameters
"""
(x) = self.validate_and_normalize_inputs(x)
tx_params = super().normalize_tx_params(tx_params)
return self.underlying_method(x).transact(tx_params.as_dict())
def estimate_gas(self, x: int, tx_params: Optional[TxParams] = None) -> int:
"""Estimate gas consumption of method call."""
(x) = self.validate_and_normalize_inputs(x)
tx_params = super().normalize_tx_params(tx_params)
return self.underlying_method(x).estimateGas(tx_params.as_dict())
class PublicAddOneMethod(ContractMethod):
"""Various interfaces to the publicAddOne method."""
def __init__(self, provider: BaseProvider, contract_address: str, contract_function: ContractFunction, validator: Validator=None):
"""Persist instance data."""
super().__init__(provider, contract_address, validator)
self.underlying_method = contract_function
def validate_and_normalize_inputs(self, x: int):
"""Validate the inputs to the publicAddOne method."""
self.validator.assert_valid(
method_name='publicAddOne',
parameter_name='x',
@ -144,16 +103,67 @@ class TestLibDummy(BaseContractWrapper):
)
# safeguard against fractional inputs
x = int(x)
func = self._get_contract_instance(
self.contract_address
).functions.publicAddOne(
x
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
return (x)
def call(self, x: int, tx_params: Optional[TxParams] = None) -> int:
"""Execute underlying contract method via eth_call.
:param tx_params: transaction parameters
"""
(x) = self.validate_and_normalize_inputs(x)
tx_params = super().normalize_tx_params(tx_params)
return self.underlying_method(x).call(tx_params.as_dict())
def send_transaction(self, x: int, tx_params: Optional[TxParams] = None) -> Union[HexBytes, bytes]:
"""Execute underlying contract method via eth_sendTransaction.
:param tx_params: transaction parameters
"""
(x) = self.validate_and_normalize_inputs(x)
tx_params = super().normalize_tx_params(tx_params)
return self.underlying_method(x).transact(tx_params.as_dict())
def estimate_gas(self, x: int, tx_params: Optional[TxParams] = None) -> int:
"""Estimate gas consumption of method call."""
(x) = self.validate_and_normalize_inputs(x)
tx_params = super().normalize_tx_params(tx_params)
return self.underlying_method(x).estimateGas(tx_params.as_dict())
# pylint: disable=too-many-public-methods,too-many-instance-attributes
class TestLibDummy:
"""Wrapper class for TestLibDummy Solidity contract."""
public_add_constant: PublicAddConstantMethod
public_add_one: PublicAddOneMethod
def __init__(
self,
provider: BaseProvider,
contract_address: str,
validator: TestLibDummyValidator = None,
):
"""Get an instance of wrapper for smart contract.
:param provider: instance of :class:`web3.providers.base.BaseProvider`
:param contract_address: where the contract has been deployed
:param validator: for validation of method inputs.
"""
self.contract_address = contract_address
if not validator:
validator = TestLibDummyValidator(provider, contract_address)
self._web3_eth = Web3( # type: ignore # pylint: disable=no-member
provider
).eth
functions = self._web3_eth.contract(address=to_checksum_address(contract_address), abi=TestLibDummy.abi()).functions
self.public_add_constant = PublicAddConstantMethod(provider, contract_address, functions.publicAddConstant, validator)
self.public_add_one = PublicAddOneMethod(provider, contract_address, functions.publicAddOne, validator)
@staticmethod
def abi():

View File

@ -44,14 +44,14 @@
"homepage": "https://github.com/0xProject/0x-monorepo/packages/instant/README.md",
"dependencies": {
"@0x/assert": "^2.1.0",
"@0x/asset-buyer": "6.1.4",
"@0x/asset-buyer": "6.1.8",
"@0x/json-schemas": "^3.0.11",
"@0x/order-utils": "^8.2.2",
"@0x/subproviders": "^4.1.2",
"@0x/subproviders": "^5.0.0",
"@0x/types": "^2.4.1",
"@0x/typescript-typings": "^4.2.3",
"@0x/utils": "^4.4.1",
"@0x/web3-wrapper": "^6.0.8",
"@0x/typescript-typings": "^4.2.4",
"@0x/utils": "^4.4.2",
"@0x/web3-wrapper": "^6.0.9",
"babel-runtime": "^6.26.0",
"bowser": "^1.9.4",
"copy-to-clipboard": "^3.0.8",

View File

@ -49,7 +49,7 @@
},
"dependencies": {
"@0x/types": "^2.4.1",
"@0x/utils": "^4.4.1",
"@0x/utils": "^4.4.2",
"@lerna/batch-packages": "^3.0.0-beta.18",
"@types/depcheck": "^0.6.0",
"async-child-process": "^1.1.1",

View File

@ -25,7 +25,7 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/python-contract-wrappers/README.md",
"devDependencies": {
"@0x/abi-gen": "^3.1.1",
"@0x/abi-gen": "^3.1.2",
"shx": "^0.2.2"
},
"publishConfig": {

View File

@ -20,10 +20,10 @@
"license": "Apache-2.0",
"dependencies": {
"0x.js": "^6.0.12",
"@0x/subproviders": "^4.1.2",
"@0x/subproviders": "^5.0.0",
"@0x/typescript-typings": "^4.2.4",
"@0x/utils": "^4.4.1",
"@0x/web3-wrapper": "^6.0.8",
"@0x/utils": "^4.4.2",
"@0x/web3-wrapper": "^6.0.9",
"body-parser": "^1.17.1",
"ethereum-types": "^2.1.4",
"ethereumjs-tx": "^1.3.5",

View File

@ -26,11 +26,11 @@
"@0x/contract-wrappers": "^9.1.7",
"@0x/json-schemas": "^3.0.11",
"@0x/order-utils": "^8.2.2",
"@0x/subproviders": "^4.1.2",
"@0x/subproviders": "^5.0.0",
"@0x/types": "^2.4.1",
"@0x/typescript-typings": "^4.2.4",
"@0x/utils": "^4.4.1",
"@0x/web3-wrapper": "^6.0.8",
"@0x/utils": "^4.4.2",
"@0x/web3-wrapper": "^6.0.9",
"@reach/dialog": "^0.1.2",
"@types/react-lazyload": "^2.3.1",
"@types/react-loadable": "^5.4.2",

View File

@ -109,7 +109,8 @@ class TestCommandExtension(TestCommand):
"""Invoke pytest."""
import pytest
exit(pytest.main(["--doctest-modules"]))
exit(pytest.main(["--doctest-modules", "-rapP"]))
# show short test summary at end ^
with open("README.md", "r") as file_handle:

View File

@ -138,7 +138,8 @@ class TestCommandExtension(TestCommand):
"""Invoke pytest."""
import pytest
exit(pytest.main(["--doctest-modules"]))
exit(pytest.main(["--doctest-modules", "-rapP"]))
# show short test summary at end ^
with open("README.md", "r") as file_handle:

View File

@ -0,0 +1,5 @@
[pycodestyle]
ignore = E501, W503
# E501 = line too long
# W503 = line break occurred before a binary operator
# we let black handle these things

View File

@ -74,7 +74,8 @@ class TestCommandExtension(TestCommand):
"""Invoke pytest."""
import pytest
exit(pytest.main(["--doctest-modules"]))
exit(pytest.main(["--doctest-modules", "-rapP"]))
# show short test summary at end ^
class LintCommand(distutils.command.build_py.build_py):

View File

@ -102,13 +102,13 @@ balance:
>>> erc20_proxy_addr = NETWORK_TO_ADDRESSES[NetworkId.GANACHE].erc20_proxy
>>> tx = zrx_token.approve(
>>> tx = zrx_token.approve.send_transaction(
... erc20_proxy_addr,
... to_wei(100, 'ether'),
... tx_params=TxParams(from_=maker_address),
... )
>>> tx = weth_token.approve(
>>> tx = weth_token.approve.send_transaction(
... erc20_proxy_addr,
... to_wei(100, 'ether'),
... tx_params=TxParams(from_=taker_address),
@ -166,7 +166,7 @@ too.
... provider=ganache,
... contract_address=NETWORK_TO_ADDRESSES[NetworkId.GANACHE].exchange,
... )
>>> tx_hash = exchange.fill_order(
>>> tx_hash = exchange.fill_order.send_transaction(
... order=order,
... taker_asset_fill_amount=order["takerAssetAmount"],
... signature=maker_signature,
@ -217,7 +217,7 @@ A Maker can cancel an order that has yet to be filled.
... )
... )
>>> tx_hash = exchange.cancel_order(
>>> tx_hash = exchange.cancel_order.send_transaction(
... order=order, tx_params=TxParams(from_=maker_address)
... )
@ -287,12 +287,40 @@ is an example where the taker fills two orders in one transaction:
Fill order_1 and order_2 together:
>>> exchange.batch_fill_orders(
>>> exchange.batch_fill_orders.send_transaction(
... orders=[order_1, order_2],
... taker_asset_fill_amounts=[1, 2],
... signatures=[signature_1, signature_2],
... tx_params=TxParams(from_=taker_address))
HexBytes('0x...')
Estimating gas consumption
--------------------------
Before executing a transaction, you may want to get an estimate of how much gas
will be consumed.
>>> exchange.cancel_order.estimate_gas(
... order=Order(
... makerAddress=maker_address,
... takerAddress='0x0000000000000000000000000000000000000000',
... exchangeAddress=exchange_address,
... senderAddress='0x0000000000000000000000000000000000000000',
... feeRecipientAddress='0x0000000000000000000000000000000000000000',
... makerAssetData=asset_data_utils.encode_erc20(weth_address),
... takerAssetData=asset_data_utils.encode_erc20(weth_address),
... salt=random.randint(1, 100000000000000000),
... makerFee=0,
... takerFee=0,
... makerAssetAmount=1000000000000000000,
... takerAssetAmount=500000000000000000000,
... expirationTimeSeconds=round(
... (datetime.utcnow() + timedelta(days=1)).timestamp()
... )
... ),
... tx_params=TxParams(from_=maker_address),
... )
73825
"""
from .tx_params import TxParams

View File

@ -1,136 +0,0 @@
"""Base wrapper class for accessing ethereum smart contracts."""
from typing import Optional, Union
from eth_utils import to_checksum_address
from web3 import Web3
from web3.providers.base import BaseProvider
from .tx_params import TxParams
class BaseContractWrapper:
"""Base class for wrapping ethereum smart contracts.
It provides functionality for instantiating a contract instance,
calling view functions, and calling functions which require
transactions.
"""
def __init__(
self,
provider: BaseProvider,
contract_address: str,
private_key: str = None,
):
"""Create an instance of BaseContractWrapper.
:param provider: instance of :class:`web3.providers.base.BaseProvider`
:param private_key: If specified, transactions will be signed locally,
via Web3.py's `eth.account.signTransaction()`:code:, before being
sent via `eth.sendRawTransaction()`:code:.
"""
self._provider = provider
self._private_key = private_key
self._web3 = Web3(provider)
self._web3_eth = self._web3.eth # pylint: disable=no-member
self.contract_address = self._validate_and_checksum_address(
contract_address
)
self._can_send_tx = False
if self._web3_eth.defaultAccount or self._web3_eth.accounts:
self._can_send_tx = True
else:
middleware_stack = getattr(self._web3, "middleware_stack")
if middleware_stack.get("sign_and_send_raw_middleware"):
self._can_send_tx = True
elif private_key:
self._private_key = private_key
self._web3_eth.defaultAccount = to_checksum_address(
self._web3_eth.account.privateKeyToAccount(
private_key
).address
)
self._can_send_tx = True
def _contract_instance(self, address: str, abi: dict):
"""Get a contract instance.
:param address: string address of contract
:param abi: dict contract ABI
:returns: instance of contract
"""
return self._web3_eth.contract(
address=to_checksum_address(address), abi=abi
)
def _validate_and_checksum_address(self, address: str):
if not self._web3.isAddress(address):
raise TypeError("Invalid address provided: {}".format(address))
return to_checksum_address(address)
def _invoke_function_call(self, func, tx_params, view_only):
if view_only:
return func.call()
if not self._can_send_tx:
raise Exception(
"Cannot send transaction because no local private_key"
" or account found."
)
if not tx_params:
tx_params = TxParams()
if not tx_params.from_:
tx_params.from_ = (
self._web3_eth.defaultAccount or self._web3_eth.accounts[0]
)
tx_params.from_ = self._validate_and_checksum_address(tx_params.from_)
if self._private_key:
res = self._sign_and_send_raw_direct(func, tx_params)
else:
res = func.transact(tx_params.as_dict())
return res
def _sign_and_send_raw_direct(self, func, tx_params):
transaction = func.buildTransaction(tx_params.as_dict())
signed_tx = self._web3_eth.account.signTransaction(
transaction, private_key=self._private_key
)
return self._web3_eth.sendRawTransaction(signed_tx.rawTransaction)
# pylint: disable=too-many-arguments
def execute_method(
self,
abi: dict,
method: str,
args: Optional[Union[list, tuple]] = None,
tx_params: Optional[TxParams] = None,
view_only: bool = False,
) -> str:
"""Execute the method on a contract instance.
:param abi: dict of contract ABI
:param method: string name of method to call
:param args: default None, list or tuple of arguments for the method
:param tx_params: default None, :class:`TxParams` transaction params
:param view_only: default False, boolean of whether the transaction
should only be validated.
:returns: str of transaction hash
"""
contract_instance = self._contract_instance(
address=self.contract_address, abi=abi
)
if args is None:
args = []
if hasattr(contract_instance.functions, method):
func = getattr(contract_instance.functions, method)(*args)
return self._invoke_function_call(
func=func, tx_params=tx_params, view_only=view_only
)
raise Exception(
"No method {} found on contract {}.".format(
self.contract_address, method
)
)

View File

@ -0,0 +1,66 @@
"""Base wrapper class for accessing ethereum smart contracts."""
from typing import Any
from eth_utils import is_address, to_checksum_address
from web3 import Web3
from web3.providers.base import BaseProvider
from .tx_params import TxParams
class Validator:
"""Base class for validating inputs to methods."""
def __init__(self, provider: BaseProvider, contract_address: str):
"""Initialize the instance."""
def assert_valid(
self, method_name: str, parameter_name: str, argument_value: Any
):
"""Raise an exception if method input is not valid.
:param method_name: Name of the method whose input is to be validated.
:param parameter_name: Name of the parameter whose input is to be
validated.
:param argument_value: Value of argument to parameter to be validated.
"""
class ContractMethod:
"""Base class for wrapping an Ethereum smart contract method."""
def __init__(
self,
provider: BaseProvider,
contract_address: str,
validator: Validator = None,
):
"""Instantiate the object.
:param provider: Instance of :class:`web3.providers.base.BaseProvider`
:param contract_address: Where the contract has been deployed to.
:param validator: Used to validate method inputs.
"""
self._web3_eth = Web3(provider).eth # pylint: disable=no-member
if validator is None:
validator = Validator(provider, contract_address)
self.validator = validator
@staticmethod
def validate_and_checksum_address(address: str):
"""Validate the given address, and return it's checksum address."""
if not is_address(address):
raise TypeError("Invalid address provided: {}".format(address))
return to_checksum_address(address)
def normalize_tx_params(self, tx_params) -> TxParams:
"""Normalize and return the given transaction parameters."""
if not tx_params:
tx_params = TxParams()
if not tx_params.from_:
tx_params.from_ = (
self._web3_eth.defaultAccount or self._web3_eth.accounts[0]
)
tx_params.from_ = self.validate_and_checksum_address(tx_params.from_)
return tx_params

View File

@ -6,21 +6,16 @@ from web3.providers.base import BaseProvider
from zero_ex import json_schemas
from . import ExchangeValidatorBase
from ..bases import Validator
from .types import order_to_jsdict
class ExchangeValidator(ExchangeValidatorBase):
class ExchangeValidator(Validator):
"""Validate inputs to Exchange methods."""
def __init__(
self,
provider: BaseProvider,
contract_address: str,
private_key: str = None,
):
def __init__(self, provider: BaseProvider, contract_address: str):
"""Initialize the class."""
super().__init__(provider, contract_address, private_key)
super().__init__(provider, contract_address)
self.contract_address = contract_address
def assert_valid(

View File

@ -1,3 +1,7 @@
from typing import Union
def to_checksum_address(address: str) -> str: ...
def remove_0x_prefix(hex_string: str) -> str: ...
def is_address(address: Union[str, bytes]) -> bool: ...

View File

@ -0,0 +1,5 @@
class ContractFunction:
def __call__(self, *args, **kwargs):
...
...

View File

@ -1,3 +1,10 @@
from typing import Any
class Contract:
def call(self): ...
functions: Any
events: Any
...

View File

@ -0,0 +1,15 @@
"""Tests for :class:`ContractMethod`."""
import pytest
from zero_ex.contract_addresses import NETWORK_TO_ADDRESSES, NetworkId
from zero_ex.contract_wrappers.bases import ContractMethod
@pytest.fixture(scope="module")
def contract_wrapper(ganache_provider):
"""Get a ContractMethod instance for testing."""
return ContractMethod(
provider=ganache_provider,
contract_address=NETWORK_TO_ADDRESSES[NetworkId.GANACHE].ether_token,
)

View File

@ -1,48 +0,0 @@
"""Tests for :class:`BaseContractWrapper`."""
import pytest
from eth_utils import to_checksum_address
from zero_ex.contract_addresses import NETWORK_TO_ADDRESSES, NetworkId
from zero_ex.contract_artifacts import abi_by_name
from zero_ex.contract_wrappers._base_contract_wrapper import (
BaseContractWrapper,
)
@pytest.fixture(scope="module")
def contract_wrapper(ganache_provider):
"""Get a BaseContractWrapper instance for testing."""
return BaseContractWrapper(
provider=ganache_provider,
contract_address=NETWORK_TO_ADDRESSES[NetworkId.GANACHE].ether_token,
)
def test_contract_wrapper__execute_method(
accounts,
contract_wrapper, # pylint: disable=redefined-outer-name
erc20_proxy_address,
):
"""Test :function:`BaseContractWrapper.execute` method."""
acc1_allowance = contract_wrapper.execute_method(
abi=abi_by_name("WETH9"),
method="allowance",
view_only=True,
args=(
to_checksum_address(accounts[3]),
to_checksum_address(erc20_proxy_address),
),
)
assert acc1_allowance == 0
with pytest.raises(Exception):
contract_wrapper.execute_method(
abi=abi_by_name("WETH9"),
method="send",
view_only=True,
args=[
to_checksum_address(accounts[3]),
to_checksum_address(erc20_proxy_address),
],
)

View File

@ -25,8 +25,8 @@ def test_erc20_wrapper__balance_of(
weth_instance, # pylint: disable=redefined-outer-name
):
"""Test getting baance of an account for an ERC20 token."""
acc1_original_weth_balance = erc20_wrapper.balance_of(accounts[0])
acc2_original_weth_balance = erc20_wrapper.balance_of(accounts[1])
acc1_original_weth_balance = erc20_wrapper.balance_of.call(accounts[0])
acc2_original_weth_balance = erc20_wrapper.balance_of.call(accounts[1])
expected_difference = 1 * 10 ** 18
@ -36,8 +36,8 @@ def test_erc20_wrapper__balance_of(
weth_instance.functions.deposit().transact(
{"from": accounts[1], "value": expected_difference}
)
acc1_weth_balance = erc20_wrapper.balance_of(accounts[0])
acc2_weth_balance = erc20_wrapper.balance_of(accounts[1])
acc1_weth_balance = erc20_wrapper.balance_of.call(accounts[0])
acc2_weth_balance = erc20_wrapper.balance_of.call(accounts[1])
assert (
acc1_weth_balance - acc1_original_weth_balance == expected_difference
@ -53,21 +53,21 @@ def test_erc20_wrapper__approve(
erc20_wrapper, # pylint: disable=redefined-outer-name
):
"""Test approving one account to spend balance from another account."""
erc20_wrapper.approve(
erc20_wrapper.approve.send_transaction(
erc20_proxy_address,
MAX_ALLOWANCE,
tx_params=TxParams(from_=accounts[0]),
)
erc20_wrapper.approve(
erc20_wrapper.approve.send_transaction(
erc20_proxy_address,
MAX_ALLOWANCE,
tx_params=TxParams(from_=accounts[1]),
)
acc_1_weth_allowance = erc20_wrapper.allowance(
acc_1_weth_allowance = erc20_wrapper.allowance.call(
accounts[0], erc20_proxy_address
)
acc_2_weth_allowance = erc20_wrapper.allowance(
acc_2_weth_allowance = erc20_wrapper.allowance.call(
accounts[1], erc20_proxy_address
)

View File

@ -77,7 +77,7 @@ def test_exchange_wrapper__fill_order(
)
order_signature = sign_hash_to_bytes(ganache_provider, maker, order_hash)
tx_hash = exchange_wrapper.fill_order(
tx_hash = exchange_wrapper.fill_order.send_transaction(
order=order,
taker_asset_fill_amount=order["takerAssetAmount"],
signature=order_signature,
@ -114,7 +114,7 @@ def test_exchange_wrapper__batch_fill_orders(
for order_hash in order_hashes
]
taker_amounts = [order["takerAssetAmount"] for order in orders]
tx_hash = exchange_wrapper.batch_fill_orders(
tx_hash = exchange_wrapper.batch_fill_orders.send_transaction(
orders=orders,
taker_asset_fill_amounts=taker_amounts,
signatures=order_signatures,

View File

@ -40,7 +40,8 @@ class TestCommandExtension(TestCommand):
"""Invoke pytest."""
import pytest
exit(pytest.main(["--doctest-modules"]))
exit(pytest.main(["--doctest-modules", "-rapP"]))
# show short test summary at end ^
class LintCommand(distutils.command.build_py.build_py):

View File

@ -20,7 +20,8 @@ class TestCommandExtension(TestCommand):
"""Invoke pytest."""
import pytest
exit(pytest.main(["--doctest-modules"]))
exit(pytest.main(["--doctest-modules", "-rapP"]))
# show short test summary at end ^
class LintCommand(distutils.command.build_py.build_py):

View File

@ -21,7 +21,8 @@ class TestCommandExtension(TestCommand):
"""Invoke pytest."""
import pytest
exit(pytest.main(["--doctest-modules"]))
exit(pytest.main(["--doctest-modules", "-rapP"]))
# show short test summary at end ^
class LintCommand(distutils.command.build_py.build_py):

View File

@ -20,9 +20,9 @@ $ ./parallel pip uninstall $(basename $(pwd))
>>>"""
from concurrent.futures import ProcessPoolExecutor
from concurrent.futures import ProcessPoolExecutor, wait
from os import chdir
from subprocess import check_call
from subprocess import CalledProcessError, check_output
from sys import argv
PACKAGES = [
@ -38,7 +38,18 @@ PACKAGES = [
def run_cmd_on_package(package: str):
"""cd to the package dir, ./setup.py lint, cd .."""
chdir(package)
check_call(f"{' '.join(argv[1:])}".split())
try:
check_output(f"{' '.join(argv[1:])}".split())
except CalledProcessError as error:
print(f"standard output from command:\n{error.output.decode('utf-8')}")
raise RuntimeError(f"Above exception raised in {package}, ") from error
finally:
chdir("..")
ProcessPoolExecutor().map(run_cmd_on_package, PACKAGES)
with ProcessPoolExecutor() as executor:
for future in executor.map(run_cmd_on_package, PACKAGES):
# iterate over map()'s return value, to resolve the futures.
# but we don't actually care what the return values are, so just `pass`.
# if any exceptions were raised by the underlying task, they'll be
# raised as the iteration encounters them.
pass

View File

@ -33,7 +33,8 @@ class TestCommandExtension(TestCommand):
"""Invoke pytest."""
import pytest
exit(pytest.main(["--doctest-modules"]))
exit(pytest.main(["--doctest-modules", "-rapP"]))
# show short test summary at end ^
class TestPublishCommand(distutils.command.build_py.build_py):

View File

@ -319,7 +319,7 @@ book. Now let's have the taker fill it:
... provider=eth_node,
... contract_address=NETWORK_TO_ADDRESSES[NetworkId.GANACHE].exchange
... )
>>> exchange.fill_order(
>>> exchange.fill_order.send_transaction(
... order=order,
... taker_asset_fill_amount=order['makerAssetAmount']/2, # note the half fill
... signature=order['signature'].replace('0x', '').encode('utf-8'),
@ -333,7 +333,7 @@ Cancelling
Note that the above fill was partial: it only filled half of the order. Now
we'll have our maker cancel the remaining order:
>>> exchange.cancel_order(
>>> exchange.cancel_order.send_transaction(
... order=order,
... tx_params=TxParams(from_=maker_address)
... )

View File

@ -655,21 +655,22 @@
dependencies:
"@0x/base-contract" "^5.1.0"
"@0x/asset-buyer@6.1.4":
version "6.1.4"
resolved "https://registry.yarnpkg.com/@0x/asset-buyer/-/asset-buyer-6.1.4.tgz#ea863b860fbae6f633846bdcf23cacbb345aefd1"
"@0x/asset-buyer@6.1.8":
version "6.1.8"
resolved "https://registry.yarnpkg.com/@0x/asset-buyer/-/asset-buyer-6.1.8.tgz#71f6abb366e89e62457c256644edb37e12113e94"
integrity sha512-JOMu38EsQexDVyzOGYJamlLDigVoGOBNHAVYIkPn4r3SLY75Shcxlb9AhUfKEMDPv3kjk70r0Iy1DmIh4HBjdA==
dependencies:
"@0x/assert" "^2.0.10"
"@0x/connect" "^5.0.9"
"@0x/contract-wrappers" "^9.1.3"
"@0x/json-schemas" "^3.0.10"
"@0x/order-utils" "^8.1.0"
"@0x/subproviders" "^4.0.6"
"@0x/types" "^2.2.2"
"@0x/typescript-typings" "^4.2.2"
"@0x/utils" "^4.3.3"
"@0x/web3-wrapper" "^6.0.6"
ethereum-types "^2.1.2"
"@0x/assert" "^2.1.0"
"@0x/connect" "^5.0.13"
"@0x/contract-wrappers" "^9.1.7"
"@0x/json-schemas" "^3.0.11"
"@0x/order-utils" "^8.2.2"
"@0x/subproviders" "^4.1.1"
"@0x/types" "^2.4.0"
"@0x/typescript-typings" "^4.2.3"
"@0x/utils" "^4.4.0"
"@0x/web3-wrapper" "^6.0.7"
ethereum-types "^2.1.3"
lodash "^4.17.11"
"@0x/base-contract@^4.0.1", "@0x/base-contract@^4.0.3":
@ -716,7 +717,7 @@
lodash "^4.17.11"
uuid "^3.3.2"
"@0x/contract-wrappers@^9.1.3", "@0x/contract-wrappers@^9.1.7":
"@0x/contract-wrappers@^9.1.7":
version "9.1.8"
resolved "https://registry.yarnpkg.com/@0x/contract-wrappers/-/contract-wrappers-9.1.8.tgz#5923d35af3e4b442a57d02f74e02620b2d5b1356"
integrity sha512-+qx0lwDAuTitP8sXA4bxRS+W81i5TaXWziD/Fcraj40XGeuHFnRXVY5FEl9V7TC0sEDyvnnF2VFc5Y+v2CnYVQ==
@ -829,7 +830,7 @@
ethers "~4.0.4"
lodash "^4.17.11"
"@0x/subproviders@^4.0.4", "@0x/subproviders@^4.0.6", "@0x/subproviders@^4.1.2":
"@0x/subproviders@^4.0.4", "@0x/subproviders@^4.1.1":
version "4.1.2"
resolved "https://registry.yarnpkg.com/@0x/subproviders/-/subproviders-4.1.2.tgz#ab7bb0f482b11ccb4615fb5dd8ca85199cd0ae23"
integrity sha512-PaK/+cC6+o3glVITnBdb/AN/ej7ulfr49KGftNRATB8Y/yI6Xa3adqgFvDh7jiKBoB/auTRFQ/TabQTcieKl6g==
@ -2011,8 +2012,9 @@
"@types/react" "*"
"@types/react-dom@^16.0.6":
version "16.0.11"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.0.11.tgz#bd10ccb0d9260343f4b9a49d4f7a8330a5c1f081"
version "16.8.5"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.5.tgz#3e3f4d99199391a7fb40aa3a155c8dd99b899cbd"
integrity sha512-idCEjROZ2cqh29+trmTmZhsBAUNQuYrF92JHKzZ5+aiFM1mlSk3bb23CK7HhYuOY75Apgap5y2jTyHzaM2AJGA==
dependencies:
"@types/react" "*"
@ -2051,6 +2053,7 @@
"@types/react-redux@^4.4.37":
version "4.4.47"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-4.4.47.tgz#12af1677116e08d413fe2620d0a85560c8a0536e"
integrity sha512-wyFTmLtEymHCjOmVVvsbNqJaGM9Q0x6sZTQfz4XkDj06P8Xe+ys9wKSQHx2Jt9J5Mi7HZnGcJaMFktn60sXluw==
dependencies:
"@types/react" "*"
redux "^3.6.0"
@ -4300,7 +4303,7 @@ buffer-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe"
buffer-from@1.x, buffer-from@^1.1.0:
buffer-from@1.x, buffer-from@>=1.1, buffer-from@^1.1.0:
version "1.1.1"
resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
@ -9287,6 +9290,13 @@ hoist-non-react-statics@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz#d2ca2dfc19c5a91c5a6615ce8e564ef0347e2a40"
hoist-non-react-statics@^3.1.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b"
integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==
dependencies:
react-is "^16.7.0"
home-or-tmp@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
@ -11428,10 +11438,15 @@ locate-path@^3.0.0:
p-locate "^3.0.0"
path-exists "^3.0.0"
lodash-es@^4.17.5, lodash-es@^4.2.1:
lodash-es@^4.17.5:
version "4.17.8"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.8.tgz#6fa8c8c5d337481df0bdf1c0d899d42473121e45"
lodash-es@^4.2.1:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78"
integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==
lodash._basecopy@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
@ -14956,11 +14971,16 @@ react-is@^16.6.0:
version "16.6.3"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.6.3.tgz#d2d7462fcfcbe6ec0da56ad69047e47e56e7eac0"
react-is@^16.7.0:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==
react-lazyload@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/react-lazyload/-/react-lazyload-2.3.0.tgz#ccb134223012447074a96543954f44b055dc6185"
react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4:
react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
@ -15000,7 +15020,20 @@ react-popper@^1.0.0-beta.6:
typed-styles "^0.0.5"
warning "^3.0.0"
react-redux@^5.0.3, react-redux@^5.0.7:
react-redux@^5.0.3:
version "5.1.1"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.1.1.tgz#88e368682c7fa80e34e055cd7ac56f5936b0f52f"
integrity sha512-LE7Ned+cv5qe7tMV5BPYkGQ5Lpg8gzgItK07c67yHvJ8t0iaD9kPFPAli/mYkiyJYrs2pJgExR2ZgsGqlrOApg==
dependencies:
"@babel/runtime" "^7.1.2"
hoist-non-react-statics "^3.1.0"
invariant "^2.2.4"
loose-envify "^1.1.0"
prop-types "^15.6.1"
react-is "^16.6.0"
react-lifecycles-compat "^3.0.0"
react-redux@^5.0.7:
version "5.0.7"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.7.tgz#0dc1076d9afb4670f993ffaef44b8f8c1155a4c8"
dependencies:
@ -15414,8 +15447,9 @@ reduce-function-call@^1.0.1:
balanced-match "^0.4.2"
redux-devtools-extension@^2.13.2:
version "2.13.2"
resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.2.tgz#e0f9a8e8dfca7c17be92c7124958a3b94eb2911d"
version "2.13.8"
resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz#37b982688626e5e4993ff87220c9bbb7cd2d96e1"
integrity sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg==
redux-devtools-extension@^2.13.5:
version "2.13.5"
@ -15431,6 +15465,7 @@ redux@*, redux@^4.0.0:
redux@^3.6.0:
version "3.7.2"
resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.2.tgz#06b73123215901d25d065be342eb026bc1c8537b"
integrity sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==
dependencies:
lodash "^4.2.1"
lodash-es "^4.2.1"
@ -15916,16 +15951,19 @@ rollbar-sourcemap-webpack-plugin@^2.4.0:
verror "^1.6.1"
rollbar@^2.4.7:
version "2.4.7"
resolved "https://registry.yarnpkg.com/rollbar/-/rollbar-2.4.7.tgz#9b1de1a0fab6b6e63fcfcd322c26081a1d8242e8"
version "2.10.0"
resolved "https://registry.yarnpkg.com/rollbar/-/rollbar-2.10.0.tgz#a18c333eb45ebd21be128afdf9bf3a0093be7218"
integrity sha512-Ifr+KB8cXsaE9Lae3o2X7jx+WAAHMxul44Bj+P+0uGxbTO4TcHFRloUWgPVtmHxuFjpDchHbhwMwMicTseEb1Q==
dependencies:
async "~1.2.1"
buffer-from ">=1.1"
console-polyfill "0.3.0"
debug "2.6.9"
error-stack-parser "1.3.3"
json-stringify-safe "~5.0.0"
lru-cache "~2.2.1"
request-ip "~2.0.1"
source-map ">=0.5.0"
uuid "3.0.x"
optionalDependencies:
decache "^3.0.5"
@ -16733,6 +16771,11 @@ source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
source-map@>=0.5.0:
version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
source-map@^0.4.2:
version "0.4.4"
resolved "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"