First auto-gen'd Python contract wrapper: ERC20 (#1878)

* abi-gen-wrappers: fix half-baked folder rename

* .circleci: give cache more descriptive name

* abi-gen: rename type field. tsName->langLocalName

* contract-artifacts: add devdoc to ERC20Token.json

Artifact changes crafted manually: re-generated artifacts from within
@0x/contracts-erc20, and then copied them into @0x/contract-artifacts,
but only committed the changes that added devdoc.

Modified @0x/contracts-erc20/compiler.json to include devdoc in the
hopes that next time contract-artifacts are re-generated en masse, the
devdoc output will just come along for the ride.

Compiling ERC20 TypeScript wrappers after adding devdoc to the artifacts
revealed some inconsistencies in the types.  ethereum-types'
DevdocOutput REQUIRED many fields which are not always present,
depending the devdoc contents itself.  Relaxing the requirement had some
ramifications.

* abi-gen: Python!

Lots more to come, but so far generating typed methods with some
parameter validation and with reasonable docstrings; enough to make
ERC20 work.

* existing erc20 python wrapper: re-order methods

In order to minimize the diff in the upcoming commit of the
auto-generated version.

* existing erc20 python wrapper: rename method

Rename method _erc20 to _get_contract_instance.

* existing erc20 python wrapper: rename vars

Rename method parameters to match names used in contract methods.

* existing erc20 python wrapper: correction

Contract method `allowance` previously was returning a transaction hash,
but it's a const method, so changed it to return the int that the
underlying method returns.

* contract_wrappers.py: pull in generated code

Custom setup.py command to pull in code previously generated into
../../packages/abi-gen-wrappers/src/generated-wrappers/py.

Changes to existing wrapper code reflect differences between the old,
manually-written wrapper and the new, auto-generated wrapper.

Reconfigured Circle CI to give Python build access to the output of the
TypeScript build, in order to import the generated wrappers from there.

* abi-gen: sanitize docstrings for pycodestyle lint

* abi-gen-templates.py: expose ABI from template

Use ABI given by template, not gotten by name from
zero_ex.contract_artifacts.

Also, expose ABI as a static method.

* py wrappers: contract addr to ctor, not methods

In all Python wrappers (old, manual ones; and new, generated ones), have
client pass the contract address to the wrapper's constructor, rather
than to the individual method calls.

* py wrappers: remove unused param `account_address`

* py wrappers: document use of `private_key`

* Rename file erc20_wrapper.py to erc20_token.py

To match the name of the underlying contract.

* Update CHANGELOG.json's

* git rm erc20_token.py

No need to keep it checked in.  Doing so would require manual overhead
of keeping the generated copy in sync with the generation code, which
may get overlooked and cause confusion for others.  Authoritative source
will be the published package on PyPI.

* abi-gen-templates: tweak CHANGELOG wording

Co-Authored-By: Fabio B <kandinsky454@protonmail.ch>

* Include transaction parameters in const calls too

* Doc contract_address param to gen'd wrapper ctor

* make myself a CODEOWNER of abi-gen*

* rename ids: langLocalName -> languageSpecificName

* Move Python generation to its own packages/ folder

* Stop duplicating contract artifacts in Python pkg!

Thanks to the way we're now using the `./setup.py pre_install`
convention, there's no longer a need to check the artifacts in to the
Python package.

* move py templates BACK to abi-gen-templates

I got a little overzealous in the previous commit that moved ALL the
python stuff into the new packages/python-contract-wrappers folder.

* Update known-good test output: prettify

* add getABIEncodedTransationData to gen'd code

It was added into the template in the following commit, but the
corresponding checked-in generated code was not updated accordingly.

f51c4f9617

* Fix missed instance of languageSpecificName change

* abi-gen: refine pipeline for testing gen'd code

- generate wrappers for test fixture contracts (dummy, etc) not in `yarn
build` but in `yarn test`

- rename folder test/generated-test/generated-wrappers to
test/generated-test/known-good, and stop writing test output to there,
instead writing it to a new test/generated-test/output folder.

- sol-compile test fixture contracts in every test run

- run unit tests separately from tests of generated and built TypeScript
wrappers.  The existing `yarn run_mocha` will run unit tests, and
there's a new `yarn run_contract_wrapper_tests`.

* abi-gen: test Python gen [known test failures]

Also generate TypeScript wrapper test code into a TypeScript folder
(alongside the newly created Python folder).

Known-good code manually corrected (from generated code) to reflect
known problems that still need to be addressed.  Namely:
  - base contract and tx params should be imported from canonical
    package, not relative path. relative path is working for wrapping
    OUR contracts, but would not be usable in a more general
    context.
  - return type missing for some generated methods.

These outstanding problems are currently causing this test to fail.

* fix failing abi-gen test: missing return types

* fix failing abi-gen test: qualify imports

* in py wrapper, simplify base class initialization

per
https://github.com/0xProject/0x-monorepo/pull/1878#discussion_r299248641

* move 3rd party typings to typescript-typings

* make package python-contract-wrappers private

* make Xianny CODEOWNER of base-contract & templates

* abi-gen: clarify --help for --backend

* remove superfluous CHANGELOG entry
This commit is contained in:
F. Eugene Aumson 2019-07-03 11:01:01 -04:00 committed by GitHub
parent f77aaaf2e0
commit d9378e9a8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 1151 additions and 4577 deletions

View File

@ -29,6 +29,10 @@ jobs:
key: repo-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo
- save_cache:
key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/python-contract-wrappers/generated
build-website:
resource_class: medium+
docker:
@ -210,14 +214,17 @@ jobs:
- run: sudo chown -R circleci:circleci /usr/local/bin
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7
- restore_cache:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
- run:
command: |
cd python-packages
python -m ensurepip
./pre_install
./install
- save_cache:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
paths:
- '/usr/local/bin'
- '/usr/local/lib/python3.7/site-packages'
@ -258,14 +265,14 @@ jobs:
- run: sudo chown -R circleci:circleci /usr/local/bin
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7
- restore_cache:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
- run:
command: |
cd python-packages/order_utils
python -m ensurepip
python -m pip install .
- save_cache:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
paths:
- '/usr/local/bin'
- '/usr/local/lib/python3.7/site-packages'
@ -286,11 +293,14 @@ jobs:
- run: sudo chown -R circleci:circleci /usr/local/bin
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7
- restore_cache:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
- run:
command: |
python -m ensurepip
cd python-packages
./pre_install
./install
./lint
static-tests:
@ -419,6 +429,8 @@ workflows:
- static-tests-python:
requires:
- test-python
- test-python
- test-python:
requires:
- build
# skip python tox run for now, as we don't yet have multiple test environments to support.
#- test-rest-python

5
.gitignore vendored
View File

@ -96,11 +96,14 @@ contracts/extensions/generated-artifacts/
contracts/exchange-forwarder/generated-artifacts/
contracts/dev-utils/generated-artifacts/
/packages/abi-gen/test/generated-test/generated-artifacts
/packages/abi-gen/test/generated-test/output
packages/sol-tracing-utils/test/fixtures/artifacts/
packages/metacoin/artifacts/
python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/
# generated contract wrappers
packages/abi-gen-wrappers/wrappers
packages/abi-gen-wrappers/src/generated-wrappers/
packages/python-contract-wrappers/generated/
contracts/coordinator/generated-wrappers/
contracts/exchange/generated-wrappers/
contracts/asset-proxy/generated-wrappers/

View File

@ -25,7 +25,7 @@ lib
/contracts/dev-utils/generated-wrappers
/contracts/dev-utils/generated-artifacts
/packages/abi-gen/test/generated-test/generated-artifacts
/packages/abi-gen/test/generated-test/generated-wrappers
/packages/abi-gen/test/generated-test/known-good
/packages/abi-gen-wrappers/src/generated-wrappers
/packages/contract-artifacts/artifacts
/python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts

View File

@ -11,10 +11,10 @@ packages/website/ @BMillman19 @fragosti @fabioberger @steveklebanoff
# Dev tools & setup
.circleci/ @LogvinovLeon
packages/abi-gen/ @LogvinovLeon
packages/base-contract/ @LogvinovLeon
packages/abi-gen/ @feuGeneA
packages/base-contract/ @xianny
packages/connect/ @fragosti
packages/abi-gen-templates/ @LogvinovLeon
packages/abi-gen-templates/ @feuGeneA @xianny
packages/contract-addresses/ @albrow
packages/contract-artifacts/ @albrow
packages/dev-utils/ @LogvinovLeon @fabioberger
@ -23,6 +23,7 @@ packages/ethereum-types/ @LogvinovLeon
packages/metacoin/ @LogvinovLeon
packages/monorepo-scripts/ @fabioberger
packages/order-utils/ @fabioberger @LogvinovLeon
packages/python-contract-wrappers/ @feuGeneA
packages/sol-compiler/ @LogvinovLeon
packages/sol-coverage/ @LogvinovLeon
packages/sol-profiler/ @LogvinovLeon

View File

@ -9,6 +9,10 @@
{
"note": "Move `getABITransactionData` to `callAsync` template",
"pr": 1863
},
{
"note": "Initial support for Python",
"pr": 1878
}
]
},

View File

@ -0,0 +1,57 @@
"""Generated wrapper for {{contractName}} 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 {{contractName}}(BaseContractWrapper):
"""Wrapper class for {{contractName}} 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={{contractName}}.abi()
)
{{#each methods}}
{{> call contractName=../contractName}}
{{/each}}
{{#each events}}
{{> event}}
{{/each}}
@staticmethod
def abi():
"""Return the ABI to the underlying contract."""
return json.loads(
'{{{ABI}}}' # noqa: E501 (line-too-long)
)

View File

@ -0,0 +1,41 @@
def {{this.languageSpecificName}}(
self,
{{> typed_params inputs=inputs}}
tx_params: Optional[TxParams] = None,
{{^this.constant}}
view_only: bool = False,
{{/this.constant}}
) ->{{#if outputs}}{{~> return_type outputs=outputs~}}{{else}} None{{/if}}:
"""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}}
:param tx_params: transaction parameters
:param view_only: whether to use transact() or call()
:returns: transaction hash
{{/if}}
"""
{{#each this.inputs}}
{{#if (equal type 'address')}}
{{this.name}} = self._validate_and_checksum_address({{this.name}})
{{else if (equal type 'uint256')}}
# safeguard against fractional inputs
{{this.name}} = int({{this.name}})
{{/if}}
{{/each}}
func = self._get_contract_instance(
self._contract_address
).functions.{{this.name}}(
{{> params}}
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only={{#if this.constant}}True{{else}}view_only{{/if}}
)

View File

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

View File

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

View File

@ -0,0 +1,13 @@
{{#if this.constant}}
{{#if outputs.length}}
{{#singleReturnValue}}
{{#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~}}

View File

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

View File

@ -1,3 +1,3 @@
public {{this.tsName}} = {
public {{languageSpecificName}} = {
{{> callAsync}}
};

View File

@ -1,4 +1,4 @@
public {{this.tsName}} = {
public {{languageSpecificName}} = {
async sendTransactionAsync(
{{> typed_params inputs=inputs}}
txData?: Partial<TxData> | undefined,
@ -15,7 +15,7 @@ public {{this.tsName}} = {
data: encodedData,
},
self._web3Wrapper.getContractDefaults(),
self.{{this.tsName}}.estimateGasAsync.bind(
self.{{languageSpecificName}}.estimateGasAsync.bind(
self,
{{> params inputs=inputs}}
),
@ -34,9 +34,9 @@ public {{this.tsName}} = {
{{/each}}
const self = this as any as {{contractName}}Contract;
{{#if inputs}}
const txHashPromise = self.{{this.tsName}}.sendTransactionAsync({{> params input=inputs}}, txData);
const txHashPromise = self.{{languageSpecificName}}.sendTransactionAsync({{> params input=inputs}}, txData);
{{else}}
const txHashPromise = self.{{this.tsName}}.sendTransactionAsync(txData);
const txHashPromise = self.{{languageSpecificName}}.sendTransactionAsync(txData);
{{/if}}
return new PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs>(
txHashPromise,

View File

@ -15,7 +15,7 @@
"lint": "tslint --format stylish --project .",
"fix": "tslint --fix --format stylish --project .",
"pre_build": "yarn generate_contract_wrappers",
"clean": "shx rm -rf lib wrappers",
"clean": "shx rm -rf lib src/generated-wrappers",
"generate_contract_wrappers": "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 src/generated-wrappers --backend ethers"
},
"config": {

View File

@ -64,6 +64,15 @@ export class EthBalanceCheckerContract extends BaseContract {
// tslint:enable boolean-naming
return result;
},
getABIEncodedTransactionData(
addresses: string[],
): string {
assert.isArray('addresses', addresses);
const self = this as any as EthBalanceCheckerContract;
const abiEncodedTransactionData = self._strictEncodeArguments('getEthBalances(address[])', [addresses
]);
return abiEncodedTransactionData;
},
};
public static async deployFrom0xArtifactAsync(
artifact: ContractArtifact | SimpleContractArtifact,

View File

@ -1,4 +1,13 @@
[
{
"version": "2.1.0",
"changes": [
{
"note": "Initial support for Python",
"pr": 1878
}
]
},
{
"version": "2.0.11",
"changes": [

View File

@ -1,5 +1,5 @@
diff $1 $2
if [ $? -ne 0 ]; then
echo "ERROR: Run 'yarn generate_contract_wrappers' to update ./test/generated_test/generated-wrappers"
echo "ERROR: Freshly generated code does not match known-good, commited output. If you're confident that the freshly generated code should be considered known-good, then copy it into there and commit it."
exit 1
fi

View File

@ -11,13 +11,14 @@
"lint": "tslint --format stylish --project . && yarn lint-contracts",
"lint-contracts": "solhint -c ../../contracts/.solhint.json contracts/**/**/**/**/*.sol",
"fix": "tslint --fix --format stylish --project . && yarn lint-contracts",
"clean": "shx rm -rf lib test/generated-test/lib",
"build": "tsc -b && yarn build:test",
"prebuild:test": "run-s compile:sol generate_contract_wrappers",
"build:test": "tsc --project test/generated-test/tsconfig.json",
"clean": "shx rm -rf lib test/generated-test/output",
"build": "tsc -b",
"build_contracts_to_wrap": "run-s compile:sol",
"build_contract_wrappers": "tsc --project test/generated-test/tsconfig.json",
"build:ci": "yarn build",
"test": "run-s run_mocha tmp_generate_contract_wrappers diff_contract_wrappers tmp_remove_contract_wrappers",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js test/generated-test/lib/**/*_test.js --timeout 100000 --bail --exit",
"test": "run-s run_mocha build_contracts_to_wrap generate_contract_wrappers diff_contract_wrappers # build_contract_wrappers run_contract_wrapper_tests HACK: note this is commented out. building those contract wrappers is broken on development right now",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/*_test.js --timeout 100000 --bail --exit",
"run_contract_wrapper_tests": "mocha --require source-map-support/register --require make-promises-safe test/generated-test/output/TypeScript/lib/**/*_test.js --timeout 100000 --bail --exit",
"test:circleci": "yarn test:coverage",
"test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
"coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
@ -27,10 +28,12 @@
"clean:sol": "rm -rf test/generated-test/generated-artifacts",
"compile:sol": "sol-compiler",
"watch:sol": "sol-compiler -w",
"generate_contract_wrappers": "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/generated-test/generated-wrappers --backend ethers",
"tmp_generate_contract_wrappers": "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 ./tmp/generated-wrappers --backend ethers",
"tmp_remove_contract_wrappers": "rm -rf ./tmp/generated-wrappers",
"diff_contract_wrappers": "./diff.sh ./tmp/generated-wrappers ./test/generated-test/generated-wrappers",
"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/generated-test/output/TypeScript/src --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/generated-test/output/Python --language Python",
"diff_contract_wrappers": "run-p diff_typescript diff_python",
"diff_typescript": "./diff.sh ./test/generated-test/known-good/TypeScript ./test/generated-test/output/TypeScript/src",
"diff_python": "./diff.sh ./test/generated-test/known-good/Python ./test/generated-test/output/Python",
"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",
@ -57,6 +60,8 @@
"@0x/typescript-typings": "^4.2.2",
"@0x/utils": "^4.3.3",
"chalk": "^2.3.0",
"change-case": "^3.0.2",
"cli-format": "^3.0.9",
"ethereum-types": "^2.1.2",
"glob": "^7.1.2",
"handlebars": "^4.0.11",

View File

@ -2,7 +2,9 @@
import { AbiEncoder, abiUtils, logUtils } from '@0x/utils';
import chalk from 'chalk';
import { AbiDefinition, ConstructorAbi, EventAbi, MethodAbi } from 'ethereum-types';
import * as changeCase from 'change-case';
import * as cliFormat from 'cli-format';
import { AbiDefinition, ConstructorAbi, DevdocOutput, EventAbi, MethodAbi } from 'ethereum-types';
import { sync as globSync } from 'glob';
import * as Handlebars from 'handlebars';
import * as _ from 'lodash';
@ -43,7 +45,7 @@ const args = yargs
normalize: true,
})
.option('backend', {
describe: `The backing Ethereum library your app uses. Either 'web3' or 'ethers'. Ethers auto-converts small ints to numbers whereas Web3 doesn't.`,
describe: `The backing Ethereum library your app uses. For TypeScript, either 'web3' or 'ethers'. Ethers auto-converts small ints to numbers whereas Web3 doesn't. For Python, the only possibility is Web3.py`,
type: 'string',
choices: [ContractsBackend.Web3, ContractsBackend.Ethers],
default: DEFAULT_BACKEND,
@ -53,6 +55,12 @@ const args = yargs
type: 'number',
default: DEFAULT_NETWORK_ID,
})
.option('language', {
describe: 'Language of output file to generate',
type: 'string',
choices: ['TypeScript', 'Python'],
default: 'TypeScript',
})
.example(
"$0 --abis 'src/artifacts/**/*.json' --out 'src/contracts/generated/' --partials 'src/templates/partials/**/*.handlebars' --template 'src/templates/contract.handlebars'",
'Full usage example',
@ -71,11 +79,42 @@ function registerPartials(): void {
}
}
Handlebars.registerHelper('parameterType', utils.solTypeToTsType.bind(utils, ParamKind.Input, args.backend));
Handlebars.registerHelper('assertionType', utils.solTypeToAssertion.bind(utils));
Handlebars.registerHelper('returnType', utils.solTypeToTsType.bind(utils, ParamKind.Output, args.backend));
if (args.language === 'TypeScript') {
Handlebars.registerHelper('parameterType', utils.solTypeToTsType.bind(utils, ParamKind.Input, args.backend));
Handlebars.registerHelper('assertionType', utils.solTypeToAssertion.bind(utils));
Handlebars.registerHelper('returnType', utils.solTypeToTsType.bind(utils, ParamKind.Output, args.backend));
} else if (args.language === 'Python') {
Handlebars.registerHelper('equal', (lhs, rhs, options) => {
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(
'sanitizeDevdocDetails',
(methodName: string, devdocDetails: string, indent: number, options) => {
// wrap to 80 columns, assuming given indent, so that generated
// docstrings can pass pycodestyle checks.
if (devdocDetails === undefined || devdocDetails.length === 0) {
return '';
}
const columnsPerRow = 80;
return new Handlebars.SafeString(
`\n${cliFormat.wrap(devdocDetails || '', {
paddingLeft: ' '.repeat(indent),
width: columnsPerRow - indent,
ansi: false,
})}\n`,
);
},
);
}
registerPartials();
function makeLanguageSpecificName(methodName: string): string {
return args.language === 'Python' ? changeCase.snake(methodName) : methodName;
}
if (_.isEmpty(abiFileNames)) {
logUtils.log(`${chalk.red(`No ABI files found.`)}`);
logUtils.log(`Please make sure you've passed the correct folder name and that the files have
@ -90,12 +129,16 @@ for (const abiFileName of abiFileNames) {
logUtils.log(`Processing: ${chalk.bold(namedContent.name)}...`);
const parsedContent = JSON.parse(namedContent.content);
let ABI;
let devdoc: DevdocOutput;
if (_.isArray(parsedContent)) {
ABI = parsedContent; // ABI file
} else if (parsedContent.abi !== undefined) {
ABI = parsedContent.abi; // Truffle artifact
} else if (parsedContent.compilerOutput.abi !== undefined) {
ABI = parsedContent.compilerOutput.abi; // 0x artifact
if (parsedContent.compilerOutput.devdoc !== undefined) {
devdoc = parsedContent.compilerOutput.devdoc;
}
}
if (ABI === undefined) {
logUtils.log(`${chalk.red(`ABI not found in ${abiFileName}.`)}`);
@ -106,7 +149,16 @@ for (const abiFileName of abiFileNames) {
}
const outFileName = utils.makeOutputFileName(namedContent.name);
const outFilePath = `${args.output}/${outFileName}.ts`;
const outFileExtension = (() => {
if (args.language === 'TypeScript') {
return 'ts';
} else if (args.language === 'Python') {
return '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)}`);
@ -127,26 +179,39 @@ for (const abiFileName of abiFileNames) {
input.name = `index_${inputIndex}`;
}
});
const functionSignature = new AbiEncoder.Method(methodAbi).getSignature();
const languageSpecificName: string = makeLanguageSpecificName(sanitizedMethodAbis[methodAbiIndex].name);
// This will make templates simpler
const methodData = {
...methodAbi,
singleReturnValue: methodAbi.outputs.length === 1,
hasReturnValue: methodAbi.outputs.length !== 0,
tsName: sanitizedMethodAbis[methodAbiIndex].name,
functionSignature: new AbiEncoder.Method(methodAbi).getSignature(),
languageSpecificName,
functionSignature,
devdoc: devdoc ? devdoc.methods[functionSignature] : undefined,
};
return methodData;
});
const eventAbis = ABI.filter((abi: AbiDefinition) => abi.type === ABI_TYPE_EVENT) as EventAbi[];
const eventsData = _.map(eventAbis, (eventAbi, eventAbiIndex: number) => {
const languageSpecificName = makeLanguageSpecificName(eventAbi.name);
const eventData = {
...eventAbi,
languageSpecificName,
};
return eventData;
});
const contextData = {
contractName: namedContent.name,
ctor,
ABI: JSON.stringify(ABI),
methods: methodsData,
events: eventAbis,
events: eventsData,
};
const renderedTsCode = template(contextData);
utils.writeOutputFile(outFilePath, renderedTsCode);
const renderedCode = template(contextData);
utils.writeOutputFile(outFilePath, renderedCode);
logUtils.log(`Created: ${chalk.bold(outFilePath)}`);
}

View File

@ -13,7 +13,7 @@ export enum ContractsBackend {
export interface Method extends MethodAbi {
singleReturnValue: boolean;
hasReturnValue: boolean;
tsName: string;
languageSpecificName: string;
functionSignature: string;
}

View File

@ -98,6 +98,45 @@ export const utils = {
throw new Error(`Unknown Solidity type found: ${solType}`);
}
},
solTypeToPyType(paramKind: ParamKind, backend: ContractsBackend, 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}]`;
return arrayPyType;
} else {
const solTypeRegexToPyType = [
{ regex: '^string$', pyType: 'str' },
{ regex: '^address$', pyType: 'str' },
{ regex: '^bool$', pyType: 'bool' },
{ regex: '^u?int\\d*$', pyType: 'int' },
{ regex: '^bytes\\d*$', pyType: 'bytes' },
];
for (const regexAndTxType of solTypeRegexToPyType) {
const { regex, pyType } = regexAndTxType;
if (solType.match(regex)) {
return pyType;
}
}
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;
}
throw new Error(`Unknown Solidity type found: ${solType}`);
}
},
isUnionType(tsType: string): boolean {
return tsType === 'number|BigNumber';
},

View File

@ -0,0 +1,207 @@
"""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 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":"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,51 @@
"""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,95 @@
"""Generated wrapper for TestLibDummy 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 TestLibDummy(BaseContractWrapper):
"""Wrapper class for TestLibDummy 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=TestLibDummy.abi()
)
def public_add_constant(
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.publicAddConstant(
x
)
return self._invoke_function_call(
func=func,
tx_params=tx_params,
view_only=True
)
def public_add_one(
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.publicAddOne(
x
)
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":"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)
)

View File

@ -23,12 +23,17 @@ import { assert } from '@0x/assert';
import * as ethers from 'ethers';
// tslint:enable:no-unused-variable
/* istanbul ignore next */
// tslint:disable:no-parameter-reassignment
// tslint:disable-next-line:class-name
export class AbiGenDummyContract extends BaseContract {
public simpleRequire = {
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<void> {
async callAsync(
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<void
> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
@ -37,7 +42,7 @@ export class AbiGenDummyContract extends BaseContract {
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const self = this as any as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('simpleRequire()', []);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
@ -51,20 +56,28 @@ export class AbiGenDummyContract extends BaseContract {
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('simpleRequire()');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<void>(rawCallResult);
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('simpleRequire()', []);
return abiEncodedTransactionData;
},
};
public ecrecoverFn = {
async callAsync(
hash: string,
v: number | BigNumber,
v: number|BigNumber,
r: string,
s: string,
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<string> {
): Promise<string
> {
assert.isString('hash', hash);
assert.isNumberOrBigNumber('v', v);
assert.isString('r', r);
@ -77,12 +90,11 @@ export class AbiGenDummyContract extends BaseContract {
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('ecrecoverFn(bytes32,uint8,bytes32,bytes32)', [
hash,
const self = this as any as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('ecrecoverFn(bytes32,uint8,bytes32,bytes32)', [hash,
v,
r,
s,
s
]);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
@ -96,13 +108,36 @@ export class AbiGenDummyContract extends BaseContract {
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('ecrecoverFn(bytes32,uint8,bytes32,bytes32)');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<string>(rawCallResult);
const result = abiEncoder.strictDecodeReturnValue<string
>(rawCallResult);
// tslint:enable boolean-naming
return result;
},
getABIEncodedTransactionData(
hash: string,
v: number|BigNumber,
r: string,
s: string,
): string {
assert.isString('hash', hash);
assert.isNumberOrBigNumber('v', v);
assert.isString('r', r);
assert.isString('s', s);
const self = this as any as AbiGenDummyContract;
const abiEncodedTransactionData = self._strictEncodeArguments('ecrecoverFn(bytes32,uint8,bytes32,bytes32)', [hash,
v,
r,
s
]);
return abiEncodedTransactionData;
},
};
public revertWithConstant = {
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<void> {
async callAsync(
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<void
> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
@ -111,7 +146,7 @@ export class AbiGenDummyContract extends BaseContract {
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const self = this as any as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('revertWithConstant()', []);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
@ -125,13 +160,24 @@ export class AbiGenDummyContract extends BaseContract {
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('revertWithConstant()');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<void>(rawCallResult);
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('revertWithConstant()', []);
return abiEncodedTransactionData;
},
};
public simpleRevert = {
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<void> {
async callAsync(
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<void
> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
@ -140,7 +186,7 @@ export class AbiGenDummyContract extends BaseContract {
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const self = this as any as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('simpleRevert()', []);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
@ -154,13 +200,24 @@ export class AbiGenDummyContract extends BaseContract {
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('simpleRevert()');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<void>(rawCallResult);
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('simpleRevert()', []);
return abiEncodedTransactionData;
},
};
public requireWithConstant = {
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<void> {
async callAsync(
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<void
> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
@ -169,7 +226,7 @@ export class AbiGenDummyContract extends BaseContract {
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const self = this as any as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('requireWithConstant()', []);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
@ -183,13 +240,25 @@ export class AbiGenDummyContract extends BaseContract {
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('requireWithConstant()');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<void>(rawCallResult);
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('requireWithConstant()', []);
return abiEncodedTransactionData;
},
};
public simplePureFunctionWithInput = {
async callAsync(x: BigNumber, callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<BigNumber> {
async callAsync(
x: BigNumber,
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<BigNumber
> {
assert.isBigNumber('x', x);
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
@ -199,8 +268,9 @@ export class AbiGenDummyContract extends BaseContract {
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('simplePureFunctionWithInput(uint256)', [x]);
const self = this as any as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('simplePureFunctionWithInput(uint256)', [x
]);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
@ -213,13 +283,27 @@ export class AbiGenDummyContract extends BaseContract {
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('simplePureFunctionWithInput(uint256)');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<BigNumber>(rawCallResult);
const result = abiEncoder.strictDecodeReturnValue<BigNumber
>(rawCallResult);
// tslint:enable boolean-naming
return result;
},
getABIEncodedTransactionData(
x: BigNumber,
): string {
assert.isBigNumber('x', x);
const self = this as any as AbiGenDummyContract;
const abiEncodedTransactionData = self._strictEncodeArguments('simplePureFunctionWithInput(uint256)', [x
]);
return abiEncodedTransactionData;
},
};
public simplePureFunction = {
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<BigNumber> {
async callAsync(
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<BigNumber
> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
@ -228,7 +312,7 @@ export class AbiGenDummyContract extends BaseContract {
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const self = this as any as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('simplePureFunction()', []);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
@ -242,13 +326,24 @@ export class AbiGenDummyContract extends BaseContract {
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('simplePureFunction()');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<BigNumber>(rawCallResult);
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('simplePureFunction()', []);
return abiEncodedTransactionData;
},
};
public pureFunctionWithConstant = {
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<BigNumber> {
async callAsync(
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<BigNumber
> {
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
schemas.numberSchema,
@ -257,7 +352,7 @@ export class AbiGenDummyContract extends BaseContract {
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as AbiGenDummyContract;
const self = this as any as AbiGenDummyContract;
const encodedData = self._strictEncodeArguments('pureFunctionWithConstant()', []);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
@ -271,10 +366,17 @@ export class AbiGenDummyContract extends BaseContract {
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('pureFunctionWithConstant()');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<BigNumber>(rawCallResult);
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('pureFunctionWithConstant()', []);
return abiEncodedTransactionData;
},
};
public static async deployFrom0xArtifactAsync(
artifact: ContractArtifact | SimpleContractArtifact,
@ -292,7 +394,7 @@ export class AbiGenDummyContract extends BaseContract {
const provider = providerUtils.standardizeOrThrow(supportedProvider);
const bytecode = artifact.compilerOutput.evm.bytecode.object;
const abi = artifact.compilerOutput.abi;
return AbiGenDummyContract.deployAsync(bytecode, abi, provider, txDefaults);
return AbiGenDummyContract.deployAsync(bytecode, abi, provider, txDefaults, );
}
public static async deployAsync(
bytecode: string,
@ -308,13 +410,17 @@ export class AbiGenDummyContract extends BaseContract {
]);
const provider = providerUtils.standardizeOrThrow(supportedProvider);
const constructorAbi = BaseContract._lookupConstructorAbi(abi);
[] = BaseContract._formatABIDataItemList(constructorAbi.inputs, [], BaseContract._bigNumberToString);
[] = BaseContract._formatABIDataItemList(
constructorAbi.inputs,
[],
BaseContract._bigNumberToString,
);
const iface = new ethers.utils.Interface(abi);
const deployInfo = iface.deployFunction;
const txData = deployInfo.encode(bytecode, []);
const web3Wrapper = new Web3Wrapper(provider);
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{ data: txData },
{data: txData},
txDefaults,
web3Wrapper.estimateGasAsync.bind(web3Wrapper),
);
@ -322,12 +428,7 @@ export class AbiGenDummyContract extends BaseContract {
logUtils.log(`transactionHash: ${txHash}`);
const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash);
logUtils.log(`AbiGenDummy successfully deployed at ${txReceipt.contractAddress}`);
const contractInstance = new AbiGenDummyContract(
abi,
txReceipt.contractAddress as string,
provider,
txDefaults,
);
const contractInstance = new AbiGenDummyContract(abi, txReceipt.contractAddress as string, provider, txDefaults);
contractInstance.constructorArgs = [];
return contractInstance;
}

View File

@ -23,6 +23,7 @@ import { assert } from '@0x/assert';
import * as ethers from 'ethers';
// tslint:enable:no-unused-variable
/* istanbul ignore next */
// tslint:disable:no-parameter-reassignment
// tslint:disable-next-line:class-name
@ -43,7 +44,7 @@ export class LibDummyContract extends BaseContract {
const provider = providerUtils.standardizeOrThrow(supportedProvider);
const bytecode = artifact.compilerOutput.evm.bytecode.object;
const abi = artifact.compilerOutput.abi;
return LibDummyContract.deployAsync(bytecode, abi, provider, txDefaults);
return LibDummyContract.deployAsync(bytecode, abi, provider, txDefaults, );
}
public static async deployAsync(
bytecode: string,
@ -59,13 +60,17 @@ export class LibDummyContract extends BaseContract {
]);
const provider = providerUtils.standardizeOrThrow(supportedProvider);
const constructorAbi = BaseContract._lookupConstructorAbi(abi);
[] = BaseContract._formatABIDataItemList(constructorAbi.inputs, [], BaseContract._bigNumberToString);
[] = BaseContract._formatABIDataItemList(
constructorAbi.inputs,
[],
BaseContract._bigNumberToString,
);
const iface = new ethers.utils.Interface(abi);
const deployInfo = iface.deployFunction;
const txData = deployInfo.encode(bytecode, []);
const web3Wrapper = new Web3Wrapper(provider);
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{ data: txData },
{data: txData},
txDefaults,
web3Wrapper.estimateGasAsync.bind(web3Wrapper),
);

View File

@ -23,12 +23,18 @@ import { assert } from '@0x/assert';
import * as ethers from 'ethers';
// tslint:enable:no-unused-variable
/* istanbul ignore next */
// tslint:disable:no-parameter-reassignment
// tslint:disable-next-line:class-name
export class TestLibDummyContract extends BaseContract {
public publicAddConstant = {
async callAsync(x: BigNumber, callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<BigNumber> {
async callAsync(
x: BigNumber,
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<BigNumber
> {
assert.isBigNumber('x', x);
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
@ -38,8 +44,9 @@ export class TestLibDummyContract extends BaseContract {
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as TestLibDummyContract;
const encodedData = self._strictEncodeArguments('publicAddConstant(uint256)', [x]);
const self = this as any as TestLibDummyContract;
const encodedData = self._strictEncodeArguments('publicAddConstant(uint256)', [x
]);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
@ -52,13 +59,28 @@ export class TestLibDummyContract extends BaseContract {
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('publicAddConstant(uint256)');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<BigNumber>(rawCallResult);
const result = abiEncoder.strictDecodeReturnValue<BigNumber
>(rawCallResult);
// tslint:enable boolean-naming
return result;
},
getABIEncodedTransactionData(
x: BigNumber,
): string {
assert.isBigNumber('x', x);
const self = this as any as TestLibDummyContract;
const abiEncodedTransactionData = self._strictEncodeArguments('publicAddConstant(uint256)', [x
]);
return abiEncodedTransactionData;
},
};
public publicAddOne = {
async callAsync(x: BigNumber, callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<BigNumber> {
async callAsync(
x: BigNumber,
callData: Partial<CallData> = {},
defaultBlock?: BlockParam,
): Promise<BigNumber
> {
assert.isBigNumber('x', x);
assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [
schemas.addressSchema,
@ -68,8 +90,9 @@ export class TestLibDummyContract extends BaseContract {
if (defaultBlock !== undefined) {
assert.isBlockParam('defaultBlock', defaultBlock);
}
const self = (this as any) as TestLibDummyContract;
const encodedData = self._strictEncodeArguments('publicAddOne(uint256)', [x]);
const self = this as any as TestLibDummyContract;
const encodedData = self._strictEncodeArguments('publicAddOne(uint256)', [x
]);
const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{
to: self.address,
@ -82,10 +105,20 @@ export class TestLibDummyContract extends BaseContract {
BaseContract._throwIfRevertWithReasonCallResult(rawCallResult);
const abiEncoder = self._lookupAbiEncoder('publicAddOne(uint256)');
// tslint:disable boolean-naming
const result = abiEncoder.strictDecodeReturnValue<BigNumber>(rawCallResult);
const result = abiEncoder.strictDecodeReturnValue<BigNumber
>(rawCallResult);
// tslint:enable boolean-naming
return result;
},
getABIEncodedTransactionData(
x: BigNumber,
): string {
assert.isBigNumber('x', x);
const self = this as any as TestLibDummyContract;
const abiEncodedTransactionData = self._strictEncodeArguments('publicAddOne(uint256)', [x
]);
return abiEncodedTransactionData;
},
};
public static async deployFrom0xArtifactAsync(
artifact: ContractArtifact | SimpleContractArtifact,
@ -103,7 +136,7 @@ export class TestLibDummyContract extends BaseContract {
const provider = providerUtils.standardizeOrThrow(supportedProvider);
const bytecode = artifact.compilerOutput.evm.bytecode.object;
const abi = artifact.compilerOutput.abi;
return TestLibDummyContract.deployAsync(bytecode, abi, provider, txDefaults);
return TestLibDummyContract.deployAsync(bytecode, abi, provider, txDefaults, );
}
public static async deployAsync(
bytecode: string,
@ -119,13 +152,17 @@ export class TestLibDummyContract extends BaseContract {
]);
const provider = providerUtils.standardizeOrThrow(supportedProvider);
const constructorAbi = BaseContract._lookupConstructorAbi(abi);
[] = BaseContract._formatABIDataItemList(constructorAbi.inputs, [], BaseContract._bigNumberToString);
[] = BaseContract._formatABIDataItemList(
constructorAbi.inputs,
[],
BaseContract._bigNumberToString,
);
const iface = new ethers.utils.Interface(abi);
const deployInfo = iface.deployFunction;
const txData = deployInfo.encode(bytecode, []);
const web3Wrapper = new Web3Wrapper(provider);
const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync(
{ data: txData },
{data: txData},
txDefaults,
web3Wrapper.estimateGasAsync.bind(web3Wrapper),
);
@ -133,12 +170,7 @@ export class TestLibDummyContract extends BaseContract {
logUtils.log(`transactionHash: ${txHash}`);
const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash);
logUtils.log(`TestLibDummy successfully deployed at ${txReceipt.contractAddress}`);
const contractInstance = new TestLibDummyContract(
abi,
txReceipt.contractAddress as string,
provider,
txDefaults,
);
const contractInstance = new TestLibDummyContract(abi, txReceipt.contractAddress as string, provider, txDefaults);
contractInstance.constructorArgs = [];
return contractInstance;
}

View File

@ -1,14 +1,16 @@
{
"extends": "../../tsconfig.json",
"extends": "../../../../tsconfig.json",
"compilerOptions": {
"resolveJsonModule": true,
"outDir": "lib",
"outDir": "./output/lib",
"rootDir": "."
},
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"./generated-artifacts/AbiGenDummy.json",
"./generated-artifacts/LibDummy.json",
"./generated-artifacts/TestLibDummy.json"
"./generated-artifacts/TestLibDummy.json",
"./output/src/abi_gen_dummy.ts",
"./output/src/lib_dummy.ts",
"./output/src/test_lib_dummy.ts"
]
}

View File

@ -4,6 +4,11 @@
"outDir": "lib",
"rootDir": "."
},
"exclude": ["./test/generated-test/**/*"],
"exclude": [
"./test/generated-test/**/*",
"./src/artifacts.ts",
"./src/wrappers.ts",
"prior two elements refer to code generated by contracts-gen for test fixture contracts"
],
"include": ["./src/**/*", "./test/*"]
}

View File

@ -1,4 +1,13 @@
[
{
"version": "2.1.3",
"changes": [
{
"note": "Made most fields in DevdocOutput optional, as they may not all be present just because devdoc is",
"pr": 1878
}
]
},
{
"version": "2.1.2",
"changes": [

Binary file not shown.

View File

@ -0,0 +1,11 @@
[
{
"version": "1.0.0",
"changes": [
{
"note": "Initial commit. Functionality tested for ERC20Token wrapper",
"pr": 1878
}
]
}
]

View File

@ -0,0 +1,41 @@
## @0x/python-contract-wrappers
Python wrappers around the 0x smart contracts, generated using @0x/abi-gen.
The code generated by this package's `build` script is consumed by
`../../python-packages/contract_wrappers/setup.py`'s `pre_install` command.
The code generated by this package should not be used directly.
## Contributing
We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
yarn config set workspaces-experimental true
```
Then install dependencies
```bash
yarn install
```
### Build
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
```bash
PKG=@0x/python-contract-wrappers yarn build
```
### Clean
```bash
yarn clean
```

View File

@ -0,0 +1,34 @@
{
"name": "@0x/python-contract-wrappers",
"version": "1.0.0",
"engines": {
"node": ">=6.12"
},
"private": true,
"description": "Python wrappers for 0x smart contracts, generated via abi-gen",
"scripts": {
"generate": "abi-gen --abis ${npm_package_config_abis} --template ../abi-gen-templates/Python/contract.handlebars --partials '../abi-gen-templates/Python/partials/**/*.handlebars' --output generated --language Python",
"build": "yarn generate",
"build:ci": "yarn build",
"clean": "shx rm -rf generated"
},
"config": {
"abis": "../contract-artifacts/artifacts/ERC20Token.json"
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/0x-monorepo.git"
},
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/0xProject/0x-monorepo/issues"
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/python-contract-wrappers/README.md",
"devDependencies": {
"@0x/abi-gen": "^2.0.10",
"shx": "^0.2.2"
},
"publishConfig": {
"access": "restricted"
}
}

View File

@ -1,4 +1,13 @@
[
{
"version": "2.0.13",
"changes": [
{
"note": "Confirm devdoc components exist before using them",
"pr": 1878
}
]
},
{
"timestamp": 1558712885,
"version": "2.0.12",

View File

@ -0,0 +1 @@
declare module 'cli-format';

View File

@ -16,6 +16,12 @@ We welcome improvements and fixes from the wider community! To report bugs withi
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Pull in artifacts from TypeScript build environment
```bash
./setup.py pre_install
```
### Install Code and Dependencies
```bash

View File

@ -3,7 +3,7 @@
"""setuptools module for contract_artifacts package."""
import subprocess # nosec
from shutil import rmtree
from shutil import copytree, rmtree
from os import environ, path
from sys import argv
@ -13,6 +13,35 @@ 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 artifacts."""
description = "Pull in the artifacts that live in the TypeScript package."
def run(self):
"""Copy files from TS build area to local src, & `black` them."""
pkgdir = path.dirname(path.realpath(argv[0]))
rmtree(
path.join(
pkgdir, "src", "zero_ex", "contract_artifacts", "artifacts"
),
ignore_errors=True,
)
copytree(
path.join(
pkgdir,
"..",
"..",
"packages",
"contract-artifacts",
"artifacts",
),
path.join(
pkgdir, "src", "zero_ex", "contract_artifacts", "artifacts"
),
)
class LintCommand(distutils.command.build_py.build_py):
"""Custom setuptools command class for running linters."""
@ -138,6 +167,7 @@ setup(
author="F. Eugene Aumson",
author_email="feuGeneA@users.noreply.github.com",
cmdclass={
"pre_install": PreInstallCommand,
"clean": CleanCommandExtension,
"lint": LintCommand,
"test": TestCommandExtension,

View File

@ -1,54 +0,0 @@
{
"schemaVersion": "2.0.0",
"contractName": "CoordinatorRegistry",
"compilerOutput": {
"abi": [
{
"constant": false,
"inputs": [{ "name": "coordinatorEndpoint", "type": "string" }],
"name": "setCoordinatorEndpoint",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "coordinatorOperator", "type": "address" }],
"name": "getCoordinatorEndpoint",
"outputs": [{ "name": "coordinatorEndpoint", "type": "string" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{ "inputs": [], "payable": false, "stateMutability": "nonpayable", "type": "constructor" },
{
"anonymous": false,
"inputs": [
{ "indexed": false, "name": "coordinatorOperator", "type": "address" },
{ "indexed": false, "name": "coordinatorEndpoint", "type": "string" }
],
"name": "CoordinatorEndpointSet",
"type": "event"
}
],
"devdoc": {
"methods": {
"getCoordinatorEndpoint(address)": {
"details": "Gets the endpoint for a Coordinator.",
"params": { "coordinatorOperator": "operator of the Coordinator endpoint." }
},
"setCoordinatorEndpoint(string)": {
"details": "Called by a Coordinator operator to set the endpoint of their Coordinator.",
"params": { "coordinatorEndpoint": "endpoint of the Coordinator." }
}
}
},
"evm": {
"bytecode": {
"object": "0x608060405234801561001057600080fd5b506104b5806100206000396000f3fe608060405234801561001057600080fd5b5060043610610052577c010000000000000000000000000000000000000000000000000000000060003504635b2388be81146100575780636c90fedb1461006c575b600080fd5b61006a6100653660046102ff565b610095565b005b61007f61007a3660046102d9565b6100f0565b60405161008c91906103d8565b60405180910390f35b3360008181526020819052604090206100af9084846101c4565b507fd060052768902f3eecb84b8eae9d3a2608a1a9e60811a33968b46b8d552f266e8184846040516100e3939291906103ae565b60405180910390a1505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081815260409182902080548351601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001861615020190931692909204918201849004840281018401909452808452606093928301828280156101b85780601f1061018d576101008083540402835291602001916101b8565b820191906000526020600020905b81548152906001019060200180831161019b57829003601f168201915b50505050509050919050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610223578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00823516178555610250565b82800160010185558215610250579182015b82811115610250578235825591602001919060010190610235565b5061025c929150610260565b5090565b61027a91905b8082111561025c5760008155600101610266565b90565b600061028982356103ed565b9392505050565b600080601f830184136102a257600080fd5b50813567ffffffffffffffff8111156102ba57600080fd5b6020830191508360018202830111156102d257600080fd5b9250929050565b6000602082840312156102eb57600080fd5b60006102f7848461027d565b949350505050565b6000806020838503121561031257600080fd5b823567ffffffffffffffff81111561032957600080fd5b61033585828601610290565b92509250509250929050565b61034a816103ed565b82525050565b6000828452602084019350610366838584610417565b61036f83610453565b9093019392505050565b6000610384826103e9565b808452610398816020860160208601610423565b6103a181610453565b9093016020019392505050565b604081016103bc8286610341565b81810360208301526103cf818486610350565b95945050505050565b602080825281016102898184610379565b5190565b60006103f8826103fe565b92915050565b73ffffffffffffffffffffffffffffffffffffffff1690565b82818337506000910152565b60005b8381101561043e578181015183820152602001610426565b8381111561044d576000848401525b50505050565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169056fea265627a7a72305820d8fc8bc6ec7167e671f9f87937212d93c49d5fbe171bbdfa06c846e5ac76151b6c6578706572696d656e74616cf50037"
}
}
},
"networks": {}
}

File diff suppressed because one or more lines are too long

View File

@ -1,134 +0,0 @@
{
"schemaVersion": "2.0.0",
"contractName": "ERC20Token",
"compilerOutput": {
"abi": [
{
"constant": false,
"inputs": [{ "name": "_spender", "type": "address" }, { "name": "_value", "type": "uint256" }],
"name": "approve",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "name": "_from", "type": "address" },
{ "name": "_to", "type": "address" },
{ "name": "_value", "type": "uint256" }
],
"name": "transferFrom",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "_owner", "type": "address" }],
"name": "balanceOf",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_to", "type": "address" }, { "name": "_value", "type": "uint256" }],
"name": "transfer",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" }],
"name": "allowance",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "_from", "type": "address" },
{ "indexed": true, "name": "_to", "type": "address" },
{ "indexed": false, "name": "_value", "type": "uint256" }
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "_owner", "type": "address" },
{ "indexed": true, "name": "_spender", "type": "address" },
{ "indexed": false, "name": "_value", "type": "uint256" }
],
"name": "Approval",
"type": "event"
}
],
"devdoc": {
"methods": {
"allowance(address,address)": {
"params": {
"_owner": "The address of the account owning tokens",
"_spender": "The address of the account able to transfer the tokens"
},
"return": "Amount of remaining tokens allowed to spent"
},
"approve(address,uint256)": {
"details": "`msg.sender` approves `_spender` to spend `_value` tokens",
"params": {
"_spender": "The address of the account able to transfer the tokens",
"_value": "The amount of wei to be approved for transfer"
},
"return": "Always true if the call has enough gas to complete execution"
},
"balanceOf(address)": {
"details": "Query the balance of owner",
"params": { "_owner": "The address from which the balance will be retrieved" },
"return": "Balance of owner"
},
"totalSupply()": { "details": "Query total supply of token", "return": "Total supply of token" },
"transfer(address,uint256)": {
"details": "send `value` token to `to` from `msg.sender`",
"params": {
"_to": "The address of the recipient",
"_value": "The amount of token to be transferred"
},
"return": "True if transfer was successful"
},
"transferFrom(address,address,uint256)": {
"details": "send `value` token to `to` from `from` on the condition it is approved by `from`",
"params": {
"_from": "The address of the sender",
"_to": "The address of the recipient",
"_value": "The amount of token to be transferred"
},
"return": "True if transfer was successful"
}
}
},
"evm": {
"bytecode": {
"object": "0x608060405234801561001057600080fd5b506106a0806100206000396000f3006080604052600436106100775763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663095ea7b3811461007c57806318160ddd146100c157806323b872dd146100e857806370a082311461011f578063a9059cbb1461014d578063dd62ed3e1461017e575b600080fd5b34801561008857600080fd5b506100ad73ffffffffffffffffffffffffffffffffffffffff600435166024356101b2565b604080519115158252519081900360200190f35b3480156100cd57600080fd5b506100d6610225565b60408051918252519081900360200190f35b3480156100f457600080fd5b506100ad73ffffffffffffffffffffffffffffffffffffffff6004358116906024351660443561022b565b34801561012b57600080fd5b506100d673ffffffffffffffffffffffffffffffffffffffff60043516610487565b34801561015957600080fd5b506100ad73ffffffffffffffffffffffffffffffffffffffff600435166024356104af565b34801561018a57600080fd5b506100d673ffffffffffffffffffffffffffffffffffffffff6004358116906024351661063c565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b60025490565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602081905260408120548211156102bf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f45524332305f494e53554646494349454e545f42414c414e4345000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8416600090815260016020908152604080832033845290915290205482111561035e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f45524332305f494e53554646494349454e545f414c4c4f57414e434500000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110156103f457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff80841660008181526020818152604080832080548801905593881680835284832080548890039055600182528483203384528252918490208054879003905583518681529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35060019392505050565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b3360009081526020819052604081205482111561052d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f45524332305f494e53554646494349454e545f42414c414e4345000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110156105c357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b336000818152602081815260408083208054879003905573ffffffffffffffffffffffffffffffffffffffff871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a350600192915050565b73ffffffffffffffffffffffffffffffffffffffff9182166000908152600160209081526040808320939094168252919091522054905600a165627a7a72305820203a592c9390a8a005821d7dffa1c27ae97bf827d8ef17cfee3a8a70776b22d90029"
}
}
},
"networks": {}
}

View File

@ -1,32 +0,0 @@
{
"schemaVersion": "2.0.0",
"contractName": "EthBalanceChecker",
"compilerOutput": {
"abi": [
{
"constant": true,
"inputs": [{ "name": "addresses", "type": "address[]" }],
"name": "getEthBalances",
"outputs": [{ "name": "", "type": "uint256[]" }],
"payable": false,
"stateMutability": "view",
"type": "function"
}
],
"devdoc": {
"methods": {
"getEthBalances(address[])": {
"details": "Batch fetches ETH balances",
"params": { "addresses": "Array of addresses." },
"return": "Array of ETH balances."
}
}
},
"evm": {
"bytecode": {
"object": "0x608060405234801561001057600080fd5b506101e5806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063a0901e5114610030575b600080fd5b6100d36004803603602081101561004657600080fd5b81019060208101813564010000000081111561006157600080fd5b82018360208201111561007357600080fd5b8035906020019184602083028401116401000000008311171561009557600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610123945050505050565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561010f5781810151838201526020016100f7565b505050509050019250505060405180910390f35b6060808251604051908082528060200260200182016040528015610151578160200160208202803883390190505b50905060005b835181146101a95783818151811061016b57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff163182828151811061019657fe5b6020908102919091010152600101610157565b509291505056fea265627a7a72305820c934dc478ccdc0f8a6d0fb6135610c21efcb23a2fd5075c6d2c4891b449b70f964736f6c63430005090032"
}
}
},
"networks": {}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,114 +0,0 @@
{
"schemaVersion": "2.0.0",
"contractName": "IAssetProxy",
"compilerOutput": {
"abi": [
{
"constant": false,
"inputs": [{ "name": "target", "type": "address" }],
"name": "addAuthorizedAddress",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "target", "type": "address" }],
"name": "removeAuthorizedAddress",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "target", "type": "address" }, { "name": "index", "type": "uint256" }],
"name": "removeAuthorizedAddressAtIndex",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "name": "assetData", "type": "bytes" },
{ "name": "from", "type": "address" },
{ "name": "to", "type": "address" },
{ "name": "amount", "type": "uint256" }
],
"name": "transferFrom",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getProxyId",
"outputs": [{ "name": "", "type": "bytes4" }],
"payable": false,
"stateMutability": "pure",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getAuthorizedAddresses",
"outputs": [{ "name": "", "type": "address[]" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "newOwner", "type": "address" }],
"name": "transferOwnership",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
],
"devdoc": {
"methods": {
"addAuthorizedAddress(address)": {
"details": "Authorizes an address.",
"params": { "target": "Address to authorize." }
},
"getAuthorizedAddresses()": {
"details": "Gets all authorized addresses.",
"return": "Array of authorized addresses."
},
"getProxyId()": {
"details": "Gets the proxy id associated with the proxy address.",
"return": "Proxy id."
},
"removeAuthorizedAddress(address)": {
"details": "Removes authorizion of an address.",
"params": { "target": "Address to remove authorization from." }
},
"removeAuthorizedAddressAtIndex(address,uint256)": {
"details": "Removes authorizion of an address.",
"params": {
"index": "Index of target in authorities array.",
"target": "Address to remove authorization from."
}
},
"transferFrom(bytes,address,address,uint256)": {
"details": "Transfers assets. Either succeeds or throws.",
"params": {
"amount": "Amount of asset to transfer.",
"assetData": "Byte array encoded for the respective asset proxy.",
"from": "Address to transfer asset from.",
"to": "Address to transfer asset to."
}
}
}
},
"evm": { "bytecode": { "object": "0x" } }
},
"networks": {}
}

View File

@ -1,36 +0,0 @@
{
"schemaVersion": "2.0.0",
"contractName": "IValidator",
"compilerOutput": {
"abi": [
{
"constant": true,
"inputs": [
{ "name": "hash", "type": "bytes32" },
{ "name": "signerAddress", "type": "address" },
{ "name": "signature", "type": "bytes" }
],
"name": "isValidSignature",
"outputs": [{ "name": "isValid", "type": "bool" }],
"payable": false,
"stateMutability": "view",
"type": "function"
}
],
"devdoc": {
"methods": {
"isValidSignature(bytes32,address,bytes)": {
"details": "Verifies that a signature is valid.",
"params": {
"hash": "Message hash that is signed.",
"signature": "Proof of signing.",
"signerAddress": "Address that should have signed the given hash."
},
"return": "Validity of order signature."
}
}
},
"evm": { "bytecode": { "object": "0x" } }
},
"networks": {}
}

View File

@ -1,28 +0,0 @@
{
"schemaVersion": "2.0.0",
"contractName": "IWallet",
"compilerOutput": {
"abi": [
{
"constant": true,
"inputs": [{ "name": "hash", "type": "bytes32" }, { "name": "signature", "type": "bytes" }],
"name": "isValidSignature",
"outputs": [{ "name": "isValid", "type": "bool" }],
"payable": false,
"stateMutability": "view",
"type": "function"
}
],
"devdoc": {
"methods": {
"isValidSignature(bytes32,bytes)": {
"details": "Verifies that a signature is valid.",
"params": { "hash": "Message hash that is signed.", "signature": "Proof of signing." },
"return": "Validity of order signature."
}
}
},
"evm": { "bytecode": { "object": "0x" } }
},
"networks": {}
}

View File

@ -1,157 +0,0 @@
{
"schemaVersion": "2.0.0",
"contractName": "WETH9",
"compilerOutput": {
"abi": [
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [{ "name": "", "type": "string" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "guy", "type": "address" }, { "name": "wad", "type": "uint256" }],
"name": "approve",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{ "name": "src", "type": "address" },
{ "name": "dst", "type": "address" },
{ "name": "wad", "type": "uint256" }
],
"name": "transferFrom",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "wad", "type": "uint256" }],
"name": "withdraw",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [{ "name": "", "type": "uint8" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "", "type": "address" }],
"name": "balanceOf",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [{ "name": "", "type": "string" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "dst", "type": "address" }, { "name": "wad", "type": "uint256" }],
"name": "transfer",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "deposit",
"outputs": [],
"payable": true,
"stateMutability": "payable",
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "", "type": "address" }, { "name": "", "type": "address" }],
"name": "allowance",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{ "payable": true, "stateMutability": "payable", "type": "fallback" },
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "_owner", "type": "address" },
{ "indexed": true, "name": "_spender", "type": "address" },
{ "indexed": false, "name": "_value", "type": "uint256" }
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "_from", "type": "address" },
{ "indexed": true, "name": "_to", "type": "address" },
{ "indexed": false, "name": "_value", "type": "uint256" }
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "_owner", "type": "address" },
{ "indexed": false, "name": "_value", "type": "uint256" }
],
"name": "Deposit",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "_owner", "type": "address" },
{ "indexed": false, "name": "_value", "type": "uint256" }
],
"name": "Withdrawal",
"type": "event"
}
],
"devdoc": { "methods": {} },
"evm": {
"bytecode": {
"object": "0x60c0604052600d60808190527f577261707065642045746865720000000000000000000000000000000000000060a090815261003e91600091906100a3565b506040805180820190915260048082527f57455448000000000000000000000000000000000000000000000000000000006020909201918252610083916001916100a3565b506002805460ff1916601217905534801561009d57600080fd5b5061013e565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100e457805160ff1916838001178555610111565b82800160010185558215610111579182015b828111156101115782518255916020019190600101906100f6565b5061011d929150610121565b5090565b61013b91905b8082111561011d5760008155600101610127565b90565b6107688061014d6000396000f3006080604052600436106100ae5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde0381146100b8578063095ea7b31461014257806318160ddd1461018757806323b872dd146101ae5780632e1a7d4d146101e5578063313ce567146101fd57806370a082311461022857806395d89b4114610256578063a9059cbb1461026b578063d0e30db0146100ae578063dd62ed3e1461029c575b6100b66102d0565b005b3480156100c457600080fd5b506100cd61031f565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101075781810151838201526020016100ef565b50505050905090810190601f1680156101345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561014e57600080fd5b5061017373ffffffffffffffffffffffffffffffffffffffff600435166024356103cb565b604080519115158252519081900360200190f35b34801561019357600080fd5b5061019c61043e565b60408051918252519081900360200190f35b3480156101ba57600080fd5b5061017373ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610443565b3480156101f157600080fd5b506100b66004356105e3565b34801561020957600080fd5b50610212610678565b6040805160ff9092168252519081900360200190f35b34801561023457600080fd5b5061019c73ffffffffffffffffffffffffffffffffffffffff60043516610681565b34801561026257600080fd5b506100cd610693565b34801561027757600080fd5b5061017373ffffffffffffffffffffffffffffffffffffffff6004351660243561070b565b3480156102a857600080fd5b5061019c73ffffffffffffffffffffffffffffffffffffffff6004358116906024351661071f565b33600081815260036020908152604091829020805434908101909155825190815291517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9281900390910190a2565b6000805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f810184900484028201840190925281815292918301828280156103c35780601f10610398576101008083540402835291602001916103c3565b820191906000526020600020905b8154815290600101906020018083116103a657829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a350600192915050565b303190565b73ffffffffffffffffffffffffffffffffffffffff831660009081526003602052604081205482111561047557600080fd5b73ffffffffffffffffffffffffffffffffffffffff841633148015906104eb575073ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14155b156105655773ffffffffffffffffffffffffffffffffffffffff8416600090815260046020908152604080832033845290915290205482111561052d57600080fd5b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020805483900390555b73ffffffffffffffffffffffffffffffffffffffff808516600081815260036020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a35060019392505050565b336000908152600360205260409020548111156105ff57600080fd5b33600081815260036020526040808220805485900390555183156108fc0291849190818181858888f1935050505015801561063e573d6000803e3d6000fd5b5060408051828152905133917f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65919081900360200190a250565b60025460ff1681565b60036020526000908152604090205481565b60018054604080516020600284861615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f810184900484028201840190925281815292918301828280156103c35780601f10610398576101008083540402835291602001916103c3565b6000610718338484610443565b9392505050565b6004602090815260009283526040808420909152908252902054815600a165627a7a72305820228981f11f47ad9630080069b0a81423fcfba5aa8e0f478a579c4bc080ba7e820029"
}
}
},
"networks": {}
}

View File

@ -1,124 +0,0 @@
{
"schemaVersion": "2.0.0",
"contractName": "ZRXToken",
"compilerOutput": {
"abi": [
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [{ "name": "", "type": "string" }],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_spender", "type": "address" }, { "name": "_value", "type": "uint256" }],
"name": "approve",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{ "name": "_from", "type": "address" },
{ "name": "_to", "type": "address" },
{ "name": "_value", "type": "uint256" }
],
"name": "transferFrom",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [{ "name": "", "type": "uint8" }],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "_owner", "type": "address" }],
"name": "balanceOf",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [{ "name": "", "type": "string" }],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [{ "name": "_to", "type": "address" }, { "name": "_value", "type": "uint256" }],
"name": "transfer",
"outputs": [{ "name": "", "type": "bool" }],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "_owner", "type": "address" }, { "name": "_spender", "type": "address" }],
"name": "allowance",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"type": "function"
},
{ "inputs": [], "payable": false, "type": "constructor" },
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "_from", "type": "address" },
{ "indexed": true, "name": "_to", "type": "address" },
{ "indexed": false, "name": "_value", "type": "uint256" }
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": true, "name": "_owner", "type": "address" },
{ "indexed": true, "name": "_spender", "type": "address" },
{ "indexed": false, "name": "_value", "type": "uint256" }
],
"name": "Approval",
"type": "event"
}
],
"devdoc": {
"methods": {
"transferFrom(address,address,uint256)": {
"details": "ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.",
"params": {
"_from": "Address to transfer from.",
"_to": "Address to transfer to.",
"_value": "Amount to transfer."
},
"return": "Success of transfer."
}
}
},
"evm": {
"bytecode": {
"object": "0x60606040526b033b2e3c9fd0803ce8000000600355341561001c57fe5b5b600354600160a060020a0333166000908152602081905260409020555b5b61078d8061004a6000396000f300606060405236156100965763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610098578063095ea7b31461014657806318160ddd1461018657806323b872dd146101a8578063313ce567146101ee57806370a082311461021457806395d89b411461024f578063a9059cbb146102fd578063dd62ed3e1461033d575bfe5b34156100a057fe5b6100a861037e565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014e57fe5b61017273ffffffffffffffffffffffffffffffffffffffff600435166024356103b5565b604080519115158252519081900360200190f35b341561018e57fe5b61019661042d565b60408051918252519081900360200190f35b34156101b057fe5b61017273ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610433565b604080519115158252519081900360200190f35b34156101f657fe5b6101fe6105d4565b6040805160ff9092168252519081900360200190f35b341561021c57fe5b61019673ffffffffffffffffffffffffffffffffffffffff600435166105d9565b60408051918252519081900360200190f35b341561025757fe5b6100a8610605565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561030557fe5b61017273ffffffffffffffffffffffffffffffffffffffff6004351660243561063c565b604080519115158252519081900360200190f35b341561034557fe5b61019673ffffffffffffffffffffffffffffffffffffffff60043581169060243516610727565b60408051918252519081900360200190f35b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104835750828110155b80156104b6575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156105c65773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156105585773ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832033909416835292905220805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506105cb565b600091505b5b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff3316600090815260208190526040812054829010801590610699575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b156107185773ffffffffffffffffffffffffffffffffffffffff33811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610427565b506000610427565b5b92915050565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600160209081526040808320938516835292905220545b929150505600a165627a7a723058201b5b70cf82a73dec658c2e60ab9a0f8e2ba01a74b66a6f5b0402f56d2ea0ffcf0029"
}
}
},
"networks": {}
}

View File

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

View File

@ -3,10 +3,11 @@
"""setuptools module for contract_wrappers package."""
import subprocess # nosec
from shutil import rmtree
from shutil import copy, rmtree
from os import environ, path
from pathlib import Path
from sys import argv
from importlib.util import find_spec
from distutils.command.clean import clean
import distutils.command.build_py
@ -14,6 +15,38 @@ from setuptools import find_packages, setup
from setuptools.command.test import test as TestCommand
BLACK_COMMAND = "black --line-length 79"
class PreInstallCommand(distutils.command.build_py.build_py):
"""Custom setuptools command class for pulling in generated code."""
description = "Pull in code generated by TypeScript"
def run(self):
"""Copy files from TS build area to local src, & `black` them."""
pkgdir = path.dirname(path.realpath(argv[0]))
copy(
path.join(
pkgdir,
"..",
"..",
"packages",
"python-contract-wrappers",
"generated",
"erc20_token.py",
),
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()
)
class TestCommandExtension(TestCommand):
"""Run pytest tests."""
@ -33,7 +66,7 @@ class LintCommand(distutils.command.build_py.build_py):
"""Run linter shell commands."""
lint_commands = [
# formatter:
"black --line-length 79 --check --diff src test setup.py".split(),
(BLACK_COMMAND + " --check --diff src test setup.py").split(),
# style guide checker (formerly pep8):
"pycodestyle src test setup.py".split(),
# docstring style checker:
@ -152,6 +185,7 @@ setup(
author_email="feuGeneA@users.noreply.github.com",
cmdclass={
"clean": CleanCommandExtension,
"pre_install": PreInstallCommand,
"lint": LintCommand,
"test": TestCommandExtension,
"test_publish": TestPublishCommand,

View File

@ -91,19 +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
>>> erc20_wrapper = ERC20Token(ganache)
>>> zrx_wrapper = ERC20Token(
... provider=ganache,
... contract_address=NETWORK_TO_ADDRESSES[NetworkId.GANACHE].zrx_token,
... )
>>> weth_wrapper = ERC20Token(
... provider=ganache,
... contract_address=NETWORK_TO_ADDRESSES[NetworkId.GANACHE].ether_token,
... )
>>> erc20_proxy_addr = NETWORK_TO_ADDRESSES[NetworkId.GANACHE].erc20_proxy
>>> tx = erc20_wrapper.approve(
... zrx_address,
>>> tx = zrx_wrapper.approve(
... erc20_proxy_addr,
... to_wei(100, 'ether'),
... tx_params=TxParams(from_=maker_address),
... )
>>> tx = erc20_wrapper.approve(
... weth_address,
>>> tx = weth_wrapper.approve(
... erc20_proxy_addr,
... to_wei(100, 'ether'),
... tx_params=TxParams(from_=taker_address),
@ -157,7 +162,10 @@ fill. This example fills the order completely, but partial fills are possible
too.
>>> from zero_ex.contract_wrappers import Exchange
>>> exchange_contract = Exchange(ganache)
>>> exchange_contract = Exchange(
... provider=ganache,
... contract_address=NETWORK_TO_ADDRESSES[NetworkId.GANACHE].exchange,
... )
>>> tx_hash = exchange_contract.fill_order(
... order=order,
... taker_amount=order["takerAssetAmount"],
@ -288,5 +296,5 @@ HexBytes('0x...')
"""
from .tx_params import TxParams
from .erc20_wrapper import ERC20Token
from .erc20_token import ERC20Token
from .exchange_wrapper import Exchange

View File

@ -15,24 +15,28 @@ class BaseContractWrapper:
It provides functionality for instantiating a contract instance,
calling view functions, and calling functions which require
transactions.
:param provider: instance of :class:`web3.providers.base.BaseProvider`
:param account_address: default None, str of account address
:param private_key: default None, str of private_key
"""
def __init__(
self,
provider: BaseProvider,
account_address: str = None,
contract_address: str,
private_key: str = None,
):
"""Create an instance of BaseContractWrapper."""
"""Create an instance of BaseContractWrapper.
:param provider: instance of :class:`web3.providers.base.BaseProvider`
:param private_key: If specified, transactions will be signed locally,
via Web3.py's `eth.account.signTransaction()`:code:, before being
sent via `eth.sendRawTransaction()`:code:.
"""
self._provider = provider
self._account_address = account_address
self._private_key = private_key
self._web3 = Web3(provider)
self._web3_eth = self._web3.eth # pylint: disable=no-member
self._contract_address = self._validate_and_checksum_address(
contract_address
)
self._can_send_tx = False
if self._web3_eth.defaultAccount or self._web3_eth.accounts:
@ -98,7 +102,6 @@ class BaseContractWrapper:
# pylint: disable=too-many-arguments
def execute_method(
self,
address: str,
abi: dict,
method: str,
args: Optional[Union[list, tuple]] = None,
@ -107,7 +110,6 @@ class BaseContractWrapper:
) -> str:
"""Execute the method on a contract instance.
:param address: string of contract address
:param abi: dict of contract ABI
:param method: string name of method to call
:param args: default None, list or tuple of arguments for the method
@ -117,7 +119,9 @@ class BaseContractWrapper:
:returns: str of transaction hash
"""
contract_instance = self._contract_instance(address=address, abi=abi)
contract_instance = self._contract_instance(
address=self._contract_address, abi=abi
)
if args is None:
args = []
if hasattr(contract_instance.functions, method):
@ -126,5 +130,7 @@ class BaseContractWrapper:
func=func, tx_params=tx_params, view_only=view_only
)
raise Exception(
"No method {} found on contract {}.".format(address, method)
"No method {} found on contract {}.".format(
self._contract_address, method
)
)

View File

@ -1,202 +0,0 @@
"""Wrapper for Ethereum ERC20 Token smart contract."""
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_artifacts import abi_by_name
from ._base_contract_wrapper import BaseContractWrapper
from .tx_params import TxParams
class ERC20Token(BaseContractWrapper):
"""Wrapper class for Ethereum ERC20 smart contract."""
def __init__(
self,
provider: BaseProvider,
account_address: str = None,
private_key: str = None,
):
"""Get an instance of wrapper for ERC20 smart contract.
:param provider: instance of :class:`web3.providers.base.BaseProvider`
"""
super(ERC20Token, self).__init__(
provider=provider,
account_address=account_address,
private_key=private_key,
)
def _erc20(self, token_address):
"""Get an instance of the ERC20 smart contract at a specific address.
:returns: ERC20 contract object
"""
return self._contract_instance(
address=token_address, abi=abi_by_name("ERC20Token")
)
# pylint: disable=too-many-arguments
def transfer(
self,
token_address: str,
to_address: str,
value: int,
tx_params: Optional[TxParams] = None,
view_only: bool = False,
) -> Union[HexBytes, bytes]:
"""Transfer the balance from owner's account to another account.
:param value: integer amount to send
:param tx_params: transaction parameters
:param view_only: whether to use transact() or call()
:returns: transaction hash
"""
token_address = self._validate_and_checksum_address(token_address)
to_address = self._validate_and_checksum_address(to_address)
# safeguard against fractional inputs
value = int(value)
func = self._erc20(token_address).functions.transfer(to_address, value)
return self._invoke_function_call(
func=func, tx_params=tx_params, view_only=view_only
)
# pylint: disable=too-many-arguments
def approve(
self,
token_address: str,
spender_address: str,
value: int,
tx_params: Optional[TxParams] = None,
view_only: bool = False,
) -> Union[HexBytes, bytes]:
"""Approve an address to spend up to `value`:code: of your tokens.
:param value: amount of allowance
:param tx_params: transaction options
:param view_only: whether to use transact() or call()
:returns: transaction hash
"""
token_address = self._validate_and_checksum_address(token_address)
spender_address = self._validate_and_checksum_address(spender_address)
# safeguard against fractional inputs
value = int(value)
func = self._erc20(token_address).functions.approve(
spender_address, value
)
return self._invoke_function_call(
func=func, tx_params=tx_params, view_only=view_only
)
# pylint: disable=too-many-arguments
def transfer_from(
self,
token_address: str,
authorized_address: str,
to_address: str,
value: int,
tx_params: Optional[TxParams] = None,
view_only: bool = False,
) -> Union[HexBytes, bytes]:
"""Transfer tokens from `authorized_address`:code: to another address.
Note that the `authorized_address`:code: must have already called
`approve`:code: for the `spender_address`:code:.
:param authorized_address: address you have been authorized to transfer
tokens from
:param value: amount to send
:param tx_params: transaction parameters
:param view_only: whether to use transact() or call()
:returns: transaction hash
"""
token_address = self._validate_and_checksum_address(token_address)
authorized_address = self._validate_and_checksum_address(
authorized_address
)
to_address = self._validate_and_checksum_address(to_address)
# safeguard against fractional inputs
value = int(value)
func = self._erc20(token_address).functions.transferFrom(
authorized_address, to_address, value
)
return self._invoke_function_call(
func=func, tx_params=tx_params, view_only=view_only
)
def total_supply(self, token_address: str) -> int:
"""Get total supply of a given ERC20 Token.
:returns: amount of tokens
"""
token_address = self._validate_and_checksum_address(token_address)
func = self._erc20(token_address).functions.totalSupply()
return self._invoke_function_call(
func=func, tx_params=None, view_only=True
)
def balance_of(self, token_address: str, owner_address: str) -> int:
"""Get token balance of a given owner address.
:returns: amount of tokens
"""
token_address = self._validate_and_checksum_address(token_address)
owner_address = self._validate_and_checksum_address(owner_address)
func = self._erc20(token_address).functions.balanceOf(owner_address)
return self._invoke_function_call(
func=func, tx_params=None, view_only=True
)
def allowance(
self, token_address: str, owner_address: str, spender_address: str
) -> Union[HexBytes, bytes]:
"""Get the amount of tokens approved for a spender.
:returns: amount of tokens
"""
token_address = self._validate_and_checksum_address(token_address)
owner_address = self._validate_and_checksum_address(owner_address)
spender_address = self._validate_and_checksum_address(spender_address)
func = self._erc20(token_address).functions.allowance(
owner_address, spender_address
)
return self._invoke_function_call(
func=func, tx_params=None, view_only=True
)
def get_transfer_event(
self, token_address: str, tx_hash: Union[HexBytes, bytes]
) -> Tuple[AttributeDict]:
"""Get the result of a transfer from its transaction hash.
:param tx_hash: hash of transfer transaction
"""
tx_receipt = self._web3_eth.getTransactionReceipt(tx_hash)
token_address = self._validate_and_checksum_address(token_address)
return (
self._erc20(token_address)
.events.Transfer()
.processReceipt(tx_receipt)
)
def get_approval_event(
self, token_address: str, tx_hash: Union[HexBytes, bytes]
) -> Tuple[AttributeDict]:
"""Get the result of an approval event from its transaction hash.
:param tx_hash: hash of approval transaction
"""
tx_receipt = self._web3_eth.getTransactionReceipt(tx_hash)
token_address = self._validate_and_checksum_address(token_address)
return (
self._erc20(token_address)
.events.Approval()
.processReceipt(tx_receipt)
)

View File

@ -32,18 +32,17 @@ class Exchange(BaseContractWrapper):
def __init__(
self,
provider: BaseProvider,
account_address: str = None,
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 account_address: str of account address
:param private_key: str of private_key
"""
super(Exchange, self).__init__(
provider=provider,
account_address=account_address,
contract_address=contract_address,
private_key=private_key,
)
self._web3_net = self._web3.net # pylint: disable=no-member

View File

@ -40,24 +40,21 @@ def erc20_proxy_address():
@pytest.fixture(scope="module")
def weth_address():
"""Get address of Wrapped Ether (WETH) token for the Ganache network."""
return NETWORK_TO_ADDRESSES[NetworkId.GANACHE].ether_token
@pytest.fixture(scope="module")
def weth_asset_data(weth_address): # pylint: disable=redefined-outer-name
def weth_asset_data(): # pylint: disable=redefined-outer-name
"""Get 0x asset data for Wrapped Ether (WETH) token."""
return asset_data_utils.encode_erc20(weth_address)
return asset_data_utils.encode_erc20(
NETWORK_TO_ADDRESSES[NetworkId.GANACHE].ether_token
)
@pytest.fixture(scope="module")
def weth_instance(
web3_eth, weth_address
): # pylint: disable=redefined-outer-name
def weth_instance(web3_eth): # pylint: disable=redefined-outer-name
"""Get an instance of the WrapperEther contract."""
return web3_eth.contract(
address=to_checksum_address(weth_address), abi=abi_by_name("WETH9")
address=to_checksum_address(
NETWORK_TO_ADDRESSES[NetworkId.GANACHE].ether_token
),
abi=abi_by_name("WETH9"),
)

View File

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

View File

@ -4,6 +4,7 @@ from decimal import Decimal
import pytest
from zero_ex.contract_addresses import NETWORK_TO_ADDRESSES, NetworkId
from zero_ex.contract_wrappers import ERC20Token, TxParams
@ -13,22 +14,19 @@ MAX_ALLOWANCE = int("{:.0f}".format(Decimal(2) ** 256 - 1))
@pytest.fixture(scope="module")
def erc20_wrapper(ganache_provider):
"""Get an instance of ERC20Token wrapper class for testing."""
return ERC20Token(ganache_provider)
return ERC20Token(
ganache_provider, NETWORK_TO_ADDRESSES[NetworkId.GANACHE].ether_token
)
def test_erc20_wrapper__balance_of(
accounts,
erc20_wrapper, # pylint: disable=redefined-outer-name
weth_address,
weth_instance, # pylint: disable=redefined-outer-name
):
"""Test getting baance of an account for an ERC20 token."""
acc1_original_weth_balance = erc20_wrapper.balance_of(
weth_address, accounts[0]
)
acc2_original_weth_balance = erc20_wrapper.balance_of(
weth_address, accounts[1]
)
acc1_original_weth_balance = erc20_wrapper.balance_of(accounts[0])
acc2_original_weth_balance = erc20_wrapper.balance_of(accounts[1])
expected_difference = 1 * 10 ** 18
@ -38,8 +36,8 @@ def test_erc20_wrapper__balance_of(
weth_instance.functions.deposit().transact(
{"from": accounts[1], "value": expected_difference}
)
acc1_weth_balance = erc20_wrapper.balance_of(weth_address, accounts[0])
acc2_weth_balance = erc20_wrapper.balance_of(weth_address, accounts[1])
acc1_weth_balance = erc20_wrapper.balance_of(accounts[0])
acc2_weth_balance = erc20_wrapper.balance_of(accounts[1])
assert (
acc1_weth_balance - acc1_original_weth_balance == expected_difference
@ -53,27 +51,24 @@ def test_erc20_wrapper__approve(
accounts,
erc20_proxy_address,
erc20_wrapper, # pylint: disable=redefined-outer-name
weth_address, # pylint: disable=redefined-outer-name
):
"""Test approving one account to spend balance from another account."""
erc20_wrapper.approve(
weth_address,
erc20_proxy_address,
MAX_ALLOWANCE,
tx_params=TxParams(from_=accounts[0]),
)
erc20_wrapper.approve(
weth_address,
erc20_proxy_address,
MAX_ALLOWANCE,
tx_params=TxParams(from_=accounts[1]),
)
acc_1_weth_allowance = erc20_wrapper.allowance(
weth_address, accounts[0], erc20_proxy_address
accounts[0], erc20_proxy_address
)
acc_2_weth_allowance = erc20_wrapper.allowance(
weth_address, accounts[1], erc20_proxy_address
accounts[1], erc20_proxy_address
)
assert acc_1_weth_allowance == MAX_ALLOWANCE

View File

@ -5,6 +5,7 @@ import random
import pytest
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.json_schemas import assert_valid
from zero_ex.order_utils import generate_order_hash_hex, Order, sign_hash
@ -13,7 +14,10 @@ from zero_ex.order_utils import generate_order_hash_hex, Order, sign_hash
@pytest.fixture(scope="module")
def exchange_wrapper(ganache_provider):
"""Get an Exchange wrapper instance."""
return Exchange(provider=ganache_provider)
return Exchange(
provider=ganache_provider,
contract_address=NETWORK_TO_ADDRESSES[NetworkId.GANACHE].exchange,
)
def create_test_order(

21
python-packages/pre_install Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env python
"""Run setup.py command `pre_install` for all packages that have one."""
from os import chdir, path
import subprocess
PACKAGES = [
"contract_wrappers",
"contract_artifacts",
]
for package in PACKAGES:
print(f"Running command `pre_install` in package {package}")
chdir(package)
subprocess.check_call(
(
path.join(".", "setup.py") + " pre_install"
).split()
)
chdir("..")

View File

@ -316,7 +316,11 @@ book. Now let's have the taker fill it:
>>> from zero_ex.contract_wrappers import Exchange, TxParams
>>> from zero_ex.order_utils import Order
>>> Exchange(eth_node).fill_order(
>>> exchange = Exchange(
... provider=eth_node,
... contract_address=NETWORK_TO_ADDRESSES[NetworkId.GANACHE].exchange
... )
>>> exchange.fill_order(
... order=order,
... taker_amount=order['makerAssetAmount']/2, # note the half fill
... signature=order['signature'],
@ -330,7 +334,7 @@ Cancelling
Note that the above fill was partial: it only filled half of the order. Now
we'll have our maker cancel the remaining order:
>>> Exchange(eth_node).cancel_order(
>>> exchange.cancel_order(
... order=order,
... tx_params=TxParams(from_=maker_address)
... )