Auto-gen Python Exchange wrapper (#1919)

* Rename existing wrapper, to match contract name

* base contract: make member var public

* json_schemas.py: stop storing copies of schemas!

* .gitignore generated erc20_token.py wrapper

* json schemas: allow uppercase digits in address

* existing exchange wrapper: re-order methods

to match method order in Solidity contract, to reduce noise in upcoming
diffs of newly generated code vs. old manually-written code.

* existing exchange wrapper: rename method params

To match contract method param names

* existing exchange wrapper: remove redundant member

* existing exchange wrapper: make signatures bytes

Not strings.

* abi-gen/test-cli: show context on diff failure

* abi-gen-templates/Py: fix broken event interface

Previous changes had removed the `token_address` parameter from all
generated methods, but this instance was missed because there weren't
tests/examples using events for the first contract for which wrappers
were generated (ERC20Token).

* abi-gen: remove unused method parameters

* abi-gen: convert Py method params to snake case

* abi-gen: rewrite Python tuple handling

* python-generated-wrappers: include Exchange

* abi-gen-templates/Py: easy linter fixes

* abi-gen-templates/Py: satisfy docstring linters

* abi-gen-templates/Py: normalize bytes before use

* contract_wrappers.py: replace Exchange w/generated

* contract_wrappers.py: rm manually written Exchange

* contract_wrappers.py/doctest: rename variables

* abi-gen: fix misspelling in docstring

Co-Authored-By: Fabio B <me@fabioberger.com>

* Py docs: error on warning, and test build in CI

* abi-gen: doc Py bytes params as requiring UTF-8

* abi-gen: git mv diff.sh test-cli/

* abi-gen: put Py wrapper in module folder, not file

This leaves space for user-defined additions to the same module, such as
for custom types, as shown herein.

* abi-gen: customizable param validation for Python

* contract_wrappers.py: JSON schema Order validation

* CircleCI Build Artifacts

For abi-gen command-line test output, for generated Python contract
wrappers as output by abi-gen, for generated Python contract wrappers as
reformatted and included in the Python package area, and for the "build"
output folder in each Python package, which includes the generated
documentation.

* CHANGELOG updates for all components

* abi-gen: grammar in comments

Co-Authored-By: Fabio B <me@fabioberger.com>

* abi-gen: CHANGELOG spelling correction

Co-Authored-By: Fabio B <me@fabioberger.com>

* order_utils.py: reverse (chronological) CHANGELOG

* abi-gen-templates: reset CHANGELOG patch version

* CHANGELOGs: use multiple entries where appropriate

* abi-gen: enable devdoc solc output in test-cli

* abi-gen-templates/Py: consolidate return type

* abi-gen/test-cli: non-pure fixture contract method

Added a method to the "dummy" test fixture contract that isn't pure.
All of the other prior method cases were pure.

* abi-gen/Py: fix const methods missing return type

* abi-gen/Py: fix wrong return types on some methods

Specifically, wrapper methods wrapping contract methods that modify
contract state and return no return value.  There was no test case for
this.  Now there is.

* contract_wrappers.py: rm generated code in `clean`

* Parallelize Py monorepo scripts (test, lint, etc)
This commit is contained in:
F. Eugene Aumson
2019-07-23 12:58:18 -04:00
committed by GitHub
parent 1e6e74878f
commit ead8099109
120 changed files with 3246 additions and 2117 deletions

View File

@@ -33,6 +33,10 @@ jobs:
key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/python-contract-wrappers/generated
- store_artifacts:
path: ~/repo/packages/python-contract-wrappers/generated
- store_artifacts:
path: ~/repo/packages/abi-gen/test-cli/output
build-website:
resource_class: medium+
docker:
@@ -204,7 +208,8 @@ jobs:
- run:
command: |
cd python-packages
./cmd_pkgs_in_dep_order.py coverage run setup.py test
./parallel coverage run setup.py test
./build_docs
- save_cache:
key: coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }}
paths:
@@ -229,6 +234,24 @@ jobs:
key: coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/python-packages/sra_client/.coverage
- store_artifacts:
path: ~/repo/python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_token/__init__.py
- store_artifacts:
path: ~/repo/python-packages/contract_wrappers/src/zero_ex/contract_wrappers/exchange/__init__.py
- store_artifacts:
path: ~/repo/python-packages/contract_addresses/build
- store_artifacts:
path: ~/repo/python-packages/contract_artifacts/build
- store_artifacts:
path: ~/repo/python-packages/contract_wrappers/build
- store_artifacts:
path: ~/repo/python-packages/json_schemas/build
- store_artifacts:
path: ~/repo/python-packages/middlewares/build
- store_artifacts:
path: ~/repo/python-packages/order_utils/build
- store_artifacts:
path: ~/repo/python-packages/sra_client/build
test-rest-python:
working_directory: ~/repo
docker:

5
.gitignore vendored
View File

@@ -113,6 +113,8 @@ contracts/erc1155/generated-wrappers/
contracts/extensions/generated-wrappers/
contracts/exchange-forwarder/generated-wrappers/
contracts/dev-utils/generated-wrappers/
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_token/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/exchange/__init__.py
# cli test output
packages/abi-gen/test-cli/output
@@ -132,3 +134,6 @@ python-packages/*/dist
__pycache__
python-packages/*/src/*.egg-info
python-packages/*/.coverage
# python keeps package-local copies of json schemas
python-packages/json_schemas/src/zero_ex/json_schemas/schemas

View File

@@ -35,3 +35,6 @@ packages/sol-coverage/test/fixtures/artifacts
.pytest_cache
.mypy_cache
.tox
packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json
packages/abi-gen/test-cli/fixtures/artifacts/LibDummy.json
packages/abi-gen/test-cli/fixtures/artifacts/TestLibDummy.json

View File

@@ -1,4 +1,13 @@
[
{
"version": "6.0.13",
"changes": [
{
"note": "re-export new ethereum-types type, TupleDataItem",
"pr": 1919
}
]
},
{
"timestamp": 1563193019,
"version": "6.0.12",

View File

@@ -131,6 +131,7 @@ export {
ConstructorAbi,
FallbackAbi,
DataItem,
TupleDataItem,
ConstructorStateMutability,
StateMutability,
Web3JsProvider,

View File

@@ -1,4 +1,25 @@
[
{
"version": "2.3.0",
"changes": [
{
"note": "Python: fix broken event handling",
"pr": 1919
},
{
"note": "Python: custom validator class support",
"pr": 1919
},
{
"note": "Python: linter fixes",
"pr": 1919
},
{
"note": "Python: normalize bytes parameters in wrapper methods",
"pr": 1919
}
]
},
{
"timestamp": 1563006338,
"version": "2.2.1",

View File

@@ -1,8 +1,17 @@
"""Generated wrapper for {{contractName}} Solidity contract."""
import json
from typing import Optional, Tuple, Union
# pylint: disable=too-many-arguments
import json
from typing import ( # pylint: disable=unused-import
Any,
List,
Optional,
Tuple,
Union,
)
from mypy_extensions import TypedDict # pylint: disable=unused-import
from hexbytes import HexBytes
from web3.datastructures import AttributeDict
from web3.providers.base import BaseProvider
@@ -11,13 +20,55 @@ from zero_ex.contract_wrappers._base_contract_wrapper import BaseContractWrapper
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.
try:
# both mypy and pylint complain about what we're doing here, but this
# works just fine, so their messages have been disabled here.
from . import ( # type: ignore # pylint: disable=import-self
{{contractName}}Validator,
)
except ImportError:
class {{contractName}}Validator({{contractName}}ValidatorBase): # type: ignore
"""No-op input validator."""
{{tupleDefinitions ABIString}}
# pylint: disable=too-many-public-methods
class {{contractName}}(BaseContractWrapper):
"""Wrapper class for {{contractName}} Solidity contract."""
"""Wrapper class for {{contractName}} Solidity contract.{{docBytesIfNecessary ABIString}}"""
def __init__(
self,
provider: BaseProvider,
contract_address: str,
validator: {{contractName}}Validator = None,
private_key: str = None,
):
"""Get an instance of wrapper for smart contract.
@@ -34,6 +85,11 @@ class {{contractName}}(BaseContractWrapper):
private_key=private_key,
)
if not validator:
validator = {{contractName}}Validator(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.
@@ -55,3 +111,5 @@ class {{contractName}}(BaseContractWrapper):
return json.loads(
'{{{ABIString}}}' # noqa: E501 (line-too-long)
)
# pylint: disable=too-many-lines

View File

@@ -6,31 +6,44 @@
{{^this.constant}}
view_only: bool = False,
{{/this.constant}}
) ->{{#if outputs}}{{~> return_type outputs=outputs~}}{{else}} None{{/if}}:
) -> {{> return_type outputs=outputs~}}:
"""Execute underlying, same-named contract method.
{{sanitizeDevdocDetails this.name this.devdoc.details 8}}
{{#each this.devdoc.params}}
:param {{@key}}: {{this}}
{{/each}}
{{#if this.constant}}
{{#if this.devdoc.return}}:returns: {{this.devdoc.return}}{{/if}}
{{else}}
{{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: transaction hash
: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')}}
{{this.name}} = self._validate_and_checksum_address({{this.name}})
{{toPythonIdentifier this.name}} = self._validate_and_checksum_address({{toPythonIdentifier this.name}})
{{else if (equal type 'uint256')}}
# safeguard against fractional inputs
{{this.name}} = int({{this.name}})
{{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
self.contract_address
).functions.{{this.name}}(
{{> params}}
)

View File

@@ -1,14 +1,13 @@
def get_{{languageSpecificName}}_event(
self, token_address: str, tx_hash: Union[HexBytes, bytes]
self, tx_hash: Union[HexBytes, bytes]
) -> Tuple[AttributeDict]:
"""Get log entry for {{name}} event.
:param tx_hash: hash of transaction emitting {{name}} event.
{{makeEventParameterDocstringRole name 8}}
"""
tx_receipt = self._web3_eth.getTransactionReceipt(tx_hash)
token_address = self._validate_and_checksum_address(token_address)
return (
self._get_contract_instance(token_address)
self._get_contract_instance(self.contract_address)
.events.{{name}}()
.processReceipt(tx_receipt)
)

View File

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

View File

@@ -1,13 +1,14 @@
{{#if this.constant}}
{{~#if outputs~}}
{{^if this.constant}}
Union[
{{~/if~}}
{{#if outputs.length}}
{{#singleReturnValue}}
{{#returnType outputs.0.type outputs.0.components}}{{~/returnType~}}
{{#returnType outputs.0.type outputs.0.components}}{{~/returnType~}}
{{/singleReturnValue}}
{{^singleReturnValue}}
[{{#each outputs}}{{#returnType type components}}{{/returnType}}{{#unless @last}}, {{/unless}}{{/each}}]
{{/singleReturnValue}}
{{/if}}
{{/if}}
{{^if this.constant}}
Union[HexBytes, bytes]
{{~/if~}}
{{else}}None
{{/if}}{{^if this.constant}}, Union[HexBytes, bytes]]{{/if~}}
{{else}}{{#if this.constant}}None{{else}}Union[None, Union[HexBytes, bytes]]{{/if}}{{/if~}}

View File

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

View File

@@ -1,4 +1,37 @@
[
{
"version": "3.1.1",
"changes": [
{
"note": "Python method parameters are now in snake case",
"pr": 1919
},
{
"note": "Python wrappers now support tuples in method parameters",
"pr": 1919
},
{
"note": "document Python method's bytes params as requiring UTF-8",
"pr": 1919
},
{
"note": "generate Python output into a contract-named folder, not a file (eg exchange/__init__.py rather than exchange.py) leaving space for user-defined additions to the same module, such as for custom types, as used by the Exchange wrapper's manually-written type aliases in the contract_wrappers.exchange.types Python module",
"pr": 1919
},
{
"note": "support for customizable parameter validation for Python wrappers",
"pr": 1919
},
{
"note": "wrap Python docstrings better, for pydocstyle compliance",
"pr": 1919
},
{
"note": "lots of fixes to satisfy linters of generated Python code",
"pr": 1919
}
]
},
{
"timestamp": 1563047529,
"version": "2.1.1",

View File

@@ -17,7 +17,8 @@
"evm.bytecode.object",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.object",
"evm.deployedBytecode.sourceMap"
"evm.deployedBytecode.sourceMap",
"devdoc"
]
}
}

View File

@@ -33,7 +33,7 @@
"generate_contract_wrappers": "run-p gen_typescript gen_python",
"gen_typescript": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output ./test-cli/output/typescript --backend ethers",
"gen_python": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/Python/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/Python/partials/**/*.handlebars' --output ./test-cli/output/python --language Python",
"diff_contract_wrappers": "./diff.sh ./test-cli/expected-output ./test-cli/output",
"diff_contract_wrappers": "test-cli/diff.sh ./test-cli/expected-output ./test-cli/output",
"coverage:report:text": "istanbul report text",
"coverage:report:html": "istanbul report html && open coverage/index.html",
"profiler:report:html": "istanbul report html && open coverage/index.html",

View File

@@ -4,7 +4,16 @@ import { AbiEncoder, abiUtils, logUtils } from '@0x/utils';
import chalk from 'chalk';
import * as changeCase from 'change-case';
import * as cliFormat from 'cli-format';
import { AbiDefinition, ConstructorAbi, ContractAbi, DevdocOutput, EventAbi, MethodAbi } from 'ethereum-types';
import {
AbiDefinition,
ConstructorAbi,
ContractAbi,
DataItem,
DevdocOutput,
EventAbi,
MethodAbi,
TupleDataItem,
} from 'ethereum-types';
import { sync as globSync } from 'glob';
import * as Handlebars from 'handlebars';
import * as _ from 'lodash';
@@ -102,8 +111,9 @@ function registerPythonHelpers(): void {
return lhs === rhs;
});
Handlebars.registerHelper('safeString', (str, options) => new Handlebars.SafeString(str));
Handlebars.registerHelper('parameterType', utils.solTypeToPyType.bind(utils, ParamKind.Input, args.backend));
Handlebars.registerHelper('returnType', utils.solTypeToPyType.bind(utils, ParamKind.Output, args.backend));
Handlebars.registerHelper('parameterType', utils.solTypeToPyType.bind(utils));
Handlebars.registerHelper('returnType', utils.solTypeToPyType.bind(utils));
Handlebars.registerHelper('toPythonIdentifier', utils.toPythonIdentifier.bind(utils));
Handlebars.registerHelper(
'sanitizeDevdocDetails',
(methodName: string, devdocDetails: string, indent: number, options) => {
@@ -116,12 +126,111 @@ function registerPythonHelpers(): void {
return new Handlebars.SafeString(
`\n${cliFormat.wrap(devdocDetails || '', {
paddingLeft: ' '.repeat(indent),
width: columnsPerRow - indent,
width: columnsPerRow,
ansi: false,
})}\n`,
);
},
);
Handlebars.registerHelper(
'makeParameterDocstringRole',
(name: string, description: string, indent: number, options) => {
let docstring = `:param ${name}:`;
if (description && description.length > 0) {
docstring = `${docstring} ${description}`;
}
return new Handlebars.SafeString(utils.wrapPythonDocstringRole(docstring, indent));
},
);
Handlebars.registerHelper(
'makeReturnDocstringRole',
(description: string, indent: number, options) =>
new Handlebars.SafeString(utils.wrapPythonDocstringRole(`:returns: ${description}`, indent)),
);
Handlebars.registerHelper(
'makeEventParameterDocstringRole',
(eventName: string, indent: number, options) =>
new Handlebars.SafeString(
utils.wrapPythonDocstringRole(
`:param tx_hash: hash of transaction emitting ${eventName} event`,
indent,
),
),
);
Handlebars.registerHelper('tupleDefinitions', (abisJSON: string, options) => {
const abis: AbiDefinition[] = JSON.parse(abisJSON);
// build an array of objects, each of which has one key, the Python
// name of a tuple, with a string value holding the Python
// definition of that tuple. Using a key-value object conveniently
// filters duplicate references to the same tuple.
const tupleDefinitions: { [pythonTupleName: string]: string } = {};
for (const abi of abis) {
let parameters: DataItem[] = [];
if (abi.hasOwnProperty('inputs')) {
// HACK(feuGeneA): using "as MethodAbi" below, but abi
// could just as well be ConstructorAbi, EventAbi, etc. We
// just need to tell the TypeScript compiler that it's NOT
// FallbackAbi, or else it would complain, "Property
// 'inputs' does not exist on type 'AbiDefinition'.
// Property 'inputs' does not exist on type
// 'FallbackAbi'.", despite the enclosing if statement.
// tslint:disable:no-unnecessary-type-assertion
parameters = parameters.concat((abi as MethodAbi).inputs);
}
if (abi.hasOwnProperty('outputs')) {
// HACK(feuGeneA): same as described above, except here we
// KNOW that it's a MethodAbi, given the enclosing if
// statement, because that's the only AbiDefinition subtype
// that actually has an outputs field.
parameters = parameters.concat((abi as MethodAbi).outputs);
}
for (const parameter of parameters) {
if (parameter.type === 'tuple') {
tupleDefinitions[
utils.makePythonTupleName((parameter as TupleDataItem).components)
] = utils.makePythonTupleClassBody((parameter as TupleDataItem).components);
}
}
}
const tupleDeclarations = [];
for (const pythonTupleName in tupleDefinitions) {
if (tupleDefinitions[pythonTupleName]) {
tupleDeclarations.push(
`class ${pythonTupleName}(TypedDict):\n """Python representation of a tuple or struct.\n\n A tuple found in an ABI may have been written in Solidity as a literal\n tuple, or it may have been written as a parameter with a Solidity\n \`struct\`:code: data type; there's no way to tell which, based solely on the\n ABI, and the name of a Solidity \`struct\`:code: is not conveyed through the\n ABI. This class represents a tuple that appeared in a method definition.\n Its name is derived from a hash of that tuple's field names, and every\n method whose ABI refers to a tuple with that same list of field names will\n have a generated wrapper method that refers to this class.\n\n Any members of type \`bytes\`:code: should be encoded as UTF-8, which can be\n accomplished via \`str.encode("utf_8")\`:code:\n """${
tupleDefinitions[pythonTupleName]
}`,
);
}
}
return new Handlebars.SafeString(tupleDeclarations.join('\n\n'));
});
Handlebars.registerHelper('docBytesIfNecessary', (abisJSON: string, options) => {
const abis: AbiDefinition[] = JSON.parse(abisJSON);
// see if any ABIs accept params of type bytes, and if so then emit
// explanatory documentation string.
for (const abi of abis) {
if (abi.hasOwnProperty('inputs')) {
// HACK(feuGeneA): using "as MethodAbi" below, but abi
// could just as well be ConstructorAbi, EventAbi, etc. We
// just need to tell the TypeScript compiler that it's NOT
// FallbackAbi, or else it would complain, "Property
// 'inputs' does not exist on type 'AbiDefinition'.
// Property 'inputs' does not exist on type
// 'FallbackAbi'.", despite the enclosing if statement.
// tslint:disable:no-unnecessary-type-assertion
if ((abi as MethodAbi).inputs) {
for (const input of (abi as MethodAbi).inputs) {
if (input.type === 'bytes') {
return new Handlebars.SafeString(
'\n\n All method parameters of type `bytes`:code: should be encoded as UTF-8,\n which can be accomplished via `str.encode("utf_8")`:code:.\n ',
);
}
}
}
}
}
return '';
});
}
if (args.language === 'TypeScript') {
registerTypeScriptHelpers();
@@ -168,16 +277,17 @@ for (const abiFileName of abiFileNames) {
}
const outFileName = utils.makeOutputFileName(namedContent.name);
const outFileExtension = (() => {
const outFilePath = (() => {
if (args.language === 'TypeScript') {
return 'ts';
return `${args.output}/${outFileName}.ts`;
} else if (args.language === 'Python') {
return 'py';
const directory = `${args.output}/${outFileName}`;
mkdirp.sync(directory);
return `${directory}/__init__.py`;
} else {
throw new Error(`Unexpected language '${args.language}'`);
}
})();
const outFilePath = `${args.output}/${outFileName}.${outFileExtension}`;
if (utils.isOutputFileUpToDate(outFilePath, [abiFileName, args.template, ...partialTemplateFileNames])) {
logUtils.log(`Already up to date: ${chalk.bold(outFilePath)}`);

View File

@@ -1,3 +1,7 @@
import { createHash } from 'crypto';
import * as changeCase from 'change-case';
import * as cliFormat from 'cli-format';
import { AbiType, ConstructorAbi, DataItem } from 'ethereum-types';
import * as fs from 'fs';
import * as _ from 'lodash';
@@ -98,12 +102,12 @@ export const utils = {
throw new Error(`Unknown Solidity type found: ${solType}`);
}
},
solTypeToPyType(paramKind: ParamKind, backend: ContractsBackend, solType: string, components?: DataItem[]): string {
solTypeToPyType(solType: string, components?: DataItem[]): string {
const trailingArrayRegex = /\[\d*\]$/;
if (solType.match(trailingArrayRegex)) {
const arrayItemSolType = solType.replace(trailingArrayRegex, '');
const arrayItemPyType = utils.solTypeToPyType(paramKind, backend, arrayItemSolType, components);
const arrayPyType = `Array[${arrayItemPyType}]`;
const arrayItemPyType = utils.solTypeToPyType(arrayItemSolType, components);
const arrayPyType = `List[${arrayItemPyType}]`;
return arrayPyType;
} else {
const solTypeRegexToPyType = [
@@ -121,18 +125,7 @@ export const utils = {
}
const TUPLE_TYPE_REGEX = '^tuple$';
if (solType.match(TUPLE_TYPE_REGEX)) {
const componentsType = _.map(components, component => {
const componentValueType = utils.solTypeToPyType(
paramKind,
backend,
component.type,
component.components,
);
const componentType = `'${component.name}': ${componentValueType}`;
return componentType;
});
const pyType = `TypedDict('${solType}(${components})', {${componentsType.join(',')}}`;
return pyType;
return utils.makePythonTupleName(components as DataItem[]);
}
throw new Error(`Unknown Solidity type found: ${solType}`);
}
@@ -190,4 +183,171 @@ export const utils = {
}
}
},
/**
* simply concatenate all of the names of the components, and convert that
* concatenation into PascalCase to conform to Python convention.
*/
makePythonTupleName(tupleComponents: DataItem[]): string {
const lengthOfHashSuffix = 8;
return `Tuple0x${createHash('MD5')
.update(_.map(tupleComponents, component => component.name).join('_'))
.digest()
.toString('hex')
.substring(0, lengthOfHashSuffix)}`;
},
/**
* @returns a string that is a Python code snippet that's intended to be
* used as the second parameter to a TypedDict() instantiation; value
* looks like "{ 'python_dict_key': python_type, ... }".
*/
makePythonTupleClassBody(tupleComponents: DataItem[]): string {
let toReturn: string = '';
for (const tupleComponent of tupleComponents) {
toReturn = `${toReturn}\n\n ${tupleComponent.name}: ${utils.solTypeToPyType(
tupleComponent.type,
tupleComponent.components,
)}`;
}
toReturn = `${toReturn}`;
return toReturn;
},
/**
* used to generate Python-parseable identifier names for parameters to
* contract methods.
*/
toPythonIdentifier(input: string): string {
let snakeCased = changeCase.snake(input);
const pythonReservedWords = [
'False',
'None',
'True',
'and',
'as',
'assert',
'break',
'class',
'continue',
'def',
'del',
'elif',
'else',
'except',
'finally',
'for',
'from',
'global',
'if',
'import',
'in',
'is',
'lambda',
'nonlocal',
'not',
'or',
'pass',
'raise',
'return',
'try',
'while',
'with',
'yield',
];
const pythonBuiltins = [
'abs',
'delattr',
'hash',
'memoryview',
'set',
'all',
'dict',
'help',
'min',
'setattr',
'any',
'dir',
'hex',
'next',
'slice',
'ascii',
'divmod',
'id',
'object',
'sorted',
'bin',
'enumerate',
'input',
'oct',
'staticmethod',
'bool',
'eval',
'int',
'open',
'str',
'breakpoint',
'exec',
'isinstance',
'ord',
'sum',
'bytearray',
'filter',
'issubclass',
'pow',
'super',
'bytes',
'float',
'iter',
'print',
'tuple',
'callable',
'format',
'len',
'property',
'type',
'chr',
'frozenset',
'list',
'range',
'vars',
'classmethod',
'getattr',
'locals',
'repr',
'zip',
'compile',
'globals',
'map',
'reversed',
'__import__',
'complex',
'hasattr',
'max',
'round',
];
if (
pythonReservedWords.includes(snakeCased) ||
pythonBuiltins.includes(snakeCased) ||
/*changeCase strips leading underscores :(*/ input[0] === '_'
) {
snakeCased = `_${snakeCased}`;
}
return snakeCased;
},
/**
* Python docstrings are used to generate documentation, and that
* transformation supports annotation of parameters, return types, etc, via
* re-Structured Text "interpreted text roles". Per the pydocstyle linter,
* such annotations should be line-wrapped at 80 columns, with a hanging
* indent of 4 columns. This function simply returns an accordingly
* wrapped and hanging-indented `role` string.
*/
wrapPythonDocstringRole(docstring: string, indent: number): string {
const columnsPerIndent = 4;
const columnsPerRow = 80;
return cliFormat.wrap(docstring, {
paddingLeft: ' '.repeat(indent),
width: columnsPerRow,
ansi: false,
hangingIndent: ' '.repeat(columnsPerIndent),
});
},
};

View File

@@ -1,4 +1,6 @@
diff -r $1 $2
diff -r -U 5 $1 $2
# -r tells diff to compare folders recursively.
# "-U 5" tells diff to output a "unified" format, with 5 lines of context.
if [ $? -ne 0 ]; then
echo "ERROR: Freshly generated output does not match expected output. If you're confident that the expected output should be updated, copy it in there and commit it."
exit 1

View File

@@ -1,243 +0,0 @@
"""Generated wrapper for AbiGenDummy Solidity contract."""
import json
from typing import Optional, Tuple, Union
from hexbytes import HexBytes
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.tx_params import TxParams
class AbiGenDummy(BaseContractWrapper):
"""Wrapper class for AbiGenDummy Solidity contract."""
def __init__(
self,
provider: BaseProvider,
contract_address: str,
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:.
"""
super().__init__(
provider=provider,
contract_address=contract_address,
private_key=private_key,
)
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=AbiGenDummy.abi()
)
def simple_require(
self,
tx_params: Optional[TxParams] = None,
) -> None:
"""Execute underlying, same-named contract method.
"""
func = self._get_contract_instance(
self._contract_address
).functions.simpleRequire(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def ecrecover_fn(
self,
hash: bytes,
v: int,
r: bytes,
s: bytes,
tx_params: Optional[TxParams] = None,
) -> str:
"""Execute underlying, same-named contract method.
"""
func = self._get_contract_instance(
self._contract_address
).functions.ecrecoverFn(
hash,
v,
r,
s
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def revert_with_constant(
self,
tx_params: Optional[TxParams] = None,
) -> None:
"""Execute underlying, same-named contract method.
"""
func = self._get_contract_instance(
self._contract_address
).functions.revertWithConstant(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def simple_revert(
self,
tx_params: Optional[TxParams] = None,
) -> None:
"""Execute underlying, same-named contract method.
"""
func = self._get_contract_instance(
self._contract_address
).functions.simpleRevert(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def require_with_constant(
self,
tx_params: Optional[TxParams] = None,
) -> None:
"""Execute underlying, same-named contract method.
"""
func = self._get_contract_instance(
self._contract_address
).functions.requireWithConstant(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def with_address_input(
self,
x: str,
a: int,
b: int,
y: str,
c: int,
tx_params: Optional[TxParams] = None,
) -> str:
"""Execute underlying, same-named contract method.
"""
x = self._validate_and_checksum_address(x)
# safeguard against fractional inputs
a = int(a)
# safeguard against fractional inputs
b = int(b)
y = self._validate_and_checksum_address(y)
# safeguard against fractional inputs
c = int(c)
func = self._get_contract_instance(
self._contract_address
).functions.withAddressInput(
x,
a,
b,
y,
c
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def simple_pure_function_with_input(
self,
x: int,
tx_params: Optional[TxParams] = None,
) -> int:
"""Execute underlying, same-named contract method.
"""
# safeguard against fractional inputs
x = int(x)
func = self._get_contract_instance(
self._contract_address
).functions.simplePureFunctionWithInput(
x
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def simple_pure_function(
self,
tx_params: Optional[TxParams] = None,
) -> int:
"""Execute underlying, same-named contract method.
"""
func = self._get_contract_instance(
self._contract_address
).functions.simplePureFunction(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def pure_function_with_constant(
self,
tx_params: Optional[TxParams] = None,
) -> int:
"""Execute underlying, same-named contract method.
"""
func = self._get_contract_instance(
self._contract_address
).functions.pureFunctionWithConstant(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
@staticmethod
def abi():
"""Return the ABI to the underlying contract."""
return json.loads(
'[{"constant":true,"inputs":[],"name":"simpleRequire","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"hash","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"ecrecoverFn","outputs":[{"name":"signerAddress","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"revertWithConstant","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"simpleRevert","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"requireWithConstant","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"x","type":"address"},{"name":"a","type":"uint256"},{"name":"b","type":"uint256"},{"name":"y","type":"address"},{"name":"c","type":"uint256"}],"name":"withAddressInput","outputs":[{"name":"z","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"x","type":"uint256"}],"name":"simplePureFunctionWithInput","outputs":[{"name":"sum","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"simplePureFunction","outputs":[{"name":"result","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"pureFunctionWithConstant","outputs":[{"name":"someConstant","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"}]' # noqa: E501 (line-too-long)
)

View File

@@ -0,0 +1,619 @@
"""Generated wrapper for AbiGenDummy Solidity contract."""
# pylint: disable=too-many-arguments
import json
from typing import ( # pylint: disable=unused-import
Any,
List,
Optional,
Tuple,
Union,
)
from mypy_extensions import TypedDict # pylint: disable=unused-import
from hexbytes import HexBytes
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.tx_params import TxParams
class AbiGenDummyValidatorBase:
"""Base class for validating inputs to AbiGenDummy 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 AbiGenDummy below.
try:
# both mypy and pylint complain about what we're doing here, but this
# works just fine, so their messages have been disabled here.
from . import ( # type: ignore # pylint: disable=import-self
AbiGenDummyValidator,
)
except ImportError:
class AbiGenDummyValidator(AbiGenDummyValidatorBase): # type: ignore
"""No-op input validator."""
class Tuple0xc9bdd2d5(TypedDict):
"""Python representation of a tuple or struct.
A tuple found in an ABI may have been written in Solidity as a literal
tuple, or it may have been written as a parameter with a Solidity
`struct`:code: data type; there's no way to tell which, based solely on the
ABI, and the name of a Solidity `struct`:code: is not conveyed through the
ABI. This class represents a tuple that appeared in a method definition.
Its name is derived from a hash of that tuple's field names, and every
method whose ABI refers to a tuple with that same list of field names will
have a generated wrapper method that refers to this class.
Any members of type `bytes`:code: should be encoded as UTF-8, which can be
accomplished via `str.encode("utf_8")`:code:
"""
innerStruct: Tuple0xcf8ad995
description: str
class Tuple0xcf8ad995(TypedDict):
"""Python representation of a tuple or struct.
A tuple found in an ABI may have been written in Solidity as a literal
tuple, or it may have been written as a parameter with a Solidity
`struct`:code: data type; there's no way to tell which, based solely on the
ABI, and the name of a Solidity `struct`:code: is not conveyed through the
ABI. This class represents a tuple that appeared in a method definition.
Its name is derived from a hash of that tuple's field names, and every
method whose ABI refers to a tuple with that same list of field names will
have a generated wrapper method that refers to this class.
Any members of type `bytes`:code: should be encoded as UTF-8, which can be
accomplished via `str.encode("utf_8")`:code:
"""
someBytes: bytes
anInteger: int
aDynamicArrayOfBytes: List[bytes]
aString: str
# pylint: disable=too-many-public-methods
class AbiGenDummy(BaseContractWrapper):
"""Wrapper class for AbiGenDummy Solidity contract.
All method parameters of type `bytes`:code: should be encoded as UTF-8,
which can be accomplished via `str.encode("utf_8")`:code:.
"""
def __init__(
self,
provider: BaseProvider,
contract_address: str,
validator: AbiGenDummyValidator = 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:.
"""
super().__init__(
provider=provider,
contract_address=contract_address,
private_key=private_key,
)
if not validator:
validator = AbiGenDummyValidator(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=AbiGenDummy.abi()
)
def simple_require(
self,
tx_params: Optional[TxParams] = None,
) -> None:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
func = self._get_contract_instance(
self.contract_address
).functions.simpleRequire(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def accepts_an_array_of_bytes(
self,
a: List[bytes],
tx_params: Optional[TxParams] = None,
) -> None:
"""Execute underlying, same-named contract method.
a method that accepts an array of bytes
:param a: the array of bytes being accepted
:param tx_params: transaction parameters
"""
self.validator.assert_valid(
method_name='acceptsAnArrayOfBytes',
parameter_name='a',
argument_value=a,
)
a = [
bytes.fromhex(a_element.decode("utf-8"))
for a_element in a
]
func = self._get_contract_instance(
self.contract_address
).functions.acceptsAnArrayOfBytes(
a
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def ecrecover_fn(
self,
_hash: bytes,
v: int,
r: bytes,
s: bytes,
tx_params: Optional[TxParams] = None,
) -> str:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
self.validator.assert_valid(
method_name='ecrecoverFn',
parameter_name='hash',
argument_value=_hash,
)
self.validator.assert_valid(
method_name='ecrecoverFn',
parameter_name='v',
argument_value=v,
)
self.validator.assert_valid(
method_name='ecrecoverFn',
parameter_name='r',
argument_value=r,
)
self.validator.assert_valid(
method_name='ecrecoverFn',
parameter_name='s',
argument_value=s,
)
func = self._get_contract_instance(
self.contract_address
).functions.ecrecoverFn(
_hash,
v,
r,
s
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def accepts_bytes(
self,
a: bytes,
tx_params: Optional[TxParams] = None,
) -> None:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
self.validator.assert_valid(
method_name='acceptsBytes',
parameter_name='a',
argument_value=a,
)
a = bytes.fromhex(a.decode("utf-8"))
func = self._get_contract_instance(
self.contract_address
).functions.acceptsBytes(
a
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def revert_with_constant(
self,
tx_params: Optional[TxParams] = None,
) -> None:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
func = self._get_contract_instance(
self.contract_address
).functions.revertWithConstant(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def simple_revert(
self,
tx_params: Optional[TxParams] = None,
) -> None:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
func = self._get_contract_instance(
self.contract_address
).functions.simpleRevert(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def nested_struct_output(
self,
tx_params: Optional[TxParams] = None,
) -> Tuple0xc9bdd2d5:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
func = self._get_contract_instance(
self.contract_address
).functions.nestedStructOutput(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def require_with_constant(
self,
tx_params: Optional[TxParams] = None,
) -> None:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
func = self._get_contract_instance(
self.contract_address
).functions.requireWithConstant(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def with_address_input(
self,
x: str,
a: int,
b: int,
y: str,
c: int,
tx_params: Optional[TxParams] = None,
) -> str:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
self.validator.assert_valid(
method_name='withAddressInput',
parameter_name='x',
argument_value=x,
)
x = self._validate_and_checksum_address(x)
self.validator.assert_valid(
method_name='withAddressInput',
parameter_name='a',
argument_value=a,
)
# safeguard against fractional inputs
a = int(a)
self.validator.assert_valid(
method_name='withAddressInput',
parameter_name='b',
argument_value=b,
)
# safeguard against fractional inputs
b = int(b)
self.validator.assert_valid(
method_name='withAddressInput',
parameter_name='y',
argument_value=y,
)
y = self._validate_and_checksum_address(y)
self.validator.assert_valid(
method_name='withAddressInput',
parameter_name='c',
argument_value=c,
)
# safeguard against fractional inputs
c = int(c)
func = self._get_contract_instance(
self.contract_address
).functions.withAddressInput(
x,
a,
b,
y,
c
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def struct_input(
self,
s: Tuple0xcf8ad995,
tx_params: Optional[TxParams] = None,
) -> None:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
self.validator.assert_valid(
method_name='structInput',
parameter_name='s',
argument_value=s,
)
func = self._get_contract_instance(
self.contract_address
).functions.structInput(
s
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def non_pure_method(
self,
tx_params: Optional[TxParams] = None,
view_only: bool = False,
) -> Union[int, Union[HexBytes, bytes]]:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
: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.
"""
func = self._get_contract_instance(
self.contract_address
).functions.nonPureMethod(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=view_only
)
def simple_pure_function_with_input(
self,
x: int,
tx_params: Optional[TxParams] = None,
) -> int:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
self.validator.assert_valid(
method_name='simplePureFunctionWithInput',
parameter_name='x',
argument_value=x,
)
# safeguard against fractional inputs
x = int(x)
func = self._get_contract_instance(
self.contract_address
).functions.simplePureFunctionWithInput(
x
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def non_pure_method_that_returns_nothing(
self,
tx_params: Optional[TxParams] = None,
view_only: bool = False,
) -> Union[None, Union[HexBytes, bytes]]:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
: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.
"""
func = self._get_contract_instance(
self.contract_address
).functions.nonPureMethodThatReturnsNothing(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=view_only
)
def simple_pure_function(
self,
tx_params: Optional[TxParams] = None,
) -> int:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
func = self._get_contract_instance(
self.contract_address
).functions.simplePureFunction(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def nested_struct_input(
self,
n: Tuple0xc9bdd2d5,
tx_params: Optional[TxParams] = None,
) -> None:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
self.validator.assert_valid(
method_name='nestedStructInput',
parameter_name='n',
argument_value=n,
)
func = self._get_contract_instance(
self.contract_address
).functions.nestedStructInput(
n
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def struct_output(
self,
tx_params: Optional[TxParams] = None,
) -> Tuple0xcf8ad995:
"""Execute underlying, same-named contract method.
a method that returns a struct
:param tx_params: transaction parameters
:returns: a Struct struct
"""
func = self._get_contract_instance(
self.contract_address
).functions.structOutput(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def pure_function_with_constant(
self,
tx_params: Optional[TxParams] = None,
) -> int:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
func = self._get_contract_instance(
self.contract_address
).functions.pureFunctionWithConstant(
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def get_an_event_event(
self, tx_hash: Union[HexBytes, bytes]
) -> Tuple[AttributeDict]:
"""Get log entry for AnEvent event.
:param tx_hash: hash of transaction emitting AnEvent event
"""
tx_receipt = self._web3_eth.getTransactionReceipt(tx_hash)
return (
self._get_contract_instance(self.contract_address)
.events.AnEvent()
.processReceipt(tx_receipt)
)
@staticmethod
def abi():
"""Return the ABI to the underlying contract."""
return json.loads(
'[{"constant":true,"inputs":[],"name":"simpleRequire","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"bytes[]"}],"name":"acceptsAnArrayOfBytes","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"hash","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"ecrecoverFn","outputs":[{"name":"signerAddress","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"bytes"}],"name":"acceptsBytes","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"revertWithConstant","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"simpleRevert","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"nestedStructOutput","outputs":[{"components":[{"components":[{"name":"someBytes","type":"bytes"},{"name":"anInteger","type":"uint32"},{"name":"aDynamicArrayOfBytes","type":"bytes[]"},{"name":"aString","type":"string"}],"name":"innerStruct","type":"tuple"},{"name":"description","type":"string"}],"name":"","type":"tuple"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"requireWithConstant","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"x","type":"address"},{"name":"a","type":"uint256"},{"name":"b","type":"uint256"},{"name":"y","type":"address"},{"name":"c","type":"uint256"}],"name":"withAddressInput","outputs":[{"name":"z","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"components":[{"name":"someBytes","type":"bytes"},{"name":"anInteger","type":"uint32"},{"name":"aDynamicArrayOfBytes","type":"bytes[]"},{"name":"aString","type":"string"}],"name":"s","type":"tuple"}],"name":"structInput","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"nonPureMethod","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"x","type":"uint256"}],"name":"simplePureFunctionWithInput","outputs":[{"name":"sum","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"nonPureMethodThatReturnsNothing","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"simplePureFunction","outputs":[{"name":"result","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"components":[{"components":[{"name":"someBytes","type":"bytes"},{"name":"anInteger","type":"uint32"},{"name":"aDynamicArrayOfBytes","type":"bytes[]"},{"name":"aString","type":"string"}],"name":"innerStruct","type":"tuple"},{"name":"description","type":"string"}],"name":"n","type":"tuple"}],"name":"nestedStructInput","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"structOutput","outputs":[{"components":[{"name":"someBytes","type":"bytes"},{"name":"anInteger","type":"uint32"},{"name":"aDynamicArrayOfBytes","type":"bytes[]"},{"name":"aString","type":"string"}],"name":"s","type":"tuple"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"pureFunctionWithConstant","outputs":[{"name":"someConstant","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"param","type":"uint8"}],"name":"AnEvent","type":"event"}]' # noqa: E501 (line-too-long)
)
# pylint: disable=too-many-lines

View File

@@ -1,51 +0,0 @@
"""Generated wrapper for LibDummy Solidity contract."""
import json
from typing import Optional, Tuple, Union
from hexbytes import HexBytes
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.tx_params import TxParams
class LibDummy(BaseContractWrapper):
"""Wrapper class for LibDummy Solidity contract."""
def __init__(
self,
provider: BaseProvider,
contract_address: str,
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:.
"""
super().__init__(
provider=provider,
contract_address=contract_address,
private_key=private_key,
)
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=LibDummy.abi()
)
@staticmethod
def abi():
"""Return the ABI to the underlying contract."""
return json.loads(
'[]' # noqa: E501 (line-too-long)
)

View File

@@ -0,0 +1,109 @@
"""Generated wrapper for LibDummy Solidity contract."""
# pylint: disable=too-many-arguments
import json
from typing import ( # pylint: disable=unused-import
Any,
List,
Optional,
Tuple,
Union,
)
from mypy_extensions import TypedDict # pylint: disable=unused-import
from hexbytes import HexBytes
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.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.
try:
# both mypy and pylint complain about what we're doing here, but this
# works just fine, so their messages have been disabled here.
from . import ( # type: ignore # pylint: disable=import-self
LibDummyValidator,
)
except ImportError:
class LibDummyValidator(LibDummyValidatorBase): # type: ignore
"""No-op input validator."""
# pylint: disable=too-many-public-methods
class LibDummy(BaseContractWrapper):
"""Wrapper class for LibDummy Solidity contract."""
def __init__(
self,
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:.
"""
super().__init__(
provider=provider,
contract_address=contract_address,
private_key=private_key,
)
if not validator:
validator = LibDummyValidator(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=LibDummy.abi()
)
@staticmethod
def abi():
"""Return the ABI to the underlying contract."""
return json.loads(
'[]' # noqa: E501 (line-too-long)
)
# pylint: disable=too-many-lines

View File

@@ -1,8 +1,17 @@
"""Generated wrapper for TestLibDummy Solidity contract."""
import json
from typing import Optional, Tuple, Union
# pylint: disable=too-many-arguments
import json
from typing import ( # pylint: disable=unused-import
Any,
List,
Optional,
Tuple,
Union,
)
from mypy_extensions import TypedDict # pylint: disable=unused-import
from hexbytes import HexBytes
from web3.datastructures import AttributeDict
from web3.providers.base import BaseProvider
@@ -11,6 +20,47 @@ from zero_ex.contract_wrappers._base_contract_wrapper import BaseContractWrapper
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.
try:
# both mypy and pylint complain about what we're doing here, but this
# works just fine, so their messages have been disabled here.
from . import ( # type: ignore # pylint: disable=import-self
TestLibDummyValidator,
)
except ImportError:
class TestLibDummyValidator(TestLibDummyValidatorBase): # type: ignore
"""No-op input validator."""
# pylint: disable=too-many-public-methods
class TestLibDummy(BaseContractWrapper):
"""Wrapper class for TestLibDummy Solidity contract."""
@@ -18,6 +68,7 @@ class TestLibDummy(BaseContractWrapper):
self,
provider: BaseProvider,
contract_address: str,
validator: TestLibDummyValidator = None,
private_key: str = None,
):
"""Get an instance of wrapper for smart contract.
@@ -34,6 +85,11 @@ class TestLibDummy(BaseContractWrapper):
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.
@@ -50,12 +106,18 @@ class TestLibDummy(BaseContractWrapper):
) -> int:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
self.validator.assert_valid(
method_name='publicAddConstant',
parameter_name='x',
argument_value=x,
)
# safeguard against fractional inputs
x = int(x)
func = self._get_contract_instance(
self._contract_address
self.contract_address
).functions.publicAddConstant(
x
)
@@ -72,12 +134,18 @@ class TestLibDummy(BaseContractWrapper):
) -> int:
"""Execute underlying, same-named contract method.
:param tx_params: transaction parameters
"""
self.validator.assert_valid(
method_name='publicAddOne',
parameter_name='x',
argument_value=x,
)
# safeguard against fractional inputs
x = int(x)
func = self._get_contract_instance(
self._contract_address
self.contract_address
).functions.publicAddOne(
x
)
@@ -93,3 +161,5 @@ class TestLibDummy(BaseContractWrapper):
return json.loads(
'[{"constant":true,"inputs":[{"name":"x","type":"uint256"}],"name":"publicAddConstant","outputs":[{"name":"result","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"x","type":"uint256"}],"name":"publicAddOne","outputs":[{"name":"result","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"}]' # noqa: E501 (line-too-long)
)
# pylint: disable=too-many-lines

View File

@@ -23,6 +23,16 @@ import { assert } from '@0x/assert';
import * as ethers from 'ethers';
// tslint:enable:no-unused-variable
export type AbiGenDummyEventArgs = AbiGenDummyAnEventEventArgs;
export enum AbiGenDummyEvents {
AnEvent = 'AnEvent',
}
export interface AbiGenDummyAnEventEventArgs extends DecodedLogArgs {
param: number;
}
/* istanbul ignore next */
// tslint:disable:no-parameter-reassignment
// tslint:disable-next-line:class-name
@@ -65,6 +75,46 @@ export class AbiGenDummyContract extends BaseContract {
return abiEncodedTransactionData;
},
};
public acceptsAnArrayOfBytes = {
async callAsync(a: string[], callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<void> {
assert.isArray('a', a);
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
schemas.jsNumber,
]);
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('acceptsAnArrayOfBytes(bytes[])', [a]);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
...callData,
data: encodedData,
},
self._web3Wrapper.getContractDefaults(),
);
callDataWithDefaults.from = callDataWithDefaults.from
? callDataWithDefaults.from.toLowerCase()
: callDataWithDefaults.from;
const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('acceptsAnArrayOfBytes(bytes[])');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<void>(rawCallResult);
// tslint:enable boolean-naming
return result;
},
getABIEncodedTransactionData(a: string[]): string {
assert.isArray('a', a);
const self = (this as any) as AbiGenDummyContract;
const abiEncodedTransactionData = self._strictEncodeArguments('acceptsAnArrayOfBytes(bytes[])', [a]);
return abiEncodedTransactionData;
},
};
public ecrecoverFn = {
async callAsync(
hash: string,
@@ -126,6 +176,46 @@ export class AbiGenDummyContract extends BaseContract {
return abiEncodedTransactionData;
},
};
public acceptsBytes = {
async callAsync(a: string, callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<void> {
assert.isString('a', a);
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
schemas.jsNumber,
]);
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('acceptsBytes(bytes)', [a]);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
...callData,
data: encodedData,
},
self._web3Wrapper.getContractDefaults(),
);
callDataWithDefaults.from = callDataWithDefaults.from
? callDataWithDefaults.from.toLowerCase()
: callDataWithDefaults.from;
const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('acceptsBytes(bytes)');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<void>(rawCallResult);
// tslint:enable boolean-naming
return result;
},
getABIEncodedTransactionData(a: string): string {
assert.isString('a', a);
const self = (this as any) as AbiGenDummyContract;
const abiEncodedTransactionData = self._strictEncodeArguments('acceptsBytes(bytes)', [a]);
return abiEncodedTransactionData;
},
};
public revertWithConstant = {
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<void> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
@@ -202,6 +292,53 @@ export class AbiGenDummyContract extends BaseContract {
return abiEncodedTransactionData;
},
};
public nestedStructOutput = {
async callAsync(
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<{
innerStruct: { someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string };
description: string;
}> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
schemas.jsNumber,
]);
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('nestedStructOutput()', []);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
...callData,
data: encodedData,
},
self._web3Wrapper.getContractDefaults(),
);
callDataWithDefaults.from = callDataWithDefaults.from
? callDataWithDefaults.from.toLowerCase()
: callDataWithDefaults.from;
const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('nestedStructOutput()');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<{
innerStruct: { someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string };
description: string;
}>(rawCallResult);
// tslint:enable boolean-naming
return result;
},
getABIEncodedTransactionData(): string {
const self = (this as any) as AbiGenDummyContract;
const abiEncodedTransactionData = self._strictEncodeArguments('nestedStructOutput()', []);
return abiEncodedTransactionData;
},
};
public requireWithConstant = {
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<void> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
@@ -302,6 +439,150 @@ export class AbiGenDummyContract extends BaseContract {
return abiEncodedTransactionData;
},
};
public structInput = {
async callAsync(
s: { someBytes: string; anInteger: number | BigNumber; aDynamicArrayOfBytes: string[]; aString: string },
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<void> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
schemas.jsNumber,
]);
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('structInput((bytes,uint32,bytes[],string))', [s]);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
...callData,
data: encodedData,
},
self._web3Wrapper.getContractDefaults(),
);
callDataWithDefaults.from = callDataWithDefaults.from
? callDataWithDefaults.from.toLowerCase()
: callDataWithDefaults.from;
const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('structInput((bytes,uint32,bytes[],string))');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<void>(rawCallResult);
// tslint:enable boolean-naming
return result;
},
getABIEncodedTransactionData(s: {
someBytes: string;
anInteger: number | BigNumber;
aDynamicArrayOfBytes: string[];
aString: string;
}): string {
const self = (this as any) as AbiGenDummyContract;
const abiEncodedTransactionData = self._strictEncodeArguments(
'structInput((bytes,uint32,bytes[],string))',
[s],
);
return abiEncodedTransactionData;
},
};
public nonPureMethod = {
async sendTransactionAsync(txData?: Partial<TxData> | undefined): Promise<string> {
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('nonPureMethod()', []);
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
...txData,
data: encodedData,
},
self._web3Wrapper.getContractDefaults(),
self.nonPureMethod.estimateGasAsync.bind(self),
);
if (txDataWithDefaults.from !== undefined) {
txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase();
}
const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
return txHash;
},
awaitTransactionSuccessAsync(
txData?: Partial<TxData>,
pollingIntervalMs?: number,
timeoutMs?: number,
): PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs> {
const self = (this as any) as AbiGenDummyContract;
const txHashPromise = self.nonPureMethod.sendTransactionAsync(txData);
return new PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs>(
txHashPromise,
(async (): Promise<TransactionReceiptWithDecodedLogs> => {
// When the transaction hash resolves, wait for it to be mined.
return self._web3Wrapper.awaitTransactionSuccessAsync(
await txHashPromise,
pollingIntervalMs,
timeoutMs,
);
})(),
);
},
async estimateGasAsync(txData?: Partial<TxData> | undefined): Promise<number> {
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('nonPureMethod()', []);
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
...txData,
data: encodedData,
},
self._web3Wrapper.getContractDefaults(),
);
if (txDataWithDefaults.from !== undefined) {
txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase();
}
const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
return gas;
},
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<BigNumber> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
schemas.jsNumber,
]);
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('nonPureMethod()', []);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
...callData,
data: encodedData,
},
self._web3Wrapper.getContractDefaults(),
);
callDataWithDefaults.from = callDataWithDefaults.from
? callDataWithDefaults.from.toLowerCase()
: callDataWithDefaults.from;
const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('nonPureMethod()');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<BigNumber>(rawCallResult);
// tslint:enable boolean-naming
return result;
},
getABIEncodedTransactionData(): string {
const self = (this as any) as AbiGenDummyContract;
const abiEncodedTransactionData = self._strictEncodeArguments('nonPureMethod()', []);
return abiEncodedTransactionData;
},
};
public simplePureFunctionWithInput = {
async callAsync(x: BigNumber, callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<BigNumber> {
assert.isBigNumber('x', x);
@@ -342,6 +623,100 @@ export class AbiGenDummyContract extends BaseContract {
return abiEncodedTransactionData;
},
};
public nonPureMethodThatReturnsNothing = {
async sendTransactionAsync(txData?: Partial<TxData> | undefined): Promise<string> {
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('nonPureMethodThatReturnsNothing()', []);
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
...txData,
data: encodedData,
},
self._web3Wrapper.getContractDefaults(),
self.nonPureMethodThatReturnsNothing.estimateGasAsync.bind(self),
);
if (txDataWithDefaults.from !== undefined) {
txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase();
}
const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
return txHash;
},
awaitTransactionSuccessAsync(
txData?: Partial<TxData>,
pollingIntervalMs?: number,
timeoutMs?: number,
): PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs> {
const self = (this as any) as AbiGenDummyContract;
const txHashPromise = self.nonPureMethodThatReturnsNothing.sendTransactionAsync(txData);
return new PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs>(
txHashPromise,
(async (): Promise<TransactionReceiptWithDecodedLogs> => {
// When the transaction hash resolves, wait for it to be mined.
return self._web3Wrapper.awaitTransactionSuccessAsync(
await txHashPromise,
pollingIntervalMs,
timeoutMs,
);
})(),
);
},
async estimateGasAsync(txData?: Partial<TxData> | undefined): Promise<number> {
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('nonPureMethodThatReturnsNothing()', []);
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
...txData,
data: encodedData,
},
self._web3Wrapper.getContractDefaults(),
);
if (txDataWithDefaults.from !== undefined) {
txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase();
}
const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
return gas;
},
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<void> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
schemas.jsNumber,
]);
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('nonPureMethodThatReturnsNothing()', []);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
...callData,
data: encodedData,
},
self._web3Wrapper.getContractDefaults(),
);
callDataWithDefaults.from = callDataWithDefaults.from
? callDataWithDefaults.from.toLowerCase()
: callDataWithDefaults.from;
const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('nonPureMethodThatReturnsNothing()');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<void>(rawCallResult);
// tslint:enable boolean-naming
return result;
},
getABIEncodedTransactionData(): string {
const self = (this as any) as AbiGenDummyContract;
const abiEncodedTransactionData = self._strictEncodeArguments('nonPureMethodThatReturnsNothing()', []);
return abiEncodedTransactionData;
},
};
public simplePureFunction = {
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<BigNumber> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
@@ -380,6 +755,116 @@ export class AbiGenDummyContract extends BaseContract {
return abiEncodedTransactionData;
},
};
public nestedStructInput = {
async callAsync(
n: {
innerStruct: {
someBytes: string;
anInteger: number | BigNumber;
aDynamicArrayOfBytes: string[];
aString: string;
};
description: string;
},
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<void> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
schemas.jsNumber,
]);
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments(
'nestedStructInput(((bytes,uint32,bytes[],string),string))',
[n],
);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
...callData,
data: encodedData,
},
self._web3Wrapper.getContractDefaults(),
);
callDataWithDefaults.from = callDataWithDefaults.from
? callDataWithDefaults.from.toLowerCase()
: callDataWithDefaults.from;
const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('nestedStructInput(((bytes,uint32,bytes[],string),string))');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<void>(rawCallResult);
// tslint:enable boolean-naming
return result;
},
getABIEncodedTransactionData(n: {
innerStruct: {
someBytes: string;
anInteger: number | BigNumber;
aDynamicArrayOfBytes: string[];
aString: string;
};
description: string;
}): string {
const self = (this as any) as AbiGenDummyContract;
const abiEncodedTransactionData = self._strictEncodeArguments(
'nestedStructInput(((bytes,uint32,bytes[],string),string))',
[n],
);
return abiEncodedTransactionData;
},
};
public structOutput = {
async callAsync(
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<{ someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string }> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
schemas.jsNumber,
]);
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('structOutput()', []);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
...callData,
data: encodedData,
},
self._web3Wrapper.getContractDefaults(),
);
callDataWithDefaults.from = callDataWithDefaults.from
? callDataWithDefaults.from.toLowerCase()
: callDataWithDefaults.from;
const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock);
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('structOutput()');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<{
someBytes: string;
anInteger: number;
aDynamicArrayOfBytes: string[];
aString: string;
}>(rawCallResult);
// tslint:enable boolean-naming
return result;
},
getABIEncodedTransactionData(): string {
const self = (this as any) as AbiGenDummyContract;
const abiEncodedTransactionData = self._strictEncodeArguments('structOutput()', []);
return abiEncodedTransactionData;
},
};
public pureFunctionWithConstant = {
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<BigNumber> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
@@ -483,6 +968,20 @@ export class AbiGenDummyContract extends BaseContract {
stateMutability: 'pure',
type: 'function',
},
{
constant: true,
inputs: [
{
name: 'a',
type: 'bytes[]',
},
],
name: 'acceptsAnArrayOfBytes',
outputs: [],
payable: false,
stateMutability: 'pure',
type: 'function',
},
{
constant: true,
inputs: [
@@ -514,6 +1013,20 @@ export class AbiGenDummyContract extends BaseContract {
stateMutability: 'pure',
type: 'function',
},
{
constant: true,
inputs: [
{
name: 'a',
type: 'bytes',
},
],
name: 'acceptsBytes',
outputs: [],
payable: false,
stateMutability: 'pure',
type: 'function',
},
{
constant: true,
inputs: [],
@@ -532,6 +1045,48 @@ export class AbiGenDummyContract extends BaseContract {
stateMutability: 'pure',
type: 'function',
},
{
constant: true,
inputs: [],
name: 'nestedStructOutput',
outputs: [
{
name: '',
type: 'tuple',
components: [
{
name: 'innerStruct',
type: 'tuple',
components: [
{
name: 'someBytes',
type: 'bytes',
},
{
name: 'anInteger',
type: 'uint32',
},
{
name: 'aDynamicArrayOfBytes',
type: 'bytes[]',
},
{
name: 'aString',
type: 'string',
},
],
},
{
name: 'description',
type: 'string',
},
],
},
],
payable: false,
stateMutability: 'pure',
type: 'function',
},
{
constant: true,
inputs: [],
@@ -576,6 +1131,52 @@ export class AbiGenDummyContract extends BaseContract {
stateMutability: 'pure',
type: 'function',
},
{
constant: true,
inputs: [
{
name: 's',
type: 'tuple',
components: [
{
name: 'someBytes',
type: 'bytes',
},
{
name: 'anInteger',
type: 'uint32',
},
{
name: 'aDynamicArrayOfBytes',
type: 'bytes[]',
},
{
name: 'aString',
type: 'string',
},
],
},
],
name: 'structInput',
outputs: [],
payable: false,
stateMutability: 'pure',
type: 'function',
},
{
constant: false,
inputs: [],
name: 'nonPureMethod',
outputs: [
{
name: '',
type: 'uint256',
},
],
payable: false,
stateMutability: 'nonpayable',
type: 'function',
},
{
constant: true,
inputs: [
@@ -595,6 +1196,15 @@ export class AbiGenDummyContract extends BaseContract {
stateMutability: 'pure',
type: 'function',
},
{
constant: false,
inputs: [],
name: 'nonPureMethodThatReturnsNothing',
outputs: [],
payable: false,
stateMutability: 'nonpayable',
type: 'function',
},
{
constant: true,
inputs: [],
@@ -609,6 +1219,80 @@ export class AbiGenDummyContract extends BaseContract {
stateMutability: 'pure',
type: 'function',
},
{
constant: true,
inputs: [
{
name: 'n',
type: 'tuple',
components: [
{
name: 'innerStruct',
type: 'tuple',
components: [
{
name: 'someBytes',
type: 'bytes',
},
{
name: 'anInteger',
type: 'uint32',
},
{
name: 'aDynamicArrayOfBytes',
type: 'bytes[]',
},
{
name: 'aString',
type: 'string',
},
],
},
{
name: 'description',
type: 'string',
},
],
},
],
name: 'nestedStructInput',
outputs: [],
payable: false,
stateMutability: 'pure',
type: 'function',
},
{
constant: true,
inputs: [],
name: 'structOutput',
outputs: [
{
name: 's',
type: 'tuple',
components: [
{
name: 'someBytes',
type: 'bytes',
},
{
name: 'anInteger',
type: 'uint32',
},
{
name: 'aDynamicArrayOfBytes',
type: 'bytes[]',
},
{
name: 'aString',
type: 'string',
},
],
},
],
payable: false,
stateMutability: 'pure',
type: 'function',
},
{
constant: true,
inputs: [],
@@ -623,6 +1307,19 @@ export class AbiGenDummyContract extends BaseContract {
stateMutability: 'pure',
type: 'function',
},
{
anonymous: false,
inputs: [
{
name: 'param',
type: 'uint8',
indexed: false,
},
],
name: 'AnEvent',
outputs: [],
type: 'event',
},
] as ContractAbi;
return abi;
}

File diff suppressed because one or more lines are too long

View File

@@ -3,17 +3,20 @@
"contractName": "LibDummy",
"compilerOutput": {
"abi": [],
"devdoc": {
"methods": {}
},
"evm": {
"bytecode": {
"linkReferences": {},
"object": "0x60556023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea265627a7a72305820a278ce8d53a26107b2f2ba78687fa040ee9ab2ecf0e44ebff0f9410c586e0c6d64736f6c634300050a0032",
"opcodes": "PUSH1 0x55 PUSH1 0x23 PUSH1 0xB DUP3 DUP3 DUP3 CODECOPY DUP1 MLOAD PUSH1 0x0 BYTE PUSH1 0x73 EQ PUSH1 0x16 JUMPI INVALID JUMPDEST ADDRESS PUSH1 0x0 MSTORE PUSH1 0x73 DUP2 MSTORE8 DUP3 DUP2 RETURN INVALID PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 LOG2 PUSH25 0xCE8D53A26107B2F2BA78687FA040EE9AB2ECF0E44EBFF0F941 0xc PC PUSH15 0xC6D64736F6C634300050A00320000 ",
"object": "0x60556023600b82828239805160001a607314601657fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea265627a7a72305820b14322cd05aa1dcae66812e472d3ab85cced78118ea7f9a5098d073b2accc45964736f6c634300050a0032",
"opcodes": "PUSH1 0x55 PUSH1 0x23 PUSH1 0xB DUP3 DUP3 DUP3 CODECOPY DUP1 MLOAD PUSH1 0x0 BYTE PUSH1 0x73 EQ PUSH1 0x16 JUMPI INVALID JUMPDEST ADDRESS PUSH1 0x0 MSTORE PUSH1 0x73 DUP2 MSTORE8 DUP3 DUP2 RETURN INVALID PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 0xb1 NUMBER 0x22 0xcd SDIV 0xaa SAR 0xca 0xe6 PUSH9 0x12E472D3AB85CCED78 GT DUP15 0xa7 0xf9 0xa5 MULMOD DUP14 SMOD EXTCODESIZE 0x2a 0xcc 0xc4 MSIZE PUSH5 0x736F6C6343 STOP SDIV EXP STOP ORIGIN ",
"sourceMap": "606:385:1:-;;132:2:-1;166:7;155:9;146:7;137:37;255:7;249:14;246:1;241:23;235:4;232:33;222:2;;269:9;222:2;293:9;290:1;283:20;323:4;314:7;306:22;347:7;338;331:24"
},
"deployedBytecode": {
"linkReferences": {},
"object": "0x73000000000000000000000000000000000000000030146080604052600080fdfea265627a7a72305820a278ce8d53a26107b2f2ba78687fa040ee9ab2ecf0e44ebff0f9410c586e0c6d64736f6c634300050a0032",
"opcodes": "PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 LOG2 PUSH25 0xCE8D53A26107B2F2BA78687FA040EE9AB2ECF0E44EBFF0F941 0xc PC PUSH15 0xC6D64736F6C634300050A00320000 ",
"object": "0x73000000000000000000000000000000000000000030146080604052600080fdfea265627a7a72305820b14322cd05aa1dcae66812e472d3ab85cced78118ea7f9a5098d073b2accc45964736f6c634300050a0032",
"opcodes": "PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 0xb1 NUMBER 0x22 0xcd SDIV 0xaa SAR 0xca 0xe6 PUSH9 0x12E472D3AB85CCED78 GT DUP15 0xa7 0xf9 0xa5 MULMOD DUP14 SMOD EXTCODESIZE 0x2a 0xcc 0xc4 MSIZE PUSH5 0x736F6C6343 STOP SDIV EXP STOP ORIGIN ",
"sourceMap": "606:385:1:-;;;;;;;;"
}
}
@@ -48,7 +51,8 @@
"evm.bytecode.object",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.object",
"evm.deployedBytecode.sourceMap"
"evm.deployedBytecode.sourceMap",
"devdoc"
]
}
},

View File

@@ -42,17 +42,20 @@
"type": "function"
}
],
"devdoc": {
"methods": {}
},
"evm": {
"bytecode": {
"linkReferences": {},
"object": "0x608060405234801561001057600080fd5b5060d78061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806322935e921460375780632b82fdf0146063575b600080fd5b605160048036036020811015604b57600080fd5b5035607d565b60408051918252519081900360200190f35b605160048036036020811015607757600080fd5b5035608c565b60006086826095565b92915050565b6000608682609c565b6104d20190565b6001019056fea265627a7a72305820c97345939b2d163165dee7bdfbbd7ca281c5bdaea7b03de53b0ceb32b097cdf864736f6c634300050a0032",
"opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0xD7 DUP1 PUSH2 0x1F PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH1 0x32 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x22935E92 EQ PUSH1 0x37 JUMPI DUP1 PUSH4 0x2B82FDF0 EQ PUSH1 0x63 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x51 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH1 0x4B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH1 0x7D JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH1 0x51 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH1 0x77 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH1 0x8C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x86 DUP3 PUSH1 0x95 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x86 DUP3 PUSH1 0x9C JUMP JUMPDEST PUSH2 0x4D2 ADD SWAP1 JUMP JUMPDEST PUSH1 0x1 ADD SWAP1 JUMP INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 0xc9 PUSH20 0x45939B2D163165DEE7BDFBBD7CA281C5BDAEA7B0 RETURNDATASIZE 0xe5 EXTCODESIZE 0xc 0xeb ORIGIN 0xb0 SWAP8 0xcd 0xf8 PUSH5 0x736F6C6343 STOP SDIV EXP STOP ORIGIN ",
"object": "0x608060405234801561001057600080fd5b5060d78061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806322935e921460375780632b82fdf0146063575b600080fd5b605160048036036020811015604b57600080fd5b5035607d565b60408051918252519081900360200190f35b605160048036036020811015607757600080fd5b5035608c565b60006086826095565b92915050565b6000608682609c565b6104d20190565b6001019056fea265627a7a72305820ddb720d14b34694daaefebcbd729af6ae04fa2232481812dd8fde63d6a4c32c164736f6c634300050a0032",
"opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0xD7 DUP1 PUSH2 0x1F PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH1 0x32 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x22935E92 EQ PUSH1 0x37 JUMPI DUP1 PUSH4 0x2B82FDF0 EQ PUSH1 0x63 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x51 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH1 0x4B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH1 0x7D JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH1 0x51 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH1 0x77 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH1 0x8C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x86 DUP3 PUSH1 0x95 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x86 DUP3 PUSH1 0x9C JUMP JUMPDEST PUSH2 0x4D2 ADD SWAP1 JUMP JUMPDEST PUSH1 0x1 ADD SWAP1 JUMP INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 0xdd 0xb7 KECCAK256 0xd1 0x4b CALLVALUE PUSH10 0x4DAAEFEBCBD729AF6AE0 0x4f LOG2 0x23 0x24 DUP2 DUP2 0x2d 0xd8 REVERT 0xe6 RETURNDATASIZE PUSH11 0x4C32C164736F6C63430005 EXP STOP ORIGIN ",
"sourceMap": "632:346:2:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;632:346:2;;;;;;;"
},
"deployedBytecode": {
"linkReferences": {},
"object": "0x6080604052348015600f57600080fd5b506004361060325760003560e01c806322935e921460375780632b82fdf0146063575b600080fd5b605160048036036020811015604b57600080fd5b5035607d565b60408051918252519081900360200190f35b605160048036036020811015607757600080fd5b5035608c565b60006086826095565b92915050565b6000608682609c565b6104d20190565b6001019056fea265627a7a72305820c97345939b2d163165dee7bdfbbd7ca281c5bdaea7b03de53b0ceb32b097cdf864736f6c634300050a0032",
"opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH1 0x32 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x22935E92 EQ PUSH1 0x37 JUMPI DUP1 PUSH4 0x2B82FDF0 EQ PUSH1 0x63 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x51 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH1 0x4B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH1 0x7D JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH1 0x51 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH1 0x77 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH1 0x8C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x86 DUP3 PUSH1 0x95 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x86 DUP3 PUSH1 0x9C JUMP JUMPDEST PUSH2 0x4D2 ADD SWAP1 JUMP JUMPDEST PUSH1 0x1 ADD SWAP1 JUMP INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 0xc9 PUSH20 0x45939B2D163165DEE7BDFBBD7CA281C5BDAEA7B0 RETURNDATASIZE 0xe5 EXTCODESIZE 0xc 0xeb ORIGIN 0xb0 SWAP8 0xcd 0xf8 PUSH5 0x736F6C6343 STOP SDIV EXP STOP ORIGIN ",
"object": "0x6080604052348015600f57600080fd5b506004361060325760003560e01c806322935e921460375780632b82fdf0146063575b600080fd5b605160048036036020811015604b57600080fd5b5035607d565b60408051918252519081900360200190f35b605160048036036020811015607757600080fd5b5035608c565b60006086826095565b92915050565b6000608682609c565b6104d20190565b6001019056fea265627a7a72305820ddb720d14b34694daaefebcbd729af6ae04fa2232481812dd8fde63d6a4c32c164736f6c634300050a0032",
"opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH1 0x32 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x22935E92 EQ PUSH1 0x37 JUMPI DUP1 PUSH4 0x2B82FDF0 EQ PUSH1 0x63 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x51 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH1 0x4B JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH1 0x7D JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH1 0x51 PUSH1 0x4 DUP1 CALLDATASIZE SUB PUSH1 0x20 DUP2 LT ISZERO PUSH1 0x77 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD PUSH1 0x8C JUMP JUMPDEST PUSH1 0x0 PUSH1 0x86 DUP3 PUSH1 0x95 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x86 DUP3 PUSH1 0x9C JUMP JUMPDEST PUSH2 0x4D2 ADD SWAP1 JUMP JUMPDEST PUSH1 0x1 ADD SWAP1 JUMP INVALID LOG2 PUSH6 0x627A7A723058 KECCAK256 0xdd 0xb7 KECCAK256 0xd1 0x4b CALLVALUE PUSH10 0x4DAAEFEBCBD729AF6AE0 0x4f LOG2 0x23 0x24 DUP2 DUP2 0x2d 0xd8 REVERT 0xe6 RETURNDATASIZE PUSH11 0x4C32C164736F6C63430005 EXP STOP ORIGIN ",
"sourceMap": "632:346:2:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;632:346:2;;;;;;;;;;;;;;;;;;;;;;;;833:143;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;833:143:2;;:::i;:::-;;;;;;;;;;;;;;;;694:133;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;694:133:2;;:::i;833:143::-;917:14;954:15;:1;:13;:15::i;:::-;947:22;833:143;-1:-1:-1;;833:143:2:o;694:133::-;773:14;810:10;:1;:8;:10::i;842:147:1:-;704:4;965:17;;842:147::o;715:121::-;828:1;824:5;;715:121::o"
}
}
@@ -91,7 +94,8 @@
"evm.bytecode.object",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.object",
"evm.deployedBytecode.sourceMap"
"evm.deployedBytecode.sourceMap",
"devdoc"
]
}
},

View File

@@ -16,6 +16,8 @@
*/
pragma experimental ABIEncoderV2;
pragma solidity ^0.5.5;
@@ -98,4 +100,36 @@ contract AbiGenDummy
return x;
}
event AnEvent(uint8 param);
function acceptsBytes(bytes memory a) public pure {}
/// @dev a method that accepts an array of bytes
/// @param a the array of bytes being accepted
function acceptsAnArrayOfBytes(bytes[] memory a) public pure {}
struct Struct {
bytes someBytes;
uint32 anInteger;
bytes[] aDynamicArrayOfBytes;
string aString;
}
function structInput(Struct memory s) public pure {}
/// @dev a method that returns a struct
/// @return a Struct struct
function structOutput() public pure returns(Struct memory s) {}
struct NestedStruct {
Struct innerStruct;
string description;
}
function nestedStructInput(NestedStruct memory n) public pure {}
function nestedStructOutput() public pure returns(NestedStruct memory) {}
uint someState;
function nonPureMethod() public returns(uint) { return someState += 1; }
function nonPureMethodThatReturnsNothing() public { someState += 1; }
}

View File

@@ -1,4 +1,13 @@
[
{
"version": "9.1.8",
"changes": [
{
"note": "re-export new ethereum-types type, TupleDataItem",
"pr": 1919
}
]
},
{
"timestamp": 1563193019,
"version": "9.1.7",

View File

@@ -105,6 +105,7 @@ export {
ConstructorAbi,
FallbackAbi,
DataItem,
TupleDataItem,
ConstructorStateMutability,
StateMutability,
Web3JsProvider,

View File

@@ -1,4 +1,13 @@
[
{
"version": "2.1.4",
"changes": [
{
"note": "new interface TupleDataItem, a DataItem that definitely has a `components` field",
"pr": 1919
}
]
},
{
"version": "2.1.3",
"changes": [

View File

@@ -131,6 +131,10 @@ export interface DataItem {
components?: DataItem[];
}
export interface TupleDataItem extends DataItem {
components: DataItem[];
}
export enum OpCode {
// 0s: Stop and Arithmetic Operations
Stop = 'STOP',

View File

@@ -1,4 +1,12 @@
[
{
"version": "3.1.11",
"changes": [
{
"note": "permit mixed-case addresses"
}
]
},
{
"timestamp": 1563006338,
"version": "3.0.11",

View File

@@ -1,5 +1,5 @@
{
"id": "/addressSchema",
"type": "string",
"pattern": "^0x[0-9a-f]{40}$"
"pattern": "^0x[0-9a-fA-F]{40}$"
}

View File

@@ -91,13 +91,7 @@ describe('Schema', () => {
validateAgainstSchema(testCases, addressSchema);
});
it('should fail for invalid addresses', () => {
const testCases = [
'0x',
'0',
'0x00',
'0xzzzzzzB11a196601eD2ce54B665CaFEca0347D42',
'0x8b0292B11a196601eD2ce54B665CaFEca0347D42',
];
const testCases = ['0x', '0', '0x00', '0xzzzzzzB11a196601eD2ce54B665CaFEca0347D42'];
const shouldFail = true;
validateAgainstSchema(testCases, addressSchema, shouldFail);
});
@@ -730,7 +724,7 @@ describe('Schema', () => {
validateAgainstSchema(testCases, relayerApiOrdersChannelSubscribeSchema);
});
it('should fail for invalid orders channel websocket subscribe message', () => {
const checksummedAddress = '0xA2b31daCf30a9C50ca473337c01d8A201ae33e32';
const bogusAddress = '0xz2b31daCf30a9C50ca473337c01d8A201ae33e32';
const testCases = [
{
type: 'subscribe',
@@ -743,7 +737,7 @@ describe('Schema', () => {
payload: {
makerAssetProxyId: '0x02571792',
takerAssetProxyId: '0xf47261b0',
makerAssetAddress: checksummedAddress,
makerAssetAddress: bogusAddress,
},
},
{

View File

@@ -5,6 +5,10 @@
{
"note": "Initial commit. Functionality tested for ERC20Token wrapper",
"pr": 1878
},
{
"note": "Include the Exchange contract in the list of generation targets",
"pr": 1919
}
]
}

View File

@@ -13,7 +13,7 @@
"clean": "shx rm -rf generated"
},
"config": {
"abis": "../contract-artifacts/artifacts/ERC20Token.json"
"abis": "../contract-artifacts/artifacts/{Exchange,ERC20Token}.json"
},
"repository": {
"type": "git",

View File

@@ -1,4 +1,13 @@
[
{
"version": "3.1.10",
"changes": [
{
"note": "re-export new ethereum-types types, TupleDataItem",
"pr": 1919
}
]
},
{
"timestamp": 1563006338,
"version": "3.1.9",

View File

@@ -4,6 +4,7 @@ export {
CompilerOptions,
CompilerSettings,
DataItem,
TupleDataItem,
DevdocOutput,
ErrorSeverity,
ErrorType,

View File

@@ -1,4 +1,13 @@
[
{
"version": "6.0.8",
"changes": [
{
"note": "re-export new ethereum-types types, TupleDataItem",
"pr": 1919
}
]
},
{
"timestamp": 1563006338,
"version": "6.0.7",

View File

@@ -43,6 +43,7 @@ export {
ConstructorAbi,
FallbackAbi,
DataItem,
TupleDataItem,
ConstructorStateMutability,
StateMutability,
Web3JsProvider,

3
python-packages/build_docs Executable file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
./parallel ./setup.py build_sphinx

View File

@@ -186,6 +186,7 @@ setup(
"build_sphinx": {
"source_dir": ("setup.py", "src"),
"build_dir": ("setup.py", "build/docs"),
"warning_is_error": ("setup.py", "true"),
}
},
)

View File

@@ -60,15 +60,6 @@ class LintCommand(distutils.command.build_py.build_py):
"mypy src setup.py".split(),
# security issue checker:
"bandit -r src ./setup.py".split(),
# HACK: ensure contract artifacts match the authoritative copies:
# this is a hack. ideally we would symlink to the authoritative
# copies, but a problem with setuptools is preventing it from
# following symlinks when gathering package_data. see
# https://github.com/pypa/setuptools/issues/415.
(
"diff src/zero_ex/contract_artifacts/artifacts"
+ " ../../packages/contract-artifacts/artifacts"
).split(),
# general linter:
"pylint src setup.py".split(),
# pylint takes relatively long to run, so it runs last, to enable
@@ -225,6 +216,7 @@ setup(
"build_sphinx": {
"source_dir": ("setup.py", "src"),
"build_dir": ("setup.py", "build/docs"),
"warning_is_error": ("setup.py", "true"),
}
},
)

View File

@@ -1,6 +1,3 @@
[MESSAGES CONTROL]
disable=C0330,line-too-long,fixme,too-few-public-methods,too-many-ancestors
disable=C0330,line-too-long,fixme,too-few-public-methods,too-many-ancestors,duplicate-code
# C0330 is "bad hanging indent". we use indents per `black`.
[SIMILARITIES]
min-similarity-lines=12

View File

@@ -1,5 +1,9 @@
# Changelog
## 2.0.0 - TBD
- Completely new implementation of the Exchange wrapper, virtually all auto-generated from the Solidity contract. Breaking changes include method parameter name changes and accepting of signatures as bytes.
## 1.0.0 - 2019-04-30
- Initial release.

View File

@@ -4,7 +4,7 @@
import subprocess # nosec
from shutil import copy, rmtree
from os import environ, path
from os import environ, path, remove
from pathlib import Path
from sys import argv
from importlib.util import find_spec
@@ -34,17 +34,37 @@ class PreInstallCommand(distutils.command.build_py.build_py):
"packages",
"python-contract-wrappers",
"generated",
"erc20_token.py",
"erc20_token",
"__init__.py",
),
path.join(
pkgdir, "src", "zero_ex", "contract_wrappers", "erc20_token"
),
)
copy(
path.join(
pkgdir,
"..",
"..",
"packages",
"python-contract-wrappers",
"generated",
"exchange",
"__init__.py",
),
path.join(
pkgdir, "src", "zero_ex", "contract_wrappers", "exchange"
),
path.join(pkgdir, "src", "zero_ex", "contract_wrappers"),
)
if find_spec("black") is None:
subprocess.check_call("pip install black".split()) # nosec
subprocess.check_call( # nosec
(
BLACK_COMMAND + " src/zero_ex/contract_wrappers/erc20_token.py"
).split()
black_command = (
BLACK_COMMAND
+ " src/zero_ex/contract_wrappers/erc20_token/__init__.py"
+ " src/zero_ex/contract_wrappers/exchange/__init__.py"
)
print(f"Running command `{black_command}`...")
subprocess.check_call(black_command.split()) # nosec
class TestCommandExtension(TestCommand):
@@ -112,6 +132,9 @@ class CleanCommandExtension(clean):
rmtree(".tox", ignore_errors=True)
rmtree(".pytest_cache", ignore_errors=True)
rmtree("src/0x_contract_wrappers.egg-info", ignore_errors=True)
# generated files:
remove("src/zero_ex/contract_wrappers/exchange/__init__.py")
remove("src/zero_ex/contract_wrappers/erc20_token/__init__.py")
class TestPublishCommand(distutils.command.build_py.build_py):
@@ -255,6 +278,7 @@ setup(
"build_sphinx": {
"source_dir": ("setup.py", "src"),
"build_dir": ("setup.py", "build/docs"),
"warning_is_error": ("setup.py", "true"),
}
},
)

View File

@@ -31,6 +31,38 @@ zero_ex.contract_wrappers.TxParams
.. autoclass:: zero_ex.contract_wrappers.TxParams
:members:
zero_ex.contract_wrappers.exchange.types
========================================
.. automodule:: zero_ex.contract_wrappers.exchange.types
.. autoclass:: zero_ex.contract_wrappers.exchange.types.Order
.. autoclass:: zero_ex.contract_wrappers.exchange.types.OrderInfo
.. autoclass:: zero_ex.contract_wrappers.exchange.types.FillResults
.. autoclass:: zero_ex.contract_wrappers.exchange.types.MatchedFillResults
zero_ex.contract_wrappers.exchange: Generated Tuples
====================================================
.. autoclass:: zero_ex.contract_wrappers.exchange.Tuple0x260219a2
This is the generated class representing `the Order struct <https://0x.org/docs/contracts#structs-Order>`_.
.. autoclass:: zero_ex.contract_wrappers.exchange.Tuple0xbb41e5b3
This is the generated class representing `the FillResults struct <https://0x.org/docs/contracts#structs-FillResults>`_.
.. autoclass:: zero_ex.contract_wrappers.exchange.Tuple0x054ca44e
This is the generated class representing `the MatchedFillResults struct <https://0x.org/docs/contracts#structs-MatchedFillResults>`_.
.. autoclass:: zero_ex.contract_wrappers.exchange.Tuple0xb1e4a1ae
This is the generated class representing `the OrderInfo struct <https://0x.org/docs/contracts#structs-OrderInfo>`_.
Indices and tables
==================

View File

@@ -91,24 +91,24 @@ we need to tell the WETH token contract to let the 0x contracts transfer our
balance:
>>> from zero_ex.contract_wrappers import ERC20Token
>>> zrx_wrapper = ERC20Token(
>>> zrx_token = ERC20Token(
... provider=ganache,
... contract_address=NETWORK_TO_ADDRESSES[NetworkId.GANACHE].zrx_token,
... )
>>> weth_wrapper = ERC20Token(
>>> weth_token = ERC20Token(
... provider=ganache,
... contract_address=NETWORK_TO_ADDRESSES[NetworkId.GANACHE].ether_token,
... )
>>> erc20_proxy_addr = NETWORK_TO_ADDRESSES[NetworkId.GANACHE].erc20_proxy
>>> tx = zrx_wrapper.approve(
>>> tx = zrx_token.approve(
... erc20_proxy_addr,
... to_wei(100, 'ether'),
... tx_params=TxParams(from_=maker_address),
... )
>>> tx = weth_wrapper.approve(
>>> tx = weth_token.approve(
... erc20_proxy_addr,
... to_wei(100, 'ether'),
... tx_params=TxParams(from_=taker_address),
@@ -117,8 +117,8 @@ balance:
Constructing an order
---------------------
>>> from zero_ex.order_utils import asset_data_utils, Order
>>> from eth_utils import remove_0x_prefix
>>> from zero_ex.contract_wrappers.exchange.types import Order
>>> from zero_ex.order_utils import asset_data_utils
>>> from datetime import datetime, timedelta
>>> import random
>>> order = Order(
@@ -143,8 +143,8 @@ For this order to be valid, our Maker must sign a hash of it:
>>> from zero_ex.order_utils import generate_order_hash_hex
>>> order_hash_hex = generate_order_hash_hex(order, exchange_address)
>>> from zero_ex.order_utils import sign_hash
>>> maker_signature = sign_hash(
>>> from zero_ex.order_utils import sign_hash_to_bytes
>>> maker_signature = sign_hash_to_bytes(
... ganache, Web3.toChecksumAddress(maker_address), order_hash_hex
... )
@@ -162,13 +162,13 @@ fill. This example fills the order completely, but partial fills are possible
too.
>>> from zero_ex.contract_wrappers import Exchange
>>> exchange_contract = Exchange(
>>> exchange = Exchange(
... provider=ganache,
... contract_address=NETWORK_TO_ADDRESSES[NetworkId.GANACHE].exchange,
... )
>>> tx_hash = exchange_contract.fill_order(
>>> tx_hash = exchange.fill_order(
... order=order,
... taker_amount=order["takerAssetAmount"],
... taker_asset_fill_amount=order["takerAssetAmount"],
... signature=maker_signature,
... tx_params=TxParams(from_=taker_address)
... )
@@ -176,10 +176,10 @@ too.
Once the transaction is mined, we can get the details of our exchange through
the exchange wrapper:
>>> exchange_contract.get_fill_event(tx_hash)
>>> exchange.get_fill_event(tx_hash)
(AttributeDict({'args': ...({'makerAddress': ...}), 'event': 'Fill', ...}),)
>>> from pprint import pprint
>>> pprint(exchange_contract.get_fill_event(tx_hash)[0].args.__dict__)
>>> pprint(exchange.get_fill_event(tx_hash)[0].args.__dict__)
{'feeRecipientAddress': '0x0000000000000000000000000000000000000000',
'makerAddress': '0x...',
'makerAssetData': b...,
@@ -191,7 +191,7 @@ the exchange wrapper:
'takerAssetData': b...,
'takerAssetFilledAmount': 100000000000000000,
'takerFeePaid': 0}
>>> exchange_contract.get_fill_event(tx_hash)[0].args.takerAssetFilledAmount
>>> exchange.get_fill_event(tx_hash)[0].args.takerAssetFilledAmount
100000000000000000
Cancelling an order
@@ -217,23 +217,23 @@ A Maker can cancel an order that has yet to be filled.
... )
... )
>>> tx_hash = exchange_contract.cancel_order(
>>> tx_hash = exchange.cancel_order(
... order=order, tx_params=TxParams(from_=maker_address)
... )
Once the transaction is mined, we can get the details of the cancellation
through the Exchange wrapper:
>>> exchange_contract.get_cancel_event(tx_hash)
>>> exchange.get_cancel_event(tx_hash)
(AttributeDict({'args': ...({'makerAddress': ...}), 'event': 'Cancel', ...}),)
>>> pprint(exchange_contract.get_cancel_event(tx_hash)[0].args.__dict__)
>>> pprint(exchange.get_cancel_event(tx_hash)[0].args.__dict__)
{'feeRecipientAddress': '0x0000000000000000000000000000000000000000',
'makerAddress': '0x...',
'makerAssetData': b...,
'orderHash': b...,
'senderAddress': '0x...',
'takerAssetData': b...}
>>> exchange_contract.get_cancel_event(tx_hash)[0].args.feeRecipientAddress
>>> exchange.get_cancel_event(tx_hash)[0].args.feeRecipientAddress
'0x0000000000000000000000000000000000000000'
Batching orders
@@ -258,10 +258,10 @@ is an example where the taker fills two orders in one transaction:
... (datetime.utcnow() + timedelta(days=1)).timestamp()
... )
... )
>>> signature_1 = sign_hash(
>>> signature_1 = sign_hash_to_bytes(
... ganache,
... Web3.toChecksumAddress(maker_address),
... generate_order_hash_hex(order_1, exchange_contract.address)
... generate_order_hash_hex(order_1, exchange.contract_address)
... )
>>> order_2 = Order(
... makerAddress=maker_address,
@@ -279,17 +279,17 @@ is an example where the taker fills two orders in one transaction:
... (datetime.utcnow() + timedelta(days=1)).timestamp()
... )
... )
>>> signature_2 = sign_hash(
>>> signature_2 = sign_hash_to_bytes(
... ganache,
... Web3.toChecksumAddress(maker_address),
... generate_order_hash_hex(order_2, exchange_contract.address)
... generate_order_hash_hex(order_2, exchange.contract_address)
... )
Fill order_1 and order_2 together:
>>> exchange_contract.batch_fill_orders(
>>> exchange.batch_fill_orders(
... orders=[order_1, order_2],
... taker_amounts=[1, 2],
... taker_asset_fill_amounts=[1, 2],
... signatures=[signature_1, signature_2],
... tx_params=TxParams(from_=taker_address))
HexBytes('0x...')
@@ -297,4 +297,4 @@ HexBytes('0x...')
from .tx_params import TxParams
from .erc20_token import ERC20Token
from .exchange_wrapper import Exchange
from .exchange import Exchange

View File

@@ -34,7 +34,7 @@ class BaseContractWrapper:
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(
self.contract_address = self._validate_and_checksum_address(
contract_address
)
@@ -120,7 +120,7 @@ class BaseContractWrapper:
:returns: str of transaction hash
"""
contract_instance = self._contract_instance(
address=self._contract_address, abi=abi
address=self.contract_address, abi=abi
)
if args is None:
args = []
@@ -131,6 +131,6 @@ class BaseContractWrapper:
)
raise Exception(
"No method {} found on contract {}.".format(
self._contract_address, method
self.contract_address, method
)
)

View File

@@ -0,0 +1,200 @@
"""Conveniences for handling types representing Exchange Solidity structs.
The `TypedDict`:code: classes in the .exchange module represent tuples
encountered in the Exchange contract's ABI. However, they have weird names,
containing hashes of the tuple's field names, because the name of a Solidity
`struct`:code: isn't conveyed through the ABI. This module provides type
aliases with human-friendly names.
Converting between the JSON wire format and the types accepted by Web3.py (eg
`bytes` vs `str`) can be onerous. This module provides conveniences for
converting Exchange structs between JSON and Python objects.
"""
from copy import copy
from typing import cast, Dict
from eth_utils import remove_0x_prefix
from zero_ex.json_schemas import assert_valid
from . import (
Tuple0xbb41e5b3,
Tuple0x260219a2,
Tuple0x054ca44e,
Tuple0xb1e4a1ae,
)
# Would rather not repeat ourselves below, but base classes are mentioned in
# the class docstrings because of a bug in sphinx rendering. Using the `..
# autoclass` directive, with the `:show-inheritance:` role, results in docs
# being rendered with just "Bases: dict", and no mention of the direct ancestor
# of each of these classes.
class FillResults(Tuple0xbb41e5b3):
"""The `FillResults`:code: Solidity struct.
Also known as
`zero_ex.contract_wrappers.exchange.Tuple0xbb41e5b3`:py:class:.
"""
class Order(Tuple0x260219a2):
"""The `Order`:code: Solidity struct.
Also known as
`zero_ex.contract_wrappers.exchange.Tuple0x260219a2`:py:class:.
"""
class MatchedFillResults(Tuple0x054ca44e):
"""The `MatchedFillResults`:code: Solidity struct.
Also known as
`zero_ex.contract_wrappers.exchange.Tuple0x054ca44e`:py:class:.
"""
class OrderInfo(Tuple0xb1e4a1ae):
"""The `OrderInfo`:code: Solidity struct.
Also known as
`zero_ex.contract_wrappers.exchange.Tuple0xb1e4a1ae`:py:class:.
"""
def order_to_jsdict(
order: Order,
exchange_address="0x0000000000000000000000000000000000000000",
signature: str = None,
) -> dict:
"""Convert a Web3-compatible order struct to a JSON-schema-compatible dict.
More specifically, do explicit decoding for the `bytes`:code: fields, and
convert numerics to strings.
>>> import pprint
>>> pprint.pprint(order_to_jsdict(
... {
... 'makerAddress': "0x0000000000000000000000000000000000000000",
... 'takerAddress': "0x0000000000000000000000000000000000000000",
... 'feeRecipientAddress':
... "0x0000000000000000000000000000000000000000",
... 'senderAddress': "0x0000000000000000000000000000000000000000",
... 'makerAssetAmount': 1,
... 'takerAssetAmount': 1,
... 'makerFee': 0,
... 'takerFee': 0,
... 'expirationTimeSeconds': 1,
... 'salt': 1,
... 'makerAssetData': (0).to_bytes(1, byteorder='big') * 20,
... 'takerAssetData': (0).to_bytes(1, byteorder='big') * 20,
... },
... ))
{'exchangeAddress': '0x0000000000000000000000000000000000000000',
'expirationTimeSeconds': '1',
'feeRecipientAddress': '0x0000000000000000000000000000000000000000',
'makerAddress': '0x0000000000000000000000000000000000000000',
'makerAssetAmount': '1',
'makerAssetData': '0x0000000000000000000000000000000000000000',
'makerFee': '0',
'salt': '1',
'senderAddress': '0x0000000000000000000000000000000000000000',
'takerAddress': '0x0000000000000000000000000000000000000000',
'takerAssetAmount': '1',
'takerAssetData': '0x0000000000000000000000000000000000000000',
'takerFee': '0'}
"""
jsdict = cast(Dict, copy(order))
# encode bytes fields
jsdict["makerAssetData"] = "0x" + order["makerAssetData"].hex()
jsdict["takerAssetData"] = "0x" + order["takerAssetData"].hex()
jsdict["exchangeAddress"] = exchange_address
jsdict["expirationTimeSeconds"] = str(order["expirationTimeSeconds"])
jsdict["makerAssetAmount"] = str(order["makerAssetAmount"])
jsdict["takerAssetAmount"] = str(order["takerAssetAmount"])
jsdict["makerFee"] = str(order["makerFee"])
jsdict["takerFee"] = str(order["takerFee"])
jsdict["salt"] = str(order["salt"])
if signature is not None:
jsdict["signature"] = signature
assert_valid(jsdict, "/orderSchema")
return jsdict
def jsdict_to_order(jsdict: dict) -> Order:
r"""Convert a JSON-schema-compatible dict order to a Web3-compatible struct.
More specifically, do explicit encoding of the `bytes`:code: fields, and
parse integers from strings.
>>> import pprint
>>> pprint.pprint(jsdict_to_order(
... {
... 'makerAddress': "0x0000000000000000000000000000000000000000",
... 'takerAddress': "0x0000000000000000000000000000000000000000",
... 'feeRecipientAddress': "0x0000000000000000000000000000000000000000",
... 'senderAddress': "0x0000000000000000000000000000000000000000",
... 'makerAssetAmount': "1000000000000000000",
... 'takerAssetAmount': "1000000000000000000",
... 'makerFee': "0",
... 'takerFee': "0",
... 'expirationTimeSeconds': "12345",
... 'salt': "12345",
... 'makerAssetData': "0x0000000000000000000000000000000000000000",
... 'takerAssetData': "0x0000000000000000000000000000000000000000",
... 'exchangeAddress': "0x0000000000000000000000000000000000000000",
... },
... ))
{'expirationTimeSeconds': 12345,
'feeRecipientAddress': '0x0000000000000000000000000000000000000000',
'makerAddress': '0x0000000000000000000000000000000000000000',
'makerAssetAmount': 1000000000000000000,
'makerAssetData': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
b'\x00\x00\x00\x00\x00\x00\x00\x00',
'makerFee': 0,
'salt': 12345,
'senderAddress': '0x0000000000000000000000000000000000000000',
'takerAddress': '0x0000000000000000000000000000000000000000',
'takerAssetAmount': 1000000000000000000,
'takerAssetData': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
b'\x00\x00\x00\x00\x00\x00\x00\x00',
'takerFee': 0}
""" # noqa: E501 (line too long)
assert_valid(jsdict, "/orderSchema")
order = cast(Order, copy(jsdict))
order["makerAssetData"] = bytes.fromhex(
remove_0x_prefix(jsdict["makerAssetData"])
)
order["takerAssetData"] = bytes.fromhex(
remove_0x_prefix(jsdict["takerAssetData"])
)
order["makerAssetAmount"] = int(jsdict["makerAssetAmount"])
order["takerAssetAmount"] = int(jsdict["takerAssetAmount"])
order["makerFee"] = int(jsdict["makerFee"])
order["takerFee"] = int(jsdict["takerFee"])
order["expirationTimeSeconds"] = int(jsdict["expirationTimeSeconds"])
order["salt"] = int(jsdict["salt"])
del order["exchangeAddress"] # type: ignore
# silence mypy pending release of
# https://github.com/python/mypy/issues/3550
return order

View File

@@ -0,0 +1,47 @@
"""Validate inputs to the Exchange contract."""
from typing import Any
from web3.providers.base import BaseProvider
from zero_ex import json_schemas
from . import ExchangeValidatorBase
from .types import order_to_jsdict
class ExchangeValidator(ExchangeValidatorBase):
"""Validate inputs to Exchange methods."""
def __init__(
self,
provider: BaseProvider,
contract_address: str,
private_key: str = None,
):
"""Initialize the class."""
super().__init__(provider, contract_address, private_key)
self.contract_address = contract_address
def assert_valid(
self, method_name: str, parameter_name: str, argument_value: Any
) -> None:
"""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.
"""
if parameter_name == "order":
json_schemas.assert_valid(
order_to_jsdict(argument_value, self.contract_address),
"/orderSchema",
)
if parameter_name == "orders":
for order in argument_value:
json_schemas.assert_valid(
order_to_jsdict(order, self.contract_address),
"/orderSchema",
)

View File

@@ -1,327 +0,0 @@
"""Wrapper for 0x Exchange smart contract."""
from typing import List, Optional, Tuple, Union
from itertools import repeat
from eth_utils import remove_0x_prefix
from hexbytes import HexBytes
from web3.providers.base import BaseProvider
from web3.datastructures import AttributeDict
from zero_ex.contract_addresses import NETWORK_TO_ADDRESSES, NetworkId
from zero_ex.contract_artifacts import abi_by_name
from zero_ex.json_schemas import assert_valid
from zero_ex.order_utils import (
Order,
generate_order_hash_hex,
is_valid_signature,
order_to_jsdict,
)
from ._base_contract_wrapper import BaseContractWrapper
from .tx_params import TxParams
class CancelDisallowedError(Exception):
"""Exception for when Cancel is not allowed."""
class Exchange(BaseContractWrapper):
"""Wrapper class for 0x Exchange smart contract."""
def __init__(
self,
provider: BaseProvider,
contract_address: str,
private_key: str = None,
):
"""Get an instance of the 0x Exchange smart contract wrapper.
:param provider: instance of :class:`web3.providers.base.BaseProvider`
:param private_key: str of private_key
"""
super(Exchange, self).__init__(
provider=provider,
contract_address=contract_address,
private_key=private_key,
)
self._web3_net = self._web3.net # pylint: disable=no-member
self.address = NETWORK_TO_ADDRESSES[
NetworkId(int(self._web3_net.version))
].exchange
self._exchange = self._contract_instance(
address=self.address, abi=abi_by_name("Exchange")
)
# pylint: disable=too-many-arguments
def fill_order(
self,
order: Order,
taker_amount: int,
signature: str,
tx_params: Optional[TxParams] = None,
view_only: bool = False,
) -> Union[HexBytes, bytes]:
"""Fill a signed order with given amount of taker asset.
This is the most basic way to fill an order. All of the other methods
call fillOrder under the hood with additional logic. This function
will attempt to fill the amount specified by the caller. However, if
the remaining fillable amount is less than the amount specified, the
remaining amount will be filled. Partial fills are allowed when
filling orders.
See the specification docs for `fillOrder
<https://github.com/0xProject/0x-protocol-specification/blob/master
/v2/v2-specification.md#fillorder>`_.
:param order: instance of :class:`zero_ex.order_utils.Order`
:param taker_amount: integer taker amount in Wei (1 Wei is 10e-18 ETH)
:param signature: str or hexstr or bytes of order hash signature
:param tx_params: default None, :class:`TxParams` transaction params
:param view_only: default False, boolean of whether to transact or
view only
:returns: transaction hash
"""
assert_valid(order_to_jsdict(order, self.address), "/orderSchema")
is_valid_signature(
self._provider,
generate_order_hash_hex(order, self.address),
signature,
order["makerAddress"],
)
# safeguard against fractional inputs
taker_fill_amount = int(taker_amount)
normalized_signature = bytes.fromhex(remove_0x_prefix(signature))
func = self._exchange.functions.fillOrder(
order, taker_fill_amount, normalized_signature
)
return self._invoke_function_call(
func=func, tx_params=tx_params, view_only=view_only
)
# pylint: disable=too-many-arguments
def batch_fill_orders(
self,
orders: List[Order],
taker_amounts: List[int],
signatures: List[str],
tx_params: Optional[TxParams] = None,
view_only: bool = False,
) -> Union[HexBytes, bytes]:
"""Call `fillOrder` sequentially for orders, amounts and signatures.
:param orders: list of instances of :class:`zero_ex.order_utils.Order`
:param taker_amounts: list of integer taker amounts in Wei
:param signatures: list of str|hexstr|bytes of order hash signature
:param tx_params: default None, :class:`TxParams` transaction params
:param view_only: default False, boolean of whether to transact or
view only
:returns: transaction hash
"""
order_jsdicts = [
order_to_jsdict(order, self.address) for order in orders
]
map(assert_valid, order_jsdicts, repeat("/orderSchema"))
# safeguard against fractional inputs
normalized_fill_amounts = [
int(taker_fill_amount) for taker_fill_amount in taker_amounts
]
normalized_signatures = [
bytes.fromhex(remove_0x_prefix(signature))
for signature in signatures
]
func = self._exchange.functions.batchFillOrders(
orders, normalized_fill_amounts, normalized_signatures
)
return self._invoke_function_call(
func=func, tx_params=tx_params, view_only=view_only
)
# pylint: disable=too-many-arguments
def fill_or_kill_order(
self,
order: Order,
taker_amount: int,
signature: str,
tx_params: Optional[TxParams] = None,
view_only: bool = False,
) -> Union[HexBytes, bytes]:
"""Attemp to `fillOrder`, revert if fill is not exact amount.
:param order: instance of :class:`zero_ex.order_utils.Order`
:param taker_amount: integer taker amount in Wei (1 Wei is 10e-18 ETH)
:param signature: str or hexstr or bytes of order hash signature
:param tx_params: default None, :class:`TxParams` transaction params
:param view_only: default False, boolean of whether to transact or
view only
:returns: transaction hash
"""
assert_valid(order_to_jsdict(order, self.address), "/orderSchema")
is_valid_signature(
self._provider,
generate_order_hash_hex(order, self.address),
signature,
order["makerAddress"],
)
# safeguard against fractional inputs
taker_fill_amount = int(taker_amount)
normalized_signature = bytes.fromhex(remove_0x_prefix(signature))
func = self._exchange.functions.fillOrKillOrder(
order, taker_fill_amount, normalized_signature
)
return self._invoke_function_call(
func=func, tx_params=tx_params, view_only=view_only
)
# pylint: disable=too-many-arguments
def batch_fill_or_kill_orders(
self,
orders: List[Order],
taker_amounts: List[int],
signatures: List[str],
tx_params: Optional[TxParams] = None,
view_only: bool = False,
) -> Union[HexBytes, bytes]:
"""Call `fillOrKillOrder` sequentially for orders.
:param orders: list of instances of :class:`zero_ex.order_utils.Order`
:param taker_amounts: list of integer taker amounts in Wei
:param signatures: list of str|hexstr|bytes of order hash signature
:param tx_params: default None, :class:`TxParams` transaction params
:param view_only: default False, boolean of whether to transact or
view only
:returns: transaction hash
"""
order_jsdicts = [
order_to_jsdict(order, self.address) for order in orders
]
map(assert_valid, order_jsdicts, repeat("/orderSchema"))
# safeguard against fractional inputs
normalized_fill_amounts = [
int(taker_fill_amount) for taker_fill_amount in taker_amounts
]
normalized_signatures = [
bytes.fromhex(remove_0x_prefix(signature))
for signature in signatures
]
func = self._exchange.functions.batchFillOrKillOrders(
orders, normalized_fill_amounts, normalized_signatures
)
return self._invoke_function_call(
func=func, tx_params=tx_params, view_only=view_only
)
def cancel_order(
self,
order: Order,
tx_params: Optional[TxParams] = None,
view_only: bool = False,
) -> Union[HexBytes, bytes]:
"""Cancel an order.
See the specification docs for `cancelOrder
<https://github.com/0xProject/0x-protocol-specification/blob/master
/v2/v2-specification.md#cancelorder>`_.
:param order: instance of :class:`zero_ex.order_utils.Order`
:param tx_params: default None, :class:`TxParams` transaction params
:param view_only: default False, boolean of whether to transact or
view only
:returns: transaction hash
"""
assert_valid(order_to_jsdict(order, self.address), "/orderSchema")
maker_address = self._validate_and_checksum_address(
order["makerAddress"]
)
if tx_params and tx_params.from_:
self._raise_if_maker_not_canceller(
maker_address,
self._validate_and_checksum_address(tx_params.from_),
)
elif self._web3_eth.defaultAccount:
self._raise_if_maker_not_canceller(
maker_address, self._web3_eth.defaultAccount
)
func = self._exchange.functions.cancelOrder(order)
return self._invoke_function_call(
func=func, tx_params=tx_params, view_only=view_only
)
def batch_cancel_orders(
self,
orders: List[Order],
tx_params: Optional[TxParams] = None,
view_only: bool = False,
) -> Union[HexBytes, bytes]:
"""Call `cancelOrder` sequentially for provided orders.
:param orders: list of instance of :class:`zero_ex.order_utils.Order`
:param tx_params: default None, :class:`TxParams` transaction params
:param view_only: default False, boolean of whether to transact or
view only
:returns: transaction hash
"""
order_jsdicts = [
order_to_jsdict(order, self.address) for order in orders
]
map(assert_valid, order_jsdicts, repeat("/orderSchema"))
maker_addresses = [
self._validate_and_checksum_address(order["makerAddress"])
for order in orders
]
if tx_params and tx_params.from_:
map(
self._raise_if_maker_not_canceller,
maker_addresses,
repeat(tx_params.from_),
)
elif self._web3_eth.defaultAccount:
map(
self._raise_if_maker_not_canceller,
maker_addresses,
repeat(self._web3_eth.defaultAccount),
)
func = self._exchange.functions.batchCancelOrders(orders)
return self._invoke_function_call(
func=func, tx_params=tx_params, view_only=view_only
)
def get_fill_event(
self, tx_hash: Union[HexBytes, bytes]
) -> Tuple[AttributeDict]:
"""Get fill event for a fill transaction.
:param tx_hash: `HexBytes` hash of fill transaction
:returns: fill event
"""
tx_receipt = self._web3_eth.getTransactionReceipt(tx_hash)
return self._exchange.events.Fill().processReceipt(tx_receipt)
def get_cancel_event(
self, tx_hash: Union[HexBytes, bytes]
) -> Tuple[AttributeDict]:
"""Get cancel event for cancel transaction.
:param tx_hash: `HexBytes` hash of cancel transaction
"""
tx_receipt = self._web3_eth.getTransactionReceipt(tx_hash)
return self._exchange.events.Cancel().processReceipt(tx_receipt)
@staticmethod
def _raise_if_maker_not_canceller(maker_address, canceller_address):
"""Raise exception is maker is not same as canceller."""
if maker_address != canceller_address:
raise CancelDisallowedError(
"Order with makerAddress {} can not be cancelled by {}".format(
maker_address, canceller_address
)
)

View File

@@ -7,8 +7,9 @@ from eth_utils import remove_0x_prefix
from zero_ex.contract_addresses import NETWORK_TO_ADDRESSES, NetworkId
from zero_ex.contract_wrappers import Exchange, TxParams
from zero_ex.contract_wrappers.exchange.types import Order
from zero_ex.json_schemas import assert_valid
from zero_ex.order_utils import generate_order_hash_hex, Order, sign_hash
from zero_ex.order_utils import generate_order_hash_hex, sign_hash_to_bytes
@pytest.fixture(scope="module")
@@ -28,20 +29,20 @@ def create_test_order(
taker_asset_data,
):
"""Create a test order."""
order: Order = {
"makerAddress": maker_address.lower(),
"takerAddress": "0x0000000000000000000000000000000000000000",
"feeRecipientAddress": "0x0000000000000000000000000000000000000000",
"senderAddress": "0x0000000000000000000000000000000000000000",
"makerAssetAmount": maker_asset_amount,
"takerAssetAmount": taker_asset_amount,
"makerFee": 0,
"takerFee": 0,
"expirationTimeSeconds": 100000000000000,
"salt": random.randint(1, 1000000000),
"makerAssetData": maker_asset_data,
"takerAssetData": taker_asset_data,
}
order = Order(
makerAddress=maker_address.lower(),
takerAddress="0x0000000000000000000000000000000000000000",
feeRecipientAddress="0x0000000000000000000000000000000000000000",
senderAddress="0x0000000000000000000000000000000000000000",
makerAssetAmount=maker_asset_amount,
takerAssetAmount=taker_asset_amount,
makerFee=0,
takerFee=0,
expirationTimeSeconds=100000000000000,
salt=random.randint(1, 1000000000),
makerAssetData=maker_asset_data,
takerAssetData=taker_asset_data,
)
return order
@@ -69,16 +70,16 @@ def test_exchange_wrapper__fill_order(
"""Test filling an order."""
taker = accounts[0]
maker = accounts[1]
exchange_address = exchange_wrapper.address
exchange_address = exchange_wrapper.contract_address
order = create_test_order(maker, 1, weth_asset_data, 1, weth_asset_data)
order_hash = generate_order_hash_hex(
order=order, exchange_address=exchange_address
)
order_signature = sign_hash(ganache_provider, maker, order_hash)
order_signature = sign_hash_to_bytes(ganache_provider, maker, order_hash)
tx_hash = exchange_wrapper.fill_order(
order=order,
taker_amount=order["takerAssetAmount"],
taker_asset_fill_amount=order["takerAssetAmount"],
signature=order_signature,
tx_params=TxParams(from_=taker),
)
@@ -98,7 +99,7 @@ def test_exchange_wrapper__batch_fill_orders(
"""Test filling a batch of orders."""
taker = accounts[0]
maker = accounts[1]
exchange_address = exchange_wrapper.address
exchange_address = exchange_wrapper.contract_address
orders = []
order_1 = create_test_order(maker, 1, weth_asset_data, 1, weth_asset_data)
order_2 = create_test_order(maker, 1, weth_asset_data, 1, weth_asset_data)
@@ -109,13 +110,13 @@ def test_exchange_wrapper__batch_fill_orders(
for order in orders
]
order_signatures = [
sign_hash(ganache_provider, maker, order_hash)
sign_hash_to_bytes(ganache_provider, maker, order_hash)
for order_hash in order_hashes
]
taker_amounts = [order["takerAssetAmount"] for order in orders]
tx_hash = exchange_wrapper.batch_fill_orders(
orders=orders,
taker_amounts=taker_amounts,
taker_asset_fill_amounts=taker_amounts,
signatures=order_signatures,
tx_params=TxParams(from_=taker),
)

View File

@@ -1,13 +1,3 @@
#!/usr/bin/env python
#!/usr/bin/env bash
"""Script to install all packages in editable mode (pip install -e .)."""
from os import path
import subprocess
# install all packages
subprocess.check_call(
(
path.join(".", "cmd_pkgs_in_dep_order.py") + " pip install -e .[dev]"
).split()
)
./parallel pip install -e .[dev]

View File

@@ -5,7 +5,7 @@
import distutils.command.build_py
from distutils.command.clean import clean
import subprocess # nosec
from shutil import rmtree
from shutil import copytree, rmtree
from os import environ, path
from sys import argv
@@ -13,6 +13,26 @@ from setuptools import find_packages, setup
from setuptools.command.test import test as TestCommand
class PreInstallCommand(distutils.command.build_py.build_py):
"""Custom setuptools command class for pulling in schemas."""
description = "Pull in the schemas that live in the TypeScript package."
def run(self):
"""Copy files from TS area to local src."""
pkgdir = path.dirname(path.realpath(argv[0]))
rmtree(
path.join(pkgdir, "src", "zero_ex", "json_schemas", "schemas"),
ignore_errors=True,
)
copytree(
path.join(
pkgdir, "..", "..", "packages", "json-schemas", "schemas"
),
path.join(pkgdir, "src", "zero_ex", "json_schemas", "schemas"),
)
class TestCommandExtension(TestCommand):
"""Run pytest tests."""
@@ -41,15 +61,6 @@ class LintCommand(distutils.command.build_py.build_py):
"mypy src test setup.py".split(),
# security issue checker:
"bandit -r src ./setup.py".split(),
# HACK: ensure json schemas don't differ from the authoritative
# copies: this is a hack. ideally we would symlink to the
# authoritative copies, but a problem with setuptools is preventing
# it from following symlinks when gathering package_data. see
# https://github.com/pypa/setuptools/issues/415.
(
"diff src/zero_ex/json_schemas/schemas"
+ " ../../packages/json-schemas/schemas"
).split(),
# general linter:
"pylint src test setup.py".split(),
# pylint takes relatively long to run, so it runs last, to enable
@@ -138,6 +149,7 @@ setup(
author="F. Eugene Aumson",
author_email="feuGeneA@users.noreply.github.com",
cmdclass={
"pre_install": PreInstallCommand,
"clean": CleanCommandExtension,
"lint": LintCommand,
"test": TestCommandExtension,
@@ -196,6 +208,7 @@ setup(
"build_sphinx": {
"source_dir": ("setup.py", "src"),
"build_dir": ("setup.py", "build/docs"),
"warning_is_error": ("setup.py", "true"),
}
},
)

View File

@@ -61,9 +61,10 @@ def assert_valid(data: Mapping, schema_id: str) -> None:
>>> from zero_ex.json_schemas import assert_valid
>>> from zero_ex.contract_addresses import NETWORK_TO_ADDRESSES, NetworkId
>>> from zero_ex.order_utils import (
... asset_data_utils, Order, order_to_jsdict
>>> from zero_ex.contract_wrappers.exchange.types import (
... Order, order_to_jsdict
... )
>>> from zero_ex.order_utils import asset_data_utils
>>> from eth_utils import remove_0x_prefix
>>> import random
>>> from datetime import datetime, timedelta

View File

@@ -1,5 +0,0 @@
{
"id": "/addressSchema",
"type": "string",
"pattern": "^0x[0-9a-f]{40}$"
}

View File

@@ -1,8 +0,0 @@
{
"id": "/AssetPairsRequestOptsSchema",
"type": "object",
"properties": {
"assetDataA": { "$ref": "/hexSchema" },
"assetDataB": { "$ref": "/hexSchema" }
}
}

View File

@@ -1,11 +0,0 @@
{
"id": "/blockParamSchema",
"oneOf": [
{
"type": "number"
},
{
"enum": ["latest", "earliest", "pending"]
}
]
}

View File

@@ -1,8 +0,0 @@
{
"id": "/blockRangeSchema",
"properties": {
"fromBlock": { "$ref": "/blockParamSchema" },
"toBlock": { "$ref": "/blockParamSchema" }
},
"type": "object"
}

View File

@@ -1,27 +0,0 @@
{
"id": "/callDataSchema",
"properties": {
"from": { "$ref": "/addressSchema" },
"to": { "$ref": "/addressSchema" },
"value": {
"oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]
},
"gas": {
"oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]
},
"gasPrice": {
"oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/jsNumberSchema" }]
},
"data": {
"type": "string",
"pattern": "^0x[0-9a-f]*$"
},
"nonce": {
"type": "number",
"minimum": 0
}
},
"required": [],
"type": "object",
"additionalProperties": false
}

View File

@@ -1,5 +0,0 @@
{
"id": "/ecSignatureParameterSchema",
"type": "string",
"pattern": "^0[xX][0-9A-Fa-f]{64}$"
}

View File

@@ -1,14 +0,0 @@
{
"id": "/ecSignatureSchema",
"properties": {
"v": {
"type": "number",
"minimum": 27,
"maximum": 28
},
"r": { "$ref": "/ecSignatureParameterSchema" },
"s": { "$ref": "/ecSignatureParameterSchema" }
},
"required": ["v", "r", "s"],
"type": "object"
}

View File

@@ -1,28 +0,0 @@
{
"id": "/eip712TypedDataSchema",
"type": "object",
"properties": {
"types": {
"type": "object",
"properties": {
"EIP712Domain": { "type": "array" }
},
"additionalProperties": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"type": { "type": "string" }
},
"required": ["name", "type"]
}
},
"required": ["EIP712Domain"]
},
"primaryType": { "type": "string" },
"domain": { "type": "object" },
"message": { "type": "object" }
},
"required": ["types", "primaryType", "domain", "message"]
}

View File

@@ -1,5 +0,0 @@
{
"id": "/hexSchema",
"type": "string",
"pattern": "^0x(([0-9a-f][0-9a-f])+)?$"
}

View File

@@ -1,7 +0,0 @@
{
"id": "/indexFilterValuesSchema",
"additionalProperties": {
"oneOf": [{ "$ref": "/numberSchema" }, { "$ref": "/addressSchema" }, { "$ref": "/orderHashSchema" }]
},
"type": "object"
}

View File

@@ -1,5 +0,0 @@
{
"id": "/jsNumberSchema",
"type": "number",
"minimum": 0
}

View File

@@ -1,5 +0,0 @@
{
"id": "/numberSchema",
"type": "string",
"pattern": "^\\d+(\\.\\d+)?$"
}

View File

@@ -1,12 +0,0 @@
{
"id": "/orderCancellationRequestsSchema",
"type": "array",
"items": {
"properties": {
"order": { "$ref": "/orderSchema" },
"takerTokenCancelAmount": { "$ref": "/wholeNumberSchema" }
},
"required": ["order", "takerTokenCancelAmount"],
"type": "object"
}
}

View File

@@ -1,24 +0,0 @@
{
"id": "/OrderConfigRequestSchema",
"type": "object",
"properties": {
"makerAddress": { "$ref": "/addressSchema" },
"takerAddress": { "$ref": "/addressSchema" },
"makerAssetAmount": { "$ref": "/wholeNumberSchema" },
"takerAssetAmount": { "$ref": "/wholeNumberSchema" },
"makerAssetData": { "$ref": "/hexSchema" },
"takerAssetData": { "$ref": "/hexSchema" },
"exchangeAddress": { "$ref": "/addressSchema" },
"expirationTimeSeconds": { "$ref": "/wholeNumberSchema" }
},
"required": [
"makerAddress",
"takerAddress",
"makerAssetAmount",
"takerAssetAmount",
"makerAssetData",
"takerAssetData",
"exchangeAddress",
"expirationTimeSeconds"
]
}

View File

@@ -1,12 +0,0 @@
{
"id": "/orderFillOrKillRequestsSchema",
"type": "array",
"items": {
"properties": {
"signedOrder": { "$ref": "/signedOrderSchema" },
"fillTakerAmount": { "$ref": "/wholeNumberSchema" }
},
"required": ["signedOrder", "fillTakerAmount"],
"type": "object"
}
}

View File

@@ -1,12 +0,0 @@
{
"id": "/orderFillRequestsSchema",
"type": "array",
"items": {
"properties": {
"signedOrder": { "$ref": "/signedOrderSchema" },
"takerTokenFillAmount": { "$ref": "/wholeNumberSchema" }
},
"required": ["signedOrder", "takerTokenFillAmount"],
"type": "object"
}
}

View File

@@ -1,5 +0,0 @@
{
"id": "/orderHashSchema",
"type": "string",
"pattern": "^0x[0-9a-fA-F]{64}$"
}

View File

@@ -1,34 +0,0 @@
{
"id": "/orderSchema",
"properties": {
"makerAddress": { "$ref": "/addressSchema" },
"takerAddress": { "$ref": "/addressSchema" },
"makerFee": { "$ref": "/wholeNumberSchema" },
"takerFee": { "$ref": "/wholeNumberSchema" },
"senderAddress": { "$ref": "/addressSchema" },
"makerAssetAmount": { "$ref": "/wholeNumberSchema" },
"takerAssetAmount": { "$ref": "/wholeNumberSchema" },
"makerAssetData": { "$ref": "/hexSchema" },
"takerAssetData": { "$ref": "/hexSchema" },
"salt": { "$ref": "/wholeNumberSchema" },
"exchangeAddress": { "$ref": "/addressSchema" },
"feeRecipientAddress": { "$ref": "/addressSchema" },
"expirationTimeSeconds": { "$ref": "/wholeNumberSchema" }
},
"required": [
"makerAddress",
"takerAddress",
"makerFee",
"takerFee",
"senderAddress",
"makerAssetAmount",
"takerAssetAmount",
"makerAssetData",
"takerAssetData",
"salt",
"exchangeAddress",
"feeRecipientAddress",
"expirationTimeSeconds"
],
"type": "object"
}

View File

@@ -1,52 +0,0 @@
{
"id": "/orderWatcherWebSocketRequestSchema",
"type": "object",
"definitions": {
"signedOrderParam": {
"type": "object",
"properties": {
"signedOrder": { "$ref": "/signedOrderSchema" }
},
"required": ["signedOrder"]
},
"orderHashParam": {
"type": "object",
"properties": {
"orderHash": { "$ref": "/hexSchema" }
},
"required": ["orderHash"]
}
},
"oneOf": [
{
"type": "object",
"properties": {
"id": { "type": "number" },
"jsonrpc": { "type": "string" },
"method": { "enum": ["ADD_ORDER"] },
"params": { "$ref": "#/definitions/signedOrderParam" }
},
"required": ["id", "jsonrpc", "method", "params"]
},
{
"type": "object",
"properties": {
"id": { "type": "number" },
"jsonrpc": { "type": "string" },
"method": { "enum": ["REMOVE_ORDER"] },
"params": { "$ref": "#/definitions/orderHashParam" }
},
"required": ["id", "jsonrpc", "method", "params"]
},
{
"type": "object",
"properties": {
"id": { "type": "number" },
"jsonrpc": { "type": "string" },
"method": { "enum": ["GET_STATS"] },
"params": {}
},
"required": ["id", "jsonrpc", "method"]
}
]
}

View File

@@ -1,10 +0,0 @@
{
"id": "/orderWatcherWebSocketUtf8MessageSchema",
"properties": {
"utf8Data": { "type": "string" }
},
"required": [
"utf8Data"
],
"type": "object"
}

View File

@@ -1,9 +0,0 @@
{
"id": "/OrderbookRequestSchema",
"type": "object",
"properties": {
"baseAssetData": { "$ref": "/hexSchema" },
"quoteAssetData": { "$ref": "/hexSchema" }
},
"required": ["baseAssetData", "quoteAssetData"]
}

View File

@@ -1,19 +0,0 @@
{
"id": "/OrdersRequestOptsSchema",
"type": "object",
"properties": {
"makerAssetProxyId": { "$ref": "/hexSchema" },
"takerAssetProxyId": { "$ref": "/hexSchema" },
"makerAssetAddress": { "$ref": "/addressSchema" },
"takerAssetAddress": { "$ref": "/addressSchema" },
"exchangeAddress": { "$ref": "/addressSchema" },
"senderAddress": { "$ref": "/addressSchema" },
"makerAssetData": { "$ref": "/hexSchema" },
"takerAssetData": { "$ref": "/hexSchema" },
"traderAssetData": { "$ref": "/hexSchema" },
"makerAddress": { "$ref": "/addressSchema" },
"takerAddress": { "$ref": "/addressSchema" },
"traderAddress": { "$ref": "/addressSchema" },
"feeRecipientAddress": { "$ref": "/addressSchema" }
}
}

View File

@@ -1,5 +0,0 @@
{
"id": "/ordersSchema",
"type": "array",
"items": { "$ref": "/orderSchema" }
}

View File

@@ -1,8 +0,0 @@
{
"id": "/PagedRequestOptsSchema",
"type": "object",
"properties": {
"page": { "type": "number" },
"perPage": { "type": "number" }
}
}

View File

@@ -1,10 +0,0 @@
{
"id": "/paginatedCollectionSchema",
"type": "object",
"properties": {
"total": { "type": "number" },
"perPage": { "type": "number" },
"page": { "type": "number" }
},
"required": ["total", "perPage", "page"]
}

View File

@@ -1,13 +0,0 @@
{
"id": "/relayerApiAssetDataPairsResponseSchema",
"type": "object",
"allOf": [
{ "$ref": "/paginatedCollectionSchema" },
{
"properties": {
"records": { "$ref": "/relayerApiAssetDataPairsSchema" }
},
"required": ["records"]
}
]
}

View File

@@ -1,12 +0,0 @@
{
"id": "/relayerApiAssetDataPairsSchema",
"type": "array",
"items": {
"properties": {
"assetDataA": { "$ref": "/relayerApiAssetDataTradeInfoSchema" },
"assetDataB": { "$ref": "/relayerApiAssetDataTradeInfoSchema" }
},
"required": ["assetDataA", "assetDataB"],
"type": "object"
}
}

View File

@@ -1,11 +0,0 @@
{
"id": "/relayerApiAssetDataTradeInfoSchema",
"type": "object",
"properties": {
"assetData": { "$ref": "/hexSchema" },
"minAmount": { "$ref": "/wholeNumberSchema" },
"maxAmount": { "$ref": "/wholeNumberSchema" },
"precision": { "type": "number" }
},
"required": ["assetData"]
}

View File

@@ -1,21 +0,0 @@
{
"id": "/relayerApiErrorResponseSchema",
"type": "object",
"properties": {
"code": { "type": "integer", "minimum": 100, "maximum": 103 },
"reason": { "type": "string" },
"validationErrors": {
"type": "array",
"items": {
"type": "object",
"properties": {
"field": { "type": "string" },
"code": { "type": "integer", "minimum": 1000, "maximum": 1006 },
"reason": { "type": "string" }
},
"required": ["field", "code", "reason"]
}
}
},
"required": ["code", "reason"]
}

View File

@@ -1,16 +0,0 @@
{
"id": "/relayerApiFeeRecipientsResponseSchema",
"type": "object",
"allOf": [
{ "$ref": "/paginatedCollectionSchema" },
{
"properties": {
"records": {
"type": "array",
"items": { "$ref": "/addressSchema" }
}
},
"required": ["records"]
}
]
}

View File

@@ -1,24 +0,0 @@
{
"id": "/relayerApiOrderConfigPayloadSchema",
"type": "object",
"properties": {
"makerAddress": { "$ref": "/addressSchema" },
"takerAddress": { "$ref": "/addressSchema" },
"makerAssetAmount": { "$ref": "/wholeNumberSchema" },
"takerAssetAmount": { "$ref": "/wholeNumberSchema" },
"makerAssetData": { "$ref": "/hexSchema" },
"takerAssetData": { "$ref": "/hexSchema" },
"exchangeAddress": { "$ref": "/addressSchema" },
"expirationTimeSeconds": { "$ref": "/wholeNumberSchema" }
},
"required": [
"makerAddress",
"takerAddress",
"makerAssetAmount",
"takerAssetAmount",
"makerAssetData",
"takerAssetData",
"exchangeAddress",
"expirationTimeSeconds"
]
}

View File

@@ -1,11 +0,0 @@
{
"id": "/relayerApiOrderConfigResponseSchema",
"type": "object",
"properties": {
"makerFee": { "$ref": "/wholeNumberSchema" },
"takerFee": { "$ref": "/wholeNumberSchema" },
"feeRecipientAddress": { "$ref": "/addressSchema" },
"senderAddress": { "$ref": "/addressSchema" }
},
"required": ["makerFee", "takerFee", "feeRecipientAddress", "senderAddress"]
}

View File

@@ -1,9 +0,0 @@
{
"id": "/relayerApiOrderSchema",
"type": "object",
"properties": {
"order": { "$ref": "/orderSchema" },
"metaData": { "type": "object" }
},
"required": ["order", "metaData"]
}

View File

@@ -1,9 +0,0 @@
{
"id": "/relayerApiOrderbookResponseSchema",
"type": "object",
"properties": {
"bids": { "$ref": "/relayerApiOrdersResponseSchema" },
"asks": { "$ref": "/relayerApiOrdersResponseSchema" }
},
"required": ["bids", "asks"]
}

View File

@@ -1,14 +0,0 @@
{
"id": "/relayerApiOrdersChannelSubscribePayloadSchema",
"type": "object",
"properties": {
"makerAssetProxyId": { "$ref": "/hexSchema" },
"takerAssetProxyId": { "$ref": "/hexSchema" },
"networkId": { "type": "number" },
"makerAssetAddress": { "$ref": "/addressSchema" },
"takerAssetAddress": { "$ref": "/addressSchema" },
"makerAssetData": { "$ref": "/hexSchema" },
"takerAssetData": { "$ref": "/hexSchema" },
"traderAssetData": { "$ref": "/hexSchema" }
}
}

View File

@@ -1,11 +0,0 @@
{
"id": "/relayerApiOrdersChannelSubscribeSchema",
"type": "object",
"properties": {
"type": { "enum": ["subscribe"] },
"channel": { "enum": ["orders"] },
"requestId": { "type": "string" },
"payload": { "$ref": "/relayerApiOrdersChannelSubscribePayloadSchema" }
},
"required": ["type", "channel", "requestId"]
}

View File

@@ -1,11 +0,0 @@
{
"id": "/relayerApiOrdersChannelUpdateSchema",
"type": "object",
"properties": {
"type": { "enum": ["update"] },
"channel": { "enum": ["orders"] },
"requestId": { "type": "string" },
"payload": { "$ref": "/relayerApiOrdersSchema" }
},
"required": ["type", "channel", "requestId"]
}

View File

@@ -1,13 +0,0 @@
{
"id": "/relayerApiOrdersResponseSchema",
"type": "object",
"allOf": [
{ "$ref": "/paginatedCollectionSchema" },
{
"properties": {
"records": { "$ref": "/relayerApiOrdersSchema" }
},
"required": ["records"]
}
]
}

View File

@@ -1,5 +0,0 @@
{
"id": "/relayerApiOrdersSchema",
"type": "array",
"items": { "$ref": "/relayerApiOrderSchema" }
}

View File

@@ -1,7 +0,0 @@
{
"id": "/RequestOptsSchema",
"type": "object",
"properties": {
"networkId": { "type": "number" }
}
}

View File

@@ -1,12 +0,0 @@
{
"id": "/signedOrderSchema",
"allOf": [
{ "$ref": "/orderSchema" },
{
"properties": {
"signature": { "$ref": "/hexSchema" }
},
"required": ["signature"]
}
]
}

Some files were not shown because too many files have changed in this diff Show More