Compare commits

..

81 Commits

Author SHA1 Message Date
Jacob Evans
bbd3c03969 Publish
- @0x/contracts-asset-proxy@2.2.6
 - @0x/contracts-coordinator@2.0.11
 - @0x/contracts-dev-utils@0.0.8
 - @0x/contracts-erc1155@1.1.13
 - @0x/contracts-erc20@2.2.12
 - @0x/contracts-erc721@2.1.13
 - @0x/contracts-exchange-forwarder@3.0.10
 - @0x/contracts-exchange-libs@3.0.6
 - @0x/contracts-exchange@2.1.12
 - @0x/contracts-extensions@4.0.6
 - @0x/contracts-multisig@3.1.12
 - @0x/contracts-test-utils@3.1.14
 - @0x/contracts-utils@3.2.2
 - 0x.js@7.0.0
 - @0x/abi-gen-templates@2.4.2
 - @0x/abi-gen-wrappers@5.3.0
 - @0x/abi-gen@4.1.1
 - @0x/assert@2.1.4
 - @0x/asset-buyer@6.1.12
 - @0x/asset-swapper@1.0.2
 - @0x/base-contract@5.3.2
 - @0x/connect@5.0.17
 - @0x/contract-addresses@3.1.0
 - @0x/contract-artifacts@2.2.0
 - @0x/contract-wrappers@11.1.0
 - @0x/dev-utils@2.3.1
 - @0x/fill-scenarios@3.0.17
 - @0x/instant@1.0.29
 - @0x/json-schemas@4.0.0
 - @0x/migrations@4.3.0
 - @0x/monorepo-scripts@1.0.35
 - @0x/order-utils@8.3.0
 - @0x/python-contract-wrappers@1.0.4
 - @0x/sol-compiler@3.1.13
 - @0x/sol-coverage@3.0.10
 - @0x/sol-doc@2.0.17
 - @0x/sol-profiler@3.1.12
 - @0x/sol-trace@2.0.18
 - @0x/sol-tracing-utils@6.0.17
 - @0x/sra-spec@2.0.15
 - @0x/subproviders@5.0.2
 - @0x/testnet-faucets@1.0.85
 - @0x/web3-wrapper@6.0.11
 - @0x/website@0.0.88
2019-08-22 14:13:00 +10:00
Jacob Evans
a4405c3d39 Updated CHANGELOGS 2019-08-22 14:12:40 +10:00
Xianny
0fe4f587d8 update ethereumjs-blockstream 6.0.0 -> ^7.0.0 (#2089) 2019-08-21 18:39:07 -07:00
Francesco Agosti
d3c714bd17 Merge pull request #2085 from 0xProject/feature/cfl-page-fix
Fix small issue on mobile nav
2019-08-21 14:54:17 -07:00
fragosti
c399b7a7d5 Add Asset Swapper to footer 2019-08-21 14:30:55 -07:00
fragosti
b9234e94fb Fix small issue on mobile nav 2019-08-21 14:30:55 -07:00
Francesco Agosti
417bb87785 Merge pull request #2081 from 0xProject/feature/cfl-page
CFL page
2019-08-20 18:24:40 -07:00
fragosti
0233ae3134 Use Asset Swapper on CFL page 2019-08-20 17:48:57 -07:00
fragosti
eed0c5dd59 Distinguish between asset swapper page and docs 2019-08-20 17:39:15 -07:00
fragosti
2b3b167095 Fix path of asset swapper link in product dropdown 2019-08-20 17:30:15 -07:00
fragosti
5d91d19808 Disable jsx-curly-spacing on cfl page 2019-08-20 17:24:49 -07:00
fragosti
0f374ddee9 Change AssetBuyer to AssetSwapper on instant page 2019-08-20 17:08:03 -07:00
Chris Kalani
a65a9913cd Fixed up some design nits and updated copy 2019-08-20 16:51:06 -07:00
fragosti
1ead32c666 Asset-Swapper -> asset-swapper 2019-08-20 15:35:39 -07:00
fragosti
d1af9fc780 use asset-swapper instead of Asset-Swapper 2019-08-20 15:31:50 -07:00
fragosti
0f06737fb6 Fix install prompt on mobile layout 2019-08-20 15:01:59 -07:00
fragosti
1676231532 Rename variables to be compatible with new backend 2019-08-20 14:36:57 -07:00
fragosti
b1caf697c8 Update titles and descriptions 2019-08-20 13:52:50 -07:00
fragosti
51481065fe Fix jumping around of editor 2019-08-20 11:56:09 -07:00
fragosti
e367da710c Fix massive i 2019-08-20 11:47:05 -07:00
fragosti
f493d6524d Change to crypto algo-traders 2019-08-20 11:22:21 -07:00
fragosti
e1b85da2a7 Make terminal text selectable 2019-08-20 11:16:28 -07:00
F. Eugene Aumson
22c6548ed1 abi-gen/test-cli: rm expected-output; use git diff (#2079)
* abi-gen/test-cli: rm expected-output; use git diff

* abi-gen/test-cli: Simplify git diff test script

* Remove abi-gen/test-cli/output from .gitignore
2019-08-20 14:08:54 -04:00
Fabio B
afb32c087d Merge pull request #2017 from jangerritharms/fix/broken-validator-signatures
Fix broken validator signatures
2019-08-20 18:44:50 +02:00
Jan-Gerrit Harms
bbc1ed1c64 Update test to adhere to v2.1 Validator revert 2019-08-20 14:53:10 +02:00
Jan-Gerrit Harms
3a46f1a27a Merge branch 'development' into fix/broken-validator-signatures 2019-08-20 09:30:21 +02:00
Jacob Evans
90cd364780 Merge pull request #2078 from 0xProject/fix/isValidSignature-2.1
Update development to 2.1 isValidSignature with magic salt
2019-08-20 16:34:48 +10:00
Jacob Evans
6795e6f078 Update comments with bytes4 values 2019-08-20 16:15:44 +10:00
fragosti
cfb3404349 Fix dogfood link 2019-08-19 20:49:35 -07:00
fragosti
0212f3ee78 Run linter 2019-08-19 19:28:42 -07:00
fragosti
6b2995a4ee Remove didError state from CFLmetrics component 2019-08-19 19:24:37 -07:00
fragosti
09e7ac54d4 Replace hummingbot link 2019-08-19 19:18:58 -07:00
fragosti
f69009d4a8 Add CFL to mobile dropdown and remove extensions for desktop 2019-08-19 19:16:26 -07:00
fragosti
206802ae33 Make layout more responsive 2019-08-19 19:08:48 -07:00
fragosti
91d4138fb8 Fix react key error 2019-08-19 18:22:17 -07:00
fragosti
cb455f951a Add loading state to CFL metrics 2019-08-19 18:19:01 -07:00
fragosti
5f25d20cd0 Improve tooltip and copy 2019-08-19 17:54:10 -07:00
fragosti
1f0e2cd910 Add info tooltip 2019-08-19 17:46:11 -07:00
Jacob Evans
1749d02701 Add python linter exception 2019-08-20 10:30:09 +10:00
fragosti
55ace3179c Add disclaimer component 2019-08-19 17:00:41 -07:00
fragosti
7866d9ccb4 Implement CFL metrics MVP 2019-08-19 16:52:40 -07:00
Brandon Millman
51f73d07fa Merge pull request #2080 from 0xProject/feature/website/adding-michael
Adding Michael Zhu to the team page
2019-08-19 13:02:18 -07:00
Francesco Agosti
63d84674ab Merge pull request #2074 from 0xProject/feature/website/remove-faq
Removing the old FAQ page and all references
2019-08-19 12:36:59 -07:00
Chris Kalani
14066997b2 Adding Michael Zhu to the team page 2019-08-19 12:34:19 -07:00
F. Eugene Aumson
28561e765a Update README.md (#2077)
* Update README.md

* top-level README.md: explain Python dependency

* top-level README.md: suggest node v6 OR v8
2019-08-19 13:55:06 -04:00
Jacob Evans
453fbbdc5d Update python doc strings 2019-08-19 15:55:28 +10:00
Jacob Evans
1e1e5ec10d Catch revert in IWallet/IValidator and return false 2019-08-19 15:45:32 +10:00
Jacob Evans
2088b0e459 Update python doc string 2019-08-19 15:13:09 +10:00
Jacob Evans
58400d9e01 Update python docs string 2019-08-19 14:40:46 +10:00
Jacob Evans
ac9375f1d2 Updated generated-wrappers? 2019-08-19 14:10:50 +10:00
Jacob Evans
db061c9355 Update Whitelist.sol 2019-08-19 12:15:46 +10:00
Jacob Evans
d5ce6c464b Update Wallet signature test 2019-08-19 11:55:48 +10:00
Jacob Evans
b06205bb7f Fix lint errors 2019-08-19 11:36:35 +10:00
Jacob Evans
f528a3e1de Update Order-utils to check magic values 2019-08-19 11:14:35 +10:00
Jacob Evans
bddfdacfad Update Interfaces for IValidator and IWallet 2019-08-19 11:08:06 +10:00
Jacob Evans
d3cdd3f235 Update development to 2.1 isValidSignature with magic salt 2019-08-19 10:35:26 +10:00
Chris Kalani
41ae45ea40 Fixed build error 2019-08-16 14:17:12 -07:00
Chris Kalani
657e0895ea Removing the olf FAW page and all references 2019-08-16 13:56:03 -07:00
Jan-Gerrit Harms
b2592d1cc2 Removed the order-watcher files that were accidentally added 2019-08-16 14:02:32 +02:00
Jan-Gerrit Harms
aa3524c3b2 Merge branch 'development' into fix/broken-validator-signatures 2019-08-16 13:04:27 +02:00
fragosti
39deb1a05f Make it possible to show figure in hero on the bottom on mobile 2019-08-15 17:23:20 -07:00
fragosti
302d08e290 Make website mobile friendly 2019-08-15 17:01:50 -07:00
fragosti
05489dd7f1 Implement basic CFL landing page 2019-08-15 16:33:52 -07:00
Jan-Gerrit Harms
55bd076602 Merge branch 'development' into fix/broken-validator-signatures 2019-08-14 09:37:20 +02:00
Jan-Gerrit Harms
7a224fe08f Merge branch 'development' into fix/broken-validator-signatures 2019-08-13 19:49:24 +02:00
Jan-Gerrit Harms
3bdeb82097 Updated CHANGELOG of 0x.js and @0x/order-watcher 2019-08-09 09:58:29 +02:00
Jan-Gerrit Harms
f49ab3f919 Merge branch 'development' into fix/broken-validator-signatures 2019-08-09 09:47:42 +02:00
Jan-Gerrit Harms
42d5bdd3ab Explicitly check exchangeAddress definedness 2019-08-09 09:39:49 +02:00
Jan-Gerrit Harms
7228cbfe92 Pass exchangeAddress instead of SignatureOpts 2019-08-09 09:36:32 +02:00
Jan-Gerrit Harms
11e2fc5bc4 Added documentation for additional parameters 2019-07-30 15:18:08 +02:00
Jan-Gerrit Harms
3e88f820b8 Prettified changelog 2019-07-30 15:11:24 +02:00
Jan-Gerrit Harms
163750f8c2 Updated internal usages of isValidSignatureAsync 2019-07-30 14:52:35 +02:00
Jan-Gerrit Harms
4aabc5d791 Fixed merge conflict in changelog 2019-07-30 14:43:24 +02:00
Jan-Gerrit Harms
c9a7b9dcc1 Appended to changelog in the order-utils package 2019-07-30 14:35:11 +02:00
Jan-Gerrit Harms
98075b5653 Revert "Updated changelog"
This reverts commit 57ae5be916.
2019-07-30 14:32:27 +02:00
Jan-Gerrit Harms
57ae5be916 Updated changelog 2019-07-30 14:26:46 +02:00
Jan-Gerrit Harms
8caf62997f Forgot formatting again 2019-07-30 13:26:27 +02:00
Jan-Gerrit Harms
f8656ad376 Added integration tests and fixed another bug 2019-07-30 13:25:36 +02:00
Jan-Gerrit Harms
29c6c2a2ad Add exports to 0x.js 2019-07-30 10:15:41 +02:00
Jan-Gerrit Harms
f2db67ef02 Fixed prettier errors 2019-07-30 09:50:54 +02:00
Jan-Gerrit Harms
72b8ef33d9 Fixes #1998, still needs Integration testing 2019-07-29 21:39:21 +02:00
2549 changed files with 180429 additions and 202551 deletions

View File

@@ -23,21 +23,37 @@ jobs:
# command: npm set prefix=/home/circleci/npm && echo 'export PATH=$HOME/circleci/npm/bin:$PATH' >> /home/circleci/.bashrc
- run:
name: install-yarn
command: npm install --force --global yarn@1.17.0
command: npm install --global yarn@1.9.4
- run:
name: yarn
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
- setup_remote_docker
- run: yarn build:ci
- run: yarn build:ci:no_website
- run: yarn build:ts
- save_cache:
key: repo-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo
- save_cache:
key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/python-contract-wrappers/generated
- store_artifacts:
path: ~/repo/packages/python-contract-wrappers/generated
- store_artifacts:
path: ~/repo/packages/abi-gen/test-cli/output
- store_artifacts:
path: ~/repo/packages/contract-wrappers/generated_docs
path: ~/repo/packages/abi-gen-wrappers/generated_docs
build-website:
resource_class: medium+
docker:
- image: nikolaik/python-nodejs:python3.7-nodejs8
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: cd packages/website && yarn build:prod
test-contracts-ganache:
resource_class: medium+
docker:
@@ -47,41 +63,19 @@ jobs:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-staking
test-exchange-ganache-3.0:
resource_class: medium+
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-dev-utils
test-contracts-geth:
docker:
- image: nikolaik/python-nodejs:python3.7-nodejs8
- image: 0xorg/devnet
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn wsrun test:circleci @0x/contracts-exchange
test-integrations-ganache-3.0:
resource_class: medium+
docker:
- image: nikolaik/python-nodejs:python3.7-nodejs8
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn wsrun test:circleci @0x/contracts-integrations
test-contracts-rest-ganache-3.0:
resource_class: medium+
docker:
- image: nikolaik/python-nodejs:python3.7-nodejs8
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-exchange-forwarder @0x/contracts-staking @0x/contracts-coordinator @0x/contracts-erc20-bridge-sampler
# TODO(dorothy-zbornak): Re-enable after updating this package for
# 3.0. At that time, also remove exclusion from monorepo
# package.json's test script.
# - run: yarn wsrun test:circleci @0x/contracts-extensions
# HACK(albrow): we need to sleep 10 seconds to ensure the devnet is
# initialized
- run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-dev-utils
test-publish:
resource_class: medium+
docker:
@@ -92,9 +86,7 @@ jobs:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run:
command: yarn test:publish:circleci
no_output_timeout: 1800
- run: yarn test:publish:circleci
test-doc-generation:
docker:
- image: nikolaik/python-nodejs:python3.7-nodejs8
@@ -103,9 +95,7 @@ jobs:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run:
command: yarn test:generate_docs:circleci
no_output_timeout: 1200
- run: yarn test:generate_docs:circleci
test-rest:
docker:
- image: nikolaik/python-nodejs:python3.7-nodejs8
@@ -116,16 +106,15 @@ jobs:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn wsrun test:circleci @0x/contracts-test-utils
- run: yarn wsrun test:circleci @0x/abi-gen
- run: yarn wsrun test:circleci @0x/asset-swapper
- run: yarn wsrun test:circleci @0x/asset-buyer
- run: yarn wsrun test:circleci @0x/contract-artifacts
- run: yarn wsrun test:circleci @0x/assert
- run: yarn wsrun test:circleci @0x/base-contract
- run: yarn wsrun test:circleci @0x/connect
- run: yarn wsrun test:circleci @0x/contract-wrappers-test
- run: yarn wsrun test:circleci @0x/contract-wrappers
- run: yarn wsrun test:circleci @0x/dev-utils
- run: yarn wsrun test:circleci @0x/json-schemas
- run: yarn wsrun test:circleci @0x/order-utils
- run: yarn wsrun test:circleci @0x/orderbook
- run: yarn wsrun test:circleci @0x/sol-compiler
- run: yarn wsrun test:circleci @0x/sol-tracing-utils
- run: yarn wsrun test:circleci @0x/sol-doc
@@ -142,9 +131,9 @@ jobs:
paths:
- ~/repo/packages/assert/coverage/lcov.info
- save_cache:
key: coverage-asset-swapper-{{ .Environment.CIRCLE_SHA1 }}
key: coverage-asset-buyer-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/asset-swapper/coverage/lcov.info
- ~/repo/packages/asset-buyer/coverage/lcov.info
- save_cache:
key: coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }}
paths:
@@ -154,9 +143,9 @@ jobs:
paths:
- ~/repo/packages/connect/coverage/lcov.info
- save_cache:
key: coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }}
key: coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/contract-wrappers-test/coverage/lcov.info
- ~/repo/packages/contract-wrappers/coverage/lcov.info
- save_cache:
key: coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }}
paths:
@@ -193,34 +182,20 @@ jobs:
working_directory: ~/repo
docker:
- image: nikolaik/python-nodejs:python3.7-nodejs8
- image: 0xorg/ganache-cli:6.0.0
- image: 0xorg/mesh:0xV3
- image: 0xorg/ganache-cli:2.2.2
- image: 0xorg/launch-kit-backend:74bcc39
environment:
ETHEREUM_RPC_URL: 'http://localhost:8545'
ETHEREUM_CHAIN_ID: '1337'
VERBOSITY: 5
BLOCK_POLLING_INTERVAL: '50ms'
ETHEREUM_RPC_MAX_REQUESTS_PER_24_HR_UTC: '1778000'
command: |
sh -c "waitForGanache () { until printf 'POST /\r\nContent-Length: 26\r\n\r\n{\"method\":\"net_listening\"}' | nc localhost 8545 | grep true; do continue; done }; waitForGanache && ./mesh"
- image: 0xorg/launch-kit-backend:v3
environment:
RPC_URL: 'http://localhost:8545'
CHAIN_ID: 1337
RPC_URL: http://localhost:8545
NETWORK_ID: 50
WHITELIST_ALL_TOKENS: True
FEE_RECIPIENT: '0x0000000000000000000000000000000000000001'
MAKER_FEE_UNIT_AMOUNT: 0
TAKER_FEE_UNIT_AMOUNT: 0
MESH_ENDPOINT: 'ws://localhost:60557'
command: |
sh -c "waitForMesh () { sleep 30; }; waitForMesh && node_modules/.bin/forever ts/lib/index.js"
sh -c "until printf 'POST /\r\nContent-Length: 26\r\n\r\n{\"method\":\"net_listening\"}' | nc localhost 8545 | grep true; do continue; done; node_modules/.bin/forever ts/lib/index.js"
steps:
- checkout
- restore_cache:
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
- run:
command: |
cd python-packages
@@ -235,14 +210,8 @@ jobs:
- run:
command: |
cd python-packages
./parallel coverage run setup.py test
./parallel_without_sra_client coverage run setup.py test
./build_docs
- run:
command: |
# copy generated wrappers into contract_wrappers/build,
# JUST so CircleCI will persist them as build artifacts.
cd python-packages/contract_wrappers/src/zero_ex
for i in contract_wrappers/[^__]*/; do mkdir -p ../../build/$i; cp $i/__init__.py ../../build/$i; done
- save_cache:
key: coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }}
paths:
@@ -267,6 +236,10 @@ jobs:
key: coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/python-packages/sra_client/.coverage
- store_artifacts:
path: ~/repo/python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_token/__init__.py
- store_artifacts:
path: ~/repo/python-packages/contract_wrappers/src/zero_ex/contract_wrappers/exchange/__init__.py
- store_artifacts:
path: ~/repo/python-packages/contract_addresses/build
- store_artifacts:
@@ -316,8 +289,7 @@ jobs:
- restore_cache:
key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
- run:
command: |
python -m ensurepip
@@ -326,7 +298,6 @@ jobs:
./install
./lint
static-tests:
resource_class: large
working_directory: ~/repo
docker:
- image: nikolaik/python-nodejs:python3.7-nodejs8
@@ -337,7 +308,6 @@ jobs:
- run: yarn lerna run lint
- run: yarn prettier:ci
- run: yarn deps_versions:ci
- run: yarn diff_md_docs:ci
- run: cd packages/0x.js && yarn build:umd:prod
- run: yarn bundlewatch
submit-coverage:
@@ -356,7 +326,7 @@ jobs:
- coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-asset-swapper-{{ .Environment.CIRCLE_SHA1 }}
- coverage-asset-buyer-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }}
@@ -365,7 +335,7 @@ jobs:
- coverage-connect-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }}
- coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }}
@@ -417,15 +387,17 @@ workflows:
main:
jobs:
- build
- test-exchange-ganache-3.0:
- build-website:
requires:
- build
- test-integrations-ganache-3.0:
requires:
- build
- test-contracts-rest-ganache-3.0:
- test-contracts-ganache:
requires:
- build
# TODO(albrow): Tests always fail on Geth right now because our fork
# is outdated. Uncomment once we have updated our Geth fork.
# - test-contracts-geth:
# requires:
# - build
- test-rest:
requires:
- build
@@ -440,15 +412,13 @@ workflows:
- build
- submit-coverage:
requires:
- test-contracts-rest-ganache-3.0
- test-exchange-ganache-3.0
- test-rest
- static-tests
- test-python
- static-tests-python:
requires:
- test-python
- test-python:
requires:
- build
- static-tests-python:
requires:
- build
# skip python tox run for now, as we don't yet have multiple test environments to support.
# - test-rest-python
#- test-rest-python

View File

@@ -13,21 +13,27 @@ contracts: ['contracts']
@0x/instant: ['packages/instant']
@0x/abi-gen-templates: ['packages/abi-gen-templates']
@0x/abi-gen: ['packages/abi-gen']
@0x/website: ['packages/website']
@0x/sol-coverage: ['packages/sol-coverage']
@0x/sol-profiler: ['packages/sol-profiler']
@0x/sol-trace: ['packages/sol-trace']
@0x/sol-tracing-utils: ['packages/sol-tracing-utils']
@0x/utils: ['packages/utils']
@0x/tslint-config: ['packages/tslint-config']
@0x/asset-swapper: ['packages/asset-swapper']
@0x/asset-buyer: ['packages/asset-buyer']
@0x/order-utils: ['packages/order-utils']
@0x/assert: ['packages/assert']
@0x/base-contract: ['packages/base-contract']
@0x/typescript-typings: ['packages/typescript-typings']
0x.js: ['packages/0x.js']
@0x/abi-gen-wrappers: ['packages/abi-gen-wrappers']
@0x/contract-artifacts: ['packages/contract-artifacts']
@0x/dev-utils: ['packages/dev-utils']
@0x/contract-wrappers: ['packages/contract-wrappers']
@0x/json-schemas: ['packages/json-schemas']
@0x/ethereum-types: ['ethereum-types']
@0x/connect: ['packages/connect']
@0x/fill-scenarios: ['packages/fill-scenarios']
@0x/dev-tools-pages: ['packages/dev-tools-pages']
@0x/testnet-faucets: ['packages/testnet-faucets']
@0x/monorepo-scripts: ['packages/monorepo-scripts']

104
.gitignore vendored
View File

@@ -40,12 +40,9 @@ build/Release
node_modules/
jspm_packages/
# TypeScript v1 declaration files
# Typescript v1 declaration files
typings/
# NVM config
.nvmrc
# Optional npm cache directory
.npm
.npmrc
@@ -78,98 +75,70 @@ TODO.md
# VSCode file
.vscode
packages/website/public/bundle*
packages/dev-tools-pages/public/bundle*
# server cli
packages/testnet-faucets/server/
# generated contract artifacts/
contracts/broker/generated-artifacts/
contracts/broker/test/generated-artifacts/
contracts/erc20-bridge-sampler/generated-artifacts/
contracts/erc20-bridge-sampler/test/generated-artifacts/
contracts/integrations/generated-artifacts/
contracts/integrations/test/generated-artifacts/
contracts/staking/generated-artifacts/
contracts/staking/test/generated-artifacts/
contracts/coordinator/generated-artifacts/
contracts/coordinator/test/generated-artifacts/
contracts/exchange/generated-artifacts/
contracts/exchange/test/generated-artifacts/
contracts/asset-proxy/generated-artifacts/
contracts/asset-proxy/test/generated-artifacts/
contracts/multisig/generated-artifacts/
contracts/multisig/test/generated-artifacts/
contracts/utils/generated-artifacts/
contracts/utils/test/generated-artifacts/
contracts/exchange-libs/generated-artifacts/
contracts/exchange-libs/test/generated-artifacts/
contracts/erc20/generated-artifacts/
contracts/erc20/test/generated-artifacts/
contracts/erc721/generated-artifacts/
contracts/erc721/test/generated-artifacts/
contracts/erc1155/generated-artifacts/
contracts/erc1155/test/generated-artifacts/
contracts/extensions/generated-artifacts/
contracts/extensions/test/generated-artifacts/
contracts/exchange-forwarder/generated-artifacts/
contracts/exchange-forwarder/test/generated-artifacts/
contracts/dev-utils/generated-artifacts/
contracts/dev-utils/test/generated-artifacts/
packages/sol-tracing-utils/test/fixtures/artifacts/
python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/
# generated truffle contract artifacts/
contracts/broker/build/
contracts/erc20-bridge-sampler/build/
contracts/staking/build/
contracts/coordinator/build/
contracts/exchange/build/
contracts/asset-proxy/build/
contracts/multisig/build/
contracts/utils/build/
contracts/exchange-libs/build/
contracts/erc20/build/
contracts/erc721/build/
contracts/erc1155/build/
contracts/extensions/build/
contracts/exchange-forwarder/build/
contracts/dev-utils/build/
# generated contract wrappers
contracts/broker/generated-wrappers/
contracts/broker/test/generated-wrappers/
packages/abi-gen-wrappers/src/generated-wrappers/
packages/python-contract-wrappers/generated/
contracts/erc20-bridge-sampler/generated-wrappers/
contracts/erc20-bridge-sampler/test/generated-wrappers/
contracts/integrations/generated-wrappers/
contracts/integrations/test/generated-wrappers/
contracts/staking/generated-wrappers/
contracts/staking/test/generated-wrappers/
contracts/coordinator/generated-wrappers/
contracts/coordinator/test/generated-wrappers/
contracts/exchange/generated-wrappers/
contracts/exchange/test/generated-wrappers/
contracts/asset-proxy/generated-wrappers/
contracts/asset-proxy/test/generated-wrappers/
contracts/multisig/generated-wrappers/
contracts/multisig/test/generated-wrappers/
contracts/utils/generated-wrappers/
contracts/utils/test/generated-wrappers/
contracts/exchange-libs/generated-wrappers/
contracts/exchange-libs/test/generated-wrappers/
contracts/erc20/generated-wrappers/
contracts/erc20/test/generated-wrappers/
contracts/erc721/generated-wrappers/
contracts/erc721/test/generated-wrappers/
contracts/erc1155/generated-wrappers/
contracts/erc1155/test/generated-wrappers/
contracts/extensions/generated-wrappers/
contracts/extensions/test/generated-wrappers/
contracts/exchange-forwarder/generated-wrappers/
contracts/exchange-forwarder/test/generated-wrappers/
contracts/dev-utils/generated-wrappers/
contracts/dev-utils/test/generated-wrappers/
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/*/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_token/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/exchange/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/asset_proxy_owner/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/coordinator/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/coordinator_registry/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc20_token/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc721_token/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dutch_auction/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_proxy/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_proxy/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_token/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/eth_balance_checker/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/forwarder/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_asset_proxy/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_validator/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_wallet/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/multi_asset_proxy/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/order_validator/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/weth9/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/zrx_token/__init__.py
# solc-bin in sol-compiler
packages/sol-compiler/solc_bin/
# Monorepo scripts
packages/*/scripts/
# python stuff
.eggs
.mypy_cache
@@ -180,14 +149,5 @@ __pycache__
python-packages/*/src/*.egg-info
python-packages/*/.coverage
# python keeps package-local copies of json schemas and contract addresses
# python keeps package-local copies of json schemas
python-packages/json_schemas/src/zero_ex/json_schemas/schemas
python-packages/contract_addresses/src/zero_ex/contract_addresses/addresses.json
# Doc README copy
packages/*/docs/README.md
.DS_Store
# the snapshot that gets built for migrations sure does have a ton of files
packages/migrations/0x_ganache_snapshot*

View File

@@ -1,86 +1,34 @@
lib
.nyc_output
/contracts/broker/generated-wrappers
/contracts/broker/test/generated-wrappers
/contracts/broker/generated-artifacts
/contracts/broker/test/generated-artifacts
/contracts/integrations/generated-wrappers
/contracts/integrations/test/generated-wrappers
/contracts/integrations/generated-artifacts
/contracts/integrations/test/generated-artifacts
/contracts/staking/generated-wrappers
/contracts/staking/test/generated-wrappers
/contracts/staking/generated-artifacts
/contracts/staking/test/generated-artifacts
/contracts/coordinator/generated-wrappers
/contracts/coordinator/test/generated-wrappers
/contracts/coordinator/generated-artifacts
/contracts/coordinator/test/generated-artifacts
/contracts/exchange/generated-wrappers
/contracts/exchange/test/generated-wrappers
/contracts/exchange/generated-artifacts
/contracts/exchange/test/generated-artifacts
/contracts/asset-proxy/generated-wrappers
/contracts/asset-proxy/test/generated-wrappers
/contracts/asset-proxy/generated-artifacts
/contracts/asset-proxy/test/generated-artifacts
/contracts/multisig/generated-wrappers
/contracts/multisig/test/generated-wrappers
/contracts/multisig/generated-artifacts
/contracts/multisig/test/generated-artifacts
/contracts/utils/generated-wrappers
/contracts/utils/test/generated-wrappers
/contracts/utils/generated-artifacts
/contracts/utils/test/generated-artifacts
/contracts/exchange-libs/generated-wrappers
/contracts/exchange-libs/test/generated-wrappers
/contracts/exchange-libs/generated-artifacts
/contracts/exchange-libs/test/generated-artifacts
/contracts/erc20/generated-wrappers
/contracts/erc20/test/generated-wrappers
/contracts/erc20/generated-artifacts
/contracts/erc20/test/generated-artifacts
/contracts/erc20-bridge-sampler/generated-wrappers
/contracts/erc20-bridge-sampler/test/generated-wrappers
/contracts/erc20-bridge-sampler/generated-artifacts
/contracts/erc20-bridge-sampler/test/generated-artifacts
/contracts/erc721/generated-wrappers
/contracts/erc721/test/generated-wrappers
/contracts/erc721/generated-artifacts
/contracts/erc721/test/generated-artifacts
/contracts/erc1155/generated-wrappers
/contracts/erc1155/test/generated-wrappers
/contracts/erc1155/generated-artifacts
/contracts/erc1155/test/generated-artifacts
/contracts/extensions/generated-wrappers
/contracts/extensions/test/generated-wrappers
/contracts/extensions/generated-artifacts
/contracts/extensions/test/generated-artifacts
/contracts/exchange-forwarder/generated-wrappers
/contracts/exchange-forwarder/test/generated-wrappers
/contracts/exchange-forwarder/generated-artifacts
/contracts/exchange-forwarder/test/generated-artifacts
/contracts/dev-utils/generated-wrappers
/contracts/dev-utils/test/generated-wrappers
/contracts/dev-utils/generated-artifacts
/contracts/dev-utils/test/generated-artifacts
/contracts/staking/build/
/contracts/coordinator/build/
/contracts/exchange/build/
/contracts/asset-proxy/build/
/contracts/multisig/build/
/contracts/utils/build/
/contracts/exchange-libs/build/
/contracts/erc20/build/
/contracts/erc721/build/
/contracts/erc1155/build/
/contracts/extensions/build/
/contracts/exchange-forwarder/build/
/contracts/dev-utils/build/
/packages/abi-gen/test-cli/output
/packages/json-schemas/schemas
/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
/packages/sra-spec/public/
/packages/dev-tools-pages/ts/**/data.json
package.json
scripts/postpublish_utils.js
packages/sol-coverage/test/fixtures/artifacts
@@ -90,5 +38,3 @@ packages/sol-coverage/test/fixtures/artifacts
packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json
packages/abi-gen/test-cli/fixtures/artifacts/LibDummy.json
packages/abi-gen/test-cli/fixtures/artifacts/TestLibDummy.json
packages/*/docs
*.sol

View File

@@ -1,6 +1,6 @@
{
"printWidth": 120,
"tabWidth": 4,
"singleQuote": true,
"trailingComma": "all"
"printWidth": 120,
"trailingComma": all,
"singleQuote": true
}

View File

@@ -5,8 +5,9 @@
# https://git-scm.com/docs/gitignore#_pattern_format
# Website
packages/asset-swapper/ @BMillman19 @fragosti @dave4506
packages/instant/ @BMillman19 @fragosti @dave4506
packages/asset-buyer/ @BMillman19 @fragosti @steveklebanoff
packages/instant/ @BMillman19 @fragosti @steveklebanoff
packages/website/ @BMillman19 @fragosti @fabioberger @steveklebanoff
# Dev tools & setup
.circleci/ @LogvinovLeon
@@ -14,8 +15,8 @@ packages/abi-gen/ @feuGeneA
packages/base-contract/ @xianny
packages/connect/ @fragosti
packages/abi-gen-templates/ @feuGeneA @xianny
packages/contract-addresses/ @abandeali1
packages/contract-artifacts/ @abandeali1
packages/contract-addresses/ @albrow
packages/contract-artifacts/ @albrow
packages/dev-utils/ @LogvinovLeon @fabioberger
packages/devnet/ @albrow
packages/ethereum-types/ @LogvinovLeon

View File

@@ -29,9 +29,9 @@ ALL PRs should be opened against `development`.
Branch names should be prefixed with `fix`, `feature` or `refactor`.
- e.g `fix/missing-import`
- e.g `fix/broken-wiki-link`
- If the PR only edits a single package, add it's name too
- e.g `fix/subproviders/missing-import`
- e.g `fix/website/broken-wiki-link`
### CHANGELOGs
@@ -55,7 +55,7 @@ If an entry without a `timestamp` already exists, this means other changes have
### Development Tooling
We strongly recommend you use the [VSCode](https://code.visualstudio.com/) text editor since most of our code is written in TypeScript and it offers amazing support for the language.
We strongly recommend you use the [VSCode](https://code.visualstudio.com/) text editor since most of our code is written in Typescript and it offers amazing support for the language.
#### Linter
@@ -89,7 +89,7 @@ A few of our coding conventions are not yet enforced by the linter/auto-formatte
1. Do not import from a project's `index.ts` (e.g import { Token } from '../src';). Always import from the source file itself.
1. Generic error variables should be named `err` instead of `e` or `error`.
1. If you _must_ cast a variable to any - try to type it back as fast as possible. (e.g., `const cw = ((zeroEx as any)._contractWrappers as ContractWrappers);`). This ensures subsequent code is type-safe.
1. Our enum conventions coincide with the recommended TypeScript conventions, using capitalized keys, and all-caps snake-case values. Eg `GetStats = 'GET_STATS'`
1. Our enum conventions coincide with the recommended Typescript conventions, using capitalized keys, and all-caps snake-case values. Eg `GetStats = 'GET_STATS'`
1. All public, exported methods/functions/classes must have associated Javadoc-style comments.
### Fix `submit-coverage` CI failure

View File

@@ -6,16 +6,21 @@
This repository is a monorepo including the 0x protocol smart contracts and numerous developer tools. Each public sub-package is independently published to NPM.
[website-url]: https://0x.org
If you're developing on 0x now or are interested in using 0x infrastructure in the future, please join our [developer mailing list][dev-mailing-list-url] for updates.
[website-url]: https://0xproject.com
[whitepaper-url]: https://0xproject.com/pdfs/0x_white_paper.pdf
[dev-mailing-list-url]: http://eepurl.com/dx4cPf
[![CircleCI](https://circleci.com/gh/0xProject/0x-monorepo.svg?style=svg&circle-token=61bf7cd8c9b4e11b132089dfcffdd1be277d1e0c)](https://circleci.com/gh/0xProject/0x-monorepo)
[![Coverage Status](https://coveralls.io/repos/github/0xProject/0x-monorepo/badge.svg?branch=development)](https://coveralls.io/github/0xProject/0x-monorepo?branch=development)
[![Discord](https://img.shields.io/badge/chat-discord.chat-yellow.svg?style=flat)](https://discordapp.com/invite/d3FTX3M)
[![Discord](https://img.shields.io/badge/chat-rocket.chat-yellow.svg?style=flat)](https://chat.0xproject.com)
[![Join the chat at https://gitter.im/0xProject/Lobby](https://badges.gitter.im/0xProject/Lobby.svg)](https://gitter.im/0xProject/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
## Packages
Visit our [developer portal](https://0x.org/docs/tools/order-utils) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below.
Visit our [developer portal](https://0xproject.com/docs/order-utils) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below.
### Python Packages
@@ -43,13 +48,12 @@ These packages are all under development. See [/contracts/README.md](/contracts/
| [`@0x/contracts-exchange-libs`](/contracts/exchange-libs) | [![npm](https://img.shields.io/npm/v/@0x/contracts-exchange-libs.svg)](https://www.npmjs.com/package/@0x/contracts-exchange-libs) | Protocol specific libraries used within the [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange) contract |
| [`@0x/contracts-extensions`](/contracts/extensions) | [![npm](https://img.shields.io/npm/v/@0x/contracts-extensions.svg)](https://www.npmjs.com/package/@0x/contracts-extensions) | Contracts that interact with and extend the functionality of the core protocol |
| [`@0x/contracts-multisig`](/contracts/multisig) | [![npm](https://img.shields.io/npm/v/@0x/contracts-multisig.svg)](https://www.npmjs.com/package/@0x/contracts-multisig) | Various implementations of multisignature wallets, including the [`AssetProxyOwner`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxyowner) contract that has permissions to upgrade the protocol |
| [`@0x/contracts-test-utils`](/contracts/test-utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-test-utils.svg)](https://www.npmjs.com/package/@0x/contracts-test-utils) | TypeScript/Javascript shared utilities used for testing contracts |
| [`@0x/contracts-test-utils`](/contracts/test-utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-test-utils.svg)](https://www.npmjs.com/package/@0x/contracts-test-utils) | Typescript/Javascript shared utilities used for testing contracts |
| [`@0x/contracts-utils`](/contracts/utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-utils.svg)](https://www.npmjs.com/package/@0x/contracts-utils) | Generic libraries and utilities used throughout all of the contracts |
| [`@0x/contracts-coordinator`](/contracts/coordinator) | [![npm](https://img.shields.io/npm/v/@0x/contracts-coordinator.svg)](https://www.npmjs.com/package/@0x/contracts-coordinator) | A contract that allows users to execute 0x transactions with permission from a Coordinator |
| [`@0x/contracts-dev-utils`](/contracts/dev-utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-dev-utils.svg)](https://www.npmjs.com/package/@0x/contracts-dev-utils) | A contract contains utility functions for developers (such as validating many orders using a single eth_call) |
| [`@0x/contracts-staking`](/contracts/staking) | [![npm](https://img.shields.io/npm/v/@0x/contracts-staking.svg)](https://www.npmjs.com/package/@0x/contracts-staking) | Implements the stake-based liquidity incentives defined by [`ZEIP-31`](https://github.com/0xProject/ZEIPs/issues/31) |
### TypeScript/Javascript Packages
### Typescript/Javascript Packages
#### 0x-specific packages
@@ -61,9 +65,11 @@ These packages are all under development. See [/contracts/README.md](/contracts/
| [`@0x/order-utils`](/packages/order-utils) | [![npm](https://img.shields.io/npm/v/@0x/order-utils.svg)](https://www.npmjs.com/package/@0x/order-utils) | A set of utilities for generating, parsing, signing and validating 0x orders |
| [`@0x/json-schemas`](/packages/json-schemas) | [![npm](https://img.shields.io/npm/v/@0x/json-schemas.svg)](https://www.npmjs.com/package/@0x/json-schemas) | 0x-related JSON schemas | |
| [`@0x/migrations`](/packages/migrations) | [![npm](https://img.shields.io/npm/v/@0x/migrations.svg)](https://www.npmjs.com/package/@0x/migrations) | Migration tool for deploying 0x smart contracts on private testnets |
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [![npm](https://img.shields.io/npm/v/@0x/contract-artifacts.svg)](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts | |
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [![npm](https://img.shields.io/npm/v/@0x/contract-artifacts.svg)](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts |
| [`@0x/abi-gen-wrappers`](/packages/abi-gen-wrappers) | [![npm](https://img.shields.io/npm/v/@0x/abi-gen-wrappers.svg)](https://www.npmjs.com/package/@0x/abi-gen-wrappers) | Low-level 0x smart contract wrappers generated using `@0x/abi-gen` |
| [`@0x/sra-spec`](/packages/sra-spec) | [![npm](https://img.shields.io/npm/v/@0x/sra-spec.svg)](https://www.npmjs.com/package/@0x/sra-spec) | OpenAPI specification for the Standard Relayer API |
| [`@0x/connect`](/packages/connect) | [![npm](https://img.shields.io/npm/v/@0x/connect.svg)](https://www.npmjs.com/package/@0x/connect) | An HTTP/WS client for interacting with the Standard Relayer API |
| [`@0x/asset-buyer`](/packages/asset-buyer) | [![npm](https://img.shields.io/npm/v/@0x/asset-buyer.svg)](https://www.npmjs.com/package/@0x/asset-buyer) | Convenience package for discovering and buying assets with Ether |
| [`@0x/asset-swapper`](/packages/asset-swapper) | [![npm](https://img.shields.io/npm/v/@0x/asset-swapper.svg)](https://www.npmjs.com/package/@0x/asset-swapper) | Convenience package for discovering and performing swaps for any ERC20 Assets |
#### Ethereum tooling
@@ -91,12 +97,15 @@ These packages are all under development. See [/contracts/README.md](/contracts/
| [`@0x/assert`](/packages/assert) | [![npm](https://img.shields.io/npm/v/@0x/assert.svg)](https://www.npmjs.com/package/@0x/assert) | Type and schema assertions used by our packages |
| [`@0x/base-contract`](/packages/base-contract) | [![npm](https://img.shields.io/npm/v/@0x/base-contract.svg)](https://www.npmjs.com/package/@0x/base-contract) | BaseContract used by auto-generated `abi-gen` wrapper contracts |
| [`@0x/dev-utils`](/packages/dev-utils) | [![npm](https://img.shields.io/npm/v/@0x/dev-utils.svg)](https://www.npmjs.com/package/@0x/dev-utils) | Dev utils to be shared across 0x packages |
| [`@0x/fill-scenarios`](/packages/fill-scenarios) | [![npm](https://img.shields.io/npm/v/@0x/fill-scenarios.svg)](https://www.npmjs.com/package/@0x/fill-scenarios) | 0x order fill scenario generator |
#### Private Packages
| Package | Description |
| ---------------------------------- | -------------------------------------------------------------------------------- |
| [`@0x/instant`](/packages/instant) | A free and flexible way to offer simple crypto purchasing in any app or website. |
| Package | Description |
| -------------------------------------------------- | -------------------------------------------------------------------------------- |
| [`@0x/instant`](/packages/instant) | A free and flexible way to offer simple crypto purchasing in any app or website. |
| [`@0x/testnet-faucets`](/packages/testnet-faucets) | A faucet micro-service that dispenses test ERC20 tokens or Ether |
| [`@0x/website`](/packages/website) | 0x website |
## Usage

View File

@@ -13,4 +13,4 @@
#### Development
Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `contract-artifacts` or `contract-wrappers` packages, which are generated from the artifact JSON. See `contract-artifacts/README.md` for instructions on updating these packages.
Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `abi-gen-wrappers` package, which are generated from the artifact JSON. To ensure consistency, clean and rebuild `abi-gen-wrappers` after any changes to the artifact JSON.

View File

@@ -1,10 +0,0 @@
# Blacklist all files
.*
*
# Whitelist lib
!lib/**/*
# Whitelist Solidity contracts
!contracts/src/**/*
# Blacklist tests in lib
/lib/test/*
# Package specific ignore

View File

@@ -1,2 +0,0 @@
# solhint can't parse `abi.decode` syntax.
contracts/src/ERC1155Proxy.sol

View File

@@ -1,282 +1,4 @@
[
{
"timestamp": 1582837861,
"version": "3.2.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1582677073,
"version": "3.2.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1582623685,
"version": "3.2.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1581748629,
"version": "3.2.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.2.0",
"changes": [
{
"note": "Add more types and functions to `IDydx`",
"pr": 2466
},
{
"note": "Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx`",
"pr": 2466
},
{
"note": "Fix broken tests.",
"pr": 2462
},
{
"note": "Remove dependency on `@0x/contracts-dev-utils`",
"pr": 2462
},
{
"note": "Add asset data decoding functions",
"pr": 2462
},
{
"note": "Add `setOperators()` to `IDydx`",
"pr": "TODO"
}
],
"timestamp": 1581204851
},
{
"timestamp": 1580988106,
"version": "3.1.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1580811564,
"version": "3.1.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "3.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.1.0",
"changes": [
{
"note": "Integration tests for DydxBridge with ERC20BridgeProxy.",
"pr": 2401
},
{
"note": "Fix `UniswapBridge` token -> token transfer call.",
"pr": 2412
},
{
"note": "Fix `KyberBridge` incorrect `minConversionRate` calculation.",
"pr": 2412
}
],
"timestamp": 1578272714
},
{
"timestamp": 1576540892,
"version": "3.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1575931811,
"version": "3.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.0.0",
"changes": [
{
"note": "Implement `KyberBridge`.",
"pr": 2352
},
{
"note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils",
"pr": 2330
},
{
"note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract",
"pr": 2034
},
{
"note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable",
"pr": 2019
},
{
"note": "Remove `LibAssetProxyIds` contract",
"pr": 2055
},
{
"note": "Compile and export all contracts, artifacts, and wrappers by default",
"pr": 2055
},
{
"note": "Remove unused dependency on IAuthorizable in IAssetProxy",
"pr": 1910
},
{
"note": "Add `ERC20BridgeProxy`",
"pr": 2220
},
{
"note": "Add `Eth2DaiBridge`",
"pr": 2221
},
{
"note": "Add `UniswapBridge`",
"pr": 2233
},
{
"note": "Replaced `SafeMath` with `LibSafeMath`",
"pr": 2254
}
],
"timestamp": 1575296764
},
{
"version": "2.3.0-beta.4",
"changes": [
{
"note": "Implement `KyberBridge`.",
"pr": 2352
},
{
"note": "Implement `DydxBridge`.",
"pr": 2365
}
],
"timestamp": 1575290197
},
{
"version": "2.3.0-beta.3",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1574238768
},
{
"version": "2.3.0-beta.2",
"changes": [
{
"note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils",
"pr": 2330
}
],
"timestamp": 1574030254
},
{
"version": "2.3.0-beta.1",
"changes": [
{
"note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract",
"pr": 2034
}
],
"timestamp": 1573159180
},
{
"version": "2.3.0-beta.0",
"changes": [
{
"note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable",
"pr": 2019
},
{
"note": "Remove `LibAssetProxyIds` contract",
"pr": 2055
},
{
"note": "Compile and export all contracts, artifacts, and wrappers by default",
"pr": 2055
},
{
"note": "Remove unused dependency on IAuthorizable in IAssetProxy",
"pr": 1910
},
{
"note": "Add `ERC20BridgeProxy`",
"pr": 2220
},
{
"note": "Add `Eth2DaiBridge`",
"pr": 2221
},
{
"note": "Add `UniswapBridge`",
"pr": 2233
},
{
"note": "Replaced `SafeMath` with `LibSafeMath`",
"pr": 2254
}
],
"timestamp": 1570135330
},
{
"timestamp": 1568744790,
"version": "2.2.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1567521715,
"version": "2.2.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1566446343,
"version": "2.2.6",
@@ -383,18 +105,6 @@
{
"note": "Update tests to use contract-built-in `awaitTransactionSuccessAsync`",
"pr": 1797
},
{
"note": "Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID",
"pr": 1819
},
{
"note": "Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()`",
"pr": 1819
},
{
"note": "Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`.",
"pr": 1819
}
],
"timestamp": 1557507213

View File

@@ -5,107 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.2.4 - _February 27, 2020_
* Dependencies updated
## v3.2.3 - _February 26, 2020_
* Dependencies updated
## v3.2.2 - _February 25, 2020_
* Dependencies updated
## v3.2.1 - _February 15, 2020_
* Dependencies updated
## v3.2.0 - _February 8, 2020_
* Add more types and functions to `IDydx` (#2466)
* Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx` (#2466)
* Fix broken tests. (#2462)
* Remove dependency on `@0x/contracts-dev-utils` (#2462)
* Add asset data decoding functions (#2462)
* Add `setOperators()` to `IDydx` (#TODO)
## v3.1.3 - _February 6, 2020_
* Dependencies updated
## v3.1.2 - _February 4, 2020_
* Dependencies updated
## v3.1.1 - _January 22, 2020_
* Dependencies updated
## v3.1.0 - _January 6, 2020_
* Integration tests for DydxBridge with ERC20BridgeProxy. (#2401)
* Fix `UniswapBridge` token -> token transfer call. (#2412)
* Fix `KyberBridge` incorrect `minConversionRate` calculation. (#2412)
## v3.0.2 - _December 17, 2019_
* Dependencies updated
## v3.0.1 - _December 9, 2019_
* Dependencies updated
## v3.0.0 - _December 2, 2019_
* Implement `KyberBridge`. (#2352)
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
* ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034)
* Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019)
* Remove `LibAssetProxyIds` contract (#2055)
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
* Remove unused dependency on IAuthorizable in IAssetProxy (#1910)
* Add `ERC20BridgeProxy` (#2220)
* Add `Eth2DaiBridge` (#2221)
* Add `UniswapBridge` (#2233)
* Replaced `SafeMath` with `LibSafeMath` (#2254)
## v2.3.0-beta.4 - _December 2, 2019_
* Implement `KyberBridge`. (#2352)
* Implement `DydxBridge`. (#2365)
## v2.3.0-beta.3 - _November 20, 2019_
* Dependencies updated
## v2.3.0-beta.2 - _November 17, 2019_
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
## v2.3.0-beta.1 - _November 7, 2019_
* ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034)
## v2.3.0-beta.0 - _October 3, 2019_
* Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019)
* Remove `LibAssetProxyIds` contract (#2055)
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
* Remove unused dependency on IAuthorizable in IAssetProxy (#1910)
* Add `ERC20BridgeProxy` (#2220)
* Add `Eth2DaiBridge` (#2221)
* Add `UniswapBridge` (#2233)
* Replaced `SafeMath` with `LibSafeMath` (#2254)
## v2.2.8 - _September 17, 2019_
* Dependencies updated
## v2.2.7 - _September 3, 2019_
* Dependencies updated
## v2.2.6 - _August 22, 2019_
* Dependencies updated
@@ -151,9 +50,6 @@ CHANGELOG
## v2.1.2 - _May 10, 2019_
* Update tests to use contract-built-in `awaitTransactionSuccessAsync` (#1797)
* Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID (#1819)
* Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()` (#1819)
* Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`. (#1819)
## v2.1.1 - _April 11, 2019_

View File

@@ -1,6 +1,6 @@
## AssetProxy
This package contains the implementations of all of the [`AssetProxy`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy) contracts available within the 0x protocol. These contracts are responsible for decoding the `assetData` sent to them and performing the actual transfer of assets. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package.
This package contains the implementations of all of the [`AssetProxy`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy) contracts available within the 0x protocol. These contracts are responsible for decoding the `assetData` sent to them and performing the actual transfer of assets. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [DEPLOYS](./DEPLOYS.json) file within this package.
## Installation
@@ -12,7 +12,7 @@ npm install @0x/contracts-asset-proxy --save
## Bug bounty
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program).
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#Bug-Bounty).
## Contributing

View File

@@ -1,11 +1,10 @@
{
"artifactsDir": "./test/generated-artifacts",
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"useDockerisedSolc": false,
"isOfflineMode": false,
"shouldSaveStandardInput": true,
"compilerSettings": {
"evmVersion": "istanbul",
"evmVersion": "constantinople",
"optimizer": {
"enabled": true,
"runs": 1000000,
@@ -23,5 +22,17 @@
]
}
}
}
},
"contracts": [
"src/ERC1155Proxy.sol",
"src/ERC20Proxy.sol",
"src/ERC721Proxy.sol",
"src/MixinAuthorizable.sol",
"src/MultiAssetProxy.sol",
"src/StaticCallProxy.sol",
"src/interfaces/IAssetData.sol",
"src/interfaces/IAssetProxy.sol",
"src/interfaces/IAuthorizable.sol",
"test/TestStaticCallTarget.sol"
]
}

View File

@@ -1,33 +0,0 @@
pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
contract Ownable is
IOwnable
{
address public owner;
constructor ()
public
{
owner = msg.sender;
}
modifier onlyOwner() {
require(
msg.sender == owner,
"ONLY_CONTRACT_OWNER"
);
_;
}
function transferOwnership(address newOwner)
public
onlyOwner
{
if (newOwner != address(0)) {
owner = newOwner;
}
}
}

View File

@@ -1,6 +1,6 @@
/*
Copyright 2019 ZeroEx Intl.
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,18 +19,18 @@
pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-utils/contracts/src/SafeMath.sol";
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
import "../archive/MixinAuthorizable.sol";
import "./MixinAuthorizable.sol";
import "./interfaces/IAssetProxy.sol";
contract ERC1155Proxy is
MixinAuthorizable,
SafeMath,
IAssetProxy
{
using LibBytes for bytes;
using LibSafeMath for uint256;
// Id of this proxy.
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC1155Assets(address,uint256[],uint256[],bytes)"));
@@ -69,9 +69,9 @@ contract ERC1155Proxy is
for (uint256 i = 0; i != length; i++) {
// We write the scaled values to an unused location in memory in order
// to avoid copying over `ids` or `data`. This is possible if they are
// identical to `values` and the offsets for each are pointing to the
// identical to `values` and the offsets for each are pointing to the
// same location in the ABI encoded calldata.
scaledValues[i] = values[i].safeMul(amount);
scaledValues[i] = safeMul(values[i], amount);
}
// Execute `safeBatchTransferFrom` call

View File

@@ -1,126 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-utils/contracts/src/Authorizable.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "./interfaces/IAssetProxy.sol";
import "./interfaces/IERC20Bridge.sol";
contract ERC20BridgeProxy is
IAssetProxy,
Authorizable
{
using LibBytes for bytes;
using LibSafeMath for uint256;
// @dev Id of this proxy. Also the result of a successful bridge call.
// bytes4(keccak256("ERC20Bridge(address,address,bytes)"))
bytes4 constant private PROXY_ID = 0xdc1600f3;
/// @dev Calls a bridge contract to transfer `amount` of ERC20 from `from`
/// to `to`. Asserts that the balance of `to` has increased by `amount`.
/// @param assetData Abi-encoded data for this asset proxy encoded as:
/// abi.encodeWithSelector(
/// bytes4 PROXY_ID,
/// address tokenAddress,
/// address bridgeAddress,
/// bytes bridgeData
/// )
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer.
function transferFrom(
bytes calldata assetData,
address from,
address to,
uint256 amount
)
external
onlyAuthorized
{
// Extract asset data fields.
(
address tokenAddress,
address bridgeAddress,
bytes memory bridgeData
) = abi.decode(
assetData.sliceDestructive(4, assetData.length),
(address, address, bytes)
);
// Remember the balance of `to` before calling the bridge.
uint256 balanceBefore = balanceOf(tokenAddress, to);
// Call the bridge, who should transfer `amount` of `tokenAddress` to
// `to`.
bytes4 success = IERC20Bridge(bridgeAddress).bridgeTransferFrom(
tokenAddress,
from,
to,
amount,
bridgeData
);
// Bridge must return the proxy ID to indicate success.
require(success == PROXY_ID, "BRIDGE_FAILED");
// Ensure that the balance of `to` has increased by at least `amount`.
require(
balanceBefore.safeAdd(amount) <= balanceOf(tokenAddress, to),
"BRIDGE_UNDERPAY"
);
}
/// @dev Gets the proxy id associated with this asset proxy.
/// @return proxyId The proxy id.
function getProxyId()
external
pure
returns (bytes4 proxyId)
{
return PROXY_ID;
}
/// @dev Retrieves the balance of `owner` for this asset.
/// @return balance The balance of the ERC20 token being transferred by this
/// asset proxy.
function balanceOf(bytes calldata assetData, address owner)
external
view
returns (uint256 balance)
{
(address tokenAddress) = abi.decode(
assetData.sliceDestructive(4, assetData.length),
(address)
);
return balanceOf(tokenAddress, owner);
}
/// @dev Retrieves the balance of `owner` given an ERC20 address.
/// @return balance The balance of the ERC20 token for `owner`.
function balanceOf(address tokenAddress, address owner)
private
view
returns (uint256 balance)
{
return IERC20Token(tokenAddress).balanceOf(owner);
}
}

View File

@@ -1,6 +1,6 @@
/*
Copyright 2019 ZeroEx Intl.
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,9 +16,9 @@
*/
pragma solidity ^0.5.9;
pragma solidity ^0.5.5;
import "../archive/MixinAuthorizable.sol";
import "./MixinAuthorizable.sol";
contract ERC20Proxy is
@@ -26,9 +26,9 @@ contract ERC20Proxy is
{
// Id of this proxy.
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
// solhint-disable-next-line payable-fallback
function ()
function ()
external
{
assembly {
@@ -117,13 +117,13 @@ contract ERC20Proxy is
// * The "token address" is offset 32+4=36 bytes into "assetData" (tables 1 & 2).
// [tokenOffset = assetDataOffsetFromHeader + 36 = calldataload(4) + 4 + 36]
let token := calldataload(add(calldataload(4), 40))
/////// Setup Header Area ///////
// This area holds the 4-byte `transferFrom` selector.
// Any trailing data in transferFromSelector will be
// overwritten in the next `mstore` call.
mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
/////// Setup Params Area ///////
// We copy the fields `from`, `to` and `amount` in bulk
// from our own calldata to the new calldata.
@@ -147,7 +147,7 @@ contract ERC20Proxy is
// If the token does return data, we require that it is a single
// nonzero 32 bytes value.
// So the transfer succeeded if the call succeeded and either
// returned nothing, or returned a non-zero 32 byte value.
// returned nothing, or returned a non-zero 32 byte value.
success := and(success, or(
iszero(returndatasize),
and(
@@ -158,7 +158,7 @@ contract ERC20Proxy is
if success {
return(0, 0)
}
// Revert with `Error("TRANSFER_FAILED")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)

View File

@@ -1,6 +1,6 @@
/*
Copyright 2019 ZeroEx Intl.
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,9 +16,9 @@
*/
pragma solidity ^0.5.9;
pragma solidity ^0.5.5;
import "../archive/MixinAuthorizable.sol";
import "./MixinAuthorizable.sol";
contract ERC721Proxy is
@@ -28,7 +28,7 @@ contract ERC721Proxy is
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
// solhint-disable-next-line payable-fallback
function ()
function ()
external
{
assembly {
@@ -93,10 +93,10 @@ contract ERC721Proxy is
// | Params | | 2 * 32 | function parameters: |
// | | 4 | 12 + 20 | 1. token address |
// | | 36 | | 2. tokenId |
// We construct calldata for the `token.transferFrom` ABI.
// The layout of this calldata is in the table below.
//
//
// | Area | Offset | Length | Contents |
// |----------|--------|---------|-------------------------------------|
// | Header | 0 | 4 | function selector |
@@ -121,7 +121,7 @@ contract ERC721Proxy is
// Any trailing data in transferFromSelector will be
// overwritten in the next `mstore` call.
mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
/////// Setup Params Area ///////
// We copy the fields `from` and `to` in bulk
// from our own calldata to the new calldata.
@@ -145,7 +145,7 @@ contract ERC721Proxy is
if success {
return(0, 0)
}
// Revert with `Error("TRANSFER_FAILED")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)

View File

@@ -1,6 +1,6 @@
/*
Copyright 2019 ZeroEx Intl.
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,16 +16,16 @@
*/
pragma solidity ^0.5.9;
pragma solidity ^0.5.5;
import "../archive/Ownable.sol";
import "../src/interfaces/IAssetProxy.sol";
import "../src/interfaces/IAssetProxyDispatcher.sol";
import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "./mixins/MAssetProxyDispatcher.sol";
import "./interfaces/IAssetProxy.sol";
contract MixinAssetProxyDispatcher is
Ownable,
IAssetProxyDispatcher
MAssetProxyDispatcher
{
// Mapping from Asset Proxy Id's to their respective Asset Proxy
mapping (bytes4 => address) public assetProxies;
@@ -69,7 +69,7 @@ contract MixinAssetProxyDispatcher is
/// @param from Address to transfer token from.
/// @param to Address to transfer token to.
/// @param amount Amount of token to transfer.
function _dispatchTransferFrom(
function dispatchTransferFrom(
bytes memory assetData,
address from,
address to,
@@ -84,7 +84,7 @@ contract MixinAssetProxyDispatcher is
assetData.length > 3,
"LENGTH_GREATER_THAN_3_REQUIRED"
);
// Lookup assetProxy. We do not use `LibBytes.readBytes4` for gas efficiency reasons.
bytes4 assetProxyId;
assembly {
@@ -100,10 +100,10 @@ contract MixinAssetProxyDispatcher is
assetProxy != address(0),
"ASSET_PROXY_DOES_NOT_EXIST"
);
// We construct calldata for the `assetProxy.transferFrom` ABI.
// The layout of this calldata is in the table below.
//
//
// | Area | Offset | Length | Contents |
// | -------- |--------|---------|-------------------------------------------- |
// | Header | 0 | 4 | function selector |
@@ -127,12 +127,12 @@ contract MixinAssetProxyDispatcher is
// `cdEnd` is the end of the calldata for `assetProxy.transferFrom`.
let cdEnd := add(cdStart, add(132, dataAreaLength))
/////// Setup Header Area ///////
// This area holds the 4-byte `transferFromSelector`.
// bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
mstore(cdStart, 0xa85e59e400000000000000000000000000000000000000000000000000000000)
/////// Setup Params Area ///////
// Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes.
// Notes:
@@ -142,7 +142,7 @@ contract MixinAssetProxyDispatcher is
mstore(add(cdStart, 36), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(cdStart, 68), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(cdStart, 100), amount)
/////// Setup Data Area ///////
// This area holds `assetData`.
let dataArea := add(cdStart, 132)
@@ -159,7 +159,7 @@ contract MixinAssetProxyDispatcher is
assetProxy, // call address of asset proxy
0, // don't send any ETH
cdStart, // pointer to start of input
sub(cdEnd, cdStart), // length of input
sub(cdEnd, cdStart), // length of input
cdStart, // write output over input
512 // reserve 512 bytes for output
)

View File

@@ -1,6 +1,6 @@
/*
Copyright 2019 ZeroEx Intl.
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,15 +16,15 @@
*/
pragma solidity ^0.5.9;
pragma solidity ^0.5.5;
import "../archive/Ownable.sol";
import "../src/interfaces/IAuthorizable.sol";
import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "./mixins/MAuthorizable.sol";
contract MixinAuthorizable is
Ownable,
IAuthorizable
MAuthorizable
{
/// @dev Only authorized addresses can invoke functions with this modifier.
modifier onlyAuthorized {

View File

@@ -1,6 +1,6 @@
/*
Copyright 2019 ZeroEx Intl.
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,10 +16,10 @@
*/
pragma solidity ^0.5.9;
pragma solidity ^0.5.5;
import "../archive/MixinAssetProxyDispatcher.sol";
import "../archive/MixinAuthorizable.sol";
import "./MixinAssetProxyDispatcher.sol";
import "./MixinAuthorizable.sol";
contract MultiAssetProxy is
@@ -105,7 +105,7 @@ contract MultiAssetProxy is
// | | 36 | | 2. offset to nestedAssetData (*) |
// | Data | | | amounts: |
// | | 68 | 32 | amounts Length |
// | | 100 | a | amounts Contents |
// | | 100 | a | amounts Contents |
// | | | | nestedAssetData: |
// | | 100 + a | 32 | nestedAssetData Length |
// | | 132 + a | b | nestedAssetData Contents (offsets) |
@@ -149,8 +149,8 @@ contract MultiAssetProxy is
// + 32 (amounts offset)
let nestedAssetDataOffset := calldataload(add(assetDataOffset, 68))
// In order to find the start of the `amounts` contents, we must add:
// assetDataOffset
// In order to find the start of the `amounts` contents, we must add:
// assetDataOffset
// + 32 (assetData len)
// + 4 (assetProxyId)
// + amountsOffset
@@ -160,8 +160,8 @@ contract MultiAssetProxy is
// Load number of elements in `amounts`
let amountsLen := calldataload(sub(amountsContentsStart, 32))
// In order to find the start of the `nestedAssetData` contents, we must add:
// assetDataOffset
// In order to find the start of the `nestedAssetData` contents, we must add:
// assetDataOffset
// + 32 (assetData len)
// + 4 (assetProxyId)
// + nestedAssetDataOffset
@@ -190,10 +190,10 @@ contract MultiAssetProxy is
// Overwrite existing offset to `assetData` with our own
mstore(4, 128)
// Load `amount`
let amount := calldataload(100)
// Calculate number of bytes in `amounts` contents
let amountsByteLen := mul(amountsLen, 32)
@@ -208,7 +208,7 @@ contract MultiAssetProxy is
let amountsElement := calldataload(add(amountsContentsStart, i))
let totalAmount := mul(amountsElement, amount)
// Revert if `amount` != 0 and multiplication resulted in an overflow
// Revert if `amount` != 0 and multiplication resulted in an overflow
if iszero(or(
iszero(amount),
eq(div(totalAmount, amount), amountsElement)
@@ -228,7 +228,7 @@ contract MultiAssetProxy is
let nestedAssetDataElementOffset := calldataload(add(nestedAssetDataContentsStart, i))
// In order to find the start of the `nestedAssetData[i]` contents, we must add:
// assetDataOffset
// assetDataOffset
// + 32 (assetData len)
// + 4 (assetProxyId)
// + nestedAssetDataOffset
@@ -274,7 +274,7 @@ contract MultiAssetProxy is
mstore(164, assetProxies_slot)
assetProxy := sload(keccak256(132, 64))
}
// Revert if AssetProxy with given id does not exist
if iszero(assetProxy) {
// Revert with `Error("ASSET_PROXY_DOES_NOT_EXIST")`
@@ -284,7 +284,7 @@ contract MultiAssetProxy is
mstore(96, 0)
revert(0, 100)
}
// Copy `nestedAssetData[i]` from calldata to memory
calldatacopy(
132, // memory slot after `amounts[i]`
@@ -298,7 +298,7 @@ contract MultiAssetProxy is
assetProxy, // call address of asset proxy
0, // don't send any ETH
0, // pointer to start of input
add(164, nestedAssetDataElementLen), // length of input
add(164, nestedAssetDataElementLen), // length of input
0, // write output over memory that won't be reused
0 // don't copy output to memory
)

View File

@@ -1,6 +1,6 @@
/*
Copyright 2019 ZeroEx Intl.
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,75 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "../interfaces/IERC20Bridge.sol";
import "../interfaces/IChai.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
// solhint-disable space-after-comma
contract ChaiBridge is
IERC20Bridge,
DeploymentConstants
{
/// @dev Withdraws `amount` of `from` address's Dai from the Chai contract.
/// Transfers `amount` of Dai to `to` address.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer.
/// @return success The magic bytes `0xdc1600f3` if successful.
function bridgeTransferFrom(
address /* tokenAddress */,
address from,
address to,
uint256 amount,
bytes calldata /* bridgeData */
)
external
returns (bytes4 success)
{
// Ensure that only the `ERC20BridgeProxy` can call this function.
require(
msg.sender == _getERC20BridgeProxyAddress(),
"ChaiBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY"
);
// Withdraw `from` address's Dai.
// NOTE: This contract must be approved to spend Chai on behalf of `from`.
bytes memory drawCalldata = abi.encodeWithSelector(
IChai(address(0)).draw.selector,
from,
amount
);
(bool success,) = _getChaiAddress().call(drawCalldata);
require(
success,
"ChaiBridge/DRAW_DAI_FAILED"
);
// Transfer Dai to `to`
// This will never fail if the `draw` call was successful
IERC20Token(_getDaiAddress()).transfer(to, amount);
return BRIDGE_SUCCESS;
}
}

View File

@@ -1,108 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IERC20Bridge.sol";
import "../interfaces/ICurve.sol";
// solhint-disable not-rely-on-time
// solhint-disable space-after-comma
contract CurveBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
/// @dev Callback for `ICurve`. Tries to buy `amount` of
/// `toTokenAddress` tokens by selling the entirety of the opposing asset
/// (DAI, USDC) to the Curve contract, then transfers the bought
/// tokens to `to`.
/// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoeded "from" token address.
/// @return success The magic bytes if successful.
function bridgeTransferFrom(
address toTokenAddress,
address /* from */,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success)
{
// Decode the bridge data to get the Curve metadata.
(address curveAddress, int128 fromCoinIdx, int128 toCoinIdx, int128 version) = abi.decode(bridgeData, (address, int128, int128, int128));
ICurve exchange = ICurve(curveAddress);
address fromTokenAddress = exchange.underlying_coins(fromCoinIdx);
require(toTokenAddress != fromTokenAddress, "CurveBridge/INVALID_PAIR");
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1));
// Try to sell all of this contract's `fromTokenAddress` token balance.
if (version == 0) {
exchange.exchange_underlying(
fromCoinIdx,
toCoinIdx,
// dx
IERC20Token(fromTokenAddress).balanceOf(address(this)),
// min dy
amount,
// expires
block.timestamp + 1
);
} else {
exchange.exchange_underlying(
fromCoinIdx,
toCoinIdx,
// dx
IERC20Token(fromTokenAddress).balanceOf(address(this)),
// min dy
amount
);
}
uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this));
// Transfer the converted `toToken`s to `to`.
LibERC20Token.transfer(toTokenAddress, to, toTokenBalance);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Magic success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@@ -1,241 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "../interfaces/IERC20Bridge.sol";
import "../interfaces/IDydxBridge.sol";
import "../interfaces/IDydx.sol";
contract DydxBridge is
IERC20Bridge,
IDydxBridge,
DeploymentConstants
{
using LibSafeMath for uint256;
/// @dev Callback for `IERC20Bridge`. Deposits or withdraws tokens from a dydx account.
/// Notes:
/// 1. This bridge must be set as an operator of the input dydx account.
/// 2. This function may only be called in the context of the 0x Exchange.
/// 3. The maker or taker of the 0x order must be the dydx account owner.
/// 4. Deposits into dydx are made from the `from` address.
/// 5. Withdrawals from dydx are made to the `to` address.
/// 6. Calling this function must always withdraw at least `amount`,
/// otherwise the `ERC20Bridge` will revert.
/// @param from The sender of the tokens and owner of the dydx account.
/// @param to The recipient of the tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to deposit or withdraw.
/// @param encodedBridgeData An abi-encoded `BridgeData` struct.
/// @return success The magic bytes if successful.
function bridgeTransferFrom(
address,
address from,
address to,
uint256 amount,
bytes calldata encodedBridgeData
)
external
returns (bytes4 success)
{
// Ensure that only the `ERC20BridgeProxy` can call this function.
require(
msg.sender == _getERC20BridgeProxyAddress(),
"DydxBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY"
);
// Decode bridge data.
(BridgeData memory bridgeData) = abi.decode(encodedBridgeData, (BridgeData));
// The dydx accounts are owned by the `from` address.
IDydx.AccountInfo[] memory accounts = _createAccounts(from, bridgeData);
// Create dydx actions to run on the dydx accounts.
IDydx.ActionArgs[] memory actions = _createActions(
from,
to,
amount,
bridgeData
);
// Run operation. This will revert on failure.
IDydx(_getDydxAddress()).operate(accounts, actions);
return BRIDGE_SUCCESS;
}
/// @dev Creates an array of accounts for dydx to operate on.
/// All accounts must belong to the same owner.
/// @param accountOwner Owner of the dydx account.
/// @param bridgeData A `BridgeData` struct.
function _createAccounts(
address accountOwner,
BridgeData memory bridgeData
)
internal
returns (IDydx.AccountInfo[] memory accounts)
{
uint256[] memory accountNumbers = bridgeData.accountNumbers;
uint256 nAccounts = accountNumbers.length;
accounts = new IDydx.AccountInfo[](nAccounts);
for (uint256 i = 0; i < nAccounts; ++i) {
accounts[i] = IDydx.AccountInfo({
owner: accountOwner,
number: accountNumbers[i]
});
}
}
/// @dev Creates an array of actions to carry out on dydx.
/// @param depositFrom Deposit value from this address (owner of the dydx account).
/// @param withdrawTo Withdraw value to this address.
/// @param amount The amount of value available to operate on.
/// @param bridgeData A `BridgeData` struct.
function _createActions(
address depositFrom,
address withdrawTo,
uint256 amount,
BridgeData memory bridgeData
)
internal
returns (IDydx.ActionArgs[] memory actions)
{
BridgeAction[] memory bridgeActions = bridgeData.actions;
uint256 nBridgeActions = bridgeActions.length;
actions = new IDydx.ActionArgs[](nBridgeActions);
for (uint256 i = 0; i < nBridgeActions; ++i) {
// Cache current bridge action.
BridgeAction memory bridgeAction = bridgeActions[i];
// Scale amount, if conversion rate is set.
uint256 scaledAmount;
if (bridgeAction.conversionRateDenominator > 0) {
scaledAmount = LibMath.safeGetPartialAmountFloor(
bridgeAction.conversionRateNumerator,
bridgeAction.conversionRateDenominator,
amount
);
} else {
scaledAmount = amount;
}
// Construct dydx action.
if (bridgeAction.actionType == BridgeActionType.Deposit) {
// Deposit tokens from the account owner into their dydx account.
actions[i] = _createDepositAction(
depositFrom,
scaledAmount,
bridgeAction
);
} else if (bridgeAction.actionType == BridgeActionType.Withdraw) {
// Withdraw tokens from dydx to the `otherAccount`.
actions[i] = _createWithdrawAction(
withdrawTo,
scaledAmount,
bridgeAction
);
} else {
// If all values in the `Action` enum are handled then this
// revert is unreachable: Solidity will revert when casting
// from `uint8` to `Action`.
revert("DydxBridge/UNRECOGNIZED_BRIDGE_ACTION");
}
}
}
/// @dev Returns a dydx `DepositAction`.
/// @param depositFrom Deposit tokens from this address who is also the account owner.
/// @param amount of tokens to deposit.
/// @param bridgeAction A `BridgeAction` struct.
/// @return depositAction The encoded dydx action.
function _createDepositAction(
address depositFrom,
uint256 amount,
BridgeAction memory bridgeAction
)
internal
pure
returns (
IDydx.ActionArgs memory depositAction
)
{
// Create dydx amount.
IDydx.AssetAmount memory dydxAmount = IDydx.AssetAmount({
sign: true, // true if positive.
denomination: IDydx.AssetDenomination.Wei, // Wei => actual token amount held in account.
ref: IDydx.AssetReference.Delta, // Delta => a relative amount.
value: amount // amount to deposit.
});
// Create dydx deposit action.
depositAction = IDydx.ActionArgs({
actionType: IDydx.ActionType.Deposit, // deposit tokens.
amount: dydxAmount, // amount to deposit.
accountIdx: bridgeAction.accountIdx, // index in the `accounts` when calling `operate`.
primaryMarketId: bridgeAction.marketId, // indicates which token to deposit.
otherAddress: depositFrom, // deposit from the account owner.
// unused parameters
secondaryMarketId: 0,
otherAccountIdx: 0,
data: hex''
});
}
/// @dev Returns a dydx `WithdrawAction`.
/// @param withdrawTo Withdraw tokens to this address.
/// @param amount of tokens to withdraw.
/// @param bridgeAction A `BridgeAction` struct.
/// @return withdrawAction The encoded dydx action.
function _createWithdrawAction(
address withdrawTo,
uint256 amount,
BridgeAction memory bridgeAction
)
internal
pure
returns (
IDydx.ActionArgs memory withdrawAction
)
{
// Create dydx amount.
IDydx.AssetAmount memory amountToWithdraw = IDydx.AssetAmount({
sign: false, // false if negative.
denomination: IDydx.AssetDenomination.Wei, // Wei => actual token amount held in account.
ref: IDydx.AssetReference.Delta, // Delta => a relative amount.
value: amount // amount to withdraw.
});
// Create withdraw action.
withdrawAction = IDydx.ActionArgs({
actionType: IDydx.ActionType.Withdraw, // withdraw tokens.
amount: amountToWithdraw, // amount to withdraw.
accountIdx: bridgeAction.accountIdx, // index in the `accounts` when calling `operate`.
primaryMarketId: bridgeAction.marketId, // indicates which token to withdraw.
otherAddress: withdrawTo, // withdraw tokens to this address.
// unused parameters
secondaryMarketId: 0,
otherAccountIdx: 0,
data: hex''
});
}
}

View File

@@ -1,87 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IERC20Bridge.sol";
import "../interfaces/IEth2Dai.sol";
// solhint-disable space-after-comma
contract Eth2DaiBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
/// `toTokenAddress` tokens by selling the entirety of the opposing asset
/// (DAI or WETH) to the Eth2Dai contract, then transfers the bought
/// tokens to `to`.
/// @param toTokenAddress The token to give to `to` (either DAI or WETH).
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoeded "from" token address.
/// @return success The magic bytes if successful.
function bridgeTransferFrom(
address toTokenAddress,
address /* from */,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success)
{
// Decode the bridge data to get the `fromTokenAddress`.
(address fromTokenAddress) = abi.decode(bridgeData, (address));
IEth2Dai exchange = IEth2Dai(_getEth2DaiAddress());
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1));
// Try to sell all of this contract's `fromTokenAddress` token balance.
uint256 boughtAmount = exchange.sellAllAmount(
fromTokenAddress,
IERC20Token(fromTokenAddress).balanceOf(address(this)),
toTokenAddress,
amount
);
// Transfer the converted `toToken`s to `to`.
LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Magic success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@@ -1,162 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "../interfaces/IERC20Bridge.sol";
import "../interfaces/IKyberNetworkProxy.sol";
// solhint-disable space-after-comma
contract KyberBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
using LibSafeMath for uint256;
// @dev Structure used internally to get around stack limits.
struct TradeState {
IKyberNetworkProxy kyber;
IEtherToken weth;
address fromTokenAddress;
uint256 fromTokenBalance;
uint256 payableAmount;
uint256 conversionRate;
}
/// @dev Kyber ETH pseudo-address.
address constant public KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev `bridgeTransferFrom()` failure result.
bytes4 constant private BRIDGE_FAILED = 0x0;
/// @dev Precision of Kyber rates.
uint256 constant private KYBER_RATE_BASE = 10 ** 18;
// solhint-disable no-empty-blocks
/// @dev Payable fallback to receive ETH from Kyber.
function ()
external
payable
{}
/// @dev Callback for `IKyberBridge`. Tries to buy `amount` of
/// `toTokenAddress` tokens by selling the entirety of the opposing asset
/// to the `KyberNetworkProxy` contract, then transfers the bought
/// tokens to `to`.
/// @param toTokenAddress The token to give to `to`.
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoeded "from" token address.
/// @return success The magic bytes if successful.
function bridgeTransferFrom(
address toTokenAddress,
address /* from */,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success)
{
TradeState memory state;
state.kyber = IKyberNetworkProxy(_getKyberNetworkProxyAddress());
state.weth = IEtherToken(_getWethAddress());
// Decode the bridge data to get the `fromTokenAddress`.
(state.fromTokenAddress) = abi.decode(bridgeData, (address));
// Query the balance of "from" tokens.
state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));
if (state.fromTokenBalance == 0) {
// Return failure if no input tokens.
return BRIDGE_FAILED;
}
// Compute the conversion rate, expressed in 18 decimals.
// The sequential notation is to get around stack limits.
state.conversionRate = KYBER_RATE_BASE;
state.conversionRate = state.conversionRate.safeMul(amount);
state.conversionRate = state.conversionRate.safeMul(
10 ** uint256(LibERC20Token.decimals(state.fromTokenAddress))
);
state.conversionRate = state.conversionRate.safeDiv(state.fromTokenBalance);
state.conversionRate = state.conversionRate.safeDiv(
10 ** uint256(LibERC20Token.decimals(toTokenAddress))
);
if (state.fromTokenAddress == toTokenAddress) {
// Just transfer the tokens if they're the same.
LibERC20Token.transfer(state.fromTokenAddress, to, state.fromTokenBalance);
return BRIDGE_SUCCESS;
} else if (state.fromTokenAddress != address(state.weth)) {
// If the input token is not WETH, grant an allowance to the exchange
// to spend them.
LibERC20Token.approve(state.fromTokenAddress, address(state.kyber), uint256(-1));
} else {
// If the input token is WETH, unwrap it and attach it to the call.
state.fromTokenAddress = KYBER_ETH_ADDRESS;
state.payableAmount = state.fromTokenBalance;
state.weth.withdraw(state.fromTokenBalance);
}
bool isToTokenWeth = toTokenAddress == address(state.weth);
// Try to sell all of this contract's input token balance through
// `KyberNetworkProxy.trade()`.
uint256 boughtAmount = state.kyber.trade.value(state.payableAmount)(
// Input token.
state.fromTokenAddress,
// Sell amount.
state.fromTokenBalance,
// Output token.
isToTokenWeth ? KYBER_ETH_ADDRESS : toTokenAddress,
// Transfer to this contract if converting to ETH, otherwise
// transfer directly to the recipient.
isToTokenWeth ? address(uint160(address(this))) : address(uint160(to)),
// Buy as much as possible.
uint256(-1),
// Compute the minimum conversion rate, which is expressed in units with
// 18 decimal places.
state.conversionRate,
// No affiliate address.
address(0)
);
// Wrap ETH output and transfer to recipient.
if (isToTokenWeth) {
state.weth.deposit.value(boughtAmount)();
state.weth.transfer(to, boughtAmount);
}
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Magic success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@@ -1,200 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IUniswapExchangeFactory.sol";
import "../interfaces/IUniswapExchange.sol";
import "../interfaces/IERC20Bridge.sol";
// solhint-disable space-after-comma
// solhint-disable not-rely-on-time
contract UniswapBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
// Struct to hold `bridgeTransferFrom()` local variables in memory and to avoid
// stack overflows.
struct WithdrawToState {
IUniswapExchange exchange;
uint256 fromTokenBalance;
IEtherToken weth;
}
// solhint-disable no-empty-blocks
/// @dev Payable fallback to receive ETH from uniswap.
function ()
external
payable
{}
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
/// token encoded in the bridge data.
/// @param toTokenAddress The token to buy and transfer to `to`.
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoded "from" token address.
/// @return success The magic bytes if successful.
function bridgeTransferFrom(
address toTokenAddress,
address /* from */,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success)
{
// State memory object to avoid stack overflows.
WithdrawToState memory state;
// Decode the bridge data to get the `fromTokenAddress`.
(address fromTokenAddress) = abi.decode(bridgeData, (address));
// Just transfer the tokens if they're the same.
if (fromTokenAddress == toTokenAddress) {
LibERC20Token.transfer(fromTokenAddress, to, amount);
return BRIDGE_SUCCESS;
}
// Get the exchange for the token pair.
state.exchange = _getUniswapExchangeForTokenPair(
fromTokenAddress,
toTokenAddress
);
// Get our balance of `fromTokenAddress` token.
state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
// Get the weth contract.
state.weth = IEtherToken(_getWethAddress());
// Convert from WETH to a token.
if (fromTokenAddress == address(state.weth)) {
// Unwrap the WETH.
state.weth.withdraw(state.fromTokenBalance);
// Buy as much of `toTokenAddress` token with ETH as possible and
// transfer it to `to`.
state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)(
// Minimum buy amount.
amount,
// Expires after this block.
block.timestamp,
// Recipient is `to`.
to
);
// Convert from a token to WETH.
} else if (toTokenAddress == address(state.weth)) {
// Grant the exchange an allowance.
_grantExchangeAllowance(state.exchange, fromTokenAddress);
// Buy as much ETH with `fromTokenAddress` token as possible.
uint256 ethBought = state.exchange.tokenToEthSwapInput(
// Sell all tokens we hold.
state.fromTokenBalance,
// Minimum buy amount.
amount,
// Expires after this block.
block.timestamp
);
// Wrap the ETH.
state.weth.deposit.value(ethBought)();
// Transfer the WETH to `to`.
IEtherToken(toTokenAddress).transfer(to, ethBought);
// Convert from one token to another.
} else {
// Grant the exchange an allowance.
_grantExchangeAllowance(state.exchange, fromTokenAddress);
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
// and transfer it to `to`.
state.exchange.tokenToTokenTransferInput(
// Sell all tokens we hold.
state.fromTokenBalance,
// Minimum buy amount.
amount,
// Must buy at least 1 intermediate ETH.
1,
// Expires after this block.
block.timestamp,
// Recipient is `to`.
to,
// Convert to `toTokenAddress`.
toTokenAddress
);
}
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
/// @dev Grants an unlimited allowance to the exchange for its token
/// on behalf of this contract.
/// @param exchange The Uniswap token exchange.
/// @param tokenAddress The token address for the exchange.
function _grantExchangeAllowance(IUniswapExchange exchange, address tokenAddress)
private
{
LibERC20Token.approve(tokenAddress, address(exchange), uint256(-1));
}
/// @dev Retrieves the uniswap exchange for a given token pair.
/// In the case of a WETH-token exchange, this will be the non-WETH token.
/// In th ecase of a token-token exchange, this will be the first token.
/// @param fromTokenAddress The address of the token we are converting from.
/// @param toTokenAddress The address of the token we are converting to.
/// @return exchange The uniswap exchange.
function _getUniswapExchangeForTokenPair(
address fromTokenAddress,
address toTokenAddress
)
private
view
returns (IUniswapExchange exchange)
{
address exchangeTokenAddress = fromTokenAddress;
// Whichever isn't WETH is the exchange token.
if (fromTokenAddress == _getWethAddress()) {
exchangeTokenAddress = toTokenAddress;
}
exchange = IUniswapExchange(
IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress())
.getExchange(exchangeTokenAddress)
);
require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN");
return exchange;
}
}

View File

@@ -1,6 +1,6 @@
/*
Copyright 2019 ZeroEx Intl.
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@
*/
// solhint-disable
pragma solidity ^0.5.9;
pragma solidity ^0.5.5;
pragma experimental ABIEncoderV2;
@@ -26,63 +26,33 @@ pragma experimental ABIEncoderV2;
// This argument is ABI encoded as one of the methods of this interface.
interface IAssetData {
/// @dev Function signature for encoding ERC20 assetData.
/// @param tokenAddress Address of ERC20Token contract.
function ERC20Token(address tokenAddress)
external;
/// @dev Function signature for encoding ERC721 assetData.
/// @param tokenAddress Address of ERC721 token contract.
/// @param tokenId Id of ERC721 token to be transferred.
function ERC721Token(
address tokenAddress,
uint256 tokenId
)
external;
/// @dev Function signature for encoding ERC1155 assetData.
/// @param tokenAddress Address of ERC1155 token contract.
/// @param tokenIds Array of ids of tokens to be transferred.
/// @param values Array of values that correspond to each token id to be transferred.
/// Note that each value will be multiplied by the amount being filled in the order before transferring.
/// @param callbackData Extra data to be passed to receiver's `onERC1155Received` callback function.
function ERC1155Assets(
address tokenAddress,
uint256[] calldata tokenIds,
uint256[] calldata values,
uint256[] calldata tokenValues,
bytes calldata callbackData
)
external;
/// @dev Function signature for encoding MultiAsset assetData.
/// @param values Array of amounts that correspond to each asset to be transferred.
/// Note that each value will be multiplied by the amount being filled in the order before transferring.
/// @param nestedAssetData Array of assetData fields that will be be dispatched to their correspnding AssetProxy contract.
function MultiAsset(
uint256[] calldata values,
uint256[] calldata amounts,
bytes[] calldata nestedAssetData
)
external;
/// @dev Function signature for encoding StaticCall assetData.
/// @param staticCallTargetAddress Address that will execute the staticcall.
/// @param staticCallData Data that will be executed via staticcall on the staticCallTargetAddress.
/// @param expectedReturnDataHash Keccak-256 hash of the expected staticcall return data.
function StaticCall(
address staticCallTargetAddress,
address callTarget,
bytes calldata staticCallData,
bytes32 expectedReturnDataHash
)
external;
/// @dev Function signature for encoding ERC20Bridge assetData.
/// @param tokenAddress Address of token to transfer.
/// @param bridgeAddress Address of the bridge contract.
/// @param bridgeData Arbitrary data to be passed to the bridge contract.
function ERC20Bridge(
address tokenAddress,
address bridgeAddress,
bytes calldata bridgeData
bytes32 callResultHash
)
external;
}

View File

@@ -1,6 +1,6 @@
/*
Copyright 2019 ZeroEx Intl.
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,7 +16,9 @@
*/
pragma solidity ^0.5.9;
pragma solidity ^0.5.5;
import "./IAuthorizable.sol";
contract IAssetProxy {

View File

@@ -1,6 +1,6 @@
/*
Copyright 2019 ZeroEx Intl.
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,17 +16,11 @@
*/
pragma solidity ^0.5.9;
pragma solidity ^0.5.5;
contract IAssetProxyDispatcher {
// Logs registration of new asset proxy
event AssetProxyRegistered(
bytes4 id, // Id of new registered AssetProxy.
address assetProxy // Address of new registered AssetProxy.
);
/// @dev Registers an asset proxy to its asset proxy id.
/// Once an asset proxy is registered, it cannot be unregistered.
/// @param assetProxy Address of new asset proxy to register.

View File

@@ -1,6 +1,6 @@
/*
Copyright 2019 ZeroEx Intl.
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
*/
pragma solidity ^0.5.9;
pragma solidity ^0.5.5;
import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
@@ -24,18 +24,6 @@ import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
contract IAuthorizable is
IOwnable
{
// Event logged when a new address is authorized.
event AuthorizedAddressAdded(
address indexed target,
address indexed caller
);
// Event logged when a currently authorized address is unauthorized.
event AuthorizedAddressRemoved(
address indexed target,
address indexed caller
);
/// @dev Authorizes an address.
/// @param target Address to authorize.
function addAuthorizedAddress(address target)
@@ -54,7 +42,7 @@ contract IAuthorizable is
uint256 index
)
external;
/// @dev Gets all authorized addresses.
/// @return Array of authorized addresses.
function getAuthorizedAddresses()

View File

@@ -1,66 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
contract PotLike {
function chi() external returns (uint256);
function rho() external returns (uint256);
function drip() external returns (uint256);
function join(uint256) external;
function exit(uint256) external;
}
// The actual Chai contract can be found here: https://github.com/dapphub/chai
contract IChai is
IERC20Token
{
/// @dev Withdraws Dai owned by `src`
/// @param src Address that owns Dai.
/// @param wad Amount of Dai to withdraw.
function draw(
address src,
uint256 wad
)
external;
/// @dev Queries Dai balance of Chai holder.
/// @param usr Address of Chai holder.
/// @return Dai balance.
function dai(address usr)
external
returns (uint256);
/// @dev Queries the Pot contract used by the Chai contract.
function pot()
external
returns (PotLike);
/// @dev Deposits Dai in exchange for Chai
/// @param dst Address to receive Chai.
/// @param wad Amount of Dai to deposit.
function join(
address dst,
uint256 wad
)
external;
}

View File

@@ -1,87 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
// solhint-disable func-name-mixedcase
interface ICurve {
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
/// This function exists on early versions of Curve (USDC/DAI)
/// @param i The token index being sold.
/// @param j The token index being bought.
/// @param sellAmount The amount of token being bought.
/// @param minBuyAmount The minimum buy amount of the token being bought.
/// @param deadline The time in seconds when this operation should expire.
function exchange_underlying(
int128 i,
int128 j,
uint256 sellAmount,
uint256 minBuyAmount,
uint256 deadline
)
external;
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
/// This function exists on later versions of Curve (USDC/DAI/USDT)
/// @param i The token index being sold.
/// @param j The token index being bought.
/// @param sellAmount The amount of token being bought.
/// @param minBuyAmount The minimum buy amount of the token being bought.
function exchange_underlying(
int128 i,
int128 j,
uint256 sellAmount,
uint256 minBuyAmount
)
external;
/// @dev Get the amount of `toToken` by selling `sellAmount` of `fromToken`
/// @param i The token index being sold.
/// @param j The token index being bought.
/// @param sellAmount The amount of token being bought.
function get_dy_underlying(
int128 i,
int128 j,
uint256 sellAmount
)
external
returns (uint256 dy);
/// @dev Get the amount of `fromToken` by buying `buyAmount` of `toToken`
/// This function exists on later versions of Curve (USDC/DAI/USDT)
/// @param i The token index being sold.
/// @param j The token index being bought.
/// @param buyAmount The amount of token being bought.
function get_dx_underlying(
int128 i,
int128 j,
uint256 buyAmount
)
external
returns (uint256 dx);
/// @dev Get the underlying token address from the token index
/// @param i The token index.
function underlying_coins(
int128 i
)
external
returns (address tokenAddress);
}

View File

@@ -1,192 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
interface IDydx {
/// @dev Represents the unique key that specifies an account
struct AccountInfo {
address owner; // The address that owns the account
uint256 number; // A nonce that allows a single address to control many accounts
}
enum ActionType {
Deposit, // supply tokens
Withdraw, // borrow tokens
Transfer, // transfer balance between accounts
Buy, // buy an amount of some token (externally)
Sell, // sell an amount of some token (externally)
Trade, // trade tokens against another account
Liquidate, // liquidate an undercollateralized or expiring account
Vaporize, // use excess tokens to zero-out a completely negative account
Call // send arbitrary data to an address
}
/// @dev Arguments that are passed to Solo in an ordered list as part of a single operation.
/// Each ActionArgs has an actionType which specifies which action struct that this data will be
/// parsed into before being processed.
struct ActionArgs {
ActionType actionType;
uint256 accountIdx;
AssetAmount amount;
uint256 primaryMarketId;
uint256 secondaryMarketId;
address otherAddress;
uint256 otherAccountIdx;
bytes data;
}
enum AssetDenomination {
Wei, // the amount is denominated in wei
Par // the amount is denominated in par
}
enum AssetReference {
Delta, // the amount is given as a delta from the current value
Target // the amount is given as an exact number to end up at
}
struct AssetAmount {
bool sign; // true if positive
AssetDenomination denomination;
AssetReference ref;
uint256 value;
}
struct D256 {
uint256 value;
}
struct Value {
uint256 value;
}
struct Price {
uint256 value;
}
struct OperatorArg {
address operator;
bool trusted;
}
/// @dev The global risk parameters that govern the health and security of the system
struct RiskParams {
// Required ratio of over-collateralization
D256 marginRatio;
// Percentage penalty incurred by liquidated accounts
D256 liquidationSpread;
// Percentage of the borrower's interest fee that gets passed to the suppliers
D256 earningsRate;
// The minimum absolute borrow value of an account
// There must be sufficient incentivize to liquidate undercollateralized accounts
Value minBorrowedValue;
}
/// @dev The main entry-point to Solo that allows users and contracts to manage accounts.
/// Take one or more actions on one or more accounts. The msg.sender must be the owner or
/// operator of all accounts except for those being liquidated, vaporized, or traded with.
/// One call to operate() is considered a singular "operation". Account collateralization is
/// ensured only after the completion of the entire operation.
/// @param accounts A list of all accounts that will be used in this operation. Cannot contain
/// duplicates. In each action, the relevant account will be referred-to by its
/// index in the list.
/// @param actions An ordered list of all actions that will be taken in this operation. The
/// actions will be processed in order.
function operate(
AccountInfo[] calldata accounts,
ActionArgs[] calldata actions
)
external;
// @dev Approves/disapproves any number of operators. An operator is an external address that has the
// same permissions to manipulate an account as the owner of the account. Operators are simply
// addresses and therefore may either be externally-owned Ethereum accounts OR smart contracts.
// Operators are also able to act as AutoTrader contracts on behalf of the account owner if the
// operator is a smart contract and implements the IAutoTrader interface.
// @param args A list of OperatorArgs which have an address and a boolean. The boolean value
// denotes whether to approve (true) or revoke approval (false) for that address.
function setOperators(OperatorArg[] calldata args) external;
/// @dev Return true if a particular address is approved as an operator for an owner's accounts.
/// Approved operators can act on the accounts of the owner as if it were the operator's own.
/// @param owner The owner of the accounts
/// @param operator The possible operator
/// @return isLocalOperator True if operator is approved for owner's accounts
function getIsLocalOperator(
address owner,
address operator
)
external
view
returns (bool isLocalOperator);
/// @dev Get the ERC20 token address for a market.
/// @param marketId The market to query
/// @return tokenAddress The token address
function getMarketTokenAddress(
uint256 marketId
)
external
view
returns (address tokenAddress);
/// @dev Get all risk parameters in a single struct.
/// @return riskParams All global risk parameters
function getRiskParams()
external
view
returns (RiskParams memory riskParams);
/// @dev Get the price of the token for a market.
/// @param marketId The market to query
/// @return price The price of each atomic unit of the token
function getMarketPrice(
uint256 marketId
)
external
view
returns (Price memory price);
/// @dev Get the margin premium for a market. A margin premium makes it so that any positions that
/// include the market require a higher collateralization to avoid being liquidated.
/// @param marketId The market to query
/// @return premium The market's margin premium
function getMarketMarginPremium(uint256 marketId)
external
view
returns (D256 memory premium);
/// @dev Get the total supplied and total borrowed values of an account adjusted by the marginPremium
/// of each market. Supplied values are divided by (1 + marginPremium) for each market and
/// borrowed values are multiplied by (1 + marginPremium) for each market. Comparing these
/// adjusted values gives the margin-ratio of the account which will be compared to the global
/// margin-ratio when determining if the account can be liquidated.
/// @param account The account to query
/// @return supplyValue The supplied value of the account (adjusted for marginPremium)
/// @return borrowValue The borrowed value of the account (adjusted for marginPremium)
function getAdjustedAccountValues(
AccountInfo calldata account
)
external
view
returns (Value memory supplyValue, Value memory borrowValue);
}

View File

@@ -1,42 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
interface IDydxBridge {
/// @dev This is the subset of `IDydx.ActionType` that are supported by the bridge.
enum BridgeActionType {
Deposit, // Deposit tokens into dydx account.
Withdraw // Withdraw tokens from dydx account.
}
struct BridgeAction {
BridgeActionType actionType; // Action to run on dydx account.
uint256 accountIdx; // Index in `BridgeData.accountNumbers` for this action.
uint256 marketId; // Market to operate on.
uint256 conversionRateNumerator; // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator).
uint256 conversionRateDenominator; // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator).
}
struct BridgeData {
uint256[] accountNumbers; // Account number used to identify the owner's specific account.
BridgeAction[] actions; // Actions to carry out on the owner's accounts.
}
}

View File

@@ -1,43 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
contract IERC20Bridge {
// @dev Result of a successful bridge call.
bytes4 constant internal BRIDGE_SUCCESS = 0xdc1600f3;
/// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
/// @param tokenAddress The address of the ERC20 token to transfer.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer.
/// @param bridgeData Arbitrary asset data needed by the bridge contract.
/// @return success The magic bytes `0xdc1600f3` if successful.
function bridgeTransferFrom(
address tokenAddress,
address from,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success);
}

View File

@@ -1,38 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
interface IEth2Dai {
/// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
/// @param fromToken The token being sold.
/// @param sellAmount The amount of `fromToken` token being sold.
/// @param toToken The token being bought.
/// @param minFillAmount Minimum amount of `toToken` token to buy.
/// @return fillAmount Amount of `toToken` bought.
function sellAllAmount(
address fromToken,
uint256 sellAmount,
address toToken,
uint256 minFillAmount
)
external
returns (uint256 fillAmount);
}

View File

@@ -1,46 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
interface IKyberNetworkProxy {
/// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens.
/// @param sellTokenAddress Token to sell.
/// @param sellAmount Amount of tokens to sell.
/// @param buyTokenAddress Token to buy.
/// @param recipientAddress Address to send bought tokens to.
/// @param maxBuyTokenAmount A limit on the amount of tokens to buy.
/// @param minConversionRate The minimal conversion rate. If actual rate
/// is lower, trade is canceled.
/// @param walletId The wallet ID to send part of the fees
/// @return boughtAmount Amount of tokens bought.
function trade(
address sellTokenAddress,
uint256 sellAmount,
address buyTokenAddress,
address payable recipientAddress,
uint256 maxBuyTokenAmount,
uint256 minConversionRate,
address walletId
)
external
payable
returns(uint256 boughtAmount);
}

View File

@@ -1,70 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
interface IUniswapExchange {
/// @dev Buys at least `minTokensBought` tokens with ETH and transfer them
/// to `recipient`.
/// @param minTokensBought The minimum number of tokens to buy.
/// @param deadline Time when this order expires.
/// @param recipient Who to transfer the tokens to.
/// @return tokensBought Amount of tokens bought.
function ethToTokenTransferInput(
uint256 minTokensBought,
uint256 deadline,
address recipient
)
external
payable
returns (uint256 tokensBought);
/// @dev Buys at least `minEthBought` ETH with tokens.
/// @param tokensSold Amount of tokens to sell.
/// @param minEthBought The minimum amount of ETH to buy.
/// @param deadline Time when this order expires.
/// @return ethBought Amount of tokens bought.
function tokenToEthSwapInput(
uint256 tokensSold,
uint256 minEthBought,
uint256 deadline
)
external
returns (uint256 ethBought);
/// @dev Buys at least `minTokensBought` tokens with the exchange token
/// and transfer them to `recipient`.
/// @param minTokensBought The minimum number of tokens to buy.
/// @param minEthBought The minimum amount of intermediate ETH to buy.
/// @param deadline Time when this order expires.
/// @param recipient Who to transfer the tokens to.
/// @param toTokenAddress The token being bought.
/// @return tokensBought Amount of tokens bought.
function tokenToTokenTransferInput(
uint256 tokensSold,
uint256 minTokensBought,
uint256 minEthBought,
uint256 deadline,
address recipient,
address toTokenAddress
)
external
returns (uint256 tokensBought);
}

View File

@@ -1,32 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "./IUniswapExchange.sol";
interface IUniswapExchangeFactory {
/// @dev Get the exchange for a token.
/// @param tokenAddress The address of the token contract.
function getExchange(address tokenAddress)
external
view
returns (address);
}

View File

@@ -0,0 +1,40 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.5;
contract LibAssetProxyIds {
// AssetProxy Ids are equiavalent the first 4 bytes of the keccak256 hash of the function signature assigned to each AssetProxy.
// ERC20Token(address)
bytes4 constant public ERC20_PROXY_ID = 0xf47261b0;
// ERC721Token(address,uint256)
bytes4 constant public ERC721_PROXY_ID = 0x02571792;
// ERC1155Assets(address,uint256[],uint256[],bytes)
bytes4 constant public ERC1155_PROXY_ID = 0xa7cb5fb7;
// MultiAsset(uint256[],bytes[])
bytes4 constant public MULTI_ASSET_PROXY_ID = 0x94cfcdd7;
// StaticCall(address,bytes,bytes32)
bytes4 constant public STATIC_CALL_PROXY_ID = 0xc339d10a;
}

View File

@@ -0,0 +1,45 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.5;
import "../interfaces/IAssetProxyDispatcher.sol";
contract MAssetProxyDispatcher is
IAssetProxyDispatcher
{
// Logs registration of new asset proxy
event AssetProxyRegistered(
bytes4 id, // Id of new registered AssetProxy.
address assetProxy // Address of new registered AssetProxy.
);
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
/// @param assetData Byte array encoded for the asset.
/// @param from Address to transfer token from.
/// @param to Address to transfer token to.
/// @param amount Amount of token to transfer.
function dispatchTransferFrom(
bytes memory assetData,
address from,
address to,
uint256 amount
)
internal;
}

View File

@@ -0,0 +1,41 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.5;
import "../interfaces/IAuthorizable.sol";
contract MAuthorizable is
IAuthorizable
{
// Event logged when a new address is authorized.
event AuthorizedAddressAdded(
address indexed target,
address indexed caller
);
// Event logged when a currently authorized address is unauthorized.
event AuthorizedAddressRemoved(
address indexed target,
address indexed caller
);
/// @dev Only authorized addresses can invoke functions with this modifier.
modifier onlyAuthorized { revert(); _; }
}

View File

@@ -1,80 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "../src/bridges/ChaiBridge.sol";
import "@0x/contracts-erc20/contracts/src/ERC20Token.sol";
contract TestChaiDai is
ERC20Token
{
address private constant ALWAYS_REVERT_ADDRESS = address(1);
function draw(
address from,
uint256 amount
)
external
{
if (from == ALWAYS_REVERT_ADDRESS) {
revert();
}
balances[msg.sender] += amount;
}
}
contract TestChaiBridge is
ChaiBridge
{
address public testChaiDai;
address private constant ALWAYS_REVERT_ADDRESS = address(1);
constructor()
public
{
testChaiDai = address(new TestChaiDai());
}
function _getDaiAddress()
internal
view
returns (address)
{
return testChaiDai;
}
function _getChaiAddress()
internal
view
returns (address)
{
return testChaiDai;
}
function _getERC20BridgeProxyAddress()
internal
view
returns (address)
{
return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender;
}
}

View File

@@ -1,246 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "../src/bridges/DydxBridge.sol";
// solhint-disable no-empty-blocks
contract TestDydxBridgeToken {
uint256 private constant INIT_HOLDER_BALANCE = 10 * 10**18; // 10 tokens
mapping (address => uint256) private _balances;
/// @dev Sets initial balance of token holders.
constructor(address[] memory holders)
public
{
for (uint256 i = 0; i != holders.length; ++i) {
_balances[holders[i]] = INIT_HOLDER_BALANCE;
}
_balances[msg.sender] = INIT_HOLDER_BALANCE;
}
/// @dev Basic transferFrom implementation.
function transferFrom(address from, address to, uint256 amount)
external
returns (bool)
{
if (_balances[from] < amount || _balances[to] + amount < _balances[to]) {
return false;
}
_balances[from] -= amount;
_balances[to] += amount;
return true;
}
/// @dev Returns balance of `holder`.
function balanceOf(address holder)
external
view
returns (uint256)
{
return _balances[holder];
}
}
// solhint-disable space-after-comma
contract TestDydxBridge is
IDydx,
DydxBridge
{
address private constant ALWAYS_REVERT_ADDRESS = address(1);
address private _testTokenAddress;
bool private _shouldRevertOnOperate;
event OperateAccount(
address owner,
uint256 number
);
event OperateAction(
ActionType actionType,
uint256 accountIdx,
bool amountSign,
AssetDenomination amountDenomination,
AssetReference amountRef,
uint256 amountValue,
uint256 primaryMarketId,
uint256 secondaryMarketId,
address otherAddress,
uint256 otherAccountId,
bytes data
);
constructor(address[] memory holders)
public
{
// Deploy a test token. This represents the asset being deposited/withdrawn from dydx.
_testTokenAddress = address(new TestDydxBridgeToken(holders));
}
/// @dev Simulates `operate` in dydx contract.
/// Emits events so that arguments can be validated client-side.
function operate(
AccountInfo[] calldata accounts,
ActionArgs[] calldata actions
)
external
{
if (_shouldRevertOnOperate) {
revert("TestDydxBridge/SHOULD_REVERT_ON_OPERATE");
}
for (uint i = 0; i < accounts.length; ++i) {
emit OperateAccount(
accounts[i].owner,
accounts[i].number
);
}
for (uint i = 0; i < actions.length; ++i) {
emit OperateAction(
actions[i].actionType,
actions[i].accountIdx,
actions[i].amount.sign,
actions[i].amount.denomination,
actions[i].amount.ref,
actions[i].amount.value,
actions[i].primaryMarketId,
actions[i].secondaryMarketId,
actions[i].otherAddress,
actions[i].otherAccountIdx,
actions[i].data
);
if (actions[i].actionType == IDydx.ActionType.Withdraw) {
require(
IERC20Token(_testTokenAddress).transferFrom(
address(this),
actions[i].otherAddress,
actions[i].amount.value
),
"TestDydxBridge/WITHDRAW_FAILED"
);
} else if (actions[i].actionType == IDydx.ActionType.Deposit) {
require(
IERC20Token(_testTokenAddress).transferFrom(
actions[i].otherAddress,
address(this),
actions[i].amount.value
),
"TestDydxBridge/DEPOSIT_FAILED"
);
} else {
revert("TestDydxBridge/UNSUPPORTED_ACTION");
}
}
}
/// @dev If `true` then subsequent calls to `operate` will revert.
function setRevertOnOperate(bool shouldRevert)
external
{
_shouldRevertOnOperate = shouldRevert;
}
/// @dev Returns test token.
function getTestToken()
external
returns (address)
{
return _testTokenAddress;
}
/// @dev Unused.
function setOperators(OperatorArg[] calldata args) external {}
/// @dev Unused.
function getIsLocalOperator(
address owner,
address operator
)
external
view
returns (bool isLocalOperator)
{}
/// @dev Unused.
function getMarketTokenAddress(
uint256 marketId
)
external
view
returns (address tokenAddress)
{}
/// @dev Unused.
function getRiskParams()
external
view
returns (RiskParams memory riskParams)
{}
/// @dev Unsused.
function getMarketPrice(
uint256 marketId
)
external
view
returns (Price memory price)
{}
/// @dev Unsused
function getMarketMarginPremium(uint256 marketId)
external
view
returns (IDydx.D256 memory premium)
{}
/// @dev Unused.
function getAdjustedAccountValues(
AccountInfo calldata account
)
external
view
returns (Value memory supplyValue, Value memory borrowValue)
{}
/// @dev overrides `_getDydxAddress()` from `DeploymentConstants` to return this address.
function _getDydxAddress()
internal
view
returns (address)
{
return address(this);
}
/// @dev overrides `_getERC20BridgeProxyAddress()` from `DeploymentConstants` for testing.
function _getERC20BridgeProxyAddress()
internal
view
returns (address)
{
return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender;
}
}

View File

@@ -1,108 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "../src/interfaces/IERC20Bridge.sol";
/// @dev Test bridge token
contract TestERC20BridgeToken {
mapping (address => uint256) private _balances;
function addBalance(address owner, int256 amount)
external
{
setBalance(owner, uint256(int256(balanceOf(owner)) + amount));
}
function setBalance(address owner, uint256 balance)
public
{
_balances[owner] = balance;
}
function balanceOf(address owner)
public
view
returns (uint256)
{
return _balances[owner];
}
}
/// @dev Test bridge contract.
contract TestERC20Bridge is
IERC20Bridge
{
TestERC20BridgeToken public testToken;
event BridgeWithdrawTo(
address tokenAddress,
address from,
address to,
uint256 amount,
bytes bridgeData
);
constructor() public {
testToken = new TestERC20BridgeToken();
}
function setTestTokenBalance(address owner, uint256 balance)
external
{
testToken.setBalance(owner, balance);
}
function bridgeTransferFrom(
address tokenAddress,
address from,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4)
{
emit BridgeWithdrawTo(
tokenAddress,
from,
to,
amount,
bridgeData
);
// Unpack the bridgeData.
(
int256 transferAmount,
bytes memory revertData,
bytes memory returnData
) = abi.decode(bridgeData, (int256, bytes, bytes));
// If `revertData` is set, revert.
if (revertData.length != 0) {
assembly { revert(add(revertData, 0x20), mload(revertData)) }
}
// Increase `to`'s balance by `transferAmount`.
TestERC20BridgeToken(tokenAddress).addBalance(to, transferAmount);
// Return `returnData`.
assembly { return(add(returnData, 0x20), mload(returnData)) }
}
}

View File

@@ -1,202 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "../src/bridges/Eth2DaiBridge.sol";
import "../src/interfaces/IEth2Dai.sol";
// solhint-disable no-simple-event-func-name
contract TestEvents {
event TokenTransfer(
address token,
address from,
address to,
uint256 amount
);
event TokenApprove(
address token,
address spender,
uint256 allowance
);
function raiseTokenTransfer(
address from,
address to,
uint256 amount
)
external
{
emit TokenTransfer(
msg.sender,
from,
to,
amount
);
}
function raiseTokenApprove(address spender, uint256 allowance)
external
{
emit TokenApprove(msg.sender, spender, allowance);
}
}
/// @dev A minimalist ERC20 token.
contract TestToken {
mapping (address => uint256) public balances;
string private _nextTransferRevertReason;
bytes private _nextTransferReturnData;
/// @dev Just calls `raiseTokenTransfer()` on the caller.
function transfer(address to, uint256 amount)
external
returns (bool)
{
TestEvents(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
if (bytes(_nextTransferRevertReason).length != 0) {
revert(_nextTransferRevertReason);
}
bytes memory returnData = _nextTransferReturnData;
assembly { return(add(returnData, 0x20), mload(returnData)) }
}
/// @dev Set the balance for `owner`.
function setBalance(address owner, uint256 balance)
external
{
balances[owner] = balance;
}
/// @dev Set the behavior of the `transfer()` call.
function setTransferBehavior(
string calldata revertReason,
bytes calldata returnData
)
external
{
_nextTransferRevertReason = revertReason;
_nextTransferReturnData = returnData;
}
/// @dev Just calls `raiseTokenApprove()` on the caller.
function approve(address spender, uint256 allowance)
external
returns (bool)
{
TestEvents(msg.sender).raiseTokenApprove(spender, allowance);
return true;
}
/// @dev Retrieve the balance for `owner`.
function balanceOf(address owner)
external
view
returns (uint256)
{
return balances[owner];
}
}
/// @dev Eth2DaiBridge overridden to mock tokens and
/// implement IEth2Dai.
contract TestEth2DaiBridge is
TestEvents,
IEth2Dai,
Eth2DaiBridge
{
event SellAllAmount(
address sellToken,
uint256 sellTokenAmount,
address buyToken,
uint256 minimumFillAmount
);
mapping (address => TestToken) public testTokens;
string private _nextRevertReason;
uint256 private _nextFillAmount;
/// @dev Create a token and set this contract's balance.
function createToken(uint256 balance)
external
returns (address tokenAddress)
{
TestToken token = new TestToken();
testTokens[address(token)] = token;
token.setBalance(address(this), balance);
return address(token);
}
/// @dev Set the behavior for `IEth2Dai.sellAllAmount()`.
function setFillBehavior(string calldata revertReason, uint256 fillAmount)
external
{
_nextRevertReason = revertReason;
_nextFillAmount = fillAmount;
}
/// @dev Set the behavior of a token's `transfer()`.
function setTransferBehavior(
address tokenAddress,
string calldata revertReason,
bytes calldata returnData
)
external
{
testTokens[tokenAddress].setTransferBehavior(revertReason, returnData);
}
/// @dev Implementation of `IEth2Dai.sellAllAmount()`
function sellAllAmount(
address sellTokenAddress,
uint256 sellTokenAmount,
address buyTokenAddress,
uint256 minimumFillAmount
)
external
returns (uint256 fillAmount)
{
emit SellAllAmount(
sellTokenAddress,
sellTokenAmount,
buyTokenAddress,
minimumFillAmount
);
if (bytes(_nextRevertReason).length != 0) {
revert(_nextRevertReason);
}
return _nextFillAmount;
}
// @dev This contract will double as the Eth2Dai contract.
function _getEth2DaiAddress()
internal
view
returns (address)
{
return address(this);
}
}

View File

@@ -1,324 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "../src/bridges/KyberBridge.sol";
import "../src/interfaces/IKyberNetworkProxy.sol";
// solhint-disable no-simple-event-func-name
interface ITestContract {
function wethWithdraw(
address payable ownerAddress,
uint256 amount
)
external;
function wethDeposit(
address ownerAddress
)
external
payable;
function tokenTransfer(
address ownerAddress,
address recipientAddress,
uint256 amount
)
external
returns (bool success);
function tokenApprove(
address ownerAddress,
address spenderAddress,
uint256 allowance
)
external
returns (bool success);
function tokenBalanceOf(
address ownerAddress
)
external
view
returns (uint256 balance);
}
/// @dev A minimalist ERC20/WETH token.
contract TestToken {
uint8 public decimals;
ITestContract private _testContract;
constructor(uint8 decimals_) public {
decimals = decimals_;
_testContract = ITestContract(msg.sender);
}
function approve(address spender, uint256 allowance)
external
returns (bool)
{
return _testContract.tokenApprove(
msg.sender,
spender,
allowance
);
}
function transfer(address recipient, uint256 amount)
external
returns (bool)
{
return _testContract.tokenTransfer(
msg.sender,
recipient,
amount
);
}
function withdraw(uint256 amount)
external
{
return _testContract.wethWithdraw(msg.sender, amount);
}
function deposit()
external
payable
{
return _testContract.wethDeposit.value(msg.value)(msg.sender);
}
function balanceOf(address owner)
external
view
returns (uint256)
{
return _testContract.tokenBalanceOf(owner);
}
}
/// @dev KyberBridge overridden to mock tokens and implement IKyberBridge.
contract TestKyberBridge is
KyberBridge,
ITestContract,
IKyberNetworkProxy
{
event KyberBridgeTrade(
uint256 msgValue,
address sellTokenAddress,
uint256 sellAmount,
address buyTokenAddress,
address payable recipientAddress,
uint256 maxBuyTokenAmount,
uint256 minConversionRate,
address walletId
);
event KyberBridgeWethWithdraw(
address ownerAddress,
uint256 amount
);
event KyberBridgeWethDeposit(
uint256 msgValue,
address ownerAddress,
uint256 amount
);
event KyberBridgeTokenApprove(
address tokenAddress,
address ownerAddress,
address spenderAddress,
uint256 allowance
);
event KyberBridgeTokenTransfer(
address tokenAddress,
address ownerAddress,
address recipientAddress,
uint256 amount
);
IEtherToken public weth;
mapping (address => mapping (address => uint256)) private _tokenBalances;
uint256 private _nextFillAmount;
constructor() public {
weth = IEtherToken(address(new TestToken(18)));
}
/// @dev Implementation of `IKyberNetworkProxy.trade()`
function trade(
address sellTokenAddress,
uint256 sellAmount,
address buyTokenAddress,
address payable recipientAddress,
uint256 maxBuyTokenAmount,
uint256 minConversionRate,
address walletId
)
external
payable
returns(uint256 boughtAmount)
{
emit KyberBridgeTrade(
msg.value,
sellTokenAddress,
sellAmount,
buyTokenAddress,
recipientAddress,
maxBuyTokenAmount,
minConversionRate,
walletId
);
return _nextFillAmount;
}
function createToken(uint8 decimals)
external
returns (address tokenAddress)
{
return address(new TestToken(decimals));
}
function setNextFillAmount(uint256 amount)
external
payable
{
if (msg.value != 0) {
require(amount == msg.value, "VALUE_AMOUNT_MISMATCH");
grantTokensTo(address(weth), address(this), msg.value);
}
_nextFillAmount = amount;
}
function wethDeposit(
address ownerAddress
)
external
payable
{
require(msg.sender == address(weth), "ONLY_WETH");
grantTokensTo(address(weth), ownerAddress, msg.value);
emit KyberBridgeWethDeposit(
msg.value,
ownerAddress,
msg.value
);
}
function wethWithdraw(
address payable ownerAddress,
uint256 amount
)
external
{
require(msg.sender == address(weth), "ONLY_WETH");
_tokenBalances[address(weth)][ownerAddress] -= amount;
ownerAddress.transfer(amount);
emit KyberBridgeWethWithdraw(
ownerAddress,
amount
);
}
function tokenApprove(
address ownerAddress,
address spenderAddress,
uint256 allowance
)
external
returns (bool success)
{
emit KyberBridgeTokenApprove(
msg.sender,
ownerAddress,
spenderAddress,
allowance
);
return true;
}
function tokenTransfer(
address ownerAddress,
address recipientAddress,
uint256 amount
)
external
returns (bool success)
{
_tokenBalances[msg.sender][ownerAddress] -= amount;
_tokenBalances[msg.sender][recipientAddress] += amount;
emit KyberBridgeTokenTransfer(
msg.sender,
ownerAddress,
recipientAddress,
amount
);
return true;
}
function tokenBalanceOf(
address ownerAddress
)
external
view
returns (uint256 balance)
{
return _tokenBalances[msg.sender][ownerAddress];
}
function grantTokensTo(address tokenAddress, address ownerAddress, uint256 amount)
public
payable
{
_tokenBalances[tokenAddress][ownerAddress] += amount;
if (tokenAddress != address(weth)) {
// Send back ether if not WETH.
msg.sender.transfer(msg.value);
} else {
require(msg.value == amount, "VALUE_AMOUNT_MISMATCH");
}
}
// @dev overridden to point to this contract.
function _getKyberNetworkProxyAddress()
internal
view
returns (address)
{
return address(this);
}
// @dev overridden to point to test WETH.
function _getWethAddress()
internal
view
returns (address)
{
return address(weth);
}
}

View File

@@ -1,6 +1,6 @@
/*
Copyright 2019 ZeroEx Intl.
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,432 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "../src/bridges/UniswapBridge.sol";
import "../src/interfaces/IUniswapExchangeFactory.sol";
import "../src/interfaces/IUniswapExchange.sol";
// solhint-disable no-simple-event-func-name
contract TestEventsRaiser {
event TokenTransfer(
address token,
address from,
address to,
uint256 amount
);
event TokenApprove(
address spender,
uint256 allowance
);
event WethDeposit(
uint256 amount
);
event WethWithdraw(
uint256 amount
);
event EthToTokenTransferInput(
address exchange,
uint256 minTokensBought,
uint256 deadline,
address recipient
);
event TokenToEthSwapInput(
address exchange,
uint256 tokensSold,
uint256 minEthBought,
uint256 deadline
);
event TokenToTokenTransferInput(
address exchange,
uint256 tokensSold,
uint256 minTokensBought,
uint256 minEthBought,
uint256 deadline,
address recipient,
address toTokenAddress
);
function raiseEthToTokenTransferInput(
uint256 minTokensBought,
uint256 deadline,
address recipient
)
external
{
emit EthToTokenTransferInput(
msg.sender,
minTokensBought,
deadline,
recipient
);
}
function raiseTokenToEthSwapInput(
uint256 tokensSold,
uint256 minEthBought,
uint256 deadline
)
external
{
emit TokenToEthSwapInput(
msg.sender,
tokensSold,
minEthBought,
deadline
);
}
function raiseTokenToTokenTransferInput(
uint256 tokensSold,
uint256 minTokensBought,
uint256 minEthBought,
uint256 deadline,
address recipient,
address toTokenAddress
)
external
{
emit TokenToTokenTransferInput(
msg.sender,
tokensSold,
minTokensBought,
minEthBought,
deadline,
recipient,
toTokenAddress
);
}
function raiseTokenTransfer(
address from,
address to,
uint256 amount
)
external
{
emit TokenTransfer(
msg.sender,
from,
to,
amount
);
}
function raiseTokenApprove(address spender, uint256 allowance)
external
{
emit TokenApprove(spender, allowance);
}
function raiseWethDeposit(uint256 amount)
external
{
emit WethDeposit(amount);
}
function raiseWethWithdraw(uint256 amount)
external
{
emit WethWithdraw(amount);
}
}
/// @dev A minimalist ERC20/WETH token.
contract TestToken {
using LibSafeMath for uint256;
mapping (address => uint256) public balances;
string private _nextRevertReason;
/// @dev Set the balance for `owner`.
function setBalance(address owner)
external
payable
{
balances[owner] = msg.value;
}
/// @dev Set the revert reason for `transfer()`,
/// `deposit()`, and `withdraw()`.
function setRevertReason(string calldata reason)
external
{
_nextRevertReason = reason;
}
/// @dev Just calls `raiseTokenTransfer()` on the caller.
function transfer(address to, uint256 amount)
external
returns (bool)
{
_revertIfReasonExists();
TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
return true;
}
/// @dev Just calls `raiseTokenApprove()` on the caller.
function approve(address spender, uint256 allowance)
external
returns (bool)
{
TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance);
return true;
}
/// @dev `IWETH.deposit()` that increases balances and calls
/// `raiseWethDeposit()` on the caller.
function deposit()
external
payable
{
_revertIfReasonExists();
balances[msg.sender] += balances[msg.sender].safeAdd(msg.value);
TestEventsRaiser(msg.sender).raiseWethDeposit(msg.value);
}
/// @dev `IWETH.withdraw()` that just reduces balances and calls
/// `raiseWethWithdraw()` on the caller.
function withdraw(uint256 amount)
external
{
_revertIfReasonExists();
balances[msg.sender] = balances[msg.sender].safeSub(amount);
msg.sender.transfer(amount);
TestEventsRaiser(msg.sender).raiseWethWithdraw(amount);
}
/// @dev Retrieve the balance for `owner`.
function balanceOf(address owner)
external
view
returns (uint256)
{
return balances[owner];
}
function _revertIfReasonExists()
private
view
{
if (bytes(_nextRevertReason).length != 0) {
revert(_nextRevertReason);
}
}
}
contract TestExchange is
IUniswapExchange
{
address public tokenAddress;
string private _nextRevertReason;
constructor(address _tokenAddress) public {
tokenAddress = _tokenAddress;
}
function setFillBehavior(
string calldata revertReason
)
external
payable
{
_nextRevertReason = revertReason;
}
function ethToTokenTransferInput(
uint256 minTokensBought,
uint256 deadline,
address recipient
)
external
payable
returns (uint256 tokensBought)
{
TestEventsRaiser(msg.sender).raiseEthToTokenTransferInput(
minTokensBought,
deadline,
recipient
);
_revertIfReasonExists();
return address(this).balance;
}
function tokenToEthSwapInput(
uint256 tokensSold,
uint256 minEthBought,
uint256 deadline
)
external
returns (uint256 ethBought)
{
TestEventsRaiser(msg.sender).raiseTokenToEthSwapInput(
tokensSold,
minEthBought,
deadline
);
_revertIfReasonExists();
uint256 fillAmount = address(this).balance;
msg.sender.transfer(fillAmount);
return fillAmount;
}
function tokenToTokenTransferInput(
uint256 tokensSold,
uint256 minTokensBought,
uint256 minEthBought,
uint256 deadline,
address recipient,
address toTokenAddress
)
external
returns (uint256 tokensBought)
{
TestEventsRaiser(msg.sender).raiseTokenToTokenTransferInput(
tokensSold,
minTokensBought,
minEthBought,
deadline,
recipient,
toTokenAddress
);
_revertIfReasonExists();
return address(this).balance;
}
function toTokenAddress()
external
view
returns (address _tokenAddress)
{
return tokenAddress;
}
function _revertIfReasonExists()
private
view
{
if (bytes(_nextRevertReason).length != 0) {
revert(_nextRevertReason);
}
}
}
/// @dev UniswapBridge overridden to mock tokens and implement IUniswapExchangeFactory.
contract TestUniswapBridge is
IUniswapExchangeFactory,
TestEventsRaiser,
UniswapBridge
{
TestToken public wethToken;
// Token address to TestToken instance.
mapping (address => TestToken) private _testTokens;
// Token address to TestExchange instance.
mapping (address => TestExchange) private _testExchanges;
constructor() public {
wethToken = new TestToken();
_testTokens[address(wethToken)] = wethToken;
}
/// @dev Sets the balance of this contract for an existing token.
/// The wei attached will be the balance.
function setTokenBalance(address tokenAddress)
external
payable
{
TestToken token = _testTokens[tokenAddress];
token.deposit.value(msg.value)();
}
/// @dev Sets the revert reason for an existing token.
function setTokenRevertReason(address tokenAddress, string calldata revertReason)
external
{
TestToken token = _testTokens[tokenAddress];
token.setRevertReason(revertReason);
}
/// @dev Create a token and exchange (if they don't exist) for a new token
/// and sets the exchange revert and fill behavior. The wei attached
/// will be the fill amount for the exchange.
/// @param tokenAddress The token address. If zero, one will be created.
/// @param revertReason The revert reason for exchange operations.
function createTokenAndExchange(
address tokenAddress,
string calldata revertReason
)
external
payable
returns (TestToken token, TestExchange exchange)
{
token = TestToken(tokenAddress);
if (tokenAddress == address(0)) {
token = new TestToken();
}
_testTokens[address(token)] = token;
exchange = _testExchanges[address(token)];
if (address(exchange) == address(0)) {
_testExchanges[address(token)] = exchange = new TestExchange(address(token));
}
exchange.setFillBehavior.value(msg.value)(revertReason);
return (token, exchange);
}
/// @dev `IUniswapExchangeFactory.getExchange`
function getExchange(address tokenAddress)
external
view
returns (address)
{
return address(_testExchanges[tokenAddress]);
}
// @dev Use `wethToken`.
function _getWethAddress()
internal
view
returns (address)
{
return address(wethToken);
}
// @dev This contract will double as the Uniswap contract.
function _getUniswapExchangeFactoryAddress()
internal
view
returns (address)
{
return address(this);
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-asset-proxy",
"version": "3.2.4",
"version": "2.2.6",
"engines": {
"node": ">=6.12"
},
@@ -12,7 +12,7 @@
"scripts": {
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
"pre_build": "run-s compile generate_contract_wrappers",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
@@ -21,24 +21,20 @@
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
"compile": "sol-compiler",
"watch": "sol-compiler -w",
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"clean": "shx rm -rf lib generated-artifacts 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 generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"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",
"coverage:report:lcov": "istanbul report lcov",
"test:circleci": "yarn test",
"contracts:gen": "contracts-gen generate",
"contracts:copy": "contracts-gen copy",
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
"compile:truffle": "truffle compile",
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
"contracts:gen": "contracts-gen",
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
},
"config": {
"abis": "./test/generated-artifacts/@(ChaiBridge|CurveBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
"abis": "./generated-artifacts/@(ERC1155Proxy|ERC20Proxy|ERC721Proxy|IAssetData|IAssetProxy|IAuthorizable|MixinAuthorizable|MultiAssetProxy|StaticCallProxy|TestStaticCallTarget).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
},
"repository": {
@@ -51,14 +47,12 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.2.2",
"@0x/contracts-gen": "^2.0.8",
"@0x/contracts-test-utils": "^5.3.1",
"@0x/contracts-utils": "^4.4.2",
"@0x/dev-utils": "^3.2.1",
"@0x/sol-compiler": "^4.0.8",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/abi-gen": "^4.1.1",
"@0x/contracts-gen": "^1.0.13",
"@0x/contracts-test-utils": "^3.1.14",
"@0x/dev-utils": "^2.3.1",
"@0x/sol-compiler": "^3.1.13",
"@0x/tslint-config": "^3.0.1",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -66,29 +60,27 @@
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^3.0.0",
"dirty-chai": "^2.0.1",
"ethereumjs-util": "^5.1.1",
"make-promises-safe": "^1.1.0",
"mocha": "^6.2.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"solhint": "^1.4.1",
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "^0.15.0",
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.2.1",
"@0x/contracts-erc1155": "^2.1.4",
"@0x/contracts-erc20": "^3.1.4",
"@0x/contracts-erc721": "^3.1.4",
"@0x/contracts-exchange-libs": "^4.3.4",
"@0x/order-utils": "^10.2.3",
"@0x/types": "^3.1.2",
"@0x/typescript-typings": "^5.0.2",
"@0x/utils": "^5.4.1",
"@0x/web3-wrapper": "^7.0.7",
"ethereum-types": "^3.1.0",
"@0x/base-contract": "^5.3.2",
"@0x/contracts-erc1155": "^1.1.13",
"@0x/contracts-erc20": "^2.2.12",
"@0x/contracts-erc721": "^2.1.13",
"@0x/contracts-utils": "^3.2.2",
"@0x/order-utils": "^8.3.0",
"@0x/types": "^2.4.1",
"@0x/typescript-typings": "^4.2.4",
"@0x/utils": "^4.5.0",
"@0x/web3-wrapper": "^6.0.11",
"ethereum-types": "^2.1.4",
"ethereumjs-util": "^5.1.1",
"lodash": "^4.17.11"
},
"publishConfig": {

View File

@@ -5,75 +5,25 @@
*/
import { ContractArtifact } from 'ethereum-types';
import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json';
import * as CurveBridge from '../generated-artifacts/CurveBridge.json';
import * as DydxBridge from '../generated-artifacts/DydxBridge.json';
import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json';
import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json';
import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json';
import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json';
import * as Eth2DaiBridge from '../generated-artifacts/Eth2DaiBridge.json';
import * as IAssetData from '../generated-artifacts/IAssetData.json';
import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json';
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
import * as IChai from '../generated-artifacts/IChai.json';
import * as ICurve from '../generated-artifacts/ICurve.json';
import * as IDydx from '../generated-artifacts/IDydx.json';
import * as IDydxBridge from '../generated-artifacts/IDydxBridge.json';
import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json';
import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json';
import * as IKyberNetworkProxy from '../generated-artifacts/IKyberNetworkProxy.json';
import * as IUniswapExchange from '../generated-artifacts/IUniswapExchange.json';
import * as IUniswapExchangeFactory from '../generated-artifacts/IUniswapExchangeFactory.json';
import * as KyberBridge from '../generated-artifacts/KyberBridge.json';
import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json';
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
import * as Ownable from '../generated-artifacts/Ownable.json';
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
import * as TestChaiBridge from '../generated-artifacts/TestChaiBridge.json';
import * as TestDydxBridge from '../generated-artifacts/TestDydxBridge.json';
import * as TestERC20Bridge from '../generated-artifacts/TestERC20Bridge.json';
import * as TestEth2DaiBridge from '../generated-artifacts/TestEth2DaiBridge.json';
import * as TestKyberBridge from '../generated-artifacts/TestKyberBridge.json';
import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json';
import * as TestUniswapBridge from '../generated-artifacts/TestUniswapBridge.json';
import * as UniswapBridge from '../generated-artifacts/UniswapBridge.json';
export const artifacts = {
MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact,
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
Ownable: Ownable as ContractArtifact,
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact,
ERC20Proxy: ERC20Proxy as ContractArtifact,
ERC721Proxy: ERC721Proxy as ContractArtifact,
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
StaticCallProxy: StaticCallProxy as ContractArtifact,
ChaiBridge: ChaiBridge as ContractArtifact,
CurveBridge: CurveBridge as ContractArtifact,
DydxBridge: DydxBridge as ContractArtifact,
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
KyberBridge: KyberBridge as ContractArtifact,
UniswapBridge: UniswapBridge as ContractArtifact,
IAssetData: IAssetData as ContractArtifact,
IAssetProxy: IAssetProxy as ContractArtifact,
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
IAuthorizable: IAuthorizable as ContractArtifact,
IChai: IChai as ContractArtifact,
ICurve: ICurve as ContractArtifact,
IDydx: IDydx as ContractArtifact,
IDydxBridge: IDydxBridge as ContractArtifact,
IERC20Bridge: IERC20Bridge as ContractArtifact,
IEth2Dai: IEth2Dai as ContractArtifact,
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
IUniswapExchange: IUniswapExchange as ContractArtifact,
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
TestChaiBridge: TestChaiBridge as ContractArtifact,
TestDydxBridge: TestDydxBridge as ContractArtifact,
TestERC20Bridge: TestERC20Bridge as ContractArtifact,
TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact,
TestKyberBridge: TestKyberBridge as ContractArtifact,
TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
TestUniswapBridge: TestUniswapBridge as ContractArtifact,
};

View File

@@ -1,112 +0,0 @@
import { AssetProxyId } from '@0x/types';
import { BigNumber, hexUtils } from '@0x/utils';
import { IAssetDataContract } from './wrappers';
const assetDataIface = new IAssetDataContract('0x0000000000000000000000000000000000000000', { isEIP1193: true } as any);
/**
* Get the proxy ID from encoded asset data.
*/
export function getAssetDataProxyId(encoded: string): AssetProxyId {
// tslint:disable-next-line: no-unnecessary-type-assertion
return hexUtils.slice(encoded, 0, 4) as AssetProxyId;
}
/**
* Decode ERC20 asset data.
*/
export function decodeERC20AssetData(encoded: string): string {
return assetDataIface.getABIDecodedTransactionData<string>('ERC20Token', encoded);
}
/**
* Decode ERC721 asset data.
*/
export function decodeERC721AssetData(encoded: string): [string, BigNumber] {
return assetDataIface.getABIDecodedTransactionData<[string, BigNumber]>('ERC721Token', encoded);
}
/**
* Decode ERC1155 asset data.
*/
export function decodeERC1155AssetData(encoded: string): [string, BigNumber[], BigNumber[], string] {
return assetDataIface.getABIDecodedTransactionData<[string, BigNumber[], BigNumber[], string]>(
'ERC1155Assets',
encoded,
);
}
/**
* Decode MultiAsset asset data.
*/
export function decodeMultiAssetData(encoded: string): [BigNumber[], string[]] {
return assetDataIface.getABIDecodedTransactionData<[BigNumber[], string[]]>('MultiAsset', encoded);
}
/**
* Decode StaticCall asset data.
*/
export function decodeStaticCallAssetData(encoded: string): [string, string, string] {
return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('StaticCall', encoded);
}
/**
* Decode ERC20Bridge asset data.
*/
export function decodeERC20BridgeAssetData(encoded: string): [string, string, string] {
return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('ERC20Bridge', encoded);
}
/**
* Encode ERC20 asset data.
*/
export function encodeERC20AssetData(tokenAddress: string): string {
return assetDataIface.ERC20Token(tokenAddress).getABIEncodedTransactionData();
}
/**
* Encode ERC721 asset data.
*/
export function encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string {
return assetDataIface.ERC721Token(tokenAddress, tokenId).getABIEncodedTransactionData();
}
/**
* Encode ERC1155 asset data.
*/
export function encodeERC1155AssetData(
tokenAddress: string,
tokenIds: BigNumber[],
values: BigNumber[],
callbackData: string,
): string {
return assetDataIface.ERC1155Assets(tokenAddress, tokenIds, values, callbackData).getABIEncodedTransactionData();
}
/**
* Encode MultiAsset asset data.
*/
export function encodeMultiAssetData(values: BigNumber[], nestedAssetData: string[]): string {
return assetDataIface.MultiAsset(values, nestedAssetData).getABIEncodedTransactionData();
}
/**
* Encode StaticCall asset data.
*/
export function encodeStaticCallAssetData(
staticCallTargetAddress: string,
staticCallData: string,
expectedReturnDataHash: string,
): string {
return assetDataIface
.StaticCall(staticCallTargetAddress, staticCallData, expectedReturnDataHash)
.getABIEncodedTransactionData();
}
/**
* Encode ERC20Bridge asset data.
*/
export function encodeERC20BridgeAssetData(tokenAddress: string, bridgeAddress: string, bridgeData: string): string {
return assetDataIface.ERC20Bridge(tokenAddress, bridgeAddress, bridgeData).getABIEncodedTransactionData();
}

View File

@@ -1,40 +0,0 @@
import { AbiEncoder, BigNumber } from '@0x/utils';
export enum DydxBridgeActionType {
Deposit,
Withdraw,
}
export interface DydxBridgeAction {
actionType: DydxBridgeActionType;
accountIdx: BigNumber;
marketId: BigNumber;
conversionRateNumerator: BigNumber;
conversionRateDenominator: BigNumber;
}
export interface DydxBridgeData {
accountNumbers: BigNumber[];
actions: DydxBridgeAction[];
}
export const dydxBridgeDataEncoder = AbiEncoder.create([
{
name: 'bridgeData',
type: 'tuple',
components: [
{ name: 'accountNumbers', type: 'uint256[]' },
{
name: 'actions',
type: 'tuple[]',
components: [
{ name: 'actionType', type: 'uint8' },
{ name: 'accountIdx', type: 'uint256' },
{ name: 'marketId', type: 'uint256' },
{ name: 'conversionRateNumerator', type: 'uint256' },
{ name: 'conversionRateDenominator', type: 'uint256' },
],
},
],
},
]);

View File

@@ -1,90 +1,3 @@
export { artifacts } from './artifacts';
export {
ChaiBridgeContract,
ERC1155ProxyContract,
ERC20BridgeProxyContract,
ERC20ProxyContract,
ERC721ProxyContract,
Eth2DaiBridgeContract,
DydxBridgeContract,
IAssetDataContract,
IAssetProxyContract,
IChaiContract,
IDydxContract,
KyberBridgeContract,
MultiAssetProxyContract,
StaticCallProxyContract,
TestDydxBridgeContract,
TestStaticCallTargetContract,
UniswapBridgeContract,
} from './wrappers';
export { ERC20Wrapper } from './erc20_wrapper';
export { ERC721Wrapper } from './erc721_wrapper';
export { ERC1155ProxyWrapper } from './erc1155_proxy_wrapper';
export { ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155';
export { DummyERC20TokenContract } from '@0x/contracts-erc20';
export { DummyERC721TokenContract } from '@0x/contracts-erc721';
export { AssetProxyId } from '@0x/types';
export {
ERC1155HoldingsByOwner,
ERC20BalancesByOwner,
ERC721TokenIdsByOwner,
ERC1155FungibleHoldingsByOwner,
ERC1155NonFungibleHoldingsByOwner,
} from '@0x/contracts-test-utils';
export {
TransactionReceiptWithDecodedLogs,
Provider,
ZeroExProvider,
JSONRPCRequestPayload,
JSONRPCErrorCallback,
TransactionReceiptStatus,
JSONRPCResponsePayload,
JSONRPCResponseError,
ContractArtifact,
ContractChains,
CompilerOpts,
StandardContractOutput,
CompilerSettings,
ContractChainData,
ContractAbi,
DevdocOutput,
EvmOutput,
CompilerSettingsMetadata,
OptimizerSettings,
OutputField,
ParamDescription,
EvmBytecodeOutput,
EvmBytecodeOutputLinkReferences,
AbiDefinition,
FunctionAbi,
EventAbi,
RevertErrorAbi,
EventParameter,
DataItem,
MethodAbi,
ConstructorAbi,
FallbackAbi,
ConstructorStateMutability,
TupleDataItem,
StateMutability,
} from 'ethereum-types';
export {
decodeERC1155AssetData,
decodeERC20AssetData,
decodeERC20BridgeAssetData,
decodeERC721AssetData,
decodeMultiAssetData,
decodeStaticCallAssetData,
encodeERC1155AssetData,
encodeERC20AssetData,
encodeERC20BridgeAssetData,
encodeERC721AssetData,
encodeMultiAssetData,
encodeStaticCallAssetData,
getAssetDataProxyId,
} from './asset_data';
export * from './dydx_bridge_encoder';
export * from './artifacts';
export * from './wrappers';
export * from '../test/utils';

View File

@@ -3,38 +3,13 @@
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../generated-wrappers/chai_bridge';
export * from '../generated-wrappers/curve_bridge';
export * from '../generated-wrappers/dydx_bridge';
export * from '../generated-wrappers/erc1155_proxy';
export * from '../generated-wrappers/erc20_bridge_proxy';
export * from '../generated-wrappers/erc20_proxy';
export * from '../generated-wrappers/erc721_proxy';
export * from '../generated-wrappers/eth2_dai_bridge';
export * from '../generated-wrappers/i_asset_data';
export * from '../generated-wrappers/i_asset_proxy';
export * from '../generated-wrappers/i_asset_proxy_dispatcher';
export * from '../generated-wrappers/i_authorizable';
export * from '../generated-wrappers/i_chai';
export * from '../generated-wrappers/i_curve';
export * from '../generated-wrappers/i_dydx';
export * from '../generated-wrappers/i_dydx_bridge';
export * from '../generated-wrappers/i_erc20_bridge';
export * from '../generated-wrappers/i_eth2_dai';
export * from '../generated-wrappers/i_kyber_network_proxy';
export * from '../generated-wrappers/i_uniswap_exchange';
export * from '../generated-wrappers/i_uniswap_exchange_factory';
export * from '../generated-wrappers/kyber_bridge';
export * from '../generated-wrappers/mixin_asset_proxy_dispatcher';
export * from '../generated-wrappers/mixin_authorizable';
export * from '../generated-wrappers/multi_asset_proxy';
export * from '../generated-wrappers/ownable';
export * from '../generated-wrappers/static_call_proxy';
export * from '../generated-wrappers/test_chai_bridge';
export * from '../generated-wrappers/test_dydx_bridge';
export * from '../generated-wrappers/test_erc20_bridge';
export * from '../generated-wrappers/test_eth2_dai_bridge';
export * from '../generated-wrappers/test_kyber_bridge';
export * from '../generated-wrappers/test_static_call_target';
export * from '../generated-wrappers/test_uniswap_bridge';
export * from '../generated-wrappers/uniswap_bridge';

View File

@@ -1,79 +0,0 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
import { ContractArtifact } from 'ethereum-types';
import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json';
import * as CurveBridge from '../test/generated-artifacts/CurveBridge.json';
import * as DydxBridge from '../test/generated-artifacts/DydxBridge.json';
import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json';
import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json';
import * as ERC20Proxy from '../test/generated-artifacts/ERC20Proxy.json';
import * as ERC721Proxy from '../test/generated-artifacts/ERC721Proxy.json';
import * as Eth2DaiBridge from '../test/generated-artifacts/Eth2DaiBridge.json';
import * as IAssetData from '../test/generated-artifacts/IAssetData.json';
import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json';
import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json';
import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json';
import * as IChai from '../test/generated-artifacts/IChai.json';
import * as ICurve from '../test/generated-artifacts/ICurve.json';
import * as IDydx from '../test/generated-artifacts/IDydx.json';
import * as IDydxBridge from '../test/generated-artifacts/IDydxBridge.json';
import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json';
import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json';
import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json';
import * as KyberBridge from '../test/generated-artifacts/KyberBridge.json';
import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json';
import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json';
import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json';
import * as Ownable from '../test/generated-artifacts/Ownable.json';
import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json';
import * as TestChaiBridge from '../test/generated-artifacts/TestChaiBridge.json';
import * as TestDydxBridge from '../test/generated-artifacts/TestDydxBridge.json';
import * as TestERC20Bridge from '../test/generated-artifacts/TestERC20Bridge.json';
import * as TestEth2DaiBridge from '../test/generated-artifacts/TestEth2DaiBridge.json';
import * as TestKyberBridge from '../test/generated-artifacts/TestKyberBridge.json';
import * as TestStaticCallTarget from '../test/generated-artifacts/TestStaticCallTarget.json';
import * as TestUniswapBridge from '../test/generated-artifacts/TestUniswapBridge.json';
import * as UniswapBridge from '../test/generated-artifacts/UniswapBridge.json';
export const artifacts = {
MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact,
MixinAuthorizable: MixinAuthorizable as ContractArtifact,
Ownable: Ownable as ContractArtifact,
ERC1155Proxy: ERC1155Proxy as ContractArtifact,
ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact,
ERC20Proxy: ERC20Proxy as ContractArtifact,
ERC721Proxy: ERC721Proxy as ContractArtifact,
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
StaticCallProxy: StaticCallProxy as ContractArtifact,
ChaiBridge: ChaiBridge as ContractArtifact,
CurveBridge: CurveBridge as ContractArtifact,
DydxBridge: DydxBridge as ContractArtifact,
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
KyberBridge: KyberBridge as ContractArtifact,
UniswapBridge: UniswapBridge as ContractArtifact,
IAssetData: IAssetData as ContractArtifact,
IAssetProxy: IAssetProxy as ContractArtifact,
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
IAuthorizable: IAuthorizable as ContractArtifact,
IChai: IChai as ContractArtifact,
ICurve: ICurve as ContractArtifact,
IDydx: IDydx as ContractArtifact,
IDydxBridge: IDydxBridge as ContractArtifact,
IERC20Bridge: IERC20Bridge as ContractArtifact,
IEth2Dai: IEth2Dai as ContractArtifact,
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
IUniswapExchange: IUniswapExchange as ContractArtifact,
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
TestChaiBridge: TestChaiBridge as ContractArtifact,
TestDydxBridge: TestDydxBridge as ContractArtifact,
TestERC20Bridge: TestERC20Bridge as ContractArtifact,
TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact,
TestKyberBridge: TestKyberBridge as ContractArtifact,
TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
TestUniswapBridge: TestUniswapBridge as ContractArtifact,
};

View File

@@ -1,20 +1,38 @@
import { blockchainTests, expect, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
import {
chaiSetup,
constants,
expectTransactionFailedAsync,
provider,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { artifacts, MixinAuthorizableContract } from '../src';
import { MixinAuthorizableContract } from './wrappers';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
blockchainTests.resets('Authorizable', () => {
describe('Authorizable', () => {
let owner: string;
let notOwner: string;
let address: string;
let authorizable: MixinAuthorizableContract;
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
[owner, address, notOwner] = accounts.slice(0, 3);
[owner, address, notOwner] = _.slice(accounts, 0, 3);
authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
artifacts.MixinAuthorizable,
provider,
@@ -22,106 +40,176 @@ blockchainTests.resets('Authorizable', () => {
artifacts,
);
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('addAuthorizedAddress', () => {
it('should revert if not called by owner', async () => {
const tx = authorizable.addAuthorizedAddress(notOwner).sendTransactionAsync({ from: notOwner });
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
it('should throw if not called by owner', async () => {
return expectTransactionFailedAsync(
authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }),
RevertReason.OnlyContractOwner,
);
});
it('should allow owner to add an authorized address', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const isAuthorized = await authorizable.authorized(address).callAsync();
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
address,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
const isAuthorized = await authorizable.authorized.callAsync(address);
expect(isAuthorized).to.be.true();
});
it('should revert if owner attempts to authorize a duplicate address', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const tx = authorizable.addAuthorizedAddress(address).sendTransactionAsync({ from: owner });
return expect(tx).to.revertWith(RevertReason.TargetAlreadyAuthorized);
it('should throw if owner attempts to authorize a duplicate address', async () => {
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
address,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
return expectTransactionFailedAsync(
authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
RevertReason.TargetAlreadyAuthorized,
);
});
});
describe('removeAuthorizedAddress', () => {
it('should revert if not called by owner', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: notOwner });
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
it('should throw if not called by owner', async () => {
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
address,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
from: notOwner,
}),
RevertReason.OnlyContractOwner,
);
});
it('should allow owner to remove an authorized address', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const isAuthorized = await authorizable.authorized(address).callAsync();
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
address,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync(
address,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
const isAuthorized = await authorizable.authorized.callAsync(address);
expect(isAuthorized).to.be.false();
});
it('should revert if owner attempts to remove an address that is not authorized', async () => {
const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: owner });
return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized);
it('should throw if owner attempts to remove an address that is not authorized', async () => {
return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
from: owner,
}),
RevertReason.TargetNotAuthorized,
);
});
});
describe('removeAuthorizedAddressAtIndex', () => {
it('should revert if not called by owner', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
it('should throw if not called by owner', async () => {
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
address,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
const index = new BigNumber(0);
const tx = authorizable
.removeAuthorizedAddressAtIndex(address, index)
.sendTransactionAsync({ from: notOwner });
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
from: notOwner,
}),
RevertReason.OnlyContractOwner,
);
});
it('should revert if index is >= authorities.length', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
it('should throw if index is >= authorities.length', async () => {
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
address,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
const index = new BigNumber(1);
const tx = authorizable
.removeAuthorizedAddressAtIndex(address, index)
.sendTransactionAsync({ from: owner });
return expect(tx).to.revertWith(RevertReason.IndexOutOfBounds);
return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
from: owner,
}),
RevertReason.IndexOutOfBounds,
);
});
it('should revert if owner attempts to remove an address that is not authorized', async () => {
it('should throw if owner attempts to remove an address that is not authorized', async () => {
const index = new BigNumber(0);
const tx = authorizable
.removeAuthorizedAddressAtIndex(address, index)
.sendTransactionAsync({ from: owner });
return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized);
return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
from: owner,
}),
RevertReason.TargetNotAuthorized,
);
});
it('should revert if address at index does not match target', async () => {
it('should throw if address at index does not match target', async () => {
const address1 = address;
const address2 = notOwner;
await authorizable.addAuthorizedAddress(address1).awaitTransactionSuccessAsync({ from: owner });
await authorizable.addAuthorizedAddress(address2).awaitTransactionSuccessAsync({ from: owner });
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
address1,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
address2,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
const address1Index = new BigNumber(0);
const tx = authorizable
.removeAuthorizedAddressAtIndex(address2, address1Index)
.sendTransactionAsync({ from: owner });
return expect(tx).to.revertWith(RevertReason.AuthorizedAddressMismatch);
return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address2, address1Index, {
from: owner,
}),
RevertReason.AuthorizedAddressMismatch,
);
});
it('should allow owner to remove an authorized address', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
address,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
const index = new BigNumber(0);
await authorizable.removeAuthorizedAddressAtIndex(address, index).awaitTransactionSuccessAsync({
from: owner,
});
const isAuthorized = await authorizable.authorized(address).callAsync();
await authorizable.removeAuthorizedAddressAtIndex.awaitTransactionSuccessAsync(
address,
index,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
const isAuthorized = await authorizable.authorized.callAsync(address);
expect(isAuthorized).to.be.false();
});
});
describe('getAuthorizedAddresses', () => {
it('should return all authorized addresses', async () => {
const initial = await authorizable.getAuthorizedAddresses().callAsync();
const initial = await authorizable.getAuthorizedAddresses.callAsync();
expect(initial).to.have.length(0);
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const afterAdd = await authorizable.getAuthorizedAddresses().callAsync();
await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
address,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
const afterAdd = await authorizable.getAuthorizedAddresses.callAsync();
expect(afterAdd).to.have.length(1);
expect(afterAdd).to.include(address);
await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const afterRemove = await authorizable.getAuthorizedAddresses().callAsync();
await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync(
address,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
const afterRemove = await authorizable.getAuthorizedAddresses.callAsync();
expect(afterRemove).to.have.length(0);
});
});

View File

@@ -1,60 +0,0 @@
import { ERC20TokenContract } from '@0x/contracts-erc20';
import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils';
import { AssetProxyId, RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { artifacts } from './artifacts';
import { TestChaiBridgeContract } from './wrappers';
blockchainTests.resets('ChaiBridge unit tests', env => {
let chaiBridgeContract: TestChaiBridgeContract;
let testDaiContract: ERC20TokenContract;
let fromAddress: string;
let toAddress: string;
const alwaysRevertAddress = '0x0000000000000000000000000000000000000001';
const amount = new BigNumber(1);
before(async () => {
[fromAddress, toAddress] = await env.getAccountAddressesAsync();
chaiBridgeContract = await TestChaiBridgeContract.deployFrom0xArtifactAsync(
artifacts.TestChaiBridge,
env.provider,
env.txDefaults,
artifacts,
);
const testChaiDaiAddress = await chaiBridgeContract.testChaiDai().callAsync();
testDaiContract = new ERC20TokenContract(testChaiDaiAddress, env.provider, env.txDefaults);
});
describe('bridgeTransferFrom()', () => {
it('fails if not called by ERC20BridgeProxy', async () => {
return expect(
chaiBridgeContract
.bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES)
.awaitTransactionSuccessAsync({ from: alwaysRevertAddress }),
).to.revertWith(RevertReason.ChaiBridgeOnlyCallableByErc20BridgeProxy);
});
it('returns magic bytes upon success', async () => {
const magicBytes = await chaiBridgeContract
.bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES)
.callAsync();
expect(magicBytes).to.eq(AssetProxyId.ERC20Bridge);
});
it('should increase the Dai balance of `toAddress` by `amount` if successful', async () => {
const initialBalance = await testDaiContract.balanceOf(toAddress).callAsync();
await chaiBridgeContract
.bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES)
.awaitTransactionSuccessAsync();
const endBalance = await testDaiContract.balanceOf(toAddress).callAsync();
expect(endBalance).to.bignumber.eq(initialBalance.plus(amount));
});
it('fails if the `chai.draw` call fails', async () => {
return expect(
chaiBridgeContract
.bridgeTransferFrom(randomAddress(), alwaysRevertAddress, toAddress, amount, constants.NULL_BYTES)
.awaitTransactionSuccessAsync(),
).to.revertWith(RevertReason.ChaiBridgeDrawDaiFailed);
});
});
});

View File

@@ -1,399 +0,0 @@
import { LibMathRevertErrors } from '@0x/contracts-exchange-libs';
import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils';
import { AssetProxyId, RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import { DydxBridgeActionType, DydxBridgeData, dydxBridgeDataEncoder } from '../src/dydx_bridge_encoder';
import { ERC20BridgeProxyContract, IAssetDataContract } from '../src/wrappers';
import { artifacts } from './artifacts';
import { TestDydxBridgeContract, TestDydxBridgeEvents } from './wrappers';
blockchainTests.resets('DydxBridge unit tests', env => {
const defaultAccountNumber = new BigNumber(1);
const marketId = new BigNumber(2);
const defaultAmount = new BigNumber(4);
const notAuthorized = '0x0000000000000000000000000000000000000001';
const defaultDepositAction = {
actionType: DydxBridgeActionType.Deposit,
accountIdx: constants.ZERO_AMOUNT,
marketId,
conversionRateNumerator: constants.ZERO_AMOUNT,
conversionRateDenominator: constants.ZERO_AMOUNT,
};
const defaultWithdrawAction = {
actionType: DydxBridgeActionType.Withdraw,
accountIdx: constants.ZERO_AMOUNT,
marketId,
conversionRateNumerator: constants.ZERO_AMOUNT,
conversionRateDenominator: constants.ZERO_AMOUNT,
};
let testContract: TestDydxBridgeContract;
let testProxyContract: ERC20BridgeProxyContract;
let assetDataEncoder: IAssetDataContract;
let owner: string;
let authorized: string;
let accountOwner: string;
let receiver: string;
before(async () => {
// Get accounts
const accounts = await env.web3Wrapper.getAvailableAddressesAsync();
[owner, authorized, accountOwner, receiver] = accounts;
// Deploy dydx bridge
testContract = await TestDydxBridgeContract.deployFrom0xArtifactAsync(
artifacts.TestDydxBridge,
env.provider,
env.txDefaults,
artifacts,
[accountOwner, receiver],
);
// Deploy test erc20 bridge proxy
testProxyContract = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync(
artifacts.ERC20BridgeProxy,
env.provider,
env.txDefaults,
artifacts,
);
await testProxyContract.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner });
// Setup asset data encoder
assetDataEncoder = new IAssetDataContract(constants.NULL_ADDRESS, env.provider);
});
describe('bridgeTransferFrom()', () => {
const callBridgeTransferFrom = async (
from: string,
to: string,
amount: BigNumber,
bridgeData: DydxBridgeData,
sender: string,
): Promise<string> => {
const returnValue = await testContract
.bridgeTransferFrom(
constants.NULL_ADDRESS,
from,
to,
amount,
dydxBridgeDataEncoder.encode({ bridgeData }),
)
.callAsync({ from: sender });
return returnValue;
};
const executeBridgeTransferFromAndVerifyEvents = async (
from: string,
to: string,
amount: BigNumber,
bridgeData: DydxBridgeData,
sender: string,
): Promise<void> => {
// Execute transaction.
const txReceipt = await testContract
.bridgeTransferFrom(
constants.NULL_ADDRESS,
from,
to,
amount,
dydxBridgeDataEncoder.encode({ bridgeData }),
)
.awaitTransactionSuccessAsync({ from: sender });
// Verify `OperateAccount` event.
const expectedOperateAccountEvents = [];
for (const accountNumber of bridgeData.accountNumbers) {
expectedOperateAccountEvents.push({
owner: accountOwner,
number: accountNumber,
});
}
verifyEventsFromLogs(txReceipt.logs, expectedOperateAccountEvents, TestDydxBridgeEvents.OperateAccount);
// Verify `OperateAction` event.
const weiDenomination = 0;
const deltaAmountRef = 0;
const expectedOperateActionEvents = [];
for (const action of bridgeData.actions) {
expectedOperateActionEvents.push({
actionType: action.actionType as number,
accountIdx: action.accountIdx,
amountSign: action.actionType === DydxBridgeActionType.Deposit ? true : false,
amountDenomination: weiDenomination,
amountRef: deltaAmountRef,
amountValue: action.conversionRateDenominator.gt(0)
? amount
.times(action.conversionRateNumerator)
.dividedToIntegerBy(action.conversionRateDenominator)
: amount,
primaryMarketId: marketId,
secondaryMarketId: constants.ZERO_AMOUNT,
otherAddress: action.actionType === DydxBridgeActionType.Deposit ? from : to,
otherAccountId: constants.ZERO_AMOUNT,
data: '0x',
});
}
verifyEventsFromLogs(txReceipt.logs, expectedOperateActionEvents, TestDydxBridgeEvents.OperateAction);
};
it('succeeds when calling with zero amount', async () => {
const bridgeData = {
accountNumbers: [defaultAccountNumber],
actions: [defaultDepositAction],
};
await executeBridgeTransferFromAndVerifyEvents(
accountOwner,
receiver,
constants.ZERO_AMOUNT,
bridgeData,
authorized,
);
});
it('succeeds when calling with no accounts', async () => {
const bridgeData = {
accountNumbers: [],
actions: [defaultDepositAction],
};
await executeBridgeTransferFromAndVerifyEvents(
accountOwner,
receiver,
defaultAmount,
bridgeData,
authorized,
);
});
it('succeeds when calling with no actions', async () => {
const bridgeData = {
accountNumbers: [defaultAccountNumber],
actions: [],
};
await executeBridgeTransferFromAndVerifyEvents(
accountOwner,
receiver,
defaultAmount,
bridgeData,
authorized,
);
});
it('succeeds when calling `operate` with the `deposit` action and a single account', async () => {
const bridgeData = {
accountNumbers: [defaultAccountNumber],
actions: [defaultDepositAction],
};
await executeBridgeTransferFromAndVerifyEvents(
accountOwner,
receiver,
defaultAmount,
bridgeData,
authorized,
);
});
it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => {
const bridgeData = {
accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
actions: [defaultDepositAction],
};
await executeBridgeTransferFromAndVerifyEvents(
accountOwner,
receiver,
defaultAmount,
bridgeData,
authorized,
);
});
it('succeeds when calling `operate` with the `withdraw` action and a single account', async () => {
const bridgeData = {
accountNumbers: [defaultAccountNumber],
actions: [defaultWithdrawAction],
};
await executeBridgeTransferFromAndVerifyEvents(
accountOwner,
receiver,
defaultAmount,
bridgeData,
authorized,
);
});
it('succeeds when calling `operate` with the `withdraw` action and multiple accounts', async () => {
const bridgeData = {
accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
actions: [defaultWithdrawAction],
};
await executeBridgeTransferFromAndVerifyEvents(
accountOwner,
receiver,
defaultAmount,
bridgeData,
authorized,
);
});
it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => {
const bridgeData = {
accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
actions: [defaultWithdrawAction, defaultDepositAction],
};
await executeBridgeTransferFromAndVerifyEvents(
accountOwner,
receiver,
defaultAmount,
bridgeData,
authorized,
);
});
it('succeeds when calling `operate` with multiple actions under a single account', async () => {
const bridgeData = {
accountNumbers: [defaultAccountNumber],
actions: [defaultWithdrawAction, defaultDepositAction],
};
await executeBridgeTransferFromAndVerifyEvents(
accountOwner,
receiver,
defaultAmount,
bridgeData,
authorized,
);
});
it('succeeds when scaling the `amount` to deposit', async () => {
const conversionRateNumerator = new BigNumber(1);
const conversionRateDenominator = new BigNumber(2);
const bridgeData = {
accountNumbers: [defaultAccountNumber],
actions: [
defaultWithdrawAction,
{
...defaultDepositAction,
conversionRateNumerator,
conversionRateDenominator,
},
],
};
await executeBridgeTransferFromAndVerifyEvents(
accountOwner,
receiver,
defaultAmount,
bridgeData,
authorized,
);
});
it('succeeds when scaling the `amount` to withdraw', async () => {
const conversionRateNumerator = new BigNumber(1);
const conversionRateDenominator = new BigNumber(2);
const bridgeData = {
accountNumbers: [defaultAccountNumber],
actions: [
defaultDepositAction,
{
...defaultWithdrawAction,
conversionRateNumerator,
conversionRateDenominator,
},
],
};
await executeBridgeTransferFromAndVerifyEvents(
accountOwner,
receiver,
defaultAmount,
bridgeData,
authorized,
);
});
it('reverts if not called by the ERC20 Bridge Proxy', async () => {
const bridgeData = {
accountNumbers: [defaultAccountNumber],
actions: [defaultDepositAction],
};
const callBridgeTransferFromPromise = callBridgeTransferFrom(
accountOwner,
receiver,
defaultAmount,
bridgeData,
notAuthorized,
);
const expectedError = RevertReason.DydxBridgeOnlyCallableByErc20BridgeProxy;
return expect(callBridgeTransferFromPromise).to.revertWith(expectedError);
});
it('should return magic bytes if call succeeds', async () => {
const bridgeData = {
accountNumbers: [defaultAccountNumber],
actions: [defaultDepositAction],
};
const returnValue = await callBridgeTransferFrom(
accountOwner,
receiver,
defaultAmount,
bridgeData,
authorized,
);
expect(returnValue).to.equal(AssetProxyId.ERC20Bridge);
});
it('should revert when `Operate` reverts', async () => {
// Set revert flag.
await testContract.setRevertOnOperate(true).awaitTransactionSuccessAsync();
// Execute transfer.
const bridgeData = {
accountNumbers: [defaultAccountNumber],
actions: [defaultDepositAction],
};
const tx = callBridgeTransferFrom(accountOwner, receiver, defaultAmount, bridgeData, authorized);
const expectedError = 'TestDydxBridge/SHOULD_REVERT_ON_OPERATE';
return expect(tx).to.revertWith(expectedError);
});
it('should revert when there is a rounding error', async () => {
// Setup a rounding error
const conversionRateNumerator = new BigNumber(5318);
const conversionRateDenominator = new BigNumber(47958);
const amount = new BigNumber(9000);
const bridgeData = {
accountNumbers: [defaultAccountNumber],
actions: [
defaultDepositAction,
{
...defaultWithdrawAction,
conversionRateNumerator,
conversionRateDenominator,
},
],
};
// Execute transfer and assert error.
const tx = callBridgeTransferFrom(accountOwner, receiver, amount, bridgeData, authorized);
const expectedError = new LibMathRevertErrors.RoundingError(
conversionRateNumerator,
conversionRateDenominator,
amount,
);
return expect(tx).to.revertWith(expectedError);
});
});
describe('ERC20BridgeProxy.transferFrom()', () => {
const bridgeData = {
accountNumbers: [defaultAccountNumber],
actions: [defaultWithdrawAction],
};
let assetData: string;
before(async () => {
const testTokenAddress = await testContract.getTestToken().callAsync();
assetData = assetDataEncoder
.ERC20Bridge(testTokenAddress, testContract.address, dydxBridgeDataEncoder.encode({ bridgeData }))
.getABIEncodedTransactionData();
});
it('should succeed if `bridgeTransferFrom` succeeds', async () => {
await testProxyContract
.transferFrom(assetData, accountOwner, receiver, defaultAmount)
.awaitTransactionSuccessAsync({ from: authorized });
});
it('should revert if `bridgeTransferFrom` reverts', async () => {
// Set revert flag.
await testContract.setRevertOnOperate(true).awaitTransactionSuccessAsync();
const tx = testProxyContract
.transferFrom(assetData, accountOwner, receiver, defaultAmount)
.awaitTransactionSuccessAsync({ from: authorized });
const expectedError = 'TestDydxBridge/SHOULD_REVERT_ON_OPERATE';
return expect(tx).to.revertWith(expectedError);
});
});
});

View File

@@ -14,8 +14,8 @@ import {
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils';
import { SafeMathRevertErrors } from '@0x/contracts-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { assetDataUtils } from '@0x/order-utils';
import { AssetProxyId, RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
@@ -23,10 +23,7 @@ import { LogWithDecodedArgs } from 'ethereum-types';
import * as ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
import { ERC1155ProxyWrapper } from '../src/erc1155_proxy_wrapper';
import { ERC1155ProxyContract, IAssetDataContract } from '../src/wrappers';
import { artifacts } from './artifacts';
import { artifacts, ERC1155ProxyContract, ERC1155ProxyWrapper } from '../src';
chaiSetup.configure();
const expect = chai.expect;
@@ -62,8 +59,6 @@ describe('ERC1155Proxy', () => {
// tokens
let fungibleTokens: BigNumber[];
let nonFungibleTokensOwnedBySpender: BigNumber[];
// IAssetData for encoding and decoding assetData
let assetDataContract: IAssetDataContract;
// tests
before(async () => {
await blockchainLifecycle.startAsync();
@@ -77,8 +72,16 @@ describe('ERC1155Proxy', () => {
const usedAddresses = ([owner, notAuthorized, authorized, spender, receiver] = _.slice(accounts, 0, 5));
erc1155ProxyWrapper = new ERC1155ProxyWrapper(provider, usedAddresses, owner);
erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync();
await erc1155Proxy.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner });
await erc1155Proxy.addAuthorizedAddress(erc1155Proxy.address).awaitTransactionSuccessAsync({ from: owner });
await erc1155Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(
authorized,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
await erc1155Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(
erc1155Proxy.address,
{ from: owner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
// deploy & configure ERC1155 tokens and receiver
[erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync();
erc1155Contract = erc1155Wrapper.getContract();
@@ -100,8 +103,6 @@ describe('ERC1155Proxy', () => {
tokenBalances.nonFungible[spender][erc1155Contract.address][nonFungibleTokenAsString][0];
nonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender);
});
// set up assetDataContract
assetDataContract = new IAssetDataContract(constants.NULL_ADDRESS, provider, { from: owner });
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
@@ -122,7 +123,7 @@ describe('ERC1155Proxy', () => {
);
});
it('should have an id of 0xa7cb5fb7', async () => {
const proxyId = await erc1155Proxy.getProxyId().callAsync();
const proxyId = await erc1155Proxy.getProxyId.callAsync();
const expectedProxyId = AssetProxyId.ERC1155;
expect(proxyId).to.equal(expectedProxyId);
});
@@ -637,9 +638,12 @@ describe('ERC1155Proxy', () => {
return value.times(valueMultiplier);
});
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const assetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
const extraData = '0102030405060708091001020304050607080910010203040506070809100102';
const assetDataWithExtraData = `${assetData}${extraData}`;
// check balances before transfer
@@ -692,20 +696,25 @@ describe('ERC1155Proxy', () => {
const tokenUri = '';
for (const tokenToCreate of tokensToCreate) {
// create token
await erc1155Wrapper
.getContract()
.createWithType(tokenToCreate, tokenUri)
.awaitTransactionSuccessAsync({
await erc1155Wrapper.getContract().createWithType.awaitTransactionSuccessAsync(
tokenToCreate,
tokenUri,
{
from: owner,
});
},
constants.AWAIT_TRANSACTION_MINED_MS,
);
// mint balance for spender
await erc1155Wrapper
.getContract()
.mintFungible(tokenToCreate, [spender], [spenderInitialBalance])
.awaitTransactionSuccessAsync({
await erc1155Wrapper.getContract().mintFungible.awaitTransactionSuccessAsync(
tokenToCreate,
[spender],
[spenderInitialBalance],
{
from: owner,
});
},
constants.AWAIT_TRANSACTION_MINED_MS,
);
}
///// Step 2/5 /////
// Check balances before transfer
@@ -738,15 +747,18 @@ describe('ERC1155Proxy', () => {
const tokensToTransfer = [new BigNumber(1), new BigNumber(2)];
const valuesToTransfer = tokensToTransfer;
const valueMultiplier = new BigNumber(2);
// hand encode optimized assetData because our tooling (based on LibAssetData.sol/ERC1155Assets) does not use optimized encoding
const selector = assetDataContract.getSelector('ERC1155Assets');
const assetDataWithoutContractAddress =
const assetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// remove the function selector and contract address from check, as these change on each test
const offsetToTokenIds = 74;
const assetDataWithoutContractAddress = assetData.substr(offsetToTokenIds);
const expectedAssetDataWithoutContractAddress =
'0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000';
const assetData = `${selector}000000000000000000000000${erc1155ContractAddress.substr(
2,
)}${assetDataWithoutContractAddress}`;
expect(assetDataWithoutContractAddress).to.be.equal(expectedAssetDataWithoutContractAddress);
///// Step 4/5 /////
// Transfer token IDs [1, 2] and amounts [1, 2] with a multiplier of 2;
// the expected trade will be token IDs [1, 2] and amounts [2, 4]
@@ -793,20 +805,25 @@ describe('ERC1155Proxy', () => {
const tokenUri = '';
for (const tokenToCreate of tokensToCreate) {
// create token
await erc1155Wrapper
.getContract()
.createWithType(tokenToCreate, tokenUri)
.awaitTransactionSuccessAsync({
await erc1155Wrapper.getContract().createWithType.awaitTransactionSuccessAsync(
tokenToCreate,
tokenUri,
{
from: owner,
});
},
constants.AWAIT_TRANSACTION_MINED_MS,
);
// mint balance for spender
await erc1155Wrapper
.getContract()
.mintFungible(tokenToCreate, [spender], [spenderInitialBalance])
.awaitTransactionSuccessAsync({
await erc1155Wrapper.getContract().mintFungible.awaitTransactionSuccessAsync(
tokenToCreate,
[spender],
[spenderInitialBalance],
{
from: owner,
});
},
constants.AWAIT_TRANSACTION_MINED_MS,
);
}
///// Step 2/5 /////
// Check balances before transfer
@@ -850,9 +867,12 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [new BigNumber(2), new BigNumber(2)];
const valueMultiplier = new BigNumber(2);
// create callback data that is the encoded version of `valuesToTransfer`
const generatedAssetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const generatedAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// remove the function selector and contract address from check, as these change on each test
const offsetToTokenIds = 74;
const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds);
@@ -917,20 +937,25 @@ describe('ERC1155Proxy', () => {
const tokenUri = '';
for (const tokenToCreate of tokensToCreate) {
// create token
await erc1155Wrapper
.getContract()
.createWithType(tokenToCreate, tokenUri)
.awaitTransactionSuccessAsync({
await erc1155Wrapper.getContract().createWithType.awaitTransactionSuccessAsync(
tokenToCreate,
tokenUri,
{
from: owner,
});
},
constants.AWAIT_TRANSACTION_MINED_MS,
);
// mint balance for spender
await erc1155Wrapper
.getContract()
.mintFungible(tokenToCreate, [spender], [spenderInitialBalance])
.awaitTransactionSuccessAsync({
await erc1155Wrapper.getContract().mintFungible.awaitTransactionSuccessAsync(
tokenToCreate,
[spender],
[spenderInitialBalance],
{
from: owner,
});
},
constants.AWAIT_TRANSACTION_MINED_MS,
);
}
///// Step 2/5 /////
// Check balances before transfer
@@ -971,9 +996,12 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [new BigNumber(1), new BigNumber(2)];
const valueMultiplier = new BigNumber(2);
// create callback data that is the encoded version of `valuesToTransfer`
const generatedAssetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const generatedAssetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// remove the function selector and contract address from check, as these change on each test
const offsetToTokenIds = 74;
const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds);
@@ -1031,9 +1059,12 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const assetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1075,9 +1106,12 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const assetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1123,9 +1157,12 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const assetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1171,9 +1208,12 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const assetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1219,9 +1259,12 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const assetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1268,9 +1311,12 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const assetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1312,9 +1358,12 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const assetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1360,9 +1409,12 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const assetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1404,9 +1456,12 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const assetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1452,10 +1507,13 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync(
const assetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
const txData = erc1155ProxyWrapper.getTransferFromAbiEncodedTxData(
spender,
receiverContract,
erc1155Contract.address,
@@ -1480,10 +1538,13 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync(
const assetData = assetDataUtils.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
const txData = erc1155ProxyWrapper.getTransferFromAbiEncodedTxData(
spender,
receiverContract,
erc1155Contract.address,
@@ -1606,9 +1667,13 @@ describe('ERC1155Proxy', () => {
it('should propagate revert reason from erc1155 contract failure', async () => {
// disable transfers
const shouldRejectTransfer = true;
await erc1155Receiver.setRejectTransferFlag(shouldRejectTransfer).awaitTransactionSuccessAsync({
from: owner,
});
await erc1155Receiver.setRejectTransferFlag.awaitTransactionSuccessAsync(
shouldRejectTransfer,
{
from: owner,
},
constants.AWAIT_TRANSACTION_MINED_MS,
);
// setup test parameters
const tokenHolders = [spender, receiverContract];
const tokensToTransfer = fungibleTokens.slice(0, 1);
@@ -1683,14 +1748,9 @@ describe('ERC1155Proxy', () => {
nftNotOwnerBalance,
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
SafeMathRevertErrors.BinOpErrorCodes.MultiplicationOverflow,
maxUintValue,
valueMultiplier,
);
// execute transfer
// note - this will overflow because we are trying to transfer `maxUintValue * 2` of the 2nd token
await expect(
await expectTransactionFailedAsync(
erc1155ProxyWrapper.transferFromAsync(
spender,
receiver,
@@ -1701,7 +1761,8 @@ describe('ERC1155Proxy', () => {
receiverCallbackData,
authorized,
),
).to.revertWith(expectedError);
RevertReason.Uint256Overflow,
);
});
it('should revert if transferring > 1 instances of a non-fungible token (valueMultiplier field >1)', async () => {
// setup test parameters
@@ -1771,23 +1832,20 @@ describe('ERC1155Proxy', () => {
// check balances before transfer
const expectedInitialBalances = [spenderInitialFungibleBalance, receiverInitialFungibleBalance];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
const expectedError = new SafeMathRevertErrors.Uint256BinOpError(
SafeMathRevertErrors.BinOpErrorCodes.SubtractionUnderflow,
spenderInitialFungibleBalance,
valuesToTransfer[0].times(valueMultiplier),
);
// execute transfer
const tx = erc1155ProxyWrapper.transferFromAsync(
spender,
receiver,
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
valueMultiplier,
receiverCallbackData,
authorized,
await expectTransactionFailedAsync(
erc1155ProxyWrapper.transferFromAsync(
spender,
receiver,
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
valueMultiplier,
receiverCallbackData,
authorized,
),
RevertReason.Uint256Underflow,
);
return expect(tx).to.revertWith(expectedError);
});
it('should revert if sender allowance is insufficient', async () => {
// dremove allowance for ERC1155 proxy

View File

@@ -1,287 +0,0 @@
import {
blockchainTests,
constants,
expect,
getRandomInteger,
Numberish,
randomAddress,
} from '@0x/contracts-test-utils';
import { AuthorizableRevertErrors } from '@0x/contracts-utils';
import { AssetProxyId } from '@0x/types';
import { AbiEncoder, BigNumber, hexUtils, StringRevertError } from '@0x/utils';
import { DecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { ERC20BridgeProxyContract, TestERC20BridgeContract } from './wrappers';
blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
const PROXY_ID = AssetProxyId.ERC20Bridge;
const BRIDGE_SUCCESS_RETURN_DATA = hexUtils.rightPad(PROXY_ID);
let owner: string;
let badCaller: string;
let assetProxy: ERC20BridgeProxyContract;
let bridgeContract: TestERC20BridgeContract;
let testTokenAddress: string;
before(async () => {
[owner, badCaller] = await env.getAccountAddressesAsync();
assetProxy = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync(
artifacts.ERC20BridgeProxy,
env.provider,
env.txDefaults,
artifacts,
);
bridgeContract = await TestERC20BridgeContract.deployFrom0xArtifactAsync(
artifacts.TestERC20Bridge,
env.provider,
env.txDefaults,
artifacts,
);
testTokenAddress = await bridgeContract.testToken().callAsync();
await assetProxy.addAuthorizedAddress(owner).awaitTransactionSuccessAsync();
});
interface AssetDataOpts {
tokenAddress: string;
bridgeAddress: string;
bridgeData: BridgeDataOpts;
}
interface BridgeDataOpts {
transferAmount: Numberish;
revertError?: string;
returnData: string;
}
function createAssetData(opts?: Partial<AssetDataOpts>): AssetDataOpts {
return _.merge(
{
tokenAddress: testTokenAddress,
bridgeAddress: bridgeContract.address,
bridgeData: createBridgeData(),
},
opts,
);
}
function createBridgeData(opts?: Partial<BridgeDataOpts>): BridgeDataOpts {
return _.merge(
{
transferAmount: constants.ZERO_AMOUNT,
returnData: BRIDGE_SUCCESS_RETURN_DATA,
},
opts,
);
}
function encodeAssetData(opts: AssetDataOpts): string {
const encoder = AbiEncoder.createMethod('ERC20BridgeProxy', [
{ name: 'tokenAddress', type: 'address' },
{ name: 'bridgeAddress', type: 'address' },
{ name: 'bridgeData', type: 'bytes' },
]);
return encoder.encode([opts.tokenAddress, opts.bridgeAddress, encodeBridgeData(opts.bridgeData)]);
}
function encodeBridgeData(opts: BridgeDataOpts): string {
const encoder = AbiEncoder.create([
{ name: 'transferAmount', type: 'int256' },
{ name: 'revertData', type: 'bytes' },
{ name: 'returnData', type: 'bytes' },
]);
const revertErrorBytes =
opts.revertError !== undefined ? new StringRevertError(opts.revertError).encode() : '0x';
return encoder.encode([new BigNumber(opts.transferAmount), revertErrorBytes, opts.returnData]);
}
async function setTestTokenBalanceAsync(_owner: string, balance: Numberish): Promise<void> {
await bridgeContract.setTestTokenBalance(_owner, new BigNumber(balance)).awaitTransactionSuccessAsync();
}
describe('transferFrom()', () => {
interface TransferFromOpts {
assetData: AssetDataOpts;
from: string;
to: string;
amount: Numberish;
}
function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
const transferAmount = _.get(opts, ['amount'], getRandomInteger(1, 100e18)) as BigNumber;
return _.merge(
{
assetData: createAssetData({
bridgeData: createBridgeData({
transferAmount,
}),
}),
from: randomAddress(),
to: randomAddress(),
amount: transferAmount,
},
opts,
);
}
async function transferFromAsync(opts?: Partial<TransferFromOpts>, caller?: string): Promise<DecodedLogs> {
const _opts = createTransferFromOpts(opts);
const { logs } = await assetProxy
.transferFrom(encodeAssetData(_opts.assetData), _opts.from, _opts.to, new BigNumber(_opts.amount))
.awaitTransactionSuccessAsync({ from: caller });
return (logs as any) as DecodedLogs;
}
it('succeeds if the bridge succeeds and balance increases by `amount`', async () => {
const tx = transferFromAsync();
return expect(tx).to.be.fulfilled('');
});
it('succeeds if balance increases more than `amount`', async () => {
const amount = getRandomInteger(1, 100e18);
const tx = transferFromAsync({
amount,
assetData: createAssetData({
bridgeData: createBridgeData({
transferAmount: amount.plus(1),
}),
}),
});
return expect(tx).to.be.fulfilled('');
});
it('passes the correct arguments to the bridge contract', async () => {
const opts = createTransferFromOpts();
const logs = await transferFromAsync(opts);
expect(logs.length).to.eq(1);
const args = logs[0].args;
expect(args.tokenAddress).to.eq(opts.assetData.tokenAddress);
expect(args.from).to.eq(opts.from);
expect(args.to).to.eq(opts.to);
expect(args.amount).to.bignumber.eq(opts.amount);
expect(args.bridgeData).to.eq(encodeBridgeData(opts.assetData.bridgeData));
});
it('fails if not called by an authorized address', async () => {
const tx = transferFromAsync({}, badCaller);
return expect(tx).to.revertWith(new AuthorizableRevertErrors.SenderNotAuthorizedError(badCaller));
});
it('fails if asset data is truncated', async () => {
const opts = createTransferFromOpts();
const truncatedAssetData = hexUtils.slice(encodeAssetData(opts.assetData), 0, -1);
const tx = assetProxy
.transferFrom(truncatedAssetData, opts.from, opts.to, new BigNumber(opts.amount))
.awaitTransactionSuccessAsync();
return expect(tx).to.be.rejected();
});
it('fails if bridge returns nothing', async () => {
const tx = transferFromAsync({
assetData: createAssetData({
bridgeData: createBridgeData({
returnData: '0x',
}),
}),
});
// This will actually revert when the AP tries to decode the return
// value.
return expect(tx).to.be.rejected();
});
it('fails if bridge returns true', async () => {
const tx = transferFromAsync({
assetData: createAssetData({
bridgeData: createBridgeData({
returnData: hexUtils.leftPad('0x1'),
}),
}),
});
// This will actually revert when the AP tries to decode the return
// value.
return expect(tx).to.be.rejected();
});
it('fails if bridge returns 0x1', async () => {
const tx = transferFromAsync({
assetData: createAssetData({
bridgeData: createBridgeData({
returnData: hexUtils.rightPad('0x1'),
}),
}),
});
return expect(tx).to.revertWith('BRIDGE_FAILED');
});
it('fails if bridge is an EOA', async () => {
const tx = transferFromAsync({
assetData: createAssetData({
bridgeAddress: randomAddress(),
}),
});
// This will actually revert when the AP tries to decode the return
// value.
return expect(tx).to.be.rejected();
});
it('fails if bridge reverts', async () => {
const revertError = 'FOOBAR';
const tx = transferFromAsync({
assetData: createAssetData({
bridgeData: createBridgeData({
revertError,
}),
}),
});
return expect(tx).to.revertWith(revertError);
});
it('fails if balance of `to` increases by less than `amount`', async () => {
const amount = getRandomInteger(1, 100e18);
const tx = transferFromAsync({
amount,
assetData: createAssetData({
bridgeData: createBridgeData({
transferAmount: amount.minus(1),
}),
}),
});
return expect(tx).to.revertWith('BRIDGE_UNDERPAY');
});
it('fails if balance of `to` decreases', async () => {
const toAddress = randomAddress();
await setTestTokenBalanceAsync(toAddress, 1e18);
const tx = transferFromAsync({
to: toAddress,
assetData: createAssetData({
bridgeData: createBridgeData({
transferAmount: -1,
}),
}),
});
return expect(tx).to.revertWith('BRIDGE_UNDERPAY');
});
});
describe('balanceOf()', () => {
it('retrieves the balance of the encoded token', async () => {
const _owner = randomAddress();
const balance = getRandomInteger(1, 100e18);
await bridgeContract.setTestTokenBalance(_owner, balance).awaitTransactionSuccessAsync();
const assetData = createAssetData({
tokenAddress: testTokenAddress,
});
const actualBalance = await assetProxy.balanceOf(encodeAssetData(assetData), _owner).callAsync();
expect(actualBalance).to.bignumber.eq(balance);
});
});
describe('getProxyId()', () => {
it('returns the correct proxy ID', async () => {
const proxyId = await assetProxy.getProxyId().callAsync();
expect(proxyId).to.eq(PROXY_ID);
});
});
});

View File

@@ -1,191 +0,0 @@
import {
blockchainTests,
constants,
expect,
filterLogsToArguments,
getRandomInteger,
Numberish,
randomAddress,
} from '@0x/contracts-test-utils';
import { AssetProxyId } from '@0x/types';
import { BigNumber, hexUtils, RawRevertError } from '@0x/utils';
import { DecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import {
TestEth2DaiBridgeContract,
TestEth2DaiBridgeEvents,
TestEth2DaiBridgeSellAllAmountEventArgs,
TestEth2DaiBridgeTokenApproveEventArgs,
TestEth2DaiBridgeTokenTransferEventArgs,
} from './wrappers';
blockchainTests.resets('Eth2DaiBridge unit tests', env => {
let testContract: TestEth2DaiBridgeContract;
before(async () => {
testContract = await TestEth2DaiBridgeContract.deployFrom0xArtifactAsync(
artifacts.TestEth2DaiBridge,
env.provider,
env.txDefaults,
artifacts,
);
});
describe('isValidSignature()', () => {
it('returns success bytes', async () => {
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
const result = await testContract
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
.callAsync();
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
});
});
describe('bridgeTransferFrom()', () => {
interface WithdrawToOpts {
toTokenAddress?: string;
fromTokenAddress?: string;
toAddress: string;
amount: Numberish;
fromTokenBalance: Numberish;
revertReason: string;
fillAmount: Numberish;
toTokentransferRevertReason: string;
toTokenTransferReturnData: string;
}
interface WithdrawToResult {
opts: WithdrawToOpts;
result: string;
logs: DecodedLogs;
}
function createWithdrawToOpts(opts?: Partial<WithdrawToOpts>): WithdrawToOpts {
return {
toAddress: randomAddress(),
amount: getRandomInteger(1, 100e18),
revertReason: '',
fillAmount: getRandomInteger(1, 100e18),
fromTokenBalance: getRandomInteger(1, 100e18),
toTokentransferRevertReason: '',
toTokenTransferReturnData: hexUtils.leftPad(1),
...opts,
};
}
async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> {
const _opts = createWithdrawToOpts(opts);
// Set the fill behavior.
await testContract
.setFillBehavior(_opts.revertReason, new BigNumber(_opts.fillAmount))
.awaitTransactionSuccessAsync();
// Create tokens and balances.
if (_opts.fromTokenAddress === undefined) {
const createTokenFn = testContract.createToken(new BigNumber(_opts.fromTokenBalance));
_opts.fromTokenAddress = await createTokenFn.callAsync();
await createTokenFn.awaitTransactionSuccessAsync();
}
if (_opts.toTokenAddress === undefined) {
const createTokenFn = testContract.createToken(constants.ZERO_AMOUNT);
_opts.toTokenAddress = await createTokenFn.callAsync();
await createTokenFn.awaitTransactionSuccessAsync();
}
// Set the transfer behavior of `toTokenAddress`.
await testContract
.setTransferBehavior(
_opts.toTokenAddress,
_opts.toTokentransferRevertReason,
_opts.toTokenTransferReturnData,
)
.awaitTransactionSuccessAsync();
// Call bridgeTransferFrom().
const bridgeTransferFromFn = testContract.bridgeTransferFrom(
// "to" token address
_opts.toTokenAddress,
// Random from address.
randomAddress(),
// To address.
_opts.toAddress,
new BigNumber(_opts.amount),
// ABI-encode the "from" token address as the bridge data.
hexUtils.leftPad(_opts.fromTokenAddress as string),
);
const result = await bridgeTransferFromFn.callAsync();
const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
return {
opts: _opts,
result,
logs: (logs as any) as DecodedLogs,
};
}
it('returns magic bytes on success', async () => {
const BRIDGE_SUCCESS_RETURN_DATA = AssetProxyId.ERC20Bridge;
const { result } = await withdrawToAsync();
expect(result).to.eq(BRIDGE_SUCCESS_RETURN_DATA);
});
it('calls `Eth2Dai.sellAllAmount()`', async () => {
const { opts, logs } = await withdrawToAsync();
const transfers = filterLogsToArguments<TestEth2DaiBridgeSellAllAmountEventArgs>(
logs,
TestEth2DaiBridgeEvents.SellAllAmount,
);
expect(transfers.length).to.eq(1);
expect(transfers[0].sellToken).to.eq(opts.fromTokenAddress);
expect(transfers[0].buyToken).to.eq(opts.toTokenAddress);
expect(transfers[0].sellTokenAmount).to.bignumber.eq(opts.fromTokenBalance);
expect(transfers[0].minimumFillAmount).to.bignumber.eq(opts.amount);
});
it('sets an unlimited allowance on the `fromTokenAddress` token', async () => {
const { opts, logs } = await withdrawToAsync();
const approvals = filterLogsToArguments<TestEth2DaiBridgeTokenApproveEventArgs>(
logs,
TestEth2DaiBridgeEvents.TokenApprove,
);
expect(approvals.length).to.eq(1);
expect(approvals[0].token).to.eq(opts.fromTokenAddress);
expect(approvals[0].spender).to.eq(testContract.address);
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
});
it('transfers filled amount to `to`', async () => {
const { opts, logs } = await withdrawToAsync();
const transfers = filterLogsToArguments<TestEth2DaiBridgeTokenTransferEventArgs>(
logs,
TestEth2DaiBridgeEvents.TokenTransfer,
);
expect(transfers.length).to.eq(1);
expect(transfers[0].token).to.eq(opts.toTokenAddress);
expect(transfers[0].from).to.eq(testContract.address);
expect(transfers[0].to).to.eq(opts.toAddress);
expect(transfers[0].amount).to.bignumber.eq(opts.fillAmount);
});
it('fails if `Eth2Dai.sellAllAmount()` reverts', async () => {
const opts = createWithdrawToOpts({ revertReason: 'FOOBAR' });
const tx = withdrawToAsync(opts);
return expect(tx).to.revertWith(opts.revertReason);
});
it('fails if `toTokenAddress.transfer()` reverts', async () => {
const opts = createWithdrawToOpts({ toTokentransferRevertReason: 'FOOBAR' });
const tx = withdrawToAsync(opts);
return expect(tx).to.revertWith(opts.toTokentransferRevertReason);
});
it('fails if `toTokenAddress.transfer()` returns false', async () => {
const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexUtils.leftPad(0) });
const tx = withdrawToAsync(opts);
return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(0)));
});
it('succeeds if `toTokenAddress.transfer()` returns true', async () => {
await withdrawToAsync({ toTokenTransferReturnData: hexUtils.leftPad(1) });
});
});
});

View File

@@ -1,283 +0,0 @@
import {
blockchainTests,
constants,
expect,
getRandomInteger,
getRandomPortion,
randomAddress,
verifyEventsFromLogs,
} from '@0x/contracts-test-utils';
import { AssetProxyId } from '@0x/types';
import { BigNumber, hexUtils } from '@0x/utils';
import { DecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { TestKyberBridgeContract, TestKyberBridgeEvents } from './wrappers';
blockchainTests.resets('KyberBridge unit tests', env => {
const KYBER_ETH_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
const FROM_TOKEN_DECIMALS = 6;
const TO_TOKEN_DECIMALS = 18;
const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS);
const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS);
const WETH_BASE = new BigNumber(10).pow(18);
const KYBER_RATE_BASE = WETH_BASE;
let testContract: TestKyberBridgeContract;
before(async () => {
testContract = await TestKyberBridgeContract.deployFrom0xArtifactAsync(
artifacts.TestKyberBridge,
env.provider,
env.txDefaults,
artifacts,
);
});
describe('isValidSignature()', () => {
it('returns success bytes', async () => {
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
const result = await testContract
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
.callAsync();
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
});
});
describe('bridgeTransferFrom()', () => {
let fromTokenAddress: string;
let toTokenAddress: string;
let wethAddress: string;
before(async () => {
wethAddress = await testContract.weth().callAsync();
fromTokenAddress = await testContract.createToken(FROM_TOKEN_DECIMALS).callAsync();
await testContract.createToken(FROM_TOKEN_DECIMALS).awaitTransactionSuccessAsync();
toTokenAddress = await testContract.createToken(TO_TOKEN_DECIMALS).callAsync();
await testContract.createToken(TO_TOKEN_DECIMALS).awaitTransactionSuccessAsync();
});
const STATIC_KYBER_TRADE_ARGS = {
maxBuyTokenAmount: constants.MAX_UINT256,
walletId: constants.NULL_ADDRESS,
};
interface TransferFromOpts {
toTokenAddress: string;
fromTokenAddress: string;
toAddress: string;
// Amount to pass into `bridgeTransferFrom()`
amount: BigNumber;
// Amount to convert in `trade()`.
fillAmount: BigNumber;
// Token balance of the bridge.
fromTokenBalance: BigNumber;
}
interface TransferFromResult {
opts: TransferFromOpts;
result: string;
logs: DecodedLogs;
}
function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100));
return {
fromTokenAddress,
toTokenAddress,
amount,
toAddress: randomAddress(),
fillAmount: getRandomPortion(amount),
fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)),
...opts,
};
}
async function withdrawToAsync(opts?: Partial<TransferFromOpts>): Promise<TransferFromResult> {
const _opts = createTransferFromOpts(opts);
// Fund the contract with input tokens.
await testContract
.grantTokensTo(_opts.fromTokenAddress, testContract.address, _opts.fromTokenBalance)
.awaitTransactionSuccessAsync({ value: _opts.fromTokenBalance });
// Fund the contract with output tokens.
await testContract.setNextFillAmount(_opts.fillAmount).awaitTransactionSuccessAsync({
value: _opts.toTokenAddress === wethAddress ? _opts.fillAmount : constants.ZERO_AMOUNT,
});
// Call bridgeTransferFrom().
const bridgeTransferFromFn = testContract.bridgeTransferFrom(
// Output token
_opts.toTokenAddress,
// Random maker address.
randomAddress(),
// Recipient address.
_opts.toAddress,
// Transfer amount.
_opts.amount,
// ABI-encode the input token address as the bridge data.
hexUtils.leftPad(_opts.fromTokenAddress),
);
const result = await bridgeTransferFromFn.callAsync();
const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
return {
opts: _opts,
result,
logs: (logs as any) as DecodedLogs,
};
}
function getMinimumConversionRate(opts: TransferFromOpts): BigNumber {
const fromBase = opts.fromTokenAddress === wethAddress ? WETH_BASE : FROM_TOKEN_BASE;
const toBase = opts.toTokenAddress === wethAddress ? WETH_BASE : TO_TOKEN_BASE;
return opts.amount
.div(toBase)
.div(opts.fromTokenBalance.div(fromBase))
.times(KYBER_RATE_BASE)
.integerValue(BigNumber.ROUND_DOWN);
}
it('returns magic bytes on success', async () => {
const BRIDGE_SUCCESS_RETURN_DATA = AssetProxyId.ERC20Bridge;
const { result } = await withdrawToAsync();
expect(result).to.eq(BRIDGE_SUCCESS_RETURN_DATA);
});
it('can trade token -> token', async () => {
const { opts, logs } = await withdrawToAsync();
verifyEventsFromLogs(
logs,
[
{
sellTokenAddress: opts.fromTokenAddress,
buyTokenAddress: opts.toTokenAddress,
sellAmount: opts.fromTokenBalance,
recipientAddress: opts.toAddress,
minConversionRate: getMinimumConversionRate(opts),
msgValue: constants.ZERO_AMOUNT,
...STATIC_KYBER_TRADE_ARGS,
},
],
TestKyberBridgeEvents.KyberBridgeTrade,
);
});
it('can trade token -> ETH', async () => {
const { opts, logs } = await withdrawToAsync({
toTokenAddress: wethAddress,
});
verifyEventsFromLogs(
logs,
[
{
sellTokenAddress: opts.fromTokenAddress,
buyTokenAddress: KYBER_ETH_ADDRESS,
sellAmount: opts.fromTokenBalance,
recipientAddress: testContract.address,
minConversionRate: getMinimumConversionRate(opts),
msgValue: constants.ZERO_AMOUNT,
...STATIC_KYBER_TRADE_ARGS,
},
],
TestKyberBridgeEvents.KyberBridgeTrade,
);
});
it('can trade ETH -> token', async () => {
const { opts, logs } = await withdrawToAsync({
fromTokenAddress: wethAddress,
});
verifyEventsFromLogs(
logs,
[
{
sellTokenAddress: KYBER_ETH_ADDRESS,
buyTokenAddress: opts.toTokenAddress,
sellAmount: opts.fromTokenBalance,
recipientAddress: opts.toAddress,
minConversionRate: getMinimumConversionRate(opts),
msgValue: opts.fromTokenBalance,
...STATIC_KYBER_TRADE_ARGS,
},
],
TestKyberBridgeEvents.KyberBridgeTrade,
);
});
it('does nothing if bridge has no token balance', async () => {
const { logs } = await withdrawToAsync({
fromTokenBalance: constants.ZERO_AMOUNT,
});
expect(logs).to.be.length(0);
});
it('only transfers the token if trading the same token', async () => {
const { opts, logs } = await withdrawToAsync({
toTokenAddress: fromTokenAddress,
});
verifyEventsFromLogs(
logs,
[
{
tokenAddress: fromTokenAddress,
ownerAddress: testContract.address,
recipientAddress: opts.toAddress,
amount: opts.fromTokenBalance,
},
],
TestKyberBridgeEvents.KyberBridgeTokenTransfer,
);
});
it('grants Kyber an allowance when selling non-WETH', async () => {
const { opts, logs } = await withdrawToAsync();
verifyEventsFromLogs(
logs,
[
{
tokenAddress: opts.fromTokenAddress,
ownerAddress: testContract.address,
spenderAddress: testContract.address,
allowance: constants.MAX_UINT256,
},
],
TestKyberBridgeEvents.KyberBridgeTokenApprove,
);
});
it('does not grant Kyber an allowance when selling WETH', async () => {
const { logs } = await withdrawToAsync({
fromTokenAddress: wethAddress,
});
verifyEventsFromLogs(logs, [], TestKyberBridgeEvents.KyberBridgeTokenApprove);
});
it('withdraws WETH and passes it to Kyber when selling WETH', async () => {
const { opts, logs } = await withdrawToAsync({
fromTokenAddress: wethAddress,
});
expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethWithdraw);
expect(logs[0].args).to.deep.eq({
ownerAddress: testContract.address,
amount: opts.fromTokenBalance,
});
expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade);
expect(logs[1].args.msgValue).to.bignumber.eq(opts.fromTokenBalance);
});
it('wraps WETH and transfers it to the recipient when buyng WETH', async () => {
const { opts, logs } = await withdrawToAsync({
toTokenAddress: wethAddress,
});
expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeTokenApprove);
expect(logs[0].args.tokenAddress).to.eq(opts.fromTokenAddress);
expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade);
expect(logs[1].args.recipientAddress).to.eq(testContract.address);
expect(logs[2].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethDeposit);
expect(logs[2].args).to.deep.eq({
msgValue: opts.fillAmount,
ownerAddress: testContract.address,
amount: opts.fillAmount,
});
});
});
});

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +1,20 @@
import {
chaiSetup,
constants,
expectTransactionFailedAsync,
expectTransactionFailedWithoutReasonAsync,
provider,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { assetDataUtils } from '@0x/order-utils';
import { AssetProxyId, RevertReason } from '@0x/types';
import { AbiEncoder, BigNumber } from '@0x/utils';
import * as chai from 'chai';
import * as ethUtil from 'ethereumjs-util';
import { artifacts } from './artifacts';
import {
IAssetDataContract,
IAssetProxyContract,
StaticCallProxyContract,
TestStaticCallTargetContract,
} from './wrappers';
import { artifacts, IAssetProxyContract, StaticCallProxyContract, TestStaticCallTargetContract } from '../src';
chaiSetup.configure();
const expect = chai.expect;
@@ -30,7 +25,6 @@ describe('StaticCallProxy', () => {
let fromAddress: string;
let toAddress: string;
let assetDataInterface: IAssetDataContract;
let staticCallProxy: IAssetProxyContract;
let staticCallTarget: TestStaticCallTargetContract;
@@ -49,14 +43,7 @@ describe('StaticCallProxy', () => {
txDefaults,
artifacts,
);
assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
staticCallProxy = new IAssetProxyContract(
staticCallProxyWithoutTransferFrom.address,
provider,
txDefaults,
{},
StaticCallProxyContract.deployedBytecode,
);
staticCallProxy = new IAssetProxyContract(staticCallProxyWithoutTransferFrom.address, provider, txDefaults);
staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync(
artifacts.TestStaticCallTarget,
provider,
@@ -84,21 +71,26 @@ describe('StaticCallProxy', () => {
);
});
it('should have an id of 0xc339d10a', async () => {
const proxyId = await staticCallProxy.getProxyId().callAsync();
const proxyId = await staticCallProxy.getProxyId.callAsync();
const expectedProxyId = AssetProxyId.StaticCall;
expect(proxyId).to.equal(expectedProxyId);
});
});
describe('transferFrom', () => {
it('should revert if assetData lies outside the bounds of calldata', async () => {
const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData();
const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData();
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
const txData = staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.getABIEncodedTransactionData();
const assetData = assetDataUtils.encodeStaticCallAssetData(
staticCallTarget.address,
staticCallData,
expectedResultHash,
);
const txData = staticCallProxy.transferFrom.getABIEncodedTransactionData(
assetData,
fromAddress,
toAddress,
amount,
);
const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080';
const txDataEndBuffer = ethUtil.toBuffer((txData.length - 2) / 2 - 4);
const paddedTxDataEndBuffer = ethUtil.setLengthLeft(txDataEndBuffer, 32);
@@ -116,22 +108,23 @@ describe('StaticCallProxy', () => {
it('should revert if the length of assetData is less than 100 bytes', async () => {
const staticCallData = constants.NULL_BYTES;
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData()
const assetData = assetDataUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
.slice(0, -128);
const assetDataByteLen = (assetData.length - 2) / 2;
expect((assetDataByteLen - 4) % 32).to.equal(0);
await expectTransactionFailedWithoutReasonAsync(
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(),
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
);
});
it('should revert if the offset to `staticCallData` points to outside of assetData', async () => {
const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData();
const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData();
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
const assetData = assetDataUtils.encodeStaticCallAssetData(
staticCallTarget.address,
staticCallData,
expectedResultHash,
);
const offsetToStaticCallData = '0000000000000000000000000000000000000000000000000000000000000060';
const assetDataEndBuffer = ethUtil.toBuffer((assetData.length - 2) / 2 - 4);
const paddedAssetDataEndBuffer = ethUtil.setLengthLeft(assetDataEndBuffer, 32);
@@ -142,86 +135,90 @@ describe('StaticCallProxy', () => {
invalidOffsetToStaticCallData,
)}${newStaticCallData}`;
await expectTransactionFailedWithoutReasonAsync(
staticCallProxy.transferFrom(badAssetData, fromAddress, toAddress, amount).sendTransactionAsync(),
staticCallProxy.transferFrom.sendTransactionAsync(badAssetData, fromAddress, toAddress, amount),
);
});
it('should revert if the callTarget attempts to write to state', async () => {
const staticCallData = staticCallTarget.updateState().getABIEncodedTransactionData();
const staticCallData = staticCallTarget.updateState.getABIEncodedTransactionData();
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
const assetData = assetDataUtils.encodeStaticCallAssetData(
staticCallTarget.address,
staticCallData,
expectedResultHash,
);
await expectTransactionFailedWithoutReasonAsync(
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(),
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
);
});
it('should revert with data provided by the callTarget if the staticcall reverts', async () => {
const staticCallData = staticCallTarget.assertEvenNumber(new BigNumber(1)).getABIEncodedTransactionData();
const staticCallData = staticCallTarget.assertEvenNumber.getABIEncodedTransactionData(new BigNumber(1));
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
return expect(
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(),
).to.revertWith(RevertReason.TargetNotEven);
const assetData = assetDataUtils.encodeStaticCallAssetData(
staticCallTarget.address,
staticCallData,
expectedResultHash,
);
await expectTransactionFailedAsync(
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
RevertReason.TargetNotEven,
);
});
it('should revert if the hash of the output is different than expected expected', async () => {
const staticCallData = staticCallTarget.isOddNumber(new BigNumber(0)).getABIEncodedTransactionData();
const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(0));
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
return expect(
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(),
).to.revertWith(RevertReason.UnexpectedStaticCallResult);
const assetData = assetDataUtils.encodeStaticCallAssetData(
staticCallTarget.address,
staticCallData,
expectedResultHash,
);
await expectTransactionFailedAsync(
staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
RevertReason.UnexpectedStaticCallResult,
);
});
it('should be successful if a function call with no inputs and no outputs is successful', async () => {
const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData();
const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData();
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
const assetData = assetDataUtils.encodeStaticCallAssetData(
staticCallTarget.address,
staticCallData,
expectedResultHash,
);
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
});
it('should be successful if the staticCallTarget is not a contract and no return value is expected', async () => {
const staticCallData = '0x0102030405060708';
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = assetDataInterface
.StaticCall(toAddress, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
const assetData = assetDataUtils.encodeStaticCallAssetData(toAddress, staticCallData, expectedResultHash);
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
});
it('should be successful if a function call with one static input returns the correct value', async () => {
const staticCallData = staticCallTarget.isOddNumber(new BigNumber(1)).getABIEncodedTransactionData();
const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(1));
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
const assetData = assetDataUtils.encodeStaticCallAssetData(
staticCallTarget.address,
staticCallData,
expectedResultHash,
);
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
});
it('should be successful if a function with one dynamic input is successful', async () => {
const dynamicInput = '0x0102030405060708';
const staticCallData = staticCallTarget.dynamicInputFunction(dynamicInput).getABIEncodedTransactionData();
const staticCallData = staticCallTarget.dynamicInputFunction.getABIEncodedTransactionData(dynamicInput);
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
const assetData = assetDataUtils.encodeStaticCallAssetData(
staticCallTarget.address,
staticCallData,
expectedResultHash,
);
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
});
it('should be successful if a function call returns a complex type', async () => {
const a = new BigNumber(1);
const b = new BigNumber(2);
const staticCallData = staticCallTarget.returnComplexType(a, b).getABIEncodedTransactionData();
const staticCallData = staticCallTarget.returnComplexType.getABIEncodedTransactionData(a, b);
const abiEncoder = new AbiEncoder.DynamicBytes({
name: '',
type: 'bytes',
@@ -234,12 +231,12 @@ describe('StaticCallProxy', () => {
const expectedResultHash = ethUtil.bufferToHex(
ethUtil.sha3(ethUtil.toBuffer(encodedExpectedResultWithOffset)),
);
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
const assetData = assetDataUtils.encodeStaticCallAssetData(
staticCallTarget.address,
staticCallData,
expectedResultHash,
);
await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
});
});
});

View File

@@ -1,370 +0,0 @@
import {
blockchainTests,
constants,
expect,
filterLogs,
filterLogsToArguments,
getRandomInteger,
Numberish,
randomAddress,
} from '@0x/contracts-test-utils';
import { AssetProxyId } from '@0x/types';
import { BigNumber, hexUtils } from '@0x/utils';
import { DecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import {
TestUniswapBridgeContract,
TestUniswapBridgeEthToTokenTransferInputEventArgs as EthToTokenTransferInputArgs,
TestUniswapBridgeEvents as ContractEvents,
TestUniswapBridgeTokenApproveEventArgs as TokenApproveArgs,
TestUniswapBridgeTokenToEthSwapInputEventArgs as TokenToEthSwapInputArgs,
TestUniswapBridgeTokenToTokenTransferInputEventArgs as TokenToTokenTransferInputArgs,
TestUniswapBridgeTokenTransferEventArgs as TokenTransferArgs,
TestUniswapBridgeWethDepositEventArgs as WethDepositArgs,
TestUniswapBridgeWethWithdrawEventArgs as WethWithdrawArgs,
} from './wrappers';
blockchainTests.resets('UniswapBridge unit tests', env => {
let testContract: TestUniswapBridgeContract;
let wethTokenAddress: string;
before(async () => {
testContract = await TestUniswapBridgeContract.deployFrom0xArtifactAsync(
artifacts.TestUniswapBridge,
env.provider,
env.txDefaults,
artifacts,
);
wethTokenAddress = await testContract.wethToken().callAsync();
});
describe('isValidSignature()', () => {
it('returns success bytes', async () => {
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
const result = await testContract
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
.callAsync();
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
});
});
describe('bridgeTransferFrom()', () => {
interface WithdrawToOpts {
fromTokenAddress: string;
toTokenAddress: string;
fromTokenBalance: Numberish;
toAddress: string;
amount: Numberish;
exchangeRevertReason: string;
exchangeFillAmount: Numberish;
toTokenRevertReason: string;
fromTokenRevertReason: string;
}
function createWithdrawToOpts(opts?: Partial<WithdrawToOpts>): WithdrawToOpts {
return {
fromTokenAddress: constants.NULL_ADDRESS,
toTokenAddress: constants.NULL_ADDRESS,
fromTokenBalance: getRandomInteger(1, 1e18),
toAddress: randomAddress(),
amount: getRandomInteger(1, 1e18),
exchangeRevertReason: '',
exchangeFillAmount: getRandomInteger(1, 1e18),
toTokenRevertReason: '',
fromTokenRevertReason: '',
...opts,
};
}
interface WithdrawToResult {
opts: WithdrawToOpts;
result: string;
logs: DecodedLogs;
blockTime: number;
}
async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> {
const _opts = createWithdrawToOpts(opts);
const callData = { value: new BigNumber(_opts.exchangeFillAmount) };
// Create the "from" token and exchange.
const createFromTokenFn = testContract.createTokenAndExchange(
_opts.fromTokenAddress,
_opts.exchangeRevertReason,
);
[_opts.fromTokenAddress] = await createFromTokenFn.callAsync(callData);
await createFromTokenFn.awaitTransactionSuccessAsync(callData);
// Create the "to" token and exchange.
const createToTokenFn = testContract.createTokenAndExchange(
_opts.toTokenAddress,
_opts.exchangeRevertReason,
);
[_opts.toTokenAddress] = await createToTokenFn.callAsync(callData);
await createToTokenFn.awaitTransactionSuccessAsync(callData);
await testContract
.setTokenRevertReason(_opts.toTokenAddress, _opts.toTokenRevertReason)
.awaitTransactionSuccessAsync();
await testContract
.setTokenRevertReason(_opts.fromTokenAddress, _opts.fromTokenRevertReason)
.awaitTransactionSuccessAsync();
// Set the token balance for the token we're converting from.
await testContract.setTokenBalance(_opts.fromTokenAddress).awaitTransactionSuccessAsync({
value: new BigNumber(_opts.fromTokenBalance),
});
// Call bridgeTransferFrom().
const bridgeTransferFromFn = testContract.bridgeTransferFrom(
// The "to" token address.
_opts.toTokenAddress,
// The "from" address.
randomAddress(),
// The "to" address.
_opts.toAddress,
// The amount to transfer to "to"
new BigNumber(_opts.amount),
// ABI-encoded "from" token address.
hexUtils.leftPad(_opts.fromTokenAddress),
);
const result = await bridgeTransferFromFn.callAsync();
const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
return {
opts: _opts,
result,
logs: (receipt.logs as any) as DecodedLogs,
blockTime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber),
};
}
async function getExchangeForTokenAsync(tokenAddress: string): Promise<string> {
return testContract.getExchange(tokenAddress).callAsync();
}
it('returns magic bytes on success', async () => {
const { result } = await withdrawToAsync();
expect(result).to.eq(AssetProxyId.ERC20Bridge);
});
it('just transfers tokens to `to` if the same tokens are in play', async () => {
const createTokenFn = await testContract.createTokenAndExchange(constants.NULL_ADDRESS, '');
const [tokenAddress] = await createTokenFn.callAsync();
await createTokenFn.awaitTransactionSuccessAsync();
const { opts, result, logs } = await withdrawToAsync({
fromTokenAddress: tokenAddress,
toTokenAddress: tokenAddress,
});
expect(result).to.eq(AssetProxyId.ERC20Bridge);
const transfers = filterLogsToArguments<TokenTransferArgs>(logs, ContractEvents.TokenTransfer);
expect(transfers.length).to.eq(1);
expect(transfers[0].token).to.eq(tokenAddress);
expect(transfers[0].from).to.eq(testContract.address);
expect(transfers[0].to).to.eq(opts.toAddress);
expect(transfers[0].amount).to.bignumber.eq(opts.amount);
});
describe('token -> token', () => {
it('calls `IUniswapExchange.tokenToTokenTransferInput()', async () => {
const { opts, logs, blockTime } = await withdrawToAsync();
const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress);
const calls = filterLogsToArguments<TokenToTokenTransferInputArgs>(
logs,
ContractEvents.TokenToTokenTransferInput,
);
expect(calls.length).to.eq(1);
expect(calls[0].exchange).to.eq(exchangeAddress);
expect(calls[0].tokensSold).to.bignumber.eq(opts.fromTokenBalance);
expect(calls[0].minTokensBought).to.bignumber.eq(opts.amount);
expect(calls[0].minEthBought).to.bignumber.eq(1);
expect(calls[0].deadline).to.bignumber.eq(blockTime);
expect(calls[0].recipient).to.eq(opts.toAddress);
expect(calls[0].toTokenAddress).to.eq(opts.toTokenAddress);
});
it('sets allowance for "from" token', async () => {
const { opts, logs } = await withdrawToAsync();
const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress);
expect(approvals.length).to.eq(1);
expect(approvals[0].spender).to.eq(exchangeAddress);
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
});
it('sets allowance for "from" token on subsequent calls', async () => {
const { opts } = await withdrawToAsync();
const { logs } = await withdrawToAsync(opts);
const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress);
expect(approvals.length).to.eq(1);
expect(approvals[0].spender).to.eq(exchangeAddress);
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
});
it('fails if "from" token does not exist', async () => {
const tx = testContract
.bridgeTransferFrom(
randomAddress(),
randomAddress(),
randomAddress(),
getRandomInteger(1, 1e18),
hexUtils.leftPad(randomAddress()),
)
.awaitTransactionSuccessAsync();
return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
});
it('fails if the exchange fails', async () => {
const revertReason = 'FOOBAR';
const tx = withdrawToAsync({
exchangeRevertReason: revertReason,
});
return expect(tx).to.eventually.be.rejectedWith(revertReason);
});
});
describe('token -> ETH', () => {
it('calls `IUniswapExchange.tokenToEthSwapInput()`, `WETH.deposit()`, then `transfer()`', async () => {
const { opts, logs, blockTime } = await withdrawToAsync({
toTokenAddress: wethTokenAddress,
});
const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress);
let calls: any = filterLogs<TokenToEthSwapInputArgs>(logs, ContractEvents.TokenToEthSwapInput);
expect(calls.length).to.eq(1);
expect(calls[0].args.exchange).to.eq(exchangeAddress);
expect(calls[0].args.tokensSold).to.bignumber.eq(opts.fromTokenBalance);
expect(calls[0].args.minEthBought).to.bignumber.eq(opts.amount);
expect(calls[0].args.deadline).to.bignumber.eq(blockTime);
calls = filterLogs<WethDepositArgs>(
logs.slice(calls[0].logIndex as number),
ContractEvents.WethDeposit,
);
expect(calls.length).to.eq(1);
expect(calls[0].args.amount).to.bignumber.eq(opts.exchangeFillAmount);
calls = filterLogs<TokenTransferArgs>(
logs.slice(calls[0].logIndex as number),
ContractEvents.TokenTransfer,
);
expect(calls.length).to.eq(1);
expect(calls[0].args.token).to.eq(opts.toTokenAddress);
expect(calls[0].args.from).to.eq(testContract.address);
expect(calls[0].args.to).to.eq(opts.toAddress);
expect(calls[0].args.amount).to.bignumber.eq(opts.exchangeFillAmount);
});
it('sets allowance for "from" token', async () => {
const { opts, logs } = await withdrawToAsync({
toTokenAddress: wethTokenAddress,
});
const transfers = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress);
expect(transfers.length).to.eq(1);
expect(transfers[0].spender).to.eq(exchangeAddress);
expect(transfers[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
});
it('sets allowance for "from" token on subsequent calls', async () => {
const { opts } = await withdrawToAsync({
toTokenAddress: wethTokenAddress,
});
const { logs } = await withdrawToAsync(opts);
const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
const exchangeAddress = await getExchangeForTokenAsync(opts.fromTokenAddress);
expect(approvals.length).to.eq(1);
expect(approvals[0].spender).to.eq(exchangeAddress);
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
});
it('fails if "from" token does not exist', async () => {
const tx = testContract
.bridgeTransferFrom(
randomAddress(),
randomAddress(),
randomAddress(),
getRandomInteger(1, 1e18),
hexUtils.leftPad(wethTokenAddress),
)
.awaitTransactionSuccessAsync();
return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
});
it('fails if `WETH.deposit()` fails', async () => {
const revertReason = 'FOOBAR';
const tx = withdrawToAsync({
toTokenAddress: wethTokenAddress,
toTokenRevertReason: revertReason,
});
return expect(tx).to.eventually.be.rejectedWith(revertReason);
});
it('fails if the exchange fails', async () => {
const revertReason = 'FOOBAR';
const tx = withdrawToAsync({
toTokenAddress: wethTokenAddress,
exchangeRevertReason: revertReason,
});
return expect(tx).to.eventually.be.rejectedWith(revertReason);
});
});
describe('ETH -> token', () => {
it('calls `WETH.withdraw()`, then `IUniswapExchange.ethToTokenTransferInput()`', async () => {
const { opts, logs, blockTime } = await withdrawToAsync({
fromTokenAddress: wethTokenAddress,
});
const exchangeAddress = await getExchangeForTokenAsync(opts.toTokenAddress);
let calls: any = filterLogs<WethWithdrawArgs>(logs, ContractEvents.WethWithdraw);
expect(calls.length).to.eq(1);
expect(calls[0].args.amount).to.bignumber.eq(opts.fromTokenBalance);
calls = filterLogs<EthToTokenTransferInputArgs>(
logs.slice(calls[0].logIndex as number),
ContractEvents.EthToTokenTransferInput,
);
expect(calls.length).to.eq(1);
expect(calls[0].args.exchange).to.eq(exchangeAddress);
expect(calls[0].args.minTokensBought).to.bignumber.eq(opts.amount);
expect(calls[0].args.deadline).to.bignumber.eq(blockTime);
expect(calls[0].args.recipient).to.eq(opts.toAddress);
});
it('does not set any allowance', async () => {
const { logs } = await withdrawToAsync({
fromTokenAddress: wethTokenAddress,
});
const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
expect(approvals).to.be.empty('');
});
it('fails if "to" token does not exist', async () => {
const tx = testContract
.bridgeTransferFrom(
wethTokenAddress,
randomAddress(),
randomAddress(),
getRandomInteger(1, 1e18),
hexUtils.leftPad(randomAddress()),
)
.awaitTransactionSuccessAsync();
return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
});
it('fails if the `WETH.withdraw()` fails', async () => {
const revertReason = 'FOOBAR';
const tx = withdrawToAsync({
fromTokenAddress: wethTokenAddress,
fromTokenRevertReason: revertReason,
});
return expect(tx).to.eventually.be.rejectedWith(revertReason);
});
it('fails if the exchange fails', async () => {
const revertReason = 'FOOBAR';
const tx = withdrawToAsync({
fromTokenAddress: wethTokenAddress,
exchangeRevertReason: revertReason,
});
return expect(tx).to.eventually.be.rejectedWith(revertReason);
});
});
});
});

View File

@@ -7,14 +7,13 @@ import {
LogDecoder,
txDefaults,
} from '@0x/contracts-test-utils';
import { assetDataUtils } from '@0x/order-utils';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { ERC1155ProxyContract, IAssetDataContract, IAssetProxyContract } from './wrappers';
import { artifacts, ERC1155ProxyContract, IAssetProxyContract } from '../../src';
export class ERC1155ProxyWrapper {
private readonly _tokenOwnerAddresses: string[];
@@ -27,7 +26,6 @@ export class ERC1155ProxyWrapper {
private readonly _logDecoder: LogDecoder;
private readonly _dummyTokenWrappers: Erc1155Wrapper[];
private readonly _assetProxyInterface: IAssetProxyContract;
private readonly _assetDataInterface: IAssetDataContract;
private _proxyContract?: ERC1155ProxyContract;
private _proxyIdIfExists?: string;
private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} };
@@ -39,7 +37,6 @@ export class ERC1155ProxyWrapper {
this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts);
this._dummyTokenWrappers = [];
this._assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider);
this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
this._tokenOwnerAddresses = tokenOwnerAddresses;
this._contractOwnerAddress = contractOwnerAddress;
this._fungibleTokenIds = [];
@@ -59,7 +56,7 @@ export class ERC1155ProxyWrapper {
txDefaults,
artifacts,
);
const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._contractOwnerAddress);
const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._provider, this._contractOwnerAddress);
this._dummyTokenWrappers.push(erc1155Wrapper);
}
return this._dummyTokenWrappers;
@@ -75,7 +72,7 @@ export class ERC1155ProxyWrapper {
txDefaults,
artifacts,
);
this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync();
this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync();
return this._proxyContract;
}
/**
@@ -98,7 +95,7 @@ export class ERC1155ProxyWrapper {
* @param extraData extra data to append to `transferFrom` transaction. Optional.
* @return abi encoded tx data.
*/
public async getTransferFromAbiEncodedTxDataAsync(
public getTransferFromAbiEncodedTxData(
from: string,
to: string,
contractAddress: string,
@@ -108,17 +105,23 @@ export class ERC1155ProxyWrapper {
receiverCallbackData: string,
authorizedSender: string,
assetData_?: string,
): Promise<string> {
): string {
this._validateProxyContractExistsOrThrow();
const assetData =
assetData_ === undefined
? this._assetDataInterface
.ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData()
? assetDataUtils.encodeERC1155AssetData(
contractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
: assetData_;
const data = this._assetProxyInterface
.transferFrom(assetData, from, to, valueMultiplier)
.getABIEncodedTransactionData();
const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
from,
to,
valueMultiplier,
);
return data;
}
/**
@@ -166,13 +169,19 @@ export class ERC1155ProxyWrapper {
this._validateProxyContractExistsOrThrow();
const assetData =
assetData_ === undefined
? this._assetDataInterface
.ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData()
? assetDataUtils.encodeERC1155AssetData(
contractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
: assetData_;
const data = this._assetProxyInterface
.transferFrom(assetData, from, to, valueMultiplier)
.getABIEncodedTransactionData();
const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData(
assetData,
from,
to,
valueMultiplier,
);
const txHash = await this._web3Wrapper.sendTransactionAsync({
to: (this._proxyContract as ERC1155ProxyContract).address,
data,
@@ -327,22 +336,6 @@ export class ERC1155ProxyWrapper {
};
return holdingsByOwner;
}
/**
* @dev Set the approval for the proxy on behalf of `userAddress` .
* @param userAddress owner of ERC1155 tokens.
* @param contractAddress address of ERC1155 contract.
* @param isApproved Whether to approve the proxy for all or not.
*/
public async setProxyAllowanceForAllAsync(
userAddress: string,
contractAddress: string,
isApproved: boolean,
): Promise<void> {
this._validateProxyContractExistsOrThrow();
const tokenWrapper = this.getContractWrapper(contractAddress);
const operator = (this._proxyContract as ERC1155ProxyContract).address;
await tokenWrapper.setApprovalForAllAsync(userAddress, operator, isApproved);
}
/**
* @dev Checks if proxy is approved to transfer tokens on behalf of `userAddress`.
* @param userAddress owner of ERC1155 tokens.
@@ -353,7 +346,7 @@ export class ERC1155ProxyWrapper {
this._validateProxyContractExistsOrThrow();
const tokenContract = this._getContractFromAddress(contractAddress);
const operator = (this._proxyContract as ERC1155ProxyContract).address;
const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync();
const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator);
return didApproveAll;
}
public getFungibleTokenIds(): BigNumber[] {

View File

@@ -1,19 +1,17 @@
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils';
import { assetDataUtils } from '@0x/order-utils';
import { BigNumber } from '@0x/utils';
import { ZeroExProvider } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { ERC20ProxyContract, IAssetDataContract } from './wrappers';
import { artifacts, ERC20ProxyContract } from '../../src';
export class ERC20Wrapper {
private readonly _tokenOwnerAddresses: string[];
private readonly _contractOwnerAddress: string;
private readonly _provider: ZeroExProvider;
private readonly _dummyTokenContracts: DummyERC20TokenContract[];
private readonly _assetDataInterface: IAssetDataContract;
private _proxyContract?: ERC20ProxyContract;
private _proxyIdIfExists?: string;
/**
@@ -28,7 +26,6 @@ export class ERC20Wrapper {
this._provider = provider;
this._tokenOwnerAddresses = tokenOwnerAddresses;
this._contractOwnerAddress = contractOwnerAddress;
this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
}
public async deployDummyTokensAsync(
numberToDeploy: number,
@@ -57,7 +54,7 @@ export class ERC20Wrapper {
txDefaults,
artifacts,
);
this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync();
this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync();
return this._proxyContract;
}
public getProxyId(): string {
@@ -69,39 +66,50 @@ export class ERC20Wrapper {
this._validateProxyContractExistsOrThrow();
for (const dummyTokenContract of this._dummyTokenContracts) {
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
await dummyTokenContract
.setBalance(tokenOwnerAddress, constants.INITIAL_ERC20_BALANCE)
.awaitTransactionSuccessAsync({ from: this._contractOwnerAddress });
await dummyTokenContract
.approve((this._proxyContract as ERC20ProxyContract).address, constants.INITIAL_ERC20_ALLOWANCE)
.awaitTransactionSuccessAsync({ from: tokenOwnerAddress });
await dummyTokenContract.setBalance.awaitTransactionSuccessAsync(
tokenOwnerAddress,
constants.INITIAL_ERC20_BALANCE,
{ from: this._contractOwnerAddress },
constants.AWAIT_TRANSACTION_MINED_MS,
);
await dummyTokenContract.approve.awaitTransactionSuccessAsync(
(this._proxyContract as ERC20ProxyContract).address,
constants.INITIAL_ERC20_ALLOWANCE,
{ from: tokenOwnerAddress },
constants.AWAIT_TRANSACTION_MINED_MS,
);
}
}
}
public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
const balance = new BigNumber(await tokenContract.balanceOf(userAddress).callAsync());
const tokenContract = this._getTokenContractFromAssetData(assetData);
const balance = new BigNumber(await tokenContract.balanceOf.callAsync(userAddress));
return balance;
}
public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
await tokenContract
.setBalance(userAddress, amount)
.awaitTransactionSuccessAsync(
{ from: this._contractOwnerAddress },
{ pollingIntervalMs: constants.AWAIT_TRANSACTION_MINED_MS },
);
const tokenContract = this._getTokenContractFromAssetData(assetData);
await tokenContract.setBalance.awaitTransactionSuccessAsync(
userAddress,
amount,
{ from: this._contractOwnerAddress },
constants.AWAIT_TRANSACTION_MINED_MS,
);
}
public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
const tokenContract = this._getTokenContractFromAssetData(assetData);
const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
const allowance = new BigNumber(await tokenContract.allowance(userAddress, proxyAddress).callAsync());
const allowance = new BigNumber(await tokenContract.allowance.callAsync(userAddress, proxyAddress));
return allowance;
}
public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
const tokenContract = this._getTokenContractFromAssetData(assetData);
const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
await tokenContract.approve(proxyAddress, amount).awaitTransactionSuccessAsync({ from: userAddress });
await tokenContract.approve.awaitTransactionSuccessAsync(
proxyAddress,
amount,
{ from: userAddress },
constants.AWAIT_TRANSACTION_MINED_MS,
);
}
public async getBalancesAsync(): Promise<ERC20BalancesByOwner> {
this._validateDummyTokenContractsExistOrThrow();
@@ -110,7 +118,7 @@ export class ERC20Wrapper {
const balanceInfo: Array<{ tokenOwnerAddress: string; tokenAddress: string }> = [];
for (const dummyTokenContract of this._dummyTokenContracts) {
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
balances.push(await dummyTokenContract.balanceOf(tokenOwnerAddress).callAsync());
balances.push(await dummyTokenContract.balanceOf.callAsync(tokenOwnerAddress));
balanceInfo.push({
tokenOwnerAddress,
tokenAddress: dummyTokenContract.address,
@@ -143,8 +151,9 @@ export class ERC20Wrapper {
const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address);
return tokenAddresses;
}
private async _getTokenContractFromAssetDataAsync(assetData: string): Promise<DummyERC20TokenContract> {
const tokenAddress = this._assetDataInterface.getABIDecodedTransactionData<string>('ERC20Token', assetData); // tslint:disable-line:no-unused-variable
private _getTokenContractFromAssetData(assetData: string): DummyERC20TokenContract {
const erc20ProxyData = assetDataUtils.decodeERC20AssetData(assetData);
const tokenAddress = erc20ProxyData.tokenAddress;
const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
if (tokenContractIfExists === undefined) {
throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);

View File

@@ -5,9 +5,7 @@ import { BigNumber } from '@0x/utils';
import { ZeroExProvider } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { ERC721ProxyContract } from './wrappers';
import { artifacts, ERC721ProxyContract } from '../../src';
export class ERC721Wrapper {
private readonly _tokenOwnerAddresses: string[];
@@ -46,7 +44,7 @@ export class ERC721Wrapper {
txDefaults,
artifacts,
);
this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync();
this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync();
return this._proxyContract;
}
public getProxyId(): string {
@@ -73,14 +71,14 @@ export class ERC721Wrapper {
}
this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId);
await this.approveProxyForAllAsync(dummyTokenContract.address, tokenOwnerAddress, true);
await this.approveProxyAsync(dummyTokenContract.address, tokenId);
}
}
}
}
public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const owner = await tokenContract.ownerOf(tokenId).callAsync();
const owner = await tokenContract.ownerOf.callAsync(tokenId);
const doesExist = owner !== constants.NULL_ADDRESS;
return doesExist;
}
@@ -88,21 +86,26 @@ export class ERC721Wrapper {
const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
await this.approveAsync(proxyAddress, tokenAddress, tokenId);
}
public async approveProxyForAllAsync(
tokenAddress: string,
ownerAddress: string,
isApproved: boolean,
): Promise<void> {
public async approveProxyForAllAsync(tokenAddress: string, tokenId: BigNumber, isApproved: boolean): Promise<void> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
await tokenContract.setApprovalForAll(proxyAddress, isApproved).awaitTransactionSuccessAsync({
from: ownerAddress,
});
await tokenContract.setApprovalForAll.awaitTransactionSuccessAsync(
proxyAddress,
isApproved,
{ from: tokenOwner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
}
public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
await tokenContract.approve(to, tokenId).awaitTransactionSuccessAsync({ from: tokenOwner });
await tokenContract.approve.awaitTransactionSuccessAsync(
to,
tokenId,
{ from: tokenOwner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
}
public async transferFromAsync(
tokenAddress: string,
@@ -111,28 +114,40 @@ export class ERC721Wrapper {
userAddress: string,
): Promise<void> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
await tokenContract.transferFrom(currentOwner, userAddress, tokenId).awaitTransactionSuccessAsync({
from: currentOwner,
});
await tokenContract.transferFrom.awaitTransactionSuccessAsync(
currentOwner,
userAddress,
tokenId,
{ from: currentOwner },
constants.AWAIT_TRANSACTION_MINED_MS,
);
}
public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
await tokenContract.mint(userAddress, tokenId).awaitTransactionSuccessAsync({
from: this._contractOwnerAddress,
});
await tokenContract.mint.awaitTransactionSuccessAsync(
userAddress,
tokenId,
{ from: this._contractOwnerAddress },
constants.AWAIT_TRANSACTION_MINED_MS,
);
}
public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
await tokenContract.burn(owner, tokenId).awaitTransactionSuccessAsync({ from: this._contractOwnerAddress });
await tokenContract.burn.awaitTransactionSuccessAsync(
owner,
tokenId,
{ from: this._contractOwnerAddress },
constants.AWAIT_TRANSACTION_MINED_MS,
);
}
public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise<string> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const owner = await tokenContract.ownerOf(tokenId).callAsync();
const owner = await tokenContract.ownerOf.callAsync(tokenId);
return owner;
}
public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const tokenOwner = await tokenContract.ownerOf(tokenId).callAsync();
const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId);
const isOwner = tokenOwner === userAddress;
return isOwner;
}
@@ -140,13 +155,13 @@ export class ERC721Wrapper {
this._validateProxyContractExistsOrThrow();
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const operator = (this._proxyContract as ERC721ProxyContract).address;
const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync();
const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator);
return didApproveAll;
}
public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
this._validateProxyContractExistsOrThrow();
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const approvedAddress = await tokenContract.getApproved(tokenId).callAsync();
const approvedAddress = await tokenContract.getApproved.callAsync(tokenId);
const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
const isProxyAnApprovedOperator = approvedAddress === proxyAddress;
return isProxyAnApprovedOperator;
@@ -163,7 +178,7 @@ export class ERC721Wrapper {
dummyTokenContract.address
];
for (const tokenId of initialTokenOwnerIds) {
tokenOwnerAddresses.push(await dummyTokenContract.ownerOf(tokenId).callAsync());
tokenOwnerAddresses.push(await dummyTokenContract.ownerOf.callAsync(tokenId));
tokenInfo.push({
tokenId,
tokenAddress: dummyTokenContract.address,

View File

@@ -0,0 +1,3 @@
export * from './erc20_wrapper';
export * from './erc721_wrapper';
export * from './erc1155_proxy_wrapper';

View File

@@ -1,40 +0,0 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../test/generated-wrappers/chai_bridge';
export * from '../test/generated-wrappers/curve_bridge';
export * from '../test/generated-wrappers/dydx_bridge';
export * from '../test/generated-wrappers/erc1155_proxy';
export * from '../test/generated-wrappers/erc20_bridge_proxy';
export * from '../test/generated-wrappers/erc20_proxy';
export * from '../test/generated-wrappers/erc721_proxy';
export * from '../test/generated-wrappers/eth2_dai_bridge';
export * from '../test/generated-wrappers/i_asset_data';
export * from '../test/generated-wrappers/i_asset_proxy';
export * from '../test/generated-wrappers/i_asset_proxy_dispatcher';
export * from '../test/generated-wrappers/i_authorizable';
export * from '../test/generated-wrappers/i_chai';
export * from '../test/generated-wrappers/i_curve';
export * from '../test/generated-wrappers/i_dydx';
export * from '../test/generated-wrappers/i_dydx_bridge';
export * from '../test/generated-wrappers/i_erc20_bridge';
export * from '../test/generated-wrappers/i_eth2_dai';
export * from '../test/generated-wrappers/i_kyber_network_proxy';
export * from '../test/generated-wrappers/i_uniswap_exchange';
export * from '../test/generated-wrappers/i_uniswap_exchange_factory';
export * from '../test/generated-wrappers/kyber_bridge';
export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher';
export * from '../test/generated-wrappers/mixin_authorizable';
export * from '../test/generated-wrappers/multi_asset_proxy';
export * from '../test/generated-wrappers/ownable';
export * from '../test/generated-wrappers/static_call_proxy';
export * from '../test/generated-wrappers/test_chai_bridge';
export * from '../test/generated-wrappers/test_dydx_bridge';
export * from '../test/generated-wrappers/test_erc20_bridge';
export * from '../test/generated-wrappers/test_eth2_dai_bridge';
export * from '../test/generated-wrappers/test_kyber_bridge';
export * from '../test/generated-wrappers/test_static_call_target';
export * from '../test/generated-wrappers/test_uniswap_bridge';
export * from '../test/generated-wrappers/uniswap_bridge';

View File

@@ -1,96 +0,0 @@
/**
* Use this file to configure your truffle project. It's seeded with some
* common settings for different networks and features like migrations,
* compilation and testing. Uncomment the ones you need or modify
* them to suit your project as necessary.
*
* More information about configuration can be found at:
*
* truffleframework.com/docs/advanced/configuration
*
* To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
* to sign your transactions before they're sent to a remote public node. Infura accounts
* are available for free at: infura.io/register.
*
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
* phrase from a file you've .gitignored so it doesn't accidentally become public.
*
*/
// const HDWalletProvider = require('truffle-hdwallet-provider');
// const infuraKey = "fj4jll3k.....";
//
// const fs = require('fs');
// const mnemonic = fs.readFileSync(".secret").toString().trim();
module.exports = {
/**
* Networks define how you connect to your ethereum client and let you set the
* defaults web3 uses to send transactions. If you don't specify one truffle
* will spin up a development blockchain for you on port 9545 when you
* run `develop` or `test`. You can ask a truffle command to use a specific
* network from the command line, e.g
*
* $ truffle test --network <network-name>
*/
networks: {
// Useful for testing. The `development` name is special - truffle uses it by default
// if it's defined here and no other network is specified at the command line.
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
// tab if you use this network and you must also set the `host`, `port` and `network_id`
// options below to some value.
//
// development: {
// host: "127.0.0.1", // Localhost (default: none)
// port: 8545, // Standard Ethereum port (default: none)
// network_id: "*", // Any network (default: none)
// },
// Another network with more advanced options...
// advanced: {
// port: 8777, // Custom port
// network_id: 1342, // Custom network
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
// from: <address>, // Account to send txs from (default: accounts[0])
// websockets: true // Enable EventEmitter interface for web3 (default: false)
// },
// Useful for deploying to a public network.
// NB: It's important to wrap the provider as a function.
// ropsten: {
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
// network_id: 3, // Ropsten's id
// gas: 5500000, // Ropsten has a lower block limit than mainnet
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
// },
// Useful for private networks
// private: {
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
// network_id: 2111, // This network is yours, in the cloud.
// production: true // Treats this network as if it was a public net. (default: false)
// }
},
// Set default mocha options here, use special reporters etc.
mocha: {
// timeout: 100000
},
// Configure your compilers
compilers: {
solc: {
version: '0.5.9',
settings: {
evmVersion: 'istanbul',
optimizer: {
enabled: true,
runs: 1000000,
details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true },
},
},
},
},
};

View File

@@ -3,76 +3,16 @@
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"generated-artifacts/ChaiBridge.json",
"generated-artifacts/CurveBridge.json",
"generated-artifacts/DydxBridge.json",
"generated-artifacts/ERC1155Proxy.json",
"generated-artifacts/ERC20BridgeProxy.json",
"generated-artifacts/ERC20Proxy.json",
"generated-artifacts/ERC721Proxy.json",
"generated-artifacts/Eth2DaiBridge.json",
"generated-artifacts/IAssetData.json",
"generated-artifacts/IAssetProxy.json",
"generated-artifacts/IAssetProxyDispatcher.json",
"generated-artifacts/IAuthorizable.json",
"generated-artifacts/IChai.json",
"generated-artifacts/ICurve.json",
"generated-artifacts/IDydx.json",
"generated-artifacts/IDydxBridge.json",
"generated-artifacts/IERC20Bridge.json",
"generated-artifacts/IEth2Dai.json",
"generated-artifacts/IKyberNetworkProxy.json",
"generated-artifacts/IUniswapExchange.json",
"generated-artifacts/IUniswapExchangeFactory.json",
"generated-artifacts/KyberBridge.json",
"generated-artifacts/MixinAssetProxyDispatcher.json",
"generated-artifacts/MixinAuthorizable.json",
"generated-artifacts/MultiAssetProxy.json",
"generated-artifacts/Ownable.json",
"generated-artifacts/StaticCallProxy.json",
"generated-artifacts/TestChaiBridge.json",
"generated-artifacts/TestDydxBridge.json",
"generated-artifacts/TestERC20Bridge.json",
"generated-artifacts/TestEth2DaiBridge.json",
"generated-artifacts/TestKyberBridge.json",
"generated-artifacts/TestStaticCallTarget.json",
"generated-artifacts/TestUniswapBridge.json",
"generated-artifacts/UniswapBridge.json",
"test/generated-artifacts/ChaiBridge.json",
"test/generated-artifacts/CurveBridge.json",
"test/generated-artifacts/DydxBridge.json",
"test/generated-artifacts/ERC1155Proxy.json",
"test/generated-artifacts/ERC20BridgeProxy.json",
"test/generated-artifacts/ERC20Proxy.json",
"test/generated-artifacts/ERC721Proxy.json",
"test/generated-artifacts/Eth2DaiBridge.json",
"test/generated-artifacts/IAssetData.json",
"test/generated-artifacts/IAssetProxy.json",
"test/generated-artifacts/IAssetProxyDispatcher.json",
"test/generated-artifacts/IAuthorizable.json",
"test/generated-artifacts/IChai.json",
"test/generated-artifacts/ICurve.json",
"test/generated-artifacts/IDydx.json",
"test/generated-artifacts/IDydxBridge.json",
"test/generated-artifacts/IERC20Bridge.json",
"test/generated-artifacts/IEth2Dai.json",
"test/generated-artifacts/IKyberNetworkProxy.json",
"test/generated-artifacts/IUniswapExchange.json",
"test/generated-artifacts/IUniswapExchangeFactory.json",
"test/generated-artifacts/KyberBridge.json",
"test/generated-artifacts/MixinAssetProxyDispatcher.json",
"test/generated-artifacts/MixinAuthorizable.json",
"test/generated-artifacts/MultiAssetProxy.json",
"test/generated-artifacts/Ownable.json",
"test/generated-artifacts/StaticCallProxy.json",
"test/generated-artifacts/TestChaiBridge.json",
"test/generated-artifacts/TestDydxBridge.json",
"test/generated-artifacts/TestERC20Bridge.json",
"test/generated-artifacts/TestEth2DaiBridge.json",
"test/generated-artifacts/TestKyberBridge.json",
"test/generated-artifacts/TestStaticCallTarget.json",
"test/generated-artifacts/TestUniswapBridge.json",
"test/generated-artifacts/UniswapBridge.json"
"generated-artifacts/TestStaticCallTarget.json"
],
"exclude": ["./deploy/solc/solc_bin"]
}

View File

@@ -1,10 +0,0 @@
# Blacklist all files
.*
*
# Whitelist lib
!lib/**/*
# Whitelist Solidity contracts
!contracts/src/**/*
# Blacklist tests in lib
/lib/test/*
# Package specific ignore

View File

@@ -1,66 +0,0 @@
[
{
"timestamp": 1582837861,
"version": "1.1.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1582677073,
"version": "1.1.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1582623685,
"version": "1.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.1.0",
"changes": [
{
"note": "Added decoders for broker data",
"pr": 2484
}
],
"timestamp": 1581748629
},
{
"timestamp": 1581204851,
"version": "1.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1580988106,
"version": "1.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.0.0",
"changes": [
{
"note": "Created package",
"pr": "2455"
}
]
}
]

View File

@@ -1,34 +0,0 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v1.1.3 - _February 27, 2020_
* Dependencies updated
## v1.1.2 - _February 26, 2020_
* Dependencies updated
## v1.1.1 - _February 25, 2020_
* Dependencies updated
## v1.1.0 - _February 15, 2020_
* Added decoders for broker data (#2484)
## v1.0.2 - _February 8, 2020_
* Dependencies updated
## v1.0.1 - _February 6, 2020_
* Dependencies updated
## v1.0.0 - _Invalid date_
* Created package (#2455)

View File

@@ -1 +0,0 @@
[]

View File

@@ -1,73 +0,0 @@
## Broker
This package contains the implementation of the [`Broker` contract](https://github.com/0xProject/ZEIPs/issues/75). This contract serves as an entry-point to the 0x Exchange for the filling of property-based orders. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package.
## Installation
**Install**
```bash
npm install @0x/contracts-broker --save
```
## Bug bounty
A bug bounty for the 3.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program).
## Contributing
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
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/contracts-broker yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0x/contracts-broker yarn watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```
#### Testing options
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).

View File

@@ -1,27 +0,0 @@
{
"artifactsDir": "./test/generated-artifacts",
"contractsDir": "./contracts",
"useDockerisedSolc": false,
"isOfflineMode": false,
"shouldSaveStandardInput": true,
"compilerSettings": {
"evmVersion": "istanbul",
"optimizer": {
"enabled": true,
"runs": 1000000,
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
},
"outputSelection": {
"*": {
"*": [
"abi",
"devdoc",
"evm.bytecode.object",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.object",
"evm.deployedBytecode.sourceMap"
]
}
}
}
}

View File

@@ -1,314 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-extensions/contracts/src/LibAssetDataTransfer.sol";
import "@0x/contracts-extensions/contracts/src/MixinWethUtils.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "./interfaces/IBroker.sol";
import "./interfaces/IPropertyValidator.sol";
import "./libs/LibBrokerRichErrors.sol";
// solhint-disable space-after-comma, var-name-mixedcase
contract Broker is
IBroker,
MixinWethUtils
{
// Contract addresses
// Address of the 0x Exchange contract
address internal EXCHANGE;
// Address of the 0x ERC1155 Asset Proxy contract
address internal ERC1155_PROXY;
// The following storage variables are used to cache data for the duration of the transcation.
// They should always cleared at the end of the transaction.
// Token IDs specified by the taker to be used to fill property-based orders.
uint256[] internal _cachedTokenIds;
// An index to the above array keeping track of which assets have been transferred.
uint256 internal _cacheIndex;
// The address that called `brokerTrade` or `batchBrokerTrade`. Assets will be transferred to
// and from this address as the effectual taker of the orders.
address internal _sender;
using LibSafeMath for uint256;
using LibBytes for bytes;
using LibAssetDataTransfer for bytes;
/// @param exchange Address of the 0x Exchange contract.
/// @param exchange Address of the Wrapped Ether contract.
/// @param exchange Address of the 0x ERC1155 Asset Proxy contract.
constructor (
address exchange,
address weth
)
public
MixinWethUtils(
exchange,
weth
)
{
EXCHANGE = exchange;
ERC1155_PROXY = IExchange(EXCHANGE).getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
}
/// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy
/// @param from Since the Broker serves as the taker of the order, this should equal `address(this)`
/// @param to This should be the maker of the order.
/// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer.
/// @param data Encodes the validator contract address and any auxiliary data it needs for property validation.
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata /* ids */,
uint256[] calldata amounts,
bytes calldata data
)
external
{
// Only the ERC1155 asset proxy contract should be calling this function.
if (msg.sender != ERC1155_PROXY) {
LibRichErrors.rrevert(LibBrokerRichErrors.OnlyERC1155ProxyError(
msg.sender
));
}
// Only `takerAssetData` should be using Broker assets
if (from != address(this)) {
LibRichErrors.rrevert(
LibBrokerRichErrors.InvalidFromAddressError(from)
);
}
// Only one asset amount should be specified.
if (amounts.length != 1) {
LibRichErrors.rrevert(
LibBrokerRichErrors.AmountsLengthMustEqualOneError(amounts.length)
);
}
uint256 cacheIndex = _cacheIndex;
uint256 remainingAmount = amounts[0];
// Verify that there are enough broker assets to transfer
if (_cachedTokenIds.length.safeSub(cacheIndex) < remainingAmount) {
LibRichErrors.rrevert(
LibBrokerRichErrors.TooFewBrokerAssetsProvidedError(_cachedTokenIds.length)
);
}
// Decode validator and params from `data`
(address tokenAddress, address validator, bytes memory propertyData) = abi.decode(
data,
(address, address, bytes)
);
while (remainingAmount != 0) {
uint256 tokenId = _cachedTokenIds[cacheIndex];
cacheIndex++;
// Validate asset properties
IPropertyValidator(validator).checkBrokerAsset(
tokenId,
propertyData
);
// Perform the transfer
IERC721Token(tokenAddress).transferFrom(
_sender,
to,
tokenId
);
remainingAmount--;
}
// Update cache index in storage
_cacheIndex = cacheIndex;
}
/// @dev Fills a single property-based order by the given amount using the given assets.
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
/// @param order The property-based order to fill. The format of a property-based order is the
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
/// underlying tokenAddress is this contract's address and the desired properties are
/// encoded in the extra data field. Also note that takerFees must be denominated in
/// WETH (or zero).
/// @param takerAssetFillAmount The amount to fill the order by.
/// @param signature The maker's signature of the given order.
/// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return fillResults Amounts filled and fees paid by the maker and taker.
function brokerTrade(
uint256[] memory brokeredTokenIds,
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
bytes memory signature,
bytes4 fillFunctionSelector,
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (LibFillResults.FillResults memory fillResults)
{
// Cache the taker-supplied asset data
_cachedTokenIds = brokeredTokenIds;
// Cache the sender's address
_sender = msg.sender;
// Sanity-check the provided function selector
if (
fillFunctionSelector != IExchange(address(0)).fillOrder.selector &&
fillFunctionSelector != IExchange(address(0)).fillOrKillOrder.selector
) {
LibBrokerRichErrors.InvalidFunctionSelectorError(fillFunctionSelector);
}
// Pay ETH affiliate fees to all feeRecipient addresses
_transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients);
// Perform the fill
bytes memory fillCalldata = abi.encodeWithSelector(
fillFunctionSelector,
order,
takerAssetFillAmount,
signature
);
// solhint-disable-next-line avoid-call-value
(bool didSucceed, bytes memory returnData) = EXCHANGE.call(fillCalldata);
if (didSucceed) {
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
} else {
// Re-throw error
LibRichErrors.rrevert(returnData);
}
// Transfer maker asset to taker
if (!order.makerAssetData.equals(WETH_ASSET_DATA)) {
order.makerAssetData.transferOut(fillResults.makerAssetFilledAmount);
}
// Refund remaining ETH to msg.sender.
_unwrapAndTransferEth(WETH.balanceOf(address(this)));
_clearStorage();
return fillResults;
}
/// @dev Fills multiple property-based orders by the given amounts using the given assets.
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
/// @param orders The property-based orders to fill. The format of a property-based order is the
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
/// underlying tokenAddress is this contract's address and the desired properties are
/// encoded in the extra data field. Also note that takerFees must be denominated in
/// WETH (or zero).
/// @param takerAssetFillAmounts The amounts to fill the orders by.
/// @param signatures The makers' signatures for the given orders.
/// @param batchFillFunctionSelector The selector for either `batchFillOrders`,
/// `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return fillResults Amounts filled and fees paid by the makers and taker.
function batchBrokerTrade(
uint256[] memory brokeredTokenIds,
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
bytes[] memory signatures,
bytes4 batchFillFunctionSelector,
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (LibFillResults.FillResults[] memory fillResults)
{
// Cache the taker-supplied asset data
_cachedTokenIds = brokeredTokenIds;
// Cache the sender's address
_sender = msg.sender;
// Sanity-check the provided function selector
if (
batchFillFunctionSelector != IExchange(address(0)).batchFillOrders.selector &&
batchFillFunctionSelector != IExchange(address(0)).batchFillOrKillOrders.selector &&
batchFillFunctionSelector != IExchange(address(0)).batchFillOrdersNoThrow.selector
) {
LibBrokerRichErrors.InvalidFunctionSelectorError(batchFillFunctionSelector);
}
// Pay ETH affiliate fees to all feeRecipient addresses
_transferEthFeesAndWrapRemaining(ethFeeAmounts, feeRecipients);
// Perform the batch fill
bytes memory batchFillCalldata = abi.encodeWithSelector(
batchFillFunctionSelector,
orders,
takerAssetFillAmounts,
signatures
);
// solhint-disable-next-line avoid-call-value
(bool didSucceed, bytes memory returnData) = EXCHANGE.call(batchFillCalldata);
if (didSucceed) {
// solhint-disable-next-line indent
fillResults = abi.decode(returnData, (LibFillResults.FillResults[]));
} else {
// Re-throw error
LibRichErrors.rrevert(returnData);
}
// Transfer maker assets to taker
for (uint256 i = 0; i < orders.length; i++) {
if (!orders[i].makerAssetData.equals(WETH_ASSET_DATA)) {
orders[i].makerAssetData.transferOut(fillResults[i].makerAssetFilledAmount);
}
}
// Refund remaining ETH to msg.sender.
_unwrapAndTransferEth(WETH.balanceOf(address(this)));
_clearStorage();
return fillResults;
}
function _clearStorage()
private
{
delete _cachedTokenIds;
_cacheIndex = 0;
_sender = address(0);
}
}

View File

@@ -1,101 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
// solhint-disable space-after-comma
interface IBroker {
/// @dev Fills a single property-based order by the given amount using the given assets.
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
/// @param order The property-based order to fill. The format of a property-based order is the
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
/// underlying tokenAddress is this contract's address and the desired properties are
/// encoded in the extra data field. Also note that takerFees must be denominated in
/// WETH (or zero).
/// @param takerAssetFillAmount The amount to fill the order by.
/// @param signature The maker's signature of the given order.
/// @param fillFunctionSelector The selector for either `fillOrder` or `fillOrKillOrder`.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return fillResults Amounts filled and fees paid by the maker and taker.
function brokerTrade(
uint256[] calldata brokeredTokenIds,
LibOrder.Order calldata order,
uint256 takerAssetFillAmount,
bytes calldata signature,
bytes4 fillFunctionSelector,
uint256[] calldata ethFeeAmounts,
address payable[] calldata feeRecipients
)
external
payable
returns (LibFillResults.FillResults memory fillResults);
/// @dev Fills multiple property-based orders by the given amounts using the given assets.
/// Pays protocol fees using either the ETH supplied by the taker to the transaction or
/// WETH acquired from the maker during settlement. The final WETH balance is sent to the taker.
/// @param brokeredTokenIds Token IDs specified by the taker to be used to fill the orders.
/// @param orders The property-based orders to fill. The format of a property-based order is the
/// same as that of a normal order, except the takerAssetData. Instaed of specifying a
/// specific ERC721 asset, the takerAssetData should be ERC1155 assetData where the
/// underlying tokenAddress is this contract's address and the desired properties are
/// encoded in the extra data field. Also note that takerFees must be denominated in
/// WETH (or zero).
/// @param takerAssetFillAmounts The amounts to fill the orders by.
/// @param signatures The makers' signatures for the given orders.
/// @param batchFillFunctionSelector The selector for either `batchFillOrders`,
/// `batchFillOrKillOrders`, or `batchFillOrdersNoThrow`.
/// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
/// @param feeRecipients Addresses that will receive ETH when orders are filled.
/// @return fillResults Amounts filled and fees paid by the makers and taker.
function batchBrokerTrade(
uint256[] calldata brokeredTokenIds,
LibOrder.Order[] calldata orders,
uint256[] calldata takerAssetFillAmounts,
bytes[] calldata signatures,
bytes4 batchFillFunctionSelector,
uint256[] calldata ethFeeAmounts,
address payable[] calldata feeRecipients
)
external
payable
returns (LibFillResults.FillResults[] memory fillResults);
/// @dev The Broker implements the ERC1155 transfer function to be compatible with the ERC1155 asset proxy
/// @param from Since the Broker serves as the taker of the order, this should equal `address(this)`
/// @param to This should be the maker of the order.
/// @param amounts Should be an array of just one `uint256`, specifying the amount of the brokered assets to transfer.
/// @param data Encodes the validator contract address and any auxiliary data it needs for property validation.
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata /* ids */,
uint256[] calldata amounts,
bytes calldata data
)
external;
}

View File

@@ -1,33 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
interface IGodsUnchained {
/// @dev Returns the proto and quality for a particular card given its token id
/// @param tokenId The id of the card to query.
/// @return proto The proto of the given card.
/// @return quality The quality of the given card
function getDetails(uint256 tokenId)
external
view
returns (uint16 proto, uint8 quality);
}

View File

@@ -1,35 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
interface IPropertyValidator {
/// @dev Checks that the given asset data satisfies the properties encoded in `propertyData`.
/// Should revert if the asset does not satisfy the specified properties.
/// @param tokenId The ERC721 tokenId of the asset to check.
/// @param propertyData Encoded properties or auxiliary data needed to perform the check.
function checkBrokerAsset(
uint256 tokenId,
bytes calldata propertyData
)
external
view;
}

View File

@@ -1,109 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
library LibBrokerRichErrors {
// bytes4(keccak256("InvalidFromAddressError(address)"))
bytes4 internal constant INVALID_FROM_ADDRESS_ERROR_SELECTOR =
0x906bfb3c;
// bytes4(keccak256("AmountsLengthMustEqualOneError(uint256)"))
bytes4 internal constant AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR =
0xba9be200;
// bytes4(keccak256("TooFewBrokerAssetsProvidedError(uint256)"))
bytes4 internal constant TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR =
0x55272586;
// bytes4(keccak256("InvalidFunctionSelectorError(bytes4)"))
bytes4 internal constant INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR =
0x540943f1;
// bytes4(keccak256("OnlyERC1155ProxyError(address)"))
bytes4 internal constant ONLY_ERC_1155_PROXY_ERROR_SELECTOR =
0xccc529af;
// solhint-disable func-name-mixedcase
function InvalidFromAddressError(
address from
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
INVALID_FROM_ADDRESS_ERROR_SELECTOR,
from
);
}
function AmountsLengthMustEqualOneError(
uint256 amountsLength
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
AMOUNTS_LENGTH_MUST_EQUAL_ONE_ERROR_SELECTOR,
amountsLength
);
}
function TooFewBrokerAssetsProvidedError(
uint256 numBrokeredAssets
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
TOO_FEW_BROKER_ASSETS_PROVIDED_ERROR_SELECTOR,
numBrokeredAssets
);
}
function InvalidFunctionSelectorError(
bytes4 selector
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
INVALID_FUNCTION_SELECTOR_ERROR_SELECTOR,
selector
);
}
function OnlyERC1155ProxyError(
address sender
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
ONLY_ERC_1155_PROXY_ERROR_SELECTOR,
sender
);
}
}

View File

@@ -1,61 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "../interfaces/IGodsUnchained.sol";
import "../interfaces/IPropertyValidator.sol";
contract GodsUnchainedValidator is
IPropertyValidator
{
IGodsUnchained internal GODS_UNCHAINED; // solhint-disable-line var-name-mixedcase
using LibBytes for bytes;
constructor(address _godsUnchained)
public
{
GODS_UNCHAINED = IGodsUnchained(_godsUnchained);
}
/// @dev Checks that the given card (encoded as assetData) has the proto and quality encoded in `propertyData`.
/// Reverts if the card doesn't match the specified proto and quality.
/// @param tokenId The ERC721 tokenId of the card to check.
/// @param propertyData Encoded proto and quality that the card is expected to have.
function checkBrokerAsset(
uint256 tokenId,
bytes calldata propertyData
)
external
view
{
(uint16 expectedProto, uint8 expectedQuality) = abi.decode(
propertyData,
(uint16, uint8)
);
// Validate card properties.
(uint16 proto, uint8 quality) = GODS_UNCHAINED.getDetails(tokenId);
require(proto == expectedProto, "GodsUnchainedValidator/PROTO_MISMATCH");
require(quality == expectedQuality, "GodsUnchainedValidator/QUALITY_MISMATCH");
}
}

View File

@@ -1,55 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc721/contracts/test/DummyERC721Token.sol";
import "../src/interfaces/IGodsUnchained.sol";
contract TestGodsUnchained is
IGodsUnchained,
DummyERC721Token
{
mapping (uint256 => uint16) internal _protoByTokenId;
mapping (uint256 => uint8) internal _qualityByTokenId;
constructor (
string memory _name,
string memory _symbol
)
public
DummyERC721Token(_name, _symbol)
{} // solhint-disable-line no-empty-blocks
function setTokenProperties(uint256 tokenId, uint16 proto, uint8 quality)
external
{
_protoByTokenId[tokenId] = proto;
_qualityByTokenId[tokenId] = quality;
}
function getDetails(uint256 tokenId)
external
view
returns (uint16 proto, uint8 quality)
{
return (_protoByTokenId[tokenId], _qualityByTokenId[tokenId]);
}
}

View File

@@ -1,96 +0,0 @@
{
"name": "@0x/contracts-broker",
"version": "1.1.3",
"engines": {
"node": ">=6.12"
},
"description": "Extension of 0x protocol for property-based orders",
"main": "lib/src/index.js",
"directories": {
"test": "test"
},
"scripts": {
"build": "yarn build:contracts && yarn build:ts",
"build:contracts": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
"build:ts": "tsc -b",
"build:ci": "yarn build",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
"compile": "sol-compiler",
"watch": "sol-compiler -w",
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"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",
"coverage:report:lcov": "istanbul report lcov",
"test:circleci": "yarn test",
"contracts:gen": "contracts-gen generate",
"contracts:copy": "contracts-gen copy",
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
"compile:truffle": "truffle compile",
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
},
"config": {
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(Broker|GodsUnchainedValidator|IBroker|IGodsUnchained|IPropertyValidator|LibBrokerRichErrors|TestGodsUnchained).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/contracts/extensions/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.2.2",
"@0x/contracts-asset-proxy": "^3.2.4",
"@0x/contracts-erc20": "^3.1.4",
"@0x/contracts-erc721": "^3.1.4",
"@0x/contracts-exchange": "^3.2.4",
"@0x/contracts-exchange-libs": "^4.3.4",
"@0x/contracts-gen": "^2.0.8",
"@0x/contracts-test-utils": "^5.3.1",
"@0x/contracts-utils": "^4.4.2",
"@0x/sol-compiler": "^4.0.8",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.1.2",
"@0x/web3-wrapper": "^7.0.7",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^3.0.0",
"dirty-chai": "^2.0.1",
"lodash": "^4.17.11",
"make-promises-safe": "^1.1.0",
"mocha": "^6.2.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"solhint": "^1.4.1",
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "^0.15.0",
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.2.1",
"@0x/order-utils": "^10.2.3",
"@0x/typescript-typings": "^5.0.2",
"@0x/utils": "^5.4.1",
"ethereum-types": "^3.1.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@@ -1,23 +0,0 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
import { ContractArtifact } from 'ethereum-types';
import * as Broker from '../generated-artifacts/Broker.json';
import * as GodsUnchainedValidator from '../generated-artifacts/GodsUnchainedValidator.json';
import * as IBroker from '../generated-artifacts/IBroker.json';
import * as IGodsUnchained from '../generated-artifacts/IGodsUnchained.json';
import * as IPropertyValidator from '../generated-artifacts/IPropertyValidator.json';
import * as LibBrokerRichErrors from '../generated-artifacts/LibBrokerRichErrors.json';
import * as TestGodsUnchained from '../generated-artifacts/TestGodsUnchained.json';
export const artifacts = {
Broker: Broker as ContractArtifact,
IBroker: IBroker as ContractArtifact,
IGodsUnchained: IGodsUnchained as ContractArtifact,
IPropertyValidator: IPropertyValidator as ContractArtifact,
LibBrokerRichErrors: LibBrokerRichErrors as ContractArtifact,
GodsUnchainedValidator: GodsUnchainedValidator as ContractArtifact,
TestGodsUnchained: TestGodsUnchained as ContractArtifact,
};

View File

@@ -1,59 +0,0 @@
import { assetDataUtils } from '@0x/order-utils';
import { ERC1155AssetData } from '@0x/types';
import { AbiEncoder, BigNumber } from '@0x/utils';
export interface GodsUnchainedProperties {
proto: BigNumber | number;
quality: BigNumber | number;
}
const propertyDataEncoder = AbiEncoder.create([{ name: 'proto', type: 'uint16' }, { name: 'quality', type: 'uint8' }]);
const brokerDataEncoder = AbiEncoder.create([
{ name: 'godsUnchainedAddress', type: 'address' },
{ name: 'validatorAddress', type: 'address' },
{ name: 'propertyData', type: 'bytes' },
]);
/**
* Encodes the given proto and quality into the bytes format expected by the GodsUnchainedValidator.
*/
export function encodePropertyData(properties: GodsUnchainedProperties): string {
return propertyDataEncoder.encode(properties);
}
/**
* Encodes the given proto and quality into ERC1155 asset data to be used as the takerAssetData
* of a property-based GodsUnchained order. Must also provide the addresses of the Broker,
* GodsUnchained, and GodsUnchainedValidator contracts. The optional bundleSize parameter specifies
* how many cards are expected for each "unit" of the takerAssetAmount. For example, If the
* takerAssetAmount is 3 and the bundleSize is 2, the taker must provide 2, 4, or 6 cards
* with the given proto and quality to fill the order. If an odd number is provided, the fill fails.
*/
export function encodeBrokerAssetData(
brokerAddress: string,
godsUnchainedAddress: string,
validatorAddress: string,
properties: GodsUnchainedProperties,
bundleSize: number = 1,
): string {
const propertyData = propertyDataEncoder.encode(properties);
const brokerData = brokerDataEncoder.encode({ godsUnchainedAddress, validatorAddress, propertyData });
return assetDataUtils.encodeERC1155AssetData(brokerAddress, [], [new BigNumber(bundleSize)], brokerData);
}
/**
* Decodes proto and quality from the bytes format expected by the GodsUnchainedValidator.
*/
export function decodePropertyData(propertyData: string): GodsUnchainedProperties {
return propertyDataEncoder.decode(propertyData);
}
/**
* Decodes proto and quality from the ERC1155 takerAssetData of a property-based GodsUnchained order.
*/
export function decodeBrokerAssetData(brokerAssetData: string): GodsUnchainedProperties {
// tslint:disable-next-line:no-unnecessary-type-assertion
const { callbackData: brokerData } = assetDataUtils.decodeAssetDataOrThrow(brokerAssetData) as ERC1155AssetData;
const { propertyData } = brokerDataEncoder.decode(brokerData);
return decodePropertyData(propertyData);
}

View File

@@ -1,32 +0,0 @@
export { artifacts } from './artifacts';
export { BrokerContract, GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers';
export * from './gods_unchained_utils';
export { BrokerRevertErrors } from '@0x/utils';
export {
ContractArtifact,
ContractChains,
CompilerOpts,
StandardContractOutput,
CompilerSettings,
ContractChainData,
ContractAbi,
DevdocOutput,
EvmOutput,
CompilerSettingsMetadata,
OptimizerSettings,
OutputField,
ParamDescription,
EvmBytecodeOutput,
AbiDefinition,
FunctionAbi,
EventAbi,
RevertErrorAbi,
EventParameter,
DataItem,
MethodAbi,
ConstructorAbi,
FallbackAbi,
ConstructorStateMutability,
TupleDataItem,
StateMutability,
} from 'ethereum-types';

View File

@@ -1,12 +0,0 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../generated-wrappers/broker';
export * from '../generated-wrappers/gods_unchained_validator';
export * from '../generated-wrappers/i_broker';
export * from '../generated-wrappers/i_gods_unchained';
export * from '../generated-wrappers/i_property_validator';
export * from '../generated-wrappers/lib_broker_rich_errors';
export * from '../generated-wrappers/test_gods_unchained';

View File

@@ -1,23 +0,0 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
import { ContractArtifact } from 'ethereum-types';
import * as Broker from '../test/generated-artifacts/Broker.json';
import * as GodsUnchainedValidator from '../test/generated-artifacts/GodsUnchainedValidator.json';
import * as IBroker from '../test/generated-artifacts/IBroker.json';
import * as IGodsUnchained from '../test/generated-artifacts/IGodsUnchained.json';
import * as IPropertyValidator from '../test/generated-artifacts/IPropertyValidator.json';
import * as LibBrokerRichErrors from '../test/generated-artifacts/LibBrokerRichErrors.json';
import * as TestGodsUnchained from '../test/generated-artifacts/TestGodsUnchained.json';
export const artifacts = {
Broker: Broker as ContractArtifact,
IBroker: IBroker as ContractArtifact,
IGodsUnchained: IGodsUnchained as ContractArtifact,
IPropertyValidator: IPropertyValidator as ContractArtifact,
LibBrokerRichErrors: LibBrokerRichErrors as ContractArtifact,
GodsUnchainedValidator: GodsUnchainedValidator as ContractArtifact,
TestGodsUnchained: TestGodsUnchained as ContractArtifact,
};

View File

@@ -1,56 +0,0 @@
import { blockchainTests, constants, expect, getRandomInteger } from '@0x/contracts-test-utils';
import { BigNumber } from '@0x/utils';
import * as _ from 'lodash';
import { encodePropertyData } from '../src/gods_unchained_utils';
import { artifacts } from './artifacts';
import { GodsUnchainedValidatorContract, TestGodsUnchainedContract } from './wrappers';
blockchainTests.resets('GodsUnchainedValidator unit tests', env => {
let godsUnchained: TestGodsUnchainedContract;
let validator: GodsUnchainedValidatorContract;
before(async () => {
godsUnchained = await TestGodsUnchainedContract.deployFrom0xArtifactAsync(
artifacts.TestGodsUnchained,
env.provider,
env.txDefaults,
artifacts,
'Gods Unchained Cards',
'GU',
);
validator = await GodsUnchainedValidatorContract.deployFrom0xArtifactAsync(
artifacts.GodsUnchainedValidator,
env.provider,
env.txDefaults,
artifacts,
godsUnchained.address,
);
});
describe('checkBrokerAsset', () => {
const proto = new BigNumber(42);
const quality = new BigNumber(7);
const propertyData = encodePropertyData({ proto, quality });
it('succeeds if assetData proto and quality match propertyData', async () => {
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
await godsUnchained.setTokenProperties(tokenId, proto, quality).awaitTransactionSuccessAsync();
await validator.checkBrokerAsset(tokenId, propertyData).callAsync();
});
it("reverts if assetData proto doesn't match propertyData", async () => {
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
await godsUnchained.setTokenProperties(tokenId, proto.plus(1), quality).awaitTransactionSuccessAsync();
const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync();
expect(tx).to.revertWith('PROTO_MISMATCH');
});
it("reverts if assetData quality doesn't match proeprtyData", async () => {
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
await godsUnchained.setTokenProperties(tokenId, proto, quality.plus(1)).awaitTransactionSuccessAsync();
const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync();
expect(tx).to.revertWith('QUALITY_MISMATCH');
});
});
});

View File

@@ -1,12 +0,0 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../test/generated-wrappers/broker';
export * from '../test/generated-wrappers/gods_unchained_validator';
export * from '../test/generated-wrappers/i_broker';
export * from '../test/generated-wrappers/i_gods_unchained';
export * from '../test/generated-wrappers/i_property_validator';
export * from '../test/generated-wrappers/lib_broker_rich_errors';
export * from '../test/generated-wrappers/test_gods_unchained';

View File

@@ -1,96 +0,0 @@
/**
* Use this file to configure your truffle project. It's seeded with some
* common settings for different networks and features like migrations,
* compilation and testing. Uncomment the ones you need or modify
* them to suit your project as necessary.
*
* More information about configuration can be found at:
*
* truffleframework.com/docs/advanced/configuration
*
* To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
* to sign your transactions before they're sent to a remote public node. Infura accounts
* are available for free at: infura.io/register.
*
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
* phrase from a file you've .gitignored so it doesn't accidentally become public.
*
*/
// const HDWalletProvider = require('truffle-hdwallet-provider');
// const infuraKey = "fj4jll3k.....";
//
// const fs = require('fs');
// const mnemonic = fs.readFileSync(".secret").toString().trim();
module.exports = {
/**
* Networks define how you connect to your ethereum client and let you set the
* defaults web3 uses to send transactions. If you don't specify one truffle
* will spin up a development blockchain for you on port 9545 when you
* run `develop` or `test`. You can ask a truffle command to use a specific
* network from the command line, e.g
*
* $ truffle test --network <network-name>
*/
networks: {
// Useful for testing. The `development` name is special - truffle uses it by default
// if it's defined here and no other network is specified at the command line.
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
// tab if you use this network and you must also set the `host`, `port` and `network_id`
// options below to some value.
//
// development: {
// host: "127.0.0.1", // Localhost (default: none)
// port: 8545, // Standard Ethereum port (default: none)
// network_id: "*", // Any network (default: none)
// },
// Another network with more advanced options...
// advanced: {
// port: 8777, // Custom port
// network_id: 1342, // Custom network
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
// from: <address>, // Account to send txs from (default: accounts[0])
// websockets: true // Enable EventEmitter interface for web3 (default: false)
// },
// Useful for deploying to a public network.
// NB: It's important to wrap the provider as a function.
// ropsten: {
// provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
// network_id: 3, // Ropsten's id
// gas: 5500000, // Ropsten has a lower block limit than mainnet
// confirmations: 2, // # of confs to wait between deployments. (default: 0)
// timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
// skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
// },
// Useful for private networks
// private: {
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
// network_id: 2111, // This network is yours, in the cloud.
// production: true // Treats this network as if it was a public net. (default: false)
// }
},
// Set default mocha options here, use special reporters etc.
mocha: {
// timeout: 100000
},
// Configure your compilers
compilers: {
solc: {
version: '0.5.9',
settings: {
evmVersion: 'istanbul',
optimizer: {
enabled: true,
runs: 1000000,
details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true },
},
},
},
},
};

View File

@@ -1,22 +0,0 @@
{
"extends": "../../tsconfig",
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"generated-artifacts/Broker.json",
"generated-artifacts/GodsUnchainedValidator.json",
"generated-artifacts/IBroker.json",
"generated-artifacts/IGodsUnchained.json",
"generated-artifacts/IPropertyValidator.json",
"generated-artifacts/LibBrokerRichErrors.json",
"generated-artifacts/TestGodsUnchained.json",
"test/generated-artifacts/Broker.json",
"test/generated-artifacts/GodsUnchainedValidator.json",
"test/generated-artifacts/IBroker.json",
"test/generated-artifacts/IGodsUnchained.json",
"test/generated-artifacts/IPropertyValidator.json",
"test/generated-artifacts/LibBrokerRichErrors.json",
"test/generated-artifacts/TestGodsUnchained.json"
],
"exclude": ["./deploy/solc/solc_bin"]
}

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