Compare commits

...

146 Commits

Author SHA1 Message Date
Jacob Evans
2113fb490d Publish
- @0x/contracts-asset-proxy@3.1.0
 - @0x/contracts-coordinator@3.0.3
 - @0x/contracts-dev-utils@1.0.3
 - @0x/contracts-erc1155@2.0.3
 - @0x/contracts-erc20-bridge-sampler@1.0.3
 - @0x/contracts-erc20@3.0.3
 - @0x/contracts-erc721@3.0.3
 - @0x/contracts-exchange-forwarder@4.0.3
 - @0x/contracts-exchange-libs@4.0.3
 - @0x/contracts-exchange@3.0.3
 - @0x/contracts-extensions@5.1.2
 - @0x/contracts-integrations@2.1.0
 - @0x/contracts-multisig@4.0.3
 - @0x/contracts-staking@2.0.3
 - @0x/contracts-test-utils@5.1.0
 - @0x/contracts-utils@4.0.3
 - 0x.js@9.0.3
 - @0x/abi-gen@5.0.3
 - @0x/assert@3.0.3
 - @0x/asset-swapper@3.0.3
 - @0x/base-contract@6.0.3
 - @0x/connect@6.0.3
 - @0x/contract-addresses@4.2.0
 - @0x/contract-artifacts@3.3.0
 - @0x/contract-wrappers-test@12.2.4
 - @0x/contract-wrappers@13.3.0
 - @0x/contracts-gen@2.0.3
 - @0x/dev-utils@3.1.0
 - @0x/instant@1.0.40
 - @0x/json-schemas@5.0.3
 - @0x/migrations@5.1.0
 - @0x/monorepo-scripts@1.0.46
 - @0x/order-utils@10.1.0
 - @0x/orderbook@2.0.1
 - @0x/sol-compiler@4.0.3
 - @0x/sol-coverage@4.0.3
 - @0x/sol-doc@3.1.0
 - @0x/sol-profiler@4.0.3
 - @0x/sol-trace@3.0.3
 - @0x/sol-tracing-utils@7.0.3
 - @0x/sra-spec@3.0.3
 - @0x/subproviders@6.0.3
 - @0x/utils@5.1.2
 - @0x/web3-wrapper@7.0.3
2020-01-06 11:10:22 +10:00
Jacob Evans
0afedbd252 Updated CHANGELOGS & MD docs 2020-01-06 11:10:03 +10:00
Jacob Evans
3dec38450a Merge pull request #2396 from Arctek/patch-1
Fix circular reference
2020-01-06 10:29:19 +10:00
Jacob Evans
d7a00b05e3 Merge pull request #2423 from 0xProject/fix/migrations-docker-wget-timestamping
@0x/migrations/Dockerfile: Remove --timestamping arg from wget invocation
2020-01-06 10:27:35 +10:00
Lawrence Forman
ff2cc8c887 Add aggregator mainnet tests (#2407)
* `@0x/contracts-erc20-bridge-sampler`: Add gas limits to external quote calls.
`@0x/contract-addresses`: Point `erc20BridgeSampler` to new version.

* `@0x/contracts-utils`: Add kovan addresses to `DeploymentConstants`.
`@0x/contract-addresses`: Add kovan `ERC20BridgeSampler` address.

* `@0x/contracts-erc20-bridge-sampler`: Fix changelog.

* `@0x/asset-swapper`: Ignore zero sample results from the sampler contract.
`@0x/asset-swapper`: Allow skipping Uniswap when dealing with low precision amounts with `minUniswapDecimals` option.
`@0x/asset-swapper`: Increase default `runLimit` from `1024` to `4096`.
`@0x/asset-swapper`: Increase default `numSamples` from `8` to `10`
`@0x/asset-swapper`: Fix ordering of optimized orders.
`@0x/asset-swapper`: Fix best and worst quotes being reversed sometimes.
`@0x/asset-swapper`: Fix rounding of quoted asset amounts.

* `@0x/asset-swapper`: Change default `minUniswapDecimals` option from 8 to 7.

* `@0x/asset-swapper`: Revert uniswap decimals fix.

* `@0x/contracts-test-utils`: Add `blockchainTests.live()` for live network tests.
`@0x/contracts-test-utils`: Add modifiers to `blockchainTests.fork()`.
`@0x/contracts-integrations`: Add aggregator mainnet tests.

* `@0x/contracts-integrations`: Fix `fork/resets` modifier ordering on dydx tests.
`@0x/contracts-integrations`: Move and tweak aggregation tests.

* `@0x/contracts-integrations`: Handle non-responsive third-party SRA ordebooks with a little more grace.

* `@0x/contracts-integrations`: Fix linter error.

* `@0x/contracts-test-utils`: Consolidate fork provider logic into `mocha_blockchain.ts`.

* `@0x/contracts-integrations`: Run prettier on aggregation fill tests.

* `@0x/dev-utils`: Add `locked` to `Web3Config`.

* `@0x/contracts-integrations`: Update mainnet fork tests.
`@0x/contracts-test-utils`: Fix forked tests being skipped.
`@0x/contracts-erc20-bridge-sampler`: Regenerate artifacts.

* `@0x/contracts-test-utils`: Remove unecessary `locked` option when creating forked ganache provider.

* Fix redundant zero check

* Set fee amount in fillable amounts test

Co-authored-by: Jacob Evans <dekz@dekz.net>
2020-01-03 23:47:40 -05:00
Lawrence Forman
0571a96cea Fix asset-swapper bugs and misc improvements. (#2406)
* `@0x/contracts-erc20-bridge-sampler`: Add gas limits to external quote calls.
`@0x/contract-addresses`: Point `erc20BridgeSampler` to new version.

* `@0x/asset-swapper`: Ignore zero sample results from the sampler contract.
`@0x/asset-swapper`: Allow skipping Uniswap when dealing with low precision amounts with `minUniswapDecimals` option.
`@0x/asset-swapper`: Increase default `runLimit` from `1024` to `4096`.
`@0x/asset-swapper`: Increase default `numSamples` from `8` to `10`
`@0x/asset-swapper`: Fix ordering of optimized orders.
`@0x/asset-swapper`: Fix best and worst quotes being reversed sometimes.
`@0x/asset-swapper`: Fix rounding of quoted asset amounts.

* `@0x/contracts-utils`: Add kovan addresses to `DeploymentConstants`.
`@0x/contract-addresses`: Add kovan `ERC20BridgeSampler` address.

* `@0x/asset-swapper`: Change default `minUniswapDecimals` option from 8 to 7.

* `@0x/contracts-erc20-bridge-sampler`: Fix changelog.

* `@0x/asset-swapper`: Revert uniswap decimals fix.

* `@0x/asset-swapper`: Undo bridge slippage when computing best case quote.

* `@0x/asset-swapper`: Take asset data from input orders instead of output orders in quote result calculation.

* `@0x/asset-swapper`: Move `SAMPLER_CONTRACT_GAS_LIMIT` constant to `market_operation_utils/constants`.

* Compare equivalent asset data

* Fix redundant zero check

* Update CHANGELOG

* Set fee amount in fillable amounts test

Co-authored-by: Jacob Evans <dekz@dekz.net>
2020-01-03 23:21:39 -05:00
Lawrence Forman
b7b457b076 Generate (complete) solidity docs (#2391)
* `@0x/sol-doc`: New doc generator.

* `@0x/sol-compiler`: Be more tolerant of AST-only compilation targets.

* `@0x/contracts-exchange`: Add more devdoc comments.
`@0x/contracts-exchange-libs`: Add more devdoc comments.

* `@0x/sol-doc`: Update package script.

* `@0x/sol-doc`: Remove unused files and update package scripts to be easier to configure.

* Add more devdocs to contracts.

* `@0x/sol-doc`: Remove doc artifacts.

* `@0x/sol-doc`: Add `.gitignore` and `.npmignore`.

* `@0x/contracts-exchange`: Fix compilation errors.

* Fix more broken contracts.

* `@0x/contracts-erc20-bridge-sampler`: Fix failing tests.

* `@0x/contracts-asset-proxy`: Remove accidentally introduced hackathion file (lol).

* `@0x/sol-doc`: Prevent some inherited contracts from being included in docs unintentionally.

* `@0x/sol-doc`: Rename test file.

* `@0x/contracts-exchange`: Update `orderEpoch` devdoc.

* `@0x/sol-doc`: Tweak event and function docs.

* Update CODEOWNERS.

* `@0x/sol-doc` Tweak function md generation.

* `@0x/sol-doc`: add `transformDocs()` tests.

* `@0x/sol-doc`: add `extract_docs` tests.

* `@0x/sol-doc` Fix linter errors.

* `@0x/contracts-erc20-bridge-sampler`: Fix broken `ERC20BridgeSampler.sol` compile.

* `@0x/sol-doc` Fix mismatched `dev-utils` dep version.

* `@0x/sol-doc`: Add `gen_md` tests.

* `@0x/sol-doc`: Remove `fs.promises` calls.

* `@0x/sol-doc`: Fix linter errors.

* `@0x/sol-doc`: Export all relevant types and functions.

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2020-01-03 22:59:18 -05:00
F. Eugene Aumson
d2c12005b2 Also publish versioned docker image tag
Not just `latest`
2020-01-03 16:51:02 -05:00
F. Eugene Aumson
25f26d7e5f Remove --timestamping arg from wget invocation 2020-01-03 12:40:40 -05:00
F. Eugene Aumson
9d5724e1a0 Fix 0xorg/ganache-cli docker image not supporting re-runs (#2420)
* Overwrite existing snapshot when unzipping

* Don't re-download snapshot if it isn't updated

* Update CHANGELOG.json
2020-01-02 20:19:06 -05:00
David Sun
784d23ec87 Merge pull request #2416 from 0xProject/feature/instant/disable-file-removal--in-s3
Instant - Added should_remove_files_in_s3 flag in discharge configuration
2019-12-22 20:54:43 -08:00
James Towle
709689a7ee Merge pull request #2417 from 0xProject/tests/fix/dev-utils-tests
Fixed the DevUtils tests
2019-12-21 16:55:33 -08:00
F. Eugene Aumson
35d5d3d995 Pare down Mesh env vars in Py test env (#2418) 2019-12-21 13:19:00 -05:00
Alex Towle
630a8d8a4e Addressed dorothy's nit 2019-12-20 19:14:52 -08:00
Alex Towle
54eb1d9055 Fixed the DevUtils tests 2019-12-20 15:51:45 -08:00
David Sun
cb63caea61 prettier 2019-12-20 12:57:40 -08:00
David Sun
8e046bb022 updated to new flag name 2019-12-20 12:07:59 -08:00
David Sun
189b53b8c4 added removal flag in configuration 2019-12-20 11:40:54 -08:00
Lawrence Forman
9b7277d464 Fix Kyber and Uniswap ERC20Bridges (#2412)
* `@0x/contracts-asset-proxy`: Fix `UniswapBridge` token -> token transfer logic.
`@0x/contract-addresses`: Update `UniswapBridge` mainnet address.

* `@0x/asset-proxy`: Fix `KyberBridge` incorrect `minConversionRate` calculation.

* `@0x/contract-addresses`: Update `KyberBridge` mainnet address.
2019-12-20 13:41:52 -05:00
F. Eugene Aumson
551a65c069 0x-sra-client.py: Fix bug in config_order, and other small improvements (#2399)
* Bug fix: unescape backslashes in regexes

Root problem is that there are too many backslashes in the SRA spec
itself.  See https://github.com/0xProject/0x-monorepo/issues/1727

This was previously fixed for heavily-tested endpoints (get and post
order, etc), but was only recently discovered for the get-order-config
endpoint.

* Demonstrate get_order_config()

* Rename DefaultApi to RelayerApi

* Simplify RelayerApi instantiation

* Document paylod and response schemas

* Stop caring which contracts are wrapped

* Increase platform agnosticism

* Update CHANGELOG

* Remove unnecessary f-string
2019-12-20 12:24:55 -05:00
F. Eugene Aumson
4c21a697f4 sra_client.py: Tweak Mesh block polling interval used in tests (#2413)
* Change Mesh block polling interval to 50ms

* Increase Mesh's Ethereum node RPC rate limit
2019-12-20 11:26:57 -05:00
Greg Hysz
a8506c07ae Merge pull request #2401 from 0xProject/feat/asset-proxy/DyDxBridgeTests
DydxBridge Contract Integration Tests
2019-12-19 22:16:44 -08:00
Greg Hysen
b0feb85b5c Fixed merge conflict 2019-12-19 21:36:43 -08:00
Greg Hysen
f371eba8ad Hardcoded address of ERC20BridgeProxy in unlocked accounts 2019-12-19 21:32:03 -08:00
Greg Hysen
265fa52ace Rounding error tests in DydxBridgeProxy 2019-12-19 21:32:03 -08:00
Greg Hysen
c1f5322d38 Added TestDydxUser contract - this is deployed to mainnent as the dYdX Account Owner for the mainnet integration tests. 2019-12-19 21:32:03 -08:00
Greg Hysen
4415e00b38 Added more integration tests for DydxBridge with the Exchange (demonstrates use cases) 2019-12-19 21:32:03 -08:00
Greg Hysen
d4e46c5a9c Updated Changelogs 2019-12-19 21:32:03 -08:00
Greg Hysen
bf5b9949fe Ran prettier 2019-12-19 21:32:03 -08:00
Greg Hysen
3c11a2b1da Increased mocha timeout for mainnet tests 2019-12-19 21:32:03 -08:00
Greg Hysen
1248868169 Added mainnet DydxBridge integration tests with dYdX SoloMargin contract 2019-12-19 21:32:03 -08:00
Greg Hysen
930b95a548 Added integration tests for DydxBridge with Exchange contract 2019-12-19 21:32:03 -08:00
Greg Hysen
27c9f68c7c Added dydx bridge to contract-addresses package 2019-12-19 21:32:02 -08:00
Greg Hysen
358d4d86a7 Added ERC20BridgeProxy.transferFrom tests for DydxBridge 2019-12-19 21:31:07 -08:00
Lawrence Forman
d55eea2239 ERC20BridgeSampler: Gas limits (#2405)
* `@0x/contracts-erc20-bridge-sampler`: Add gas limits to external quote calls.
`@0x/contract-addresses`: Point `erc20BridgeSampler` to new version.

* `@0x/contracts-utils`: Add kovan addresses to `DeploymentConstants`.
`@0x/contract-addresses`: Add kovan `ERC20BridgeSampler` address.

* `@0x/contracts-erc20-bridge-sampler`: Fix changelog.

* `@0x/contracts-erc20-bridge-contracts`: Fix invalid CHANGELOG json (I hope).
2019-12-20 00:08:39 -05:00
David Sun
4507954ea5 Merge pull request #2410 from 0xProject/fix/instant/coverage
Fix bundlewatch for instant and passing static-test
2019-12-19 22:37:42 -05:00
David Sun
8e0a83f8d8 bundlewatch 2019-12-19 19:20:24 -08:00
David Sun
b6ec09e6cf Merge pull request #2409 from 0xProject/feature/instant/minor-fixes-dai-aggregator
Fixes for instant (DAI + disable aggregator functionality)
2019-12-19 20:21:59 -05:00
David Sun
ed4e90623d more fixes 2019-12-19 16:49:20 -08:00
David Sun
38cdb48748 fixes 2019-12-19 16:36:00 -08:00
James Towle
71bfe9b745 Merge pull request #2402 from 0xProject/deploy/dev-utils/12-18-2019
Added artifacts, addresses, and wrappers
2019-12-19 14:38:01 -08:00
Alex Towle
9e7645a167 Removed hand-written timestamps 2019-12-19 13:26:00 -08:00
Alex Towle
6dccc37143 Removed forbidden fields in artifact 2019-12-19 11:40:49 -08:00
Alex Towle
3310310d8c Added artifacts, addresses, and wrappers 2019-12-19 10:32:01 -08:00
Greg Hysz
abb499aad8 Merge pull request #2403 from 0xProject/fix/circle/yarnInstall
Fix Circle builds
2019-12-19 10:24:48 -08:00
Greg Hysen
1afc09b08a Workaround for https://github.com/yarnpkg/yarn/issues/7773 2019-12-19 01:12:46 -08:00
Alex Browne
0e86d72f05 Merge pull request #2384 from 0xProject/update-code-owners-contracts-albrow
Update CODEOWNERS
2019-12-18 13:48:31 -08:00
mzhu25
c9857a2764 Merge pull request #2392 from 0xProject/feature/fuzz/better-input-gen
`@0x/contracts-integrations`: Better input generation for fuzzing
2019-12-18 12:03:23 -08:00
Michael Zhu
701ba3902c add comments 2019-12-18 11:38:33 -08:00
Michael Zhu
bb3ec970a9 lint 2019-12-18 11:38:33 -08:00
Michael Zhu
1d023e6db5 Add optional parameter to sample and sampleSize 2019-12-18 11:38:33 -08:00
Michael Zhu
1bd906ecb3 Add optional distribution parameter to Pseudorandom.integer, use Kumaraswamy distribution for operator share 2019-12-18 11:38:33 -08:00
James Towle
7cbffdb86b Merge pull request #2400 from 0xProject/feature/dev-utils/duplicate-erc721-bug-fix
Duplicate ERC721 Bug Fix
2019-12-18 10:46:27 -08:00
Alex Towle
b979196ffd Remove the taker patch 2019-12-17 19:02:57 -08:00
Alex Towle
2949db5f49 Fixed the bug and added tests that fail without the patch 2019-12-17 19:02:57 -08:00
Alex Towle
47c3ed9705 Fixed the bug and moved "contracts-tests" to "contracts-integrations" 2019-12-17 19:02:57 -08:00
xianny
51ca3109eb Publish
- @0x/contracts-asset-proxy@3.0.2
 - @0x/contracts-coordinator@3.0.2
 - @0x/contracts-dev-utils@1.0.2
 - @0x/contracts-erc1155@2.0.2
 - @0x/contracts-erc20-bridge-sampler@1.0.2
 - @0x/contracts-erc20@3.0.2
 - @0x/contracts-erc721@3.0.2
 - @0x/contracts-exchange-forwarder@4.0.2
 - @0x/contracts-exchange-libs@4.0.2
 - @0x/contracts-exchange@3.0.2
 - @0x/contracts-extensions@5.1.1
 - @0x/contracts-integrations@2.0.2
 - @0x/contracts-multisig@4.0.2
 - @0x/contracts-staking@2.0.2
 - @0x/contracts-test-utils@5.0.1
 - @0x/contracts-tests@0.0.8
 - @0x/contracts-utils@4.0.2
 - 0x.js@9.0.2
 - @0x/abi-gen@5.0.2
 - @0x/assert@3.0.2
 - @0x/asset-swapper@3.0.2
 - @0x/base-contract@6.0.2
 - @0x/connect@6.0.2
 - @0x/contract-addresses@4.1.0
 - @0x/contract-artifacts@3.2.0
 - @0x/contract-wrappers-test@12.2.3
 - @0x/contract-wrappers@13.2.0
 - @0x/contracts-gen@2.0.2
 - @0x/dev-utils@3.0.2
 - @0x/instant@1.0.39
 - @0x/json-schemas@5.0.2
 - @0x/migrations@5.0.2
 - @0x/monorepo-scripts@1.0.45
 - @0x/order-utils@10.0.1
 - @0x/orderbook@2.0.0
 - @0x/sol-compiler@4.0.2
 - @0x/sol-coverage@4.0.2
 - @0x/sol-doc@3.0.2
 - @0x/sol-profiler@4.0.2
 - @0x/sol-resolver@3.0.2
 - @0x/sol-trace@3.0.2
 - @0x/sol-tracing-utils@7.0.2
 - @0x/sra-spec@3.0.2
 - @0x/subproviders@6.0.2
 - @0x/types@3.1.1
 - @0x/typescript-typings@5.0.1
 - @0x/utils@5.1.1
 - @0x/web3-wrapper@7.0.2
2019-12-16 16:05:16 -08:00
xianny
2bcb79dc44 Updated CHANGELOGS & MD docs 2019-12-16 16:05:03 -08:00
xianny
ecec985649 pin python regex version 2019-12-16 14:22:48 -08:00
Lawrence Forman
994908549d Asset-swapper aggregator utils (#2353)
* `@0x/asset-swapper`: Add ERC20Bridge aggregator library.

* `@0x/asset-swapper`: Finish off `aggregate.ts`.

* `@0x/types`: Add `OrderWithoutDomain` type.

* `@0x/asset-swapper`: Add testing infra for sampler/aggregator.

* `@0x/types`: Add `SignedOrderWithoutDomain` type.

* `@0x/asset-swapper`: Update aggregator to take and return orders with signatures.

* `@0x/asset-swapper`: Fix broken aggregator tests.

* `@0x/asset-swapper`: Pass the sampler contract into aggregator entry points.

* `@0x/contract-artifacts`: Add `IERC20BridgeSampler` artifact.

* `@0x/contract-wrappers`: Add `IERC20BridgeSampler` wrapper.

* `@0x/asset-swapper`: Address review comments.

* fixed testing

* refactored aggregate.ts and embeded into asset-swapper

* added adjusted rates for taker and maker fees

* remove PrunedSignedOrders

* updated contract-addresses and addressed some other todos

* streamlined logic

* patched in lawrences changes

* renamed aggregator utils and removed market_utils.ts

* added ack heartbeats

* fixed bug

* patches

* added dummy order things

* Dummy with valid sig

* Tweak gas price calculation to wei

* added test coverage and fixed bugs

* fixed migrations

* Fix CHANGELOGs and types export

* Deploy latest ERC20BridgeSampler on Mainnet

* `@0x/types` Revert CHANGELOG.

* `@0x/asset-swapper`: Address review comments.
`@0x/contract-addresses`: Make kyber lowercase.

* made protocol fee multiplier async

* `@0x/asset-swapper: Fix build errors and do some code cleanup.

* use assetDataUtils where possible
2019-12-16 12:35:58 -08:00
Arctek
e00f059a4a Fix circular refence 2019-12-14 16:00:05 +10:30
Greg Hysz
6808e0d531 Merge pull request #2365 from 0xProject/feat/asset-proxy/DyDxBridge
dYdX Bridge
2019-12-13 13:46:06 -08:00
Greg Hysen
410c95308a Updated dydx account encoding to assume that all actions are on partial balances 2019-12-13 12:02:23 -08:00
Greg Hysen
bec1f23616 Fixed merge conflicts 2019-12-13 11:06:16 -08:00
Greg Hysen
34596b7f83 Use safeGetPartialAmountFloor 2019-12-13 10:58:22 -08:00
Greg Hysen
5ca7169ee5 Reverted to version of dydx bridge that only allows from to be the account owner 2019-12-13 10:58:22 -08:00
Greg Hysen
3300aaa1b9 Refactored so that deposits are done from taker asset data and withdrawals from maker asset data. 2019-12-13 10:58:22 -08:00
Greg Hysen
54afc8a4a1 Fixed merge conflicts 2019-12-13 10:58:22 -08:00
Greg Hysen
f19f4310f4 Updating bridge to work w/o MultiAssetProxy 2019-12-13 10:57:57 -08:00
Greg Hysen
444125a7e1 Simplified the dydx bridge implememtation that does not use the bridge as the maker. 2019-12-13 10:57:57 -08:00
Greg Hysen
56cbb69401 DyDx bridge implementation using contract as maker with signature validation. 2019-12-13 10:56:54 -08:00
Lawrence Forman
70870ffcd2 Swallow reverts in ERC20BridgeSampler (#2395)
* `@0x/erc20-bridge-sampler`: Do not query empty/unsigned orders. Swallow revets on DEX quotes.

* `@0x/contracts-utils`: Add `DEV_UTILS_ADDRESS` and `KYBER_ETH_ADDRESS` to `DeploymentConstants`.

* `@0x/contracts-erc20-bridge-sampler`: Address review comments.
2019-12-13 10:53:25 -08:00
mzhu25
a556d91673 Merge pull request #2387 from 0xProject/feature/fuzz/staking-rewards
`@0x/contracts-integrations`: Staking rewards fuzz test
2019-12-12 15:43:29 -08:00
Michael Zhu
8ecbde8e1e Chagne StoredBalance functions to not mutate in place 2019-12-12 15:21:42 -08:00
Michael Zhu
a24b293818 register actors in the SimulationEnvironment constructor 2019-12-12 14:38:07 -08:00
Xianny
cab5ebf94b re-enable coordinator client tests (#2394) 2019-12-12 14:36:52 -08:00
Jacob Evans
a54b5baef2 Merge pull request #2393 from 0xProject/feature/orderbook-orderstore-async
orderbook: Make OrderStore async for use in db adapter
2019-12-12 10:30:17 -08:00
Jacob Evans
c324fe204e Make OrderStore async for use in db adapter
CHANGELOGS
2019-12-12 09:43:07 -08:00
Amir Bandeali
37d972ed9e Merge pull request #2389 from 0xProject/feat/contracts/mainnet-fork
Allow mainnet fork to be used for contract tests
2019-12-11 22:50:09 -08:00
Michael Zhu
e4a3b1cb05 fix bug in LibFractions reference function 2019-12-11 18:12:02 -08:00
Michael Zhu
49538f272e address comments 2019-12-11 16:54:48 -08:00
mzhu25
1283232144 Merge pull request #2372 from 0xProject/feature/fuzz/prng
`@0x/contracts-integrations`: Seeded RNG and simulation logging
2019-12-11 10:23:08 -08:00
Michael Zhu
2f9891f0aa fix CI failures 2019-12-10 00:32:48 -08:00
Michael Zhu
865a2b1fb0 add/update comments 2019-12-09 23:45:38 -08:00
Michael Zhu
1fde62eeb6 fix bug in finalizePool 2019-12-09 23:45:38 -08:00
Michael Zhu
6754cd48e2 refactor + fix lint 2019-12-09 23:45:38 -08:00
Michael Zhu
ccb477687a fixing bugs 2019-12-09 23:45:38 -08:00
Michael Zhu
be0e6c8925 Staking rewards simulation/fuzz test 2019-12-09 23:45:38 -08:00
Michael Zhu
1c2cb947c0 Add assertion generators to keeper, staker, taker mixins for the new function assertions 2019-12-09 23:45:38 -08:00
Michael Zhu
4663eec950 Add function assertions required for staking rewards fuzzing: withdrawDelegatorRewards, finalizePool, and endEpoch. Also adds payProtocolFee-related assertions to fillOrder 2019-12-09 23:45:37 -08:00
Michael Zhu
fff3c1eb36 update pool membership simulation to use multiple makers and takers, partial fills 2019-12-09 23:43:16 -08:00
Michael Zhu
4b7434d1e8 post-rebase lockfile update 2019-12-09 23:42:32 -08:00
Michael Zhu
8cc35a60e6 Add yarn command to run a specific fuzz test 2019-12-09 23:42:32 -08:00
Michael Zhu
130653a1aa move logger, pseudorandom, wrapper_interfaces to framework/utils/ 2019-12-09 23:42:32 -08:00
Michael Zhu
1dcbebd130 lint 2019-12-09 23:42:32 -08:00
Michael Zhu
faf306ad23 Simulation logging, hopefully address function assertion lifetime issue 2019-12-09 23:42:32 -08:00
Michael Zhu
d11cdcd5d2 Use seeded rng for simulations 2019-12-09 23:42:32 -08:00
Amir Bandeali
0e59bd0bf3 Add mainnet config tests 2019-12-09 16:16:22 -08:00
Amir Bandeali
c0c6154ec1 Add fork option to describe and blockchainTests 2019-12-09 16:14:41 -08:00
Amir Bandeali
cb5384c2fb Use fork configs if FORK_RPC_URL env var is set 2019-12-09 16:14:41 -08:00
Amir Bandeali
038c836fe5 Rename fillorder_test to fill_order_test 2019-12-09 16:14:41 -08:00
xianny
6b0f3570b9 Publish
- @0x/contracts-asset-proxy@3.0.1
 - @0x/contracts-coordinator@3.0.1
 - @0x/contracts-dev-utils@1.0.1
 - @0x/contracts-erc1155@2.0.1
 - @0x/contracts-erc20-bridge-sampler@1.0.1
 - @0x/contracts-erc20@3.0.1
 - @0x/contracts-erc721@3.0.1
 - @0x/contracts-exchange-forwarder@4.0.1
 - @0x/contracts-exchange-libs@4.0.1
 - @0x/contracts-exchange@3.0.1
 - @0x/contracts-extensions@5.1.0
 - @0x/contracts-integrations@2.0.1
 - @0x/contracts-multisig@4.0.1
 - @0x/contracts-staking@2.0.1
 - @0x/contracts-test-utils@5.0.0
 - @0x/contracts-tests@0.0.7
 - @0x/contracts-utils@4.0.1
 - 0x.js@9.0.1
 - @0x/abi-gen@5.0.1
 - @0x/assert@3.0.1
 - @0x/asset-swapper@3.0.1
 - @0x/base-contract@6.0.1
 - @0x/connect@6.0.1
 - @0x/contract-artifacts@3.1.0
 - @0x/contract-wrappers-test@12.2.2
 - @0x/contract-wrappers@13.1.0
 - @0x/contracts-gen@2.0.1
 - @0x/dev-utils@3.0.1
 - @0x/instant@1.0.38
 - @0x/json-schemas@5.0.1
 - @0x/migrations@5.0.1
 - @0x/monorepo-scripts@1.0.44
 - @0x/order-utils@10.0.0
 - @0x/orderbook@1.0.1
 - @0x/sol-compiler@4.0.1
 - @0x/sol-coverage@4.0.1
 - @0x/sol-doc@3.0.1
 - @0x/sol-profiler@4.0.1
 - @0x/sol-resolver@3.0.1
 - @0x/sol-trace@3.0.1
 - @0x/sol-tracing-utils@7.0.1
 - @0x/sra-spec@3.0.1
 - @0x/subproviders@6.0.1
 - @0x/types@3.1.0
 - @0x/utils@5.1.0
 - @0x/web3-wrapper@7.0.1
2019-12-09 14:53:19 -08:00
xianny
71de0d04f3 Updated CHANGELOGS & MD docs 2019-12-09 14:53:05 -08:00
Xianny
99debff5d2 Add syntactic sugar for assetDataUtils (#2388)
* add syntactic sugar for assetDataUtils
2019-12-09 13:55:58 -08:00
Amir Bandeali
3bac6fcb27 Merge pull request #2377 from 0xProject/feat/forwarder/multi-affiliate-fees
Forwarder affiliate fee usability improvements
2019-12-08 19:13:28 -08:00
Amir Bandeali
4b842b81a0 Address PR feedback 2019-12-08 16:28:00 -08:00
Amir Bandeali
e2e4d048ab Update tests to use new Forwarder interface 2019-12-04 21:23:55 -08:00
Amir Bandeali
5574c368cd Allow different ETh fees to be specified for different feeRecipient addresses 2019-12-04 21:23:55 -08:00
Amir Bandeali
0d34f7b92e Add EthFeeLengthMismatchError 2019-12-04 21:23:55 -08:00
Amir Bandeali
5be0632e01 Add tests with multiple fee recipients 2019-12-04 21:23:55 -08:00
Amir Bandeali
79ea0bf9f4 Allow affiliate fee to be split between multiple fee recipient addresses 2019-12-04 21:23:54 -08:00
Amir Bandeali
b1929cb688 Update affiliate fee tests 2019-12-04 21:23:54 -08:00
Amir Bandeali
5ad98700e5 Remove FeePercentageTooLargeError rich revert 2019-12-04 21:22:54 -08:00
Amir Bandeali
a54624b697 Do not return ethFeePaid 2019-12-04 21:22:54 -08:00
Amir Bandeali
ca34c865af Remove max fee percentage for affiliate fees 2019-12-04 21:22:54 -08:00
Amir Bandeali
dde57b1eca Make affiliate fee a flat amount 2019-12-04 21:22:54 -08:00
Amir Bandeali
264b06938e Merge pull request #2378 from 0xProject/feat/bridges/chai-bridge
Implement ChaiBridge
2019-12-04 16:25:46 -08:00
John Johnson
99edb303e2 Merge pull request #2386 from 0xProject/feature/fix-unbound-provider
Fix unbound method in provider standardizer
2019-12-04 15:44:22 -08:00
John Johnson
104cc24dfc Fixing unbound provider (metamask v7.7 incorrectly binds this) 2019-12-04 15:09:00 -08:00
Xianny
fcbcbac889 Remove assetDataUtils everywhere (#2373)
* remove assetDataUtils everywhere

* export IAssetDataContract from @0x/contract-wrappers to allow @0x/instant to decode asset data  synchronously

* export generic function `decodeAssetDataOrThrow` and add ERC20Bridge support

* export `hexUtils` from order-utils instead of contracts-test-utils
2019-12-04 13:08:08 -08:00
mzhu25
b86d19028c Merge pull request #2366 from 0xProject/feature/fuzz/makers-and-takers
Pool Member Fuzz Tests
2019-12-04 11:12:55 -08:00
F. Eugene Aumson
4f17a251d3 Python publish for v3 (#2383)
* Remove pre-release suffixes from version numbers

* For wrapper test, pull latest ganache image first

* For wrapper test, unpin ganache, use beta snapshot

* In docs, advise using beta ganache snapshot

Because we haven't yet published the non-beta snapshot

* Unpin package interdependencies

* unpin tests from beta 0xorg/ganache-cli version

* use beta ganache snapshot

* Set release date in CHANGELOGs

* In testing deployment, stop testing pre-releases

* Include rmtree("build") in all clean commands

* Fix clean not cleaning what it thought it was

* In monorepo script, install pkgs 1st then dev deps

* Stop pinning ganache snapshot version

* In test setup, wait longer for mesh to start up

* Fix broken hyperlinks in docs

* fix missing \n that was breaking doc rendering

* In monorepo script comment, fix typo, and clarify
2019-12-04 08:42:00 -08:00
Alex Browne
731a823cc2 Update CODEOWNERS
Remove albrow as code owner for the `contract-addresses` and `contract-artifacts` packages. It's been a long time since I've worked on these packages and I am no longer the best person to review changes to them.
2019-12-03 17:19:08 -08:00
Michael Zhu
3d79fe2bf4 post-rebase lockfile update 2019-12-03 15:34:59 -08:00
Alex Towle
474399154f Addressed last review comment 2019-12-03 14:41:53 -08:00
Alex Towle
19f5153d0e Addressed some review feedback 2019-12-03 14:41:53 -08:00
Alex Towle
ce11271866 Appease the linter 2019-12-03 14:40:18 -08:00
Alex Towle
86cf353296 Improved the fuzz test 2019-12-03 14:40:07 -08:00
Alex Towle
36df5dc721 Implemented a hacky version of the fillOrder fuzz tests 2019-12-03 14:40:07 -08:00
Alex Towle
1e44a9c942 Made function assertions work with the new wrappers 2019-12-03 14:39:29 -08:00
mzhu25
8685cf9036 Merge pull request #2357 from 0xProject/refactor/integrations/transaction-tests
`@0x/contracts-integrations`: Transaction integration tests
2019-12-03 11:04:11 -08:00
Michael Zhu
2232870b09 address comments 2019-12-03 10:35:59 -08:00
Amir Bandeali
b68acd101e Fix failing tests 2019-12-03 08:46:47 -08:00
Amir Bandeali
173ba9b2b5 Add ChaiBridge unit tests 2019-12-02 16:42:17 -08:00
Amir Bandeali
64ed1f87d3 Rethrow custom error string if draw call fails 2019-12-02 16:42:17 -08:00
Michael Zhu
1ca085ec4a address comments 2019-12-02 15:39:03 -08:00
Michael Zhu
e332b7535c prettier 2019-12-02 15:39:02 -08:00
Michael Zhu
79eb613b3e Use AbiEncoder for methodAbiToFunctionSignature 2019-12-02 15:39:02 -08:00
Michael Zhu
5a79ec28d1 transaction protocol fee integration tests 2019-12-02 15:39:02 -08:00
Michael Zhu
97e65a02c0 fix test nesting 2019-12-02 15:39:02 -08:00
Michael Zhu
e87c786b77 fix dataItemsToABIString 2019-12-02 15:39:02 -08:00
Michael Zhu
251d30d47f refactor transaction integration tests to use new framework 2019-12-02 15:39:02 -08:00
Amir Bandeali
7a3f878c11 Add ChaiBridge to boilerplate 2019-12-01 15:57:01 -08:00
Amir Bandeali
b8439598bc Remove redundant getters from bridges 2019-12-01 15:55:27 -08:00
Amir Bandeali
7fb0818923 Implement ChaiBridge 2019-12-01 15:54:58 -08:00
Amir Bandeali
a7c435adc4 Add mainnet deployment addresses for Dai, Chai, and ERC20BridgeProxy 2019-12-01 15:40:29 -08:00
497 changed files with 21737 additions and 8414 deletions

View File

@@ -23,7 +23,7 @@ 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 --global yarn@1.17.0
command: npm install --force --global yarn@1.17.0
- run:
name: yarn
command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
@@ -77,7 +77,7 @@ 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-asset-proxy @0x/contracts-exchange-forwarder @0x/contracts-tests @0x/contracts-staking @0x/contracts-coordinator @0x/contracts-erc20-bridge-sampler
- 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-tests @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.
@@ -193,20 +193,14 @@ jobs:
working_directory: ~/repo
docker:
- image: nikolaik/python-nodejs:python3.7-nodejs8
- image: 0xorg/ganache-cli:4.4.0-beta.1
environment:
VERSION: latest
SNAPSHOT_NAME: 0x_ganache_snapshot-v3-beta
- image: 0xorg/ganache-cli
- image: 0xorg/mesh:0xV3
environment:
ETHEREUM_RPC_URL: 'http://localhost:8545'
ETHEREUM_NETWORK_ID: '50'
ETHEREUM_CHAIN_ID: '1337'
USE_BOOTSTRAP_LIST: 'true'
VERBOSITY: 3
PRIVATE_KEY_PATH: ''
BLOCK_POLLING_INTERVAL: '5s'
P2P_LISTEN_PORT: '60557'
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
@@ -219,7 +213,7 @@ jobs:
TAKER_FEE_UNIT_AMOUNT: 0
MESH_ENDPOINT: 'ws://localhost:60557'
command: |
sh -c "waitForMesh () { sleep 5; }; waitForMesh && node_modules/.bin/forever ts/lib/index.js"
sh -c "waitForMesh () { sleep 30; }; waitForMesh && node_modules/.bin/forever ts/lib/index.js"
steps:
- checkout
- restore_cache:

28
.gitignore vendored
View File

@@ -160,33 +160,7 @@ 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/dev_utils/__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/erc1155_mintable/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc1155_proxy/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_bridge_proxy/__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/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/staking/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/staking_proxy/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/static_call_proxy/__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
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/zrx_vault/__init__.py
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/*/__init__.py
# solc-bin in sol-compiler
packages/sol-compiler/solc_bin/

View File

@@ -14,8 +14,8 @@ packages/abi-gen/ @feuGeneA
packages/base-contract/ @xianny
packages/connect/ @fragosti
packages/abi-gen-templates/ @feuGeneA @xianny
packages/contract-addresses/ @albrow
packages/contract-artifacts/ @albrow
packages/contract-addresses/ @abandeali1
packages/contract-artifacts/ @abandeali1
packages/dev-utils/ @LogvinovLeon @fabioberger
packages/devnet/ @albrow
packages/ethereum-types/ @LogvinovLeon

View File

@@ -1,4 +1,40 @@
[
{
"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": [
@@ -55,6 +91,10 @@
{
"note": "Implement `KyberBridge`.",
"pr": 2352
},
{
"note": "Implement `DydxBridge`.",
"pr": 2365
}
],
"timestamp": 1575290197

View File

@@ -5,6 +5,20 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## 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)
@@ -22,6 +36,7 @@ CHANGELOG
## v2.3.0-beta.4 - _December 2, 2019_
* Implement `KyberBridge`. (#2352)
* Implement `DydxBridge`. (#2365)
## v2.3.0-beta.3 - _November 20, 2019_

View File

@@ -0,0 +1,75 @@
/*
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 `0x37708e9b` 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

@@ -0,0 +1,241 @@
/*
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.
accountId: bridgeAction.accountId, // 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,
otherAccountId: 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.
accountId: bridgeAction.accountId, // 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,
otherAccountId: 0,
data: hex''
});
}
}

View File

@@ -55,7 +55,7 @@ contract Eth2DaiBridge is
// Decode the bridge data to get the `fromTokenAddress`.
(address fromTokenAddress) = abi.decode(bridgeData, (address));
IEth2Dai exchange = _getEth2DaiContract();
IEth2Dai exchange = IEth2Dai(_getEth2DaiAddress());
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
LibERC20Token.approve(fromTokenAddress, address(exchange), uint256(-1));
@@ -84,14 +84,4 @@ contract Eth2DaiBridge is
{
return LEGACY_WALLET_MAGIC_VALUE;
}
/// @dev Overridable way to get the eth2dai contract.
/// @return exchange The Eth2Dai exchange contract.
function _getEth2DaiContract()
internal
view
returns (IEth2Dai exchange)
{
return IEth2Dai(_getEth2DaiAddress());
}
}

View File

@@ -24,6 +24,7 @@ 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";
@@ -34,6 +35,8 @@ contract KyberBridge is
IWallet,
DeploymentConstants
{
using LibSafeMath for uint256;
// @dev Structure used internally to get around stack limits.
struct TradeState {
IKyberNetworkProxy kyber;
@@ -41,6 +44,7 @@ contract KyberBridge is
address fromTokenAddress;
uint256 fromTokenBalance;
uint256 payableAmount;
uint256 conversionRate;
}
/// @dev Kyber ETH pseudo-address.
@@ -77,15 +81,27 @@ contract KyberBridge is
returns (bytes4 success)
{
TradeState memory state;
state.kyber = _getKyberContract();
state.weth = _getWETHContract();
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);
@@ -118,7 +134,7 @@ contract KyberBridge is
uint256(-1),
// Compute the minimum conversion rate, which is expressed in units with
// 18 decimal places.
(KYBER_RATE_BASE * amount) / state.fromTokenBalance,
state.conversionRate,
// No affiliate address.
address(0)
);
@@ -143,24 +159,4 @@ contract KyberBridge is
{
return LEGACY_WALLET_MAGIC_VALUE;
}
/// @dev Overridable way to get the `KyberNetworkProxy` contract.
/// @return kyber The `IKyberNetworkProxy` contract.
function _getKyberContract()
internal
view
returns (IKyberNetworkProxy kyber)
{
return IKyberNetworkProxy(_getKyberNetworkProxyAddress());
}
/// @dev Overridable way to get the WETH contract.
/// @return weth The WETH contract.
function _getWETHContract()
internal
view
returns (IEtherToken weth)
{
return IEtherToken(_getWETHAddress());
}
}

View File

@@ -88,7 +88,7 @@ contract UniswapBridge is
// Get our balance of `fromTokenAddress` token.
state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
// Get the weth contract.
state.weth = getWethContract();
state.weth = IEtherToken(_getWethAddress());
// Convert from WETH to a token.
if (fromTokenAddress == address(state.weth)) {
@@ -134,8 +134,8 @@ contract UniswapBridge is
state.fromTokenBalance,
// Minimum buy amount.
amount,
// No minimum intermediate ETH buy amount.
0,
// Must buy at least 1 intermediate ETH.
1,
// Expires after this block.
block.timestamp,
// Recipient is `to`.
@@ -161,26 +161,6 @@ contract UniswapBridge is
return LEGACY_WALLET_MAGIC_VALUE;
}
/// @dev Overridable way to get the weth contract.
/// @return token The WETH contract.
function getWethContract()
public
view
returns (IEtherToken token)
{
return IEtherToken(_getWETHAddress());
}
/// @dev Overridable way to get the uniswap exchange factory contract.
/// @return factory The exchange factory contract.
function getUniswapExchangeFactoryContract()
public
view
returns (IUniswapExchangeFactory factory)
{
return IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress());
}
/// @dev Grants an unlimited allowance to the exchange for its token
/// on behalf of this contract.
/// @param exchange The Uniswap token exchange.
@@ -207,11 +187,12 @@ contract UniswapBridge is
{
address exchangeTokenAddress = fromTokenAddress;
// Whichever isn't WETH is the exchange token.
if (fromTokenAddress == address(getWethContract())) {
if (fromTokenAddress == _getWethAddress()) {
exchangeTokenAddress = toTokenAddress;
}
exchange = IUniswapExchange(
getUniswapExchangeFactoryContract().getExchange(exchangeTokenAddress)
IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress())
.getExchange(exchangeTokenAddress)
);
require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN");
return exchange;

View File

@@ -0,0 +1,33 @@
/*
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;
// The actual Chai contract can be found here: https://github.com/dapphub/chai
contract IChai {
/// @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;
}

View File

@@ -0,0 +1,89 @@
/*
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 accountId;
AssetAmount amount;
uint256 primaryMarketId;
uint256 secondaryMarketId;
address otherAddress;
uint256 otherAccountId;
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;
}
/// @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;
}

View File

@@ -0,0 +1,42 @@
/*
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 accountId; // 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

@@ -0,0 +1,80 @@
/*
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

@@ -0,0 +1,191 @@
/*
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";
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 accountId,
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].accountId,
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].otherAccountId,
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 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

@@ -192,11 +192,11 @@ contract TestEth2DaiBridge is
}
// @dev This contract will double as the Eth2Dai contract.
function _getEth2DaiContract()
function _getEth2DaiAddress()
internal
view
returns (IEth2Dai)
returns (address)
{
return IEth2Dai(address(this));
return address(this);
}
}

View File

@@ -67,9 +67,11 @@ interface ITestContract {
/// @dev A minimalist ERC20/WETH token.
contract TestToken {
uint8 public decimals;
ITestContract private _testContract;
constructor() public {
constructor(uint8 decimals_) public {
decimals = decimals_;
_testContract = ITestContract(msg.sender);
}
@@ -165,7 +167,7 @@ contract TestKyberBridge is
uint256 private _nextFillAmount;
constructor() public {
weth = IEtherToken(address(new TestToken()));
weth = IEtherToken(address(new TestToken(18)));
}
/// @dev Implementation of `IKyberNetworkProxy.trade()`
@@ -195,11 +197,11 @@ contract TestKyberBridge is
return _nextFillAmount;
}
function createToken()
function createToken(uint8 decimals)
external
returns (address tokenAddress)
{
return address(new TestToken());
return address(new TestToken(decimals));
}
function setNextFillAmount(uint256 amount)
@@ -303,20 +305,20 @@ contract TestKyberBridge is
}
// @dev overridden to point to this contract.
function _getKyberContract()
function _getKyberNetworkProxyAddress()
internal
view
returns (IKyberNetworkProxy kyber)
returns (address)
{
return IKyberNetworkProxy(address(this));
return address(this);
}
// @dev overridden to point to test WETH.
function _getWETHContract()
function _getWethAddress()
internal
view
returns (IEtherToken weth_)
returns (address)
{
return weth;
return address(weth);
}
}

View File

@@ -413,20 +413,20 @@ contract TestUniswapBridge is
}
// @dev Use `wethToken`.
function getWethContract()
public
function _getWethAddress()
internal
view
returns (IEtherToken)
returns (address)
{
return IEtherToken(address(wethToken));
return address(wethToken);
}
// @dev This contract will double as the Uniswap contract.
function getUniswapExchangeFactoryContract()
public
function _getUniswapExchangeFactoryAddress()
internal
view
returns (IUniswapExchangeFactory)
returns (address)
{
return IUniswapExchangeFactory(address(this));
return address(this);
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-asset-proxy",
"version": "3.0.0",
"version": "3.1.0",
"engines": {
"node": ">=6.12"
},
@@ -38,8 +38,7 @@
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
},
"config": {
"publicInterfaceContracts": "ERC1155Proxy,ERC20Proxy,ERC721Proxy,MultiAssetProxy,StaticCallProxy,ERC20BridgeProxy,Eth2DaiBridge,IAssetData,IAssetProxy,UniswapBridge,KyberBridge,TestStaticCallTarget",
"abis": "./test/generated-artifacts/@(ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
"abis": "./test/generated-artifacts/@(ChaiBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
},
"repository": {
@@ -52,15 +51,15 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.0",
"@0x/contracts-gen": "^2.0.0",
"@0x/contracts-test-utils": "^4.0.0",
"@0x/contracts-utils": "^4.0.0",
"@0x/dev-utils": "^3.0.0",
"@0x/sol-compiler": "^4.0.0",
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/contracts-utils": "^4.0.3",
"@0x/dev-utils": "^3.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.0.0",
"@0x/types": "^3.1.1",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -80,15 +79,16 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.0",
"@0x/contracts-dev-utils": "^1.0.0",
"@0x/contracts-erc1155": "^2.0.0",
"@0x/contracts-erc20": "^3.0.0",
"@0x/contracts-erc721": "^3.0.0",
"@0x/order-utils": "^9.0.0",
"@0x/typescript-typings": "^5.0.0",
"@0x/utils": "^5.0.0",
"@0x/web3-wrapper": "^7.0.0",
"@0x/base-contract": "^6.0.3",
"@0x/contracts-dev-utils": "^1.0.3",
"@0x/contracts-erc1155": "^2.0.3",
"@0x/contracts-erc20": "^3.0.3",
"@0x/contracts-erc721": "^3.0.3",
"@0x/contracts-exchange-libs": "^4.0.3",
"@0x/order-utils": "^10.1.0",
"@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.1.2",
"@0x/web3-wrapper": "^7.0.3",
"ethereum-types": "^3.0.0",
"lodash": "^4.17.11"
},

View File

@@ -5,6 +5,8 @@
*/
import { ContractArtifact } from 'ethereum-types';
import * as ChaiBridge from '../generated-artifacts/ChaiBridge.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';
@@ -12,22 +14,62 @@ 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 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,
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
StaticCallProxy: StaticCallProxy as ContractArtifact,
ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact,
ChaiBridge: ChaiBridge 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,
UniswapBridge: UniswapBridge as ContractArtifact,
KyberBridge: KyberBridge as ContractArtifact,
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
IAuthorizable: IAuthorizable as ContractArtifact,
IChai: IChai 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

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

View File

@@ -5,6 +5,8 @@ export {
ERC20ProxyContract,
ERC721ProxyContract,
Eth2DaiBridgeContract,
DydxBridgeContract,
TestDydxBridgeContract,
IAssetDataContract,
IAssetProxyContract,
MultiAssetProxyContract,
@@ -62,3 +64,4 @@ export {
TupleDataItem,
StateMutability,
} from 'ethereum-types';
export * from './dydx_bridge_encoder';

View File

@@ -3,6 +3,8 @@
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../generated-wrappers/chai_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';
@@ -10,8 +12,27 @@ 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_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

@@ -5,6 +5,8 @@
*/
import { ContractArtifact } from 'ethereum-types';
import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.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';
@@ -14,6 +16,9 @@ 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 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';
@@ -25,6 +30,8 @@ import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizabl
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';
@@ -41,6 +48,8 @@ export const artifacts = {
ERC721Proxy: ERC721Proxy as ContractArtifact,
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
StaticCallProxy: StaticCallProxy as ContractArtifact,
ChaiBridge: ChaiBridge as ContractArtifact,
DydxBridge: DydxBridge as ContractArtifact,
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
KyberBridge: KyberBridge as ContractArtifact,
UniswapBridge: UniswapBridge as ContractArtifact,
@@ -48,11 +57,16 @@ export const artifacts = {
IAssetProxy: IAssetProxy as ContractArtifact,
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
IAuthorizable: IAuthorizable as ContractArtifact,
IChai: IChai 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,

View File

@@ -0,0 +1,60 @@
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

@@ -0,0 +1,399 @@
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,
accountId: constants.ZERO_AMOUNT,
marketId,
conversionRateNumerator: constants.ZERO_AMOUNT,
conversionRateDenominator: constants.ZERO_AMOUNT,
};
const defaultWithdrawAction = {
actionType: DydxBridgeActionType.Withdraw,
accountId: 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,
accountId: action.accountId,
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

@@ -3,15 +3,12 @@ import {
constants,
expect,
getRandomInteger,
hexLeftPad,
hexRightPad,
hexSlice,
Numberish,
randomAddress,
} from '@0x/contracts-test-utils';
import { AuthorizableRevertErrors } from '@0x/contracts-utils';
import { AssetProxyId } from '@0x/types';
import { AbiEncoder, BigNumber, StringRevertError } from '@0x/utils';
import { AbiEncoder, BigNumber, hexUtils, StringRevertError } from '@0x/utils';
import { DecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
@@ -21,7 +18,7 @@ import { ERC20BridgeProxyContract, TestERC20BridgeContract } from './wrappers';
blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
const PROXY_ID = AssetProxyId.ERC20Bridge;
const BRIDGE_SUCCESS_RETURN_DATA = hexRightPad(PROXY_ID);
const BRIDGE_SUCCESS_RETURN_DATA = hexUtils.rightPad(PROXY_ID);
let owner: string;
let badCaller: string;
let assetProxy: ERC20BridgeProxyContract;
@@ -173,7 +170,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
it('fails if asset data is truncated', async () => {
const opts = createTransferFromOpts();
const truncatedAssetData = hexSlice(encodeAssetData(opts.assetData), 0, -1);
const truncatedAssetData = hexUtils.slice(encodeAssetData(opts.assetData), 0, -1);
const tx = assetProxy
.transferFrom(truncatedAssetData, opts.from, opts.to, new BigNumber(opts.amount))
.awaitTransactionSuccessAsync();
@@ -197,7 +194,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
const tx = transferFromAsync({
assetData: createAssetData({
bridgeData: createBridgeData({
returnData: hexLeftPad('0x1'),
returnData: hexUtils.leftPad('0x1'),
}),
}),
});
@@ -210,7 +207,7 @@ blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
const tx = transferFromAsync({
assetData: createAssetData({
bridgeData: createBridgeData({
returnData: hexRightPad('0x1'),
returnData: hexUtils.rightPad('0x1'),
}),
}),
});

View File

@@ -4,13 +4,11 @@ import {
expect,
filterLogsToArguments,
getRandomInteger,
hexLeftPad,
hexRandom,
Numberish,
randomAddress,
} from '@0x/contracts-test-utils';
import { AssetProxyId } from '@0x/types';
import { BigNumber, RawRevertError } from '@0x/utils';
import { BigNumber, hexUtils, RawRevertError } from '@0x/utils';
import { DecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
@@ -39,7 +37,9 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
describe('isValidSignature()', () => {
it('returns success bytes', async () => {
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
const result = await testContract.isValidSignature(hexRandom(), hexRandom(_.random(0, 32))).callAsync();
const result = await testContract
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
.callAsync();
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
});
});
@@ -71,7 +71,7 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
fillAmount: getRandomInteger(1, 100e18),
fromTokenBalance: getRandomInteger(1, 100e18),
toTokentransferRevertReason: '',
toTokenTransferReturnData: hexLeftPad(1),
toTokenTransferReturnData: hexUtils.leftPad(1),
...opts,
};
}
@@ -111,7 +111,7 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
_opts.toAddress,
new BigNumber(_opts.amount),
// ABI-encode the "from" token address as the bridge data.
hexLeftPad(_opts.fromTokenAddress as string),
hexUtils.leftPad(_opts.fromTokenAddress as string),
);
const result = await bridgeTransferFromFn.callAsync();
const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
@@ -179,13 +179,13 @@ blockchainTests.resets('Eth2DaiBridge unit tests', env => {
});
it('fails if `toTokenAddress.transfer()` returns false', async () => {
const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexLeftPad(0) });
const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexUtils.leftPad(0) });
const tx = withdrawToAsync(opts);
return expect(tx).to.revertWith(new RawRevertError(hexLeftPad(0)));
return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(0)));
});
it('succeeds if `toTokenAddress.transfer()` returns true', async () => {
await withdrawToAsync({ toTokenTransferReturnData: hexLeftPad(1) });
await withdrawToAsync({ toTokenTransferReturnData: hexUtils.leftPad(1) });
});
});
});

View File

@@ -3,13 +3,12 @@ import {
constants,
expect,
getRandomInteger,
hexLeftPad,
hexRandom,
getRandomPortion,
randomAddress,
verifyEventsFromLogs,
} from '@0x/contracts-test-utils';
import { AssetProxyId } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { BigNumber, hexUtils } from '@0x/utils';
import { DecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
@@ -19,6 +18,12 @@ 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 () => {
@@ -33,7 +38,9 @@ blockchainTests.resets('KyberBridge unit tests', env => {
describe('isValidSignature()', () => {
it('returns success bytes', async () => {
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
const result = await testContract.isValidSignature(hexRandom(), hexRandom(_.random(0, 32))).callAsync();
const result = await testContract
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
.callAsync();
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
});
});
@@ -45,10 +52,10 @@ blockchainTests.resets('KyberBridge unit tests', env => {
before(async () => {
wethAddress = await testContract.weth().callAsync();
fromTokenAddress = await testContract.createToken().callAsync();
await testContract.createToken().awaitTransactionSuccessAsync();
toTokenAddress = await testContract.createToken().callAsync();
await testContract.createToken().awaitTransactionSuccessAsync();
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 = {
@@ -75,13 +82,14 @@ blockchainTests.resets('KyberBridge unit tests', env => {
}
function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100));
return {
fromTokenAddress,
toTokenAddress,
amount,
toAddress: randomAddress(),
amount: getRandomInteger(1, 10e18),
fillAmount: getRandomInteger(1, 10e18),
fromTokenBalance: getRandomInteger(1, 10e18),
fillAmount: getRandomPortion(amount),
fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)),
...opts,
};
}
@@ -107,7 +115,7 @@ blockchainTests.resets('KyberBridge unit tests', env => {
// Transfer amount.
_opts.amount,
// ABI-encode the input token address as the bridge data.
hexLeftPad(_opts.fromTokenAddress),
hexUtils.leftPad(_opts.fromTokenAddress),
);
const result = await bridgeTransferFromFn.callAsync();
const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
@@ -119,9 +127,12 @@ blockchainTests.resets('KyberBridge unit tests', env => {
}
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
.times(constants.ONE_ETHER)
.div(opts.fromTokenBalance)
.div(toBase)
.div(opts.fromTokenBalance.div(fromBase))
.times(KYBER_RATE_BASE)
.integerValue(BigNumber.ROUND_DOWN);
}

View File

@@ -5,13 +5,11 @@ import {
filterLogs,
filterLogsToArguments,
getRandomInteger,
hexLeftPad,
hexRandom,
Numberish,
randomAddress,
} from '@0x/contracts-test-utils';
import { AssetProxyId } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { BigNumber, hexUtils } from '@0x/utils';
import { DecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
@@ -46,7 +44,9 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
describe('isValidSignature()', () => {
it('returns success bytes', async () => {
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
const result = await testContract.isValidSignature(hexRandom(), hexRandom(_.random(0, 32))).callAsync();
const result = await testContract
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
.callAsync();
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
});
});
@@ -126,7 +126,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
// The amount to transfer to "to"
new BigNumber(_opts.amount),
// ABI-encoded "from" token address.
hexLeftPad(_opts.fromTokenAddress),
hexUtils.leftPad(_opts.fromTokenAddress),
);
const result = await bridgeTransferFromFn.callAsync();
const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
@@ -176,7 +176,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
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(0);
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);
@@ -208,7 +208,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
randomAddress(),
randomAddress(),
getRandomInteger(1, 1e18),
hexLeftPad(randomAddress()),
hexUtils.leftPad(randomAddress()),
)
.awaitTransactionSuccessAsync();
return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
@@ -282,7 +282,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
randomAddress(),
randomAddress(),
getRandomInteger(1, 1e18),
hexLeftPad(wethTokenAddress),
hexUtils.leftPad(wethTokenAddress),
)
.awaitTransactionSuccessAsync();
return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');
@@ -342,7 +342,7 @@ blockchainTests.resets('UniswapBridge unit tests', env => {
randomAddress(),
randomAddress(),
getRandomInteger(1, 1e18),
hexLeftPad(randomAddress()),
hexUtils.leftPad(randomAddress()),
)
.awaitTransactionSuccessAsync();
return expect(tx).to.eventually.be.rejectedWith('NO_UNISWAP_EXCHANGE_FOR_TOKEN');

View File

@@ -3,6 +3,8 @@
* 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/dydx_bridge';
export * from '../test/generated-wrappers/erc1155_proxy';
export * from '../test/generated-wrappers/erc20_bridge_proxy';
export * from '../test/generated-wrappers/erc20_proxy';
@@ -12,6 +14,9 @@ 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_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';
@@ -23,6 +28,8 @@ 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';

View File

@@ -3,6 +3,8 @@
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"generated-artifacts/ChaiBridge.json",
"generated-artifacts/DydxBridge.json",
"generated-artifacts/ERC1155Proxy.json",
"generated-artifacts/ERC20BridgeProxy.json",
"generated-artifacts/ERC20Proxy.json",
@@ -10,11 +12,32 @@
"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/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/DydxBridge.json",
"test/generated-artifacts/ERC1155Proxy.json",
"test/generated-artifacts/ERC20BridgeProxy.json",
"test/generated-artifacts/ERC20Proxy.json",
@@ -24,6 +47,9 @@
"test/generated-artifacts/IAssetProxy.json",
"test/generated-artifacts/IAssetProxyDispatcher.json",
"test/generated-artifacts/IAuthorizable.json",
"test/generated-artifacts/IChai.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",
@@ -35,6 +61,8 @@
"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",

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1578272714,
"version": "3.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"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": [

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.0.3 - _January 6, 2020_
* Dependencies updated
## v3.0.2 - _December 17, 2019_
* Dependencies updated
## v3.0.1 - _December 9, 2019_
* Dependencies updated
## v3.0.0 - _December 2, 2019_
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-coordinator",
"version": "3.0.0",
"version": "3.0.3",
"engines": {
"node": ">=6.12"
},
@@ -52,19 +52,19 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.0",
"@0x/contracts-asset-proxy": "^3.0.0",
"@0x/contracts-dev-utils": "^1.0.0",
"@0x/contracts-erc20": "^3.0.0",
"@0x/contracts-exchange": "^3.0.0",
"@0x/contracts-gen": "^2.0.0",
"@0x/contracts-test-utils": "^4.0.0",
"@0x/dev-utils": "^3.0.0",
"@0x/order-utils": "^9.0.0",
"@0x/sol-compiler": "^4.0.0",
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-asset-proxy": "^3.1.0",
"@0x/contracts-dev-utils": "^1.0.3",
"@0x/contracts-erc20": "^3.0.3",
"@0x/contracts-exchange": "^3.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/dev-utils": "^3.1.0",
"@0x/order-utils": "^10.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/web3-wrapper": "^7.0.0",
"@0x/web3-wrapper": "^7.0.3",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -84,14 +84,14 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/assert": "^3.0.0",
"@0x/base-contract": "^6.0.0",
"@0x/contract-addresses": "^4.0.0",
"@0x/contracts-utils": "^4.0.0",
"@0x/json-schemas": "^5.0.0",
"@0x/types": "^3.0.0",
"@0x/typescript-typings": "^5.0.0",
"@0x/utils": "^5.0.0",
"@0x/assert": "^3.0.3",
"@0x/base-contract": "^6.0.3",
"@0x/contract-addresses": "^4.2.0",
"@0x/contracts-utils": "^4.0.3",
"@0x/json-schemas": "^5.0.3",
"@0x/types": "^3.1.1",
"@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.1.2",
"ethereum-types": "^3.0.0",
"http-status-codes": "^1.3.2"
},

View File

@@ -1,5 +1,6 @@
import { hexConcat, signingUtils } from '@0x/contracts-test-utils';
import { signingUtils } from '@0x/contracts-test-utils';
import { SignatureType, SignedZeroExTransaction } from '@0x/types';
import { hexUtils } from '@0x/utils';
import { hashUtils } from './hash_utils';
import { SignedCoordinatorApproval } from './types';
@@ -27,7 +28,7 @@ export class ApprovalFactory {
const signedApproval = {
txOrigin,
transaction,
signature: hexConcat(signatureBuff),
signature: hexUtils.concat(signatureBuff),
};
return signedApproval;
}

View File

@@ -1,7 +1,6 @@
import { hexConcat } from '@0x/contracts-test-utils';
import { eip712Utils } from '@0x/order-utils';
import { SignedZeroExTransaction } from '@0x/types';
import { signTypedDataUtils } from '@0x/utils';
import { hexUtils, signTypedDataUtils } from '@0x/utils';
export const hashUtils = {
async getApprovalHashBufferAsync(
@@ -22,7 +21,9 @@ export const hashUtils = {
verifyingContract: string,
txOrigin: string,
): Promise<string> {
const hashHex = hexConcat(await hashUtils.getApprovalHashBufferAsync(transaction, verifyingContract, txOrigin));
const hashHex = hexUtils.concat(
await hashUtils.getApprovalHashBufferAsync(transaction, verifyingContract, txOrigin),
);
return hashHex;
},
};

View File

@@ -4,15 +4,13 @@ import {
constants,
ExchangeFunctionName,
expect,
hexConcat,
hexSlice,
randomAddress,
TransactionFactory,
transactionHashUtils,
} from '@0x/contracts-test-utils';
import { LibBytesRevertErrors } from '@0x/contracts-utils';
import { SignatureType, SignedOrder } from '@0x/types';
import { BigNumber, CoordinatorRevertErrors } from '@0x/utils';
import { BigNumber, CoordinatorRevertErrors, hexUtils } from '@0x/utils';
import { ApprovalFactory } from '../src/approval_factory';
@@ -89,8 +87,8 @@ blockchainTests.resets('Mixins tests', env => {
it('should revert with with the Illegal signature type', async () => {
const data = constants.NULL_BYTES;
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
transaction.signature = hexConcat(
hexSlice(transaction.signature, 0, transaction.signature.length - 1),
transaction.signature = hexUtils.concat(
hexUtils.slice(transaction.signature, 0, transaction.signature.length - 1),
SignatureType.Illegal,
);
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
@@ -105,7 +103,7 @@ blockchainTests.resets('Mixins tests', env => {
it('should revert with with the Invalid signature type', async () => {
const data = constants.NULL_BYTES;
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
transaction.signature = hexConcat(SignatureType.Invalid);
transaction.signature = hexUtils.concat(SignatureType.Invalid);
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
expect(mixins.getSignerAddress(transactionHash, transaction.signature).callAsync()).to.revertWith(
new CoordinatorRevertErrors.SignatureError(
@@ -118,8 +116,8 @@ blockchainTests.resets('Mixins tests', env => {
it('should revert with with a signature type that equals `NSignatureTypes`', async () => {
const data = constants.NULL_BYTES;
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
transaction.signature = hexConcat(
hexSlice(transaction.signature, 0, transaction.signature.length - 1),
transaction.signature = hexUtils.concat(
hexUtils.slice(transaction.signature, 0, transaction.signature.length - 1),
SignatureType.NSignatureTypes,
);
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
@@ -134,8 +132,8 @@ blockchainTests.resets('Mixins tests', env => {
it("should revert with with a signature type that isn't supported", async () => {
const data = constants.NULL_BYTES;
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
transaction.signature = hexConcat(
hexSlice(transaction.signature, 0, transaction.signature.length - 1),
transaction.signature = hexUtils.concat(
hexUtils.slice(transaction.signature, 0, transaction.signature.length - 1),
SignatureType.Wallet,
);
const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
@@ -296,10 +294,10 @@ blockchainTests.resets('Mixins tests', env => {
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
const signature = hexConcat(
hexSlice(approval.signature, 0, 2),
const signature = hexUtils.concat(
hexUtils.slice(approval.signature, 0, 2),
'0xFFFFFFFF',
hexSlice(approval.signature, 6),
hexUtils.slice(approval.signature, 6),
);
const tx = mixins
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
@@ -432,10 +430,10 @@ blockchainTests.resets('Mixins tests', env => {
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
const signature = hexConcat(
hexSlice(approval.signature, 0, 2),
const signature = hexUtils.concat(
hexUtils.slice(approval.signature, 0, 2),
'0xFFFFFFFF',
hexSlice(approval.signature, 6),
hexUtils.slice(approval.signature, 6),
);
const tx = mixins
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
@@ -454,10 +452,10 @@ blockchainTests.resets('Mixins tests', env => {
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const approval1 = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress);
const approvalSignature2 = hexConcat(
hexSlice(approval2.signature, 0, 2),
const approvalSignature2 = hexUtils.concat(
hexUtils.slice(approval2.signature, 0, 2),
'0xFFFFFFFF',
hexSlice(approval2.signature, 6),
hexUtils.slice(approval2.signature, 6),
);
const tx = mixins
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
@@ -476,10 +474,10 @@ blockchainTests.resets('Mixins tests', env => {
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress);
const approvalSignature2 = hexConcat(
hexSlice(approval2.signature, 0, 2),
const approvalSignature2 = hexUtils.concat(
hexUtils.slice(approval2.signature, 0, 2),
'0xFFFFFFFF',
hexSlice(approval2.signature, 6),
hexUtils.slice(approval2.signature, 6),
);
const tx = mixins
.assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, [

View File

@@ -1,4 +1,32 @@
[
{
"version": "1.0.3",
"changes": [
{
"note": "Fixed ERC721 duplicate token ID bug",
"pr": 2400
}
],
"timestamp": 1578272714
},
{
"timestamp": 1576540892,
"version": "1.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1575931811,
"version": "1.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.0.0",
"changes": [

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.3 - _January 6, 2020_
* Fixed ERC721 duplicate token ID bug (#2400)
## v1.0.2 - _December 17, 2019_
* Dependencies updated
## v1.0.1 - _December 9, 2019_
* Dependencies updated
## v1.0.0 - _December 2, 2019_
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)

View File

@@ -7,7 +7,7 @@
"evmVersion": "constantinople",
"optimizer": {
"enabled": true,
"runs": 1666,
"runs": 200,
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
},
"outputSelection": {

View File

@@ -35,8 +35,7 @@ contract DevUtils is
OrderValidationUtils,
LibTransactionDecoder,
LibEIP712ExchangeDomain,
EthBalanceChecker,
OrderTransferSimulationUtils
EthBalanceChecker
{
constructor (address _exchange)
public

View File

@@ -147,7 +147,7 @@ contract LibAssetData {
balance = scaledBalance;
}
}
}
}
// Balance will be 0 if assetProxyId is unknown
return balance;
@@ -316,7 +316,7 @@ contract LibAssetData {
return (balances, allowances);
}
/// @dev Decode AssetProxy identifier
/// @dev Decode AssetProxy identifier
/// @param assetData AssetProxy-compliant asset data describing an ERC-20, ERC-721, ERC1155, or MultiAsset asset.
/// @return The AssetProxy identifier
function decodeAssetProxyId(bytes memory assetData)
@@ -353,7 +353,7 @@ contract LibAssetData {
/// @dev Decode ERC-20 asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC-20 asset.
/// @return The AssetProxy identifier, and the address of the ERC-20
/// @return The AssetProxy identifier, and the address of the ERC-20
/// contract hosting this asset.
function decodeERC20AssetData(bytes memory assetData)
public
@@ -591,7 +591,7 @@ contract LibAssetData {
function revertIfInvalidAssetData(bytes memory assetData)
public
pure
pure
{
bytes4 assetProxyId = assetData.readBytes4(0);

View File

@@ -54,6 +54,51 @@ contract OrderTransferSimulationUtils is
_EXCHANGE = IExchange(_exchange);
}
/// @dev Simulates the maker transfers within an order and returns the index of the first failed transfer.
/// @param order The order to simulate transfers for.
/// @param takerAddress The address of the taker that will fill the order.
/// @param takerAssetFillAmount The amount of takerAsset that the taker wished to fill.
/// @return The index of the first failed transfer (or 4 if all transfers are successful).
function getSimulatedOrderMakerTransferResults(
LibOrder.Order memory order,
address takerAddress,
uint256 takerAssetFillAmount
)
public
returns (OrderTransferResults orderTransferResults)
{
LibFillResults.FillResults memory fillResults = LibFillResults.calculateFillResults(
order,
takerAssetFillAmount,
_EXCHANGE.protocolFeeMultiplier(),
tx.gasprice
);
bytes[] memory assetData = new bytes[](2);
address[] memory fromAddresses = new address[](2);
address[] memory toAddresses = new address[](2);
uint256[] memory amounts = new uint256[](2);
// Transfer `makerAsset` from maker to taker
assetData[0] = order.makerAssetData;
fromAddresses[0] = order.makerAddress;
toAddresses[0] = takerAddress;
amounts[0] = fillResults.makerAssetFilledAmount;
// Transfer `makerFeeAsset` from maker to feeRecipient
assetData[1] = order.makerFeeAssetData;
fromAddresses[1] = order.makerAddress;
toAddresses[1] = order.feeRecipientAddress;
amounts[1] = fillResults.makerFeePaid;
return _simulateTransferFromCalls(
assetData,
fromAddresses,
toAddresses,
amounts
);
}
/// @dev Simulates all of the transfers within an order and returns the index of the first failed transfer.
/// @param order The order to simulate transfers for.
/// @param takerAddress The address of the taker that will fill the order.
@@ -104,6 +149,54 @@ contract OrderTransferSimulationUtils is
toAddresses[3] = order.feeRecipientAddress;
amounts[3] = fillResults.makerFeePaid;
return _simulateTransferFromCalls(
assetData,
fromAddresses,
toAddresses,
amounts
);
}
/// @dev Simulates all of the transfers for each given order and returns the indices of each first failed transfer.
/// @param orders Array of orders to individually simulate transfers for.
/// @param takerAddresses Array of addresses of takers that will fill each order.
/// @param takerAssetFillAmounts Array of amounts of takerAsset that will be filled for each order.
/// @return The indices of the first failed transfer (or 4 if all transfers are successful) for each order.
function getSimulatedOrdersTransferResults(
LibOrder.Order[] memory orders,
address[] memory takerAddresses,
uint256[] memory takerAssetFillAmounts
)
public
returns (OrderTransferResults[] memory orderTransferResults)
{
uint256 length = orders.length;
orderTransferResults = new OrderTransferResults[](length);
for (uint256 i = 0; i != length; i++) {
orderTransferResults[i] = getSimulatedOrderTransferResults(
orders[i],
takerAddresses[i],
takerAssetFillAmounts[i]
);
}
return orderTransferResults;
}
/// @dev Makes the simulation call with information about the transfers and processes
/// the returndata.
/// @param assetData The assetdata to use to make transfers.
/// @param fromAddresses The addresses to transfer funds.
/// @param toAddresses The addresses that will receive funds
/// @param amounts The amounts involved in the transfer.
function _simulateTransferFromCalls(
bytes[] memory assetData,
address[] memory fromAddresses,
address[] memory toAddresses,
uint256[] memory amounts
)
internal
returns (OrderTransferResults orderTransferResults)
{
// Encode data for `simulateDispatchTransferFromCalls(assetData, fromAddresses, toAddresses, amounts)`
bytes memory simulateDispatchTransferFromCallsData = abi.encodeWithSelector(
IExchange(address(0)).simulateDispatchTransferFromCalls.selector,
@@ -132,29 +225,4 @@ contract OrderTransferSimulationUtils is
revert("UNKNOWN_RETURN_DATA");
}
}
/// @dev Simulates all of the transfers for each given order and returns the indices of each first failed transfer.
/// @param orders Array of orders to individually simulate transfers for.
/// @param takerAddresses Array of addresses of takers that will fill each order.
/// @param takerAssetFillAmounts Array of amounts of takerAsset that will be filled for each order.
/// @return The indices of the first failed transfer (or 4 if all transfers are successful) for each order.
function getSimulatedOrdersTransferResults(
LibOrder.Order[] memory orders,
address[] memory takerAddresses,
uint256[] memory takerAssetFillAmounts
)
public
returns (OrderTransferResults[] memory orderTransferResults)
{
uint256 length = orders.length;
orderTransferResults = new OrderTransferResults[](length);
for (uint256 i = 0; i != length; i++) {
orderTransferResults[i] = getSimulatedOrderTransferResults(
orders[i],
takerAddresses[i],
takerAssetFillAmounts[i]
);
}
return orderTransferResults;
}
}

View File

@@ -16,7 +16,7 @@
*/
pragma solidity ^0.5.5;
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
@@ -25,10 +25,12 @@ import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "./LibAssetData.sol";
import "./OrderTransferSimulationUtils.sol";
contract OrderValidationUtils is
LibAssetData
LibAssetData,
OrderTransferSimulationUtils
{
using LibBytes for bytes;
using LibSafeMath for uint256;
@@ -50,7 +52,6 @@ contract OrderValidationUtils is
/// amount of each asset that can be filled.
function getOrderRelevantState(LibOrder.Order memory order, bytes memory signature)
public
view
returns (
LibOrder.OrderInfo memory orderInfo,
uint256 fillableTakerAssetAmount,
@@ -99,7 +100,6 @@ contract OrderValidationUtils is
} else {
// Get the transferable amount of the `makerFeeAsset`
uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount(makerAddress, order.makerFeeAssetData);
uint256 transferableMakerToTakerAmount = LibMath.getPartialAmountFloor(
transferableMakerAssetAmount,
order.makerAssetAmount,
@@ -120,6 +120,13 @@ contract OrderValidationUtils is
transferableTakerAssetAmount
);
// Execute the maker transfers.
fillableTakerAssetAmount = getSimulatedOrderMakerTransferResults(
order,
order.takerAddress,
fillableTakerAssetAmount
) == OrderTransferResults.TransfersSuccessful ? fillableTakerAssetAmount : 0;
return (orderInfo, fillableTakerAssetAmount, isValidSignature);
}
@@ -135,7 +142,6 @@ contract OrderValidationUtils is
/// the `takerAssetData` to get the final amount of each asset that can be filled.
function getOrderRelevantStates(LibOrder.Order[] memory orders, bytes[] memory signatures)
public
view
returns (
LibOrder.OrderInfo[] memory ordersInfo,
uint256[] memory fillableTakerAssetAmounts,

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-dev-utils",
"version": "1.0.0",
"version": "1.0.3",
"engines": {
"node": ">=6.12"
},
@@ -8,7 +8,7 @@
"main": "lib/src/index.js",
"scripts": {
"build": "yarn pre_build && tsc -b",
"test": "yarn assert_deployable && echo !!! Tests are run via @0x/contracts-tests !!!",
"test": "yarn assert_deployable && echo !!! Tests are run via @0x/contracts-integrations !!!",
"assert_deployable": "node -e \"const bytecodeLen = (require('./generated-artifacts/DevUtils.json').compilerOutput.evm.bytecode.object.length-2)/2; assert(bytecodeLen<=0x6000,'DevUtils contract is too big to deploy, per EIP-170. '+bytecodeLen+'>'+0x6000)\"",
"build:ci": "yarn build",
"pre_build": "run-s compile quantify_bytecode contracts:gen generate_contract_wrappers contracts:copy",
@@ -41,10 +41,10 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.0",
"@0x/assert": "^3.0.0",
"@0x/contracts-gen": "^2.0.0",
"@0x/sol-compiler": "^4.0.0",
"@0x/abi-gen": "^5.0.3",
"@0x/assert": "^3.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/sol-compiler": "^4.0.3",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@types/node": "*",
@@ -59,7 +59,7 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.0"
"@0x/base-contract": "^6.0.3"
},
"publishConfig": {
"access": "public"

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1578272714,
"version": "2.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1576540892,
"version": "2.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1575931811,
"version": "2.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "2.0.0",
"changes": [

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v2.0.3 - _January 6, 2020_
* Dependencies updated
## v2.0.2 - _December 17, 2019_
* Dependencies updated
## v2.0.1 - _December 9, 2019_
* Dependencies updated
## v2.0.0 - _December 2, 2019_
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc1155",
"version": "2.0.0",
"version": "2.0.3",
"engines": {
"node": ">=6.12"
},
@@ -52,15 +52,15 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.0",
"@0x/contracts-gen": "^2.0.0",
"@0x/contracts-utils": "^4.0.0",
"@0x/dev-utils": "^3.0.0",
"@0x/sol-compiler": "^4.0.0",
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-utils": "^4.0.3",
"@0x/dev-utils": "^3.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.0.0",
"@0x/typescript-typings": "^5.0.0",
"@0x/types": "^3.1.1",
"@0x/typescript-typings": "^5.0.1",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -80,10 +80,10 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.0",
"@0x/contracts-test-utils": "^4.0.0",
"@0x/utils": "^5.0.0",
"@0x/web3-wrapper": "^7.0.0",
"@0x/base-contract": "^6.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/utils": "^5.1.2",
"@0x/web3-wrapper": "^7.0.3",
"lodash": "^4.17.11"
},
"publishConfig": {

View File

@@ -1,4 +1,33 @@
[
{
"version": "1.0.3",
"changes": [
{
"note": "Add gas limits to external quote calls.",
"pr": 2405
}
],
"timestamp": 1578272714
},
{
"version": "1.0.2",
"changes": [
{
"note": "Do not query empty/unsigned orders. Swallow revets on DEX quotes.",
"pr": 2395
}
],
"timestamp": 1576540892
},
{
"timestamp": 1575931811,
"version": "1.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.0.0",
"changes": [

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.0.3 - _January 6, 2020_
* Add gas limits to external quote calls. (#2405)
## v1.0.2 - _December 17, 2019_
* Do not query empty/unsigned orders. Swallow revets on DEX quotes. (#2395)
## v1.0.1 - _December 9, 2019_
* Dependencies updated
## v1.0.0 - _December 2, 2019_
* Created package. (#2344)

View File

@@ -1,92 +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/IUniswapExchangeFactory.sol";
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "./IEth2Dai.sol";
import "./IKyberNetwork.sol";
contract DeploymentConstants {
/// @dev Address of the 0x Exchange contract.
address constant public EXCHANGE_ADDRESS = 0x080bf510FCbF18b91105470639e9561022937712;
/// @dev Address of the Eth2Dai MatchingMarket contract.
address constant public ETH2DAI_ADDRESS = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e;
/// @dev Address of the UniswapExchangeFactory contract.
address constant public UNISWAP_EXCHANGE_FACTORY_ADDRESS = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
/// @dev Address of the KyberNeworkProxy contract.
address constant public KYBER_NETWORK_PROXY_ADDRESS = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755;
/// @dev Address of the WETH contract.
address constant public WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
/// @dev Kyber ETH pseudo-address.
address constant public KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev An overridable way to retrieve the 0x Exchange contract.
/// @return zeroex The 0x Exchange contract.
function _getExchangeContract()
internal
view
returns (IExchange zeroex)
{
return IExchange(EXCHANGE_ADDRESS);
}
/// @dev An overridable way to retrieve the Eth2Dai exchange contract.
/// @return eth2dai The Eth2Dai exchange contract.
function _getEth2DaiContract()
internal
view
returns (IEth2Dai eth2dai)
{
return IEth2Dai(ETH2DAI_ADDRESS);
}
/// @dev An overridable way to retrieve the Uniswap exchange factory contract.
/// @return uniswap The UniswapExchangeFactory contract.
function _getUniswapExchangeFactoryContract()
internal
view
returns (IUniswapExchangeFactory uniswap)
{
return IUniswapExchangeFactory(UNISWAP_EXCHANGE_FACTORY_ADDRESS);
}
/// @dev An overridable way to retrieve the Kyber network proxy contract.
/// @return kyber The KyberNeworkProxy contract.
function _getKyberNetworkContract()
internal
view
returns (IKyberNetwork kyber)
{
return IKyberNetwork(KYBER_NETWORK_PROXY_ADDRESS);
}
/// @dev An overridable way to retrieve the WETH contract address.
/// @return weth The WETH contract address.
function _getWETHAddress()
internal
view
returns (address weth)
{
return WETH_ADDRESS;
}
}

View File

@@ -23,11 +23,13 @@ import "@0x/contracts-asset-proxy/contracts/src/interfaces/IUniswapExchangeFacto
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "./IDevUtils.sol";
import "./IERC20BridgeSampler.sol";
import "./IEth2Dai.sol";
import "./IKyberNetwork.sol";
import "./IUniswapExchangeQuotes.sol";
import "./DeploymentConstants.sol";
contract ERC20BridgeSampler is
@@ -35,29 +37,38 @@ contract ERC20BridgeSampler is
DeploymentConstants
{
bytes4 constant internal ERC20_PROXY_ID = 0xf47261b0; // bytes4(keccak256("ERC20Token(address)"));
uint256 constant internal KYBER_SAMPLE_CALL_GAS = 600e3;
uint256 constant internal UNISWAP_SAMPLE_CALL_GAS = 150e3;
uint256 constant internal ETH2DAI_SAMPLE_CALL_GAS = 250e3;
/// @dev Query native orders and sample sell quotes on multiple DEXes at once.
/// @param orders Native orders to query.
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
/// @param takerTokenAmounts Taker token sell amount for each sample.
/// @return orderInfos `OrderInfo`s for each order in `orders`.
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
/// by each order in `orders`.
/// @return makerTokenAmountsBySource Maker amounts bought for each source at
/// each taker token amount. First indexed by source index, then sample
/// index.
function queryOrdersAndSampleSells(
LibOrder.Order[] memory orders,
bytes[] memory orderSignatures,
address[] memory sources,
uint256[] memory takerTokenAmounts
)
public
view
returns (
LibOrder.OrderInfo[] memory orderInfos,
uint256[] memory orderFillableTakerAssetAmounts,
uint256[][] memory makerTokenAmountsBySource
)
{
require(orders.length != 0, "EMPTY_ORDERS");
orderInfos = queryOrders(orders);
require(orders.length != 0, "ERC20BridgeSampler/EMPTY_ORDERS");
orderFillableTakerAssetAmounts = getOrderFillableTakerAssetAmounts(
orders,
orderSignatures
);
makerTokenAmountsBySource = sampleSells(
sources,
_assetDataToTokenAddress(orders[0].takerAssetData),
@@ -68,26 +79,32 @@ contract ERC20BridgeSampler is
/// @dev Query native orders and sample buy quotes on multiple DEXes at once.
/// @param orders Native orders to query.
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
/// @param makerTokenAmounts Maker token buy amount for each sample.
/// @return orderInfos `OrderInfo`s for each order in `orders`.
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
/// by each order in `orders`.
/// @return takerTokenAmountsBySource Taker amounts sold for each source at
/// each maker token amount. First indexed by source index, then sample
/// index.
function queryOrdersAndSampleBuys(
LibOrder.Order[] memory orders,
bytes[] memory orderSignatures,
address[] memory sources,
uint256[] memory makerTokenAmounts
)
public
view
returns (
LibOrder.OrderInfo[] memory orderInfos,
uint256[] memory orderFillableMakerAssetAmounts,
uint256[][] memory makerTokenAmountsBySource
)
{
require(orders.length != 0, "EMPTY_ORDERS");
orderInfos = queryOrders(orders);
require(orders.length != 0, "ERC20BridgeSampler/EMPTY_ORDERS");
orderFillableMakerAssetAmounts = getOrderFillableMakerAssetAmounts(
orders,
orderSignatures
);
makerTokenAmountsBySource = sampleBuys(
sources,
_assetDataToTokenAddress(orders[0].takerAssetData),
@@ -96,18 +113,77 @@ contract ERC20BridgeSampler is
);
}
/// @dev Queries the status of several native orders.
/// @dev Queries the fillable taker asset amounts of native orders.
/// Effectively ignores orders that have empty signatures or
/// maker/taker asset amounts (returning 0).
/// @param orders Native orders to query.
/// @return orderInfos Order info for each respective order.
function queryOrders(LibOrder.Order[] memory orders)
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
/// by each order in `orders`.
function getOrderFillableTakerAssetAmounts(
LibOrder.Order[] memory orders,
bytes[] memory orderSignatures
)
public
view
returns (LibOrder.OrderInfo[] memory orderInfos)
returns (uint256[] memory orderFillableTakerAssetAmounts)
{
uint256 numOrders = orders.length;
orderInfos = new LibOrder.OrderInfo[](numOrders);
for (uint256 i = 0; i < numOrders; i++) {
orderInfos[i] = _getExchangeContract().getOrderInfo(orders[i]);
orderFillableTakerAssetAmounts = new uint256[](orders.length);
for (uint256 i = 0; i != orders.length; i++) {
// Ignore orders with no signature or empty maker/taker amounts.
if (orderSignatures[i].length == 0 ||
orders[i].makerAssetAmount == 0 ||
orders[i].takerAssetAmount == 0) {
orderFillableTakerAssetAmounts[i] = 0;
continue;
}
(
LibOrder.OrderInfo memory orderInfo,
uint256 fillableTakerAssetAmount,
bool isValidSignature
) = IDevUtils(_getDevUtilsAddress()).getOrderRelevantState(
orders[i],
orderSignatures[i]
);
// The fillable amount is zero if the order is not fillable or if the
// signature is invalid.
if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE ||
!isValidSignature) {
orderFillableTakerAssetAmounts[i] = 0;
} else {
orderFillableTakerAssetAmounts[i] = fillableTakerAssetAmount;
}
}
}
/// @dev Queries the fillable taker asset amounts of native orders.
/// Effectively ignores orders that have empty signatures or
/// @param orders Native orders to query.
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
/// by each order in `orders`.
function getOrderFillableMakerAssetAmounts(
LibOrder.Order[] memory orders,
bytes[] memory orderSignatures
)
public
view
returns (uint256[] memory orderFillableMakerAssetAmounts)
{
orderFillableMakerAssetAmounts = getOrderFillableTakerAssetAmounts(
orders,
orderSignatures
);
// `orderFillableMakerAssetAmounts` now holds taker asset amounts, so
// convert them to maker asset amounts.
for (uint256 i = 0; i < orders.length; ++i) {
if (orderFillableMakerAssetAmounts[i] != 0) {
orderFillableMakerAssetAmounts[i] = LibMath.getPartialAmountCeil(
orderFillableMakerAssetAmounts[i],
orders[i].takerAssetAmount,
orders[i].makerAssetAmount
);
}
}
}
@@ -187,18 +263,25 @@ contract ERC20BridgeSampler is
returns (uint256[] memory makerTokenAmounts)
{
_assertValidPair(makerToken, takerToken);
address _takerToken = takerToken == _getWETHAddress() ? KYBER_ETH_ADDRESS : takerToken;
address _makerToken = makerToken == _getWETHAddress() ? KYBER_ETH_ADDRESS : makerToken;
address _takerToken = takerToken == _getWethAddress() ? KYBER_ETH_ADDRESS : takerToken;
address _makerToken = makerToken == _getWethAddress() ? KYBER_ETH_ADDRESS : makerToken;
uint256 takerTokenDecimals = _getTokenDecimals(takerToken);
uint256 makerTokenDecimals = _getTokenDecimals(makerToken);
uint256 numSamples = takerTokenAmounts.length;
makerTokenAmounts = new uint256[](numSamples);
for (uint256 i = 0; i < numSamples; i++) {
(uint256 rate,) = _getKyberNetworkContract().getExpectedRate(
_takerToken,
_makerToken,
takerTokenAmounts[i]
);
(bool didSucceed, bytes memory resultData) =
_getKyberNetworkProxyAddress().staticcall.gas(KYBER_SAMPLE_CALL_GAS)(
abi.encodeWithSelector(
IKyberNetwork(0).getExpectedRate.selector,
_takerToken,
_makerToken,
takerTokenAmounts[i]
));
uint256 rate = 0;
if (didSucceed) {
rate = abi.decode(resultData, (uint256));
}
makerTokenAmounts[i] =
rate *
takerTokenAmounts[i] *
@@ -227,11 +310,19 @@ contract ERC20BridgeSampler is
uint256 numSamples = takerTokenAmounts.length;
makerTokenAmounts = new uint256[](numSamples);
for (uint256 i = 0; i < numSamples; i++) {
makerTokenAmounts[i] = _getEth2DaiContract().getBuyAmount(
makerToken,
takerToken,
takerTokenAmounts[i]
);
(bool didSucceed, bytes memory resultData) =
_getEth2DaiAddress().staticcall.gas(ETH2DAI_SAMPLE_CALL_GAS)(
abi.encodeWithSelector(
IEth2Dai(0).getBuyAmount.selector,
makerToken,
takerToken,
takerTokenAmounts[i]
));
uint256 buyAmount = 0;
if (didSucceed) {
buyAmount = abi.decode(resultData, (uint256));
}
makerTokenAmounts[i] = buyAmount;
}
}
@@ -254,11 +345,19 @@ contract ERC20BridgeSampler is
uint256 numSamples = makerTokenAmounts.length;
takerTokenAmounts = new uint256[](numSamples);
for (uint256 i = 0; i < numSamples; i++) {
takerTokenAmounts[i] = _getEth2DaiContract().getPayAmount(
takerToken,
makerToken,
makerTokenAmounts[i]
);
(bool didSucceed, bytes memory resultData) =
_getEth2DaiAddress().staticcall.gas(ETH2DAI_SAMPLE_CALL_GAS)(
abi.encodeWithSelector(
IEth2Dai(0).getPayAmount.selector,
takerToken,
makerToken,
makerTokenAmounts[i]
));
uint256 sellAmount = 0;
if (didSucceed) {
sellAmount = abi.decode(resultData, (uint256));
}
takerTokenAmounts[i] = sellAmount;
}
}
@@ -280,26 +379,38 @@ contract ERC20BridgeSampler is
_assertValidPair(makerToken, takerToken);
uint256 numSamples = takerTokenAmounts.length;
makerTokenAmounts = new uint256[](numSamples);
IUniswapExchangeQuotes takerTokenExchange = takerToken == _getWETHAddress() ?
IUniswapExchangeQuotes takerTokenExchange = takerToken == _getWethAddress() ?
IUniswapExchangeQuotes(0) : _getUniswapExchange(takerToken);
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWETHAddress() ?
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
for (uint256 i = 0; i < numSamples; i++) {
if (makerToken == _getWETHAddress()) {
makerTokenAmounts[i] = takerTokenExchange.getTokenToEthInputPrice(
if (makerToken == _getWethAddress()) {
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
address(takerTokenExchange),
takerTokenExchange.getTokenToEthInputPrice.selector,
takerTokenAmounts[i]
);
} else if (takerToken == _getWETHAddress()) {
makerTokenAmounts[i] = makerTokenExchange.getEthToTokenInputPrice(
} else if (takerToken == _getWethAddress()) {
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
address(makerTokenExchange),
makerTokenExchange.getEthToTokenInputPrice.selector,
takerTokenAmounts[i]
);
} else {
uint256 ethBought = takerTokenExchange.getTokenToEthInputPrice(
uint256 ethBought = _callUniswapExchangePriceFunction(
address(takerTokenExchange),
takerTokenExchange.getTokenToEthInputPrice.selector,
takerTokenAmounts[i]
);
makerTokenAmounts[i] = makerTokenExchange.getEthToTokenInputPrice(
ethBought
);
if (ethBought != 0) {
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
address(makerTokenExchange),
makerTokenExchange.getEthToTokenInputPrice.selector,
ethBought
);
} else {
makerTokenAmounts[i] = 0;
}
}
}
}
@@ -322,26 +433,38 @@ contract ERC20BridgeSampler is
_assertValidPair(makerToken, takerToken);
uint256 numSamples = makerTokenAmounts.length;
takerTokenAmounts = new uint256[](numSamples);
IUniswapExchangeQuotes takerTokenExchange = takerToken == _getWETHAddress() ?
IUniswapExchangeQuotes takerTokenExchange = takerToken == _getWethAddress() ?
IUniswapExchangeQuotes(0) : _getUniswapExchange(takerToken);
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWETHAddress() ?
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
for (uint256 i = 0; i < numSamples; i++) {
if (makerToken == _getWETHAddress()) {
takerTokenAmounts[i] = takerTokenExchange.getTokenToEthOutputPrice(
if (makerToken == _getWethAddress()) {
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
address(takerTokenExchange),
takerTokenExchange.getTokenToEthOutputPrice.selector,
makerTokenAmounts[i]
);
} else if (takerToken == _getWETHAddress()) {
takerTokenAmounts[i] = makerTokenExchange.getEthToTokenOutputPrice(
} else if (takerToken == _getWethAddress()) {
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
address(makerTokenExchange),
makerTokenExchange.getEthToTokenOutputPrice.selector,
makerTokenAmounts[i]
);
} else {
uint256 ethSold = makerTokenExchange.getEthToTokenOutputPrice(
uint256 ethSold = _callUniswapExchangePriceFunction(
address(makerTokenExchange),
makerTokenExchange.getEthToTokenOutputPrice.selector,
makerTokenAmounts[i]
);
takerTokenAmounts[i] = takerTokenExchange.getTokenToEthOutputPrice(
ethSold
);
if (ethSold != 0) {
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
address(takerTokenExchange),
takerTokenExchange.getTokenToEthOutputPrice.selector,
ethSold
);
} else {
takerTokenAmounts[i] = 0;
}
}
}
}
@@ -357,6 +480,35 @@ contract ERC20BridgeSampler is
return LibERC20Token.decimals(tokenAddress);
}
/// @dev Gracefully calls a Uniswap pricing function.
/// @param uniswapExchangeAddress Address of an `IUniswapExchangeQuotes` exchange.
/// @param functionSelector Selector of the target function.
/// @param inputAmount Quantity parameter particular to the pricing function.
/// @return outputAmount The returned amount from the function call. Will be
/// zero if the call fails or if `uniswapExchangeAddress` is zero.
function _callUniswapExchangePriceFunction(
address uniswapExchangeAddress,
bytes4 functionSelector,
uint256 inputAmount
)
private
view
returns (uint256 outputAmount)
{
if (uniswapExchangeAddress == address(0)) {
return 0;
}
(bool didSucceed, bytes memory resultData) =
uniswapExchangeAddress.staticcall.gas(UNISWAP_SAMPLE_CALL_GAS)(
abi.encodeWithSelector(
functionSelector,
inputAmount
));
if (didSucceed) {
outputAmount = abi.decode(resultData, (uint256));
}
}
/// @dev Samples a supported sell source, defined by its address.
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
@@ -373,16 +525,16 @@ contract ERC20BridgeSampler is
view
returns (uint256[] memory makerTokenAmounts)
{
if (source == address(_getEth2DaiContract())) {
if (source == _getEth2DaiAddress()) {
return sampleSellsFromEth2Dai(takerToken, makerToken, takerTokenAmounts);
}
if (source == address(_getUniswapExchangeFactoryContract())) {
if (source == _getUniswapExchangeFactoryAddress()) {
return sampleSellsFromUniswap(takerToken, makerToken, takerTokenAmounts);
}
if (source == address(_getKyberNetworkContract())) {
if (source == _getKyberNetworkProxyAddress()) {
return sampleSellsFromKyberNetwork(takerToken, makerToken, takerTokenAmounts);
}
revert("UNSUPPORTED_SOURCE");
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
}
/// @dev Samples a supported buy source, defined by its address.
@@ -401,13 +553,13 @@ contract ERC20BridgeSampler is
view
returns (uint256[] memory takerTokenAmounts)
{
if (source == address(_getEth2DaiContract())) {
if (source == _getEth2DaiAddress()) {
return sampleBuysFromEth2Dai(takerToken, makerToken, makerTokenAmounts);
}
if (source == address(_getUniswapExchangeFactoryContract())) {
if (source == _getUniswapExchangeFactoryAddress()) {
return sampleBuysFromUniswap(takerToken, makerToken, makerTokenAmounts);
}
revert("UNSUPPORTED_SOURCE");
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
}
/// @dev Retrive an existing Uniswap exchange contract.
@@ -420,9 +572,9 @@ contract ERC20BridgeSampler is
returns (IUniswapExchangeQuotes exchange)
{
exchange = IUniswapExchangeQuotes(
address(_getUniswapExchangeFactoryContract().getExchange(tokenAddress))
address(IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress())
.getExchange(tokenAddress))
);
require(address(exchange) != address(0), "UNSUPPORTED_UNISWAP_EXCHANGE");
}
/// @dev Extract the token address from ERC20 proxy asset data.
@@ -433,19 +585,19 @@ contract ERC20BridgeSampler is
pure
returns (address tokenAddress)
{
require(assetData.length == 36, "INVALID_ASSET_DATA");
require(assetData.length == 36, "ERC20BridgeSampler/INVALID_ASSET_DATA");
bytes4 selector;
assembly {
selector := and(mload(add(assetData, 0x20)), 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)
tokenAddress := mload(add(assetData, 0x24))
}
require(selector == ERC20_PROXY_ID, "UNSUPPORTED_ASSET_PROXY");
require(selector == ERC20_PROXY_ID, "ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY");
}
function _assertValidPair(address makerToken, address takerToken)
private
pure
{
require(makerToken != takerToken, "INVALID_TOKEN_PAIR");
require(makerToken != takerToken, "ERC20BridgeSampler/INVALID_TOKEN_PAIR");
}
}

View File

@@ -0,0 +1,45 @@
/*
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/LibOrder.sol";
interface IDevUtils {
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
/// @param order The order structure.
/// @param signature Signature provided by maker that proves the order's authenticity.
/// `0x01` can always be provided if the signature does not need to be validated.
/// @return The orderInfo (hash, status, and `takerAssetAmount` already filled for the given order),
/// fillableTakerAssetAmount (amount of the order's `takerAssetAmount` that is fillable given all on-chain state),
/// and isValidSignature (validity of the provided signature).
/// NOTE: If the `takerAssetData` encodes data for multiple assets, `fillableTakerAssetAmount` will represent a "scaled"
/// amount, meaning it must be multiplied by all the individual asset amounts within the `takerAssetData` to get the final
/// amount of each asset that can be filled.
function getOrderRelevantState(LibOrder.Order calldata order, bytes calldata signature)
external
view
returns (
LibOrder.OrderInfo memory orderInfo,
uint256 fillableTakerAssetAmount,
bool isValidSignature
);
}

View File

@@ -19,59 +19,82 @@
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
interface IERC20BridgeSampler {
/// @dev Query native orders and sample sell orders on multiple DEXes at once.
/// @dev Query native orders and sample sell quotes on multiple DEXes at once.
/// @param orders Native orders to query.
/// @param sources Address of each DEX. Passing in an unknown DEX will throw.
/// @param takerTokenAmounts Taker sell amount for each sample.
/// @return orderInfos `OrderInfo`s for each order in `orders`.
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
/// @param takerTokenAmounts Taker token sell amount for each sample.
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
/// by each order in `orders`.
/// @return makerTokenAmountsBySource Maker amounts bought for each source at
/// each taker token amount. First indexed by source index, then sample
/// index.
function queryOrdersAndSampleSells(
LibOrder.Order[] calldata orders,
bytes[] calldata orderSignatures,
address[] calldata sources,
uint256[] calldata takerTokenAmounts
)
external
view
returns (
LibOrder.OrderInfo[] memory orderInfos,
uint256[] memory orderFillableTakerAssetAmounts,
uint256[][] memory makerTokenAmountsBySource
);
/// @dev Query native orders and sample buy orders on multiple DEXes at once.
/// @dev Query native orders and sample buy quotes on multiple DEXes at once.
/// @param orders Native orders to query.
/// @param sources Address of each DEX. Passing in an unknown DEX will throw.
/// @param makerTokenAmounts Maker sell amount for each sample.
/// @return orderInfos `OrderInfo`s for each order in `orders`.
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
/// @param makerTokenAmounts Maker token buy amount for each sample.
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
/// by each order in `orders`.
/// @return takerTokenAmountsBySource Taker amounts sold for each source at
/// each maker token amount. First indexed by source index, then sample
/// index.
function queryOrdersAndSampleBuys(
LibOrder.Order[] calldata orders,
bytes[] calldata orderSignatures,
address[] calldata sources,
uint256[] calldata makerTokenAmounts
)
external
view
returns (
LibOrder.OrderInfo[] memory orderInfos,
uint256[] memory orderFillableMakerAssetAmounts,
uint256[][] memory makerTokenAmountsBySource
);
/// @dev Queries the status of several native orders.
/// @dev Queries the fillable taker asset amounts of native orders.
/// @param orders Native orders to query.
/// @return orderInfos Order info for each respective order.
function queryOrders(LibOrder.Order[] calldata orders)
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @return orderFillableTakerAssetAmounts How much taker asset can be filled
/// by each order in `orders`.
function getOrderFillableTakerAssetAmounts(
LibOrder.Order[] calldata orders,
bytes[] calldata orderSignatures
)
external
view
returns (LibOrder.OrderInfo[] memory orderInfos);
returns (uint256[] memory orderFillableTakerAssetAmounts);
/// @dev Queries the fillable maker asset amounts of native orders.
/// @param orders Native orders to query.
/// @param orderSignatures Signatures for each respective order in `orders`.
/// @return orderFillableMakerAssetAmounts How much maker asset can be filled
/// by each order in `orders`.
function getOrderFillableMakerAssetAmounts(
LibOrder.Order[] calldata orders,
bytes[] calldata orderSignatures
)
external
view
returns (uint256[] memory orderFillableMakerAssetAmounts);
/// @dev Sample sell quotes on multiple DEXes at once.
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.

View File

@@ -23,6 +23,7 @@ import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "../src/ERC20BridgeSampler.sol";
import "../src/IEth2Dai.sol";
import "../src/IDevUtils.sol";
import "../src/IKyberNetwork.sol";
@@ -90,9 +91,28 @@ library LibDeterministicQuotes {
}
contract FailTrigger {
// Give this address a balance to force operations to fail.
address payable constant public FAILURE_ADDRESS = 0xe9dB8717BC5DFB20aaf538b4a5a02B7791FF430C;
// Funds `FAILURE_ADDRESS`.
function enableFailTrigger() external payable {
FAILURE_ADDRESS.transfer(msg.value);
}
function _revertIfShouldFail() internal view {
if (FAILURE_ADDRESS.balance != 0) {
revert("FAIL_TRIGGERED");
}
}
}
contract TestERC20BridgeSamplerUniswapExchange is
IUniswapExchangeQuotes,
DeploymentConstants
DeploymentConstants,
FailTrigger
{
bytes32 constant private BASE_SALT = 0x1d6a6a0506b0b4a554b907a4c29d9f4674e461989d9c1921feb17b26716385ab;
@@ -112,10 +132,11 @@ contract TestERC20BridgeSamplerUniswapExchange is
view
returns (uint256 tokensBought)
{
_revertIfShouldFail();
return LibDeterministicQuotes.getDeterministicSellQuote(
salt,
tokenAddress,
WETH_ADDRESS,
_getWethAddress(),
ethSold
);
}
@@ -128,9 +149,10 @@ contract TestERC20BridgeSamplerUniswapExchange is
view
returns (uint256 ethSold)
{
_revertIfShouldFail();
return LibDeterministicQuotes.getDeterministicBuyQuote(
salt,
WETH_ADDRESS,
_getWethAddress(),
tokenAddress,
tokensBought
);
@@ -144,10 +166,11 @@ contract TestERC20BridgeSamplerUniswapExchange is
view
returns (uint256 ethBought)
{
_revertIfShouldFail();
return LibDeterministicQuotes.getDeterministicSellQuote(
salt,
tokenAddress,
WETH_ADDRESS,
_getWethAddress(),
tokensSold
);
}
@@ -160,9 +183,10 @@ contract TestERC20BridgeSamplerUniswapExchange is
view
returns (uint256 tokensSold)
{
_revertIfShouldFail();
return LibDeterministicQuotes.getDeterministicBuyQuote(
salt,
WETH_ADDRESS,
_getWethAddress(),
tokenAddress,
ethBought
);
@@ -172,7 +196,8 @@ contract TestERC20BridgeSamplerUniswapExchange is
contract TestERC20BridgeSamplerKyberNetwork is
IKyberNetwork,
DeploymentConstants
DeploymentConstants,
FailTrigger
{
bytes32 constant private SALT = 0x0ff3ca9d46195c39f9a12afb74207b4970349fb3cfb1e459bbf170298d326bc7;
address constant public ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
@@ -187,8 +212,9 @@ contract TestERC20BridgeSamplerKyberNetwork is
view
returns (uint256 expectedRate, uint256)
{
fromToken = fromToken == ETH_ADDRESS ? WETH_ADDRESS : fromToken;
toToken = toToken == ETH_ADDRESS ? WETH_ADDRESS : toToken;
_revertIfShouldFail();
fromToken = fromToken == ETH_ADDRESS ? _getWethAddress() : fromToken;
toToken = toToken == ETH_ADDRESS ? _getWethAddress() : toToken;
expectedRate = LibDeterministicQuotes.getDeterministicRate(
SALT,
fromToken,
@@ -199,7 +225,8 @@ contract TestERC20BridgeSamplerKyberNetwork is
contract TestERC20BridgeSamplerEth2Dai is
IEth2Dai
IEth2Dai,
FailTrigger
{
bytes32 constant private SALT = 0xb713b61bb9bb2958a0f5d1534b21e94fc68c4c0c034b0902ed844f2f6cd1b4f7;
@@ -213,6 +240,7 @@ contract TestERC20BridgeSamplerEth2Dai is
view
returns (uint256 buyAmount)
{
_revertIfShouldFail();
return LibDeterministicQuotes.getDeterministicSellQuote(
SALT,
payToken,
@@ -231,6 +259,7 @@ contract TestERC20BridgeSamplerEth2Dai is
view
returns (uint256 payAmount)
{
_revertIfShouldFail();
return LibDeterministicQuotes.getDeterministicBuyQuote(
SALT,
payToken,
@@ -269,12 +298,15 @@ contract TestERC20BridgeSamplerUniswapExchangeFactory is
contract TestERC20BridgeSampler is
ERC20BridgeSampler
ERC20BridgeSampler,
FailTrigger
{
TestERC20BridgeSamplerUniswapExchangeFactory public uniswap;
TestERC20BridgeSamplerEth2Dai public eth2Dai;
TestERC20BridgeSamplerKyberNetwork public kyber;
uint8 private constant MAX_ORDER_STATUS = uint8(LibOrder.OrderStatus.CANCELLED) + 1;
constructor() public {
uniswap = new TestERC20BridgeSamplerUniswapExchangeFactory();
eth2Dai = new TestERC20BridgeSamplerEth2Dai();
@@ -288,18 +320,29 @@ contract TestERC20BridgeSampler is
uniswap.createTokenExchanges(tokenAddresses);
}
// `IExchange.getOrderInfo()`, overridden to return deterministic order infos.
function getOrderInfo(LibOrder.Order memory order)
// `IDevUtils.getOrderRelevantState()`, overridden to return deterministic
// states.
function getOrderRelevantState(
LibOrder.Order memory order,
bytes memory
)
public
pure
returns (LibOrder.OrderInfo memory orderInfo)
view
returns (
LibOrder.OrderInfo memory orderInfo,
uint256 fillableTakerAssetAmount,
bool isValidSignature
)
{
// The order hash is just the hash of the salt.
bytes32 orderHash = keccak256(abi.encode(order.salt));
// Everything else is derived from the hash.
orderInfo.orderHash = orderHash;
orderInfo.orderStatus = uint8(uint256(orderHash) % uint8(-1));
orderInfo.orderStatus = LibOrder.OrderStatus(uint256(orderHash) % MAX_ORDER_STATUS);
orderInfo.orderTakerAssetFilledAmount = uint256(orderHash) % order.takerAssetAmount;
fillableTakerAssetAmount =
order.takerAssetAmount - orderInfo.orderTakerAssetFilledAmount;
isValidSignature = uint256(orderHash) % 2 == 1;
}
// Overriden to return deterministic decimals.
@@ -312,38 +355,38 @@ contract TestERC20BridgeSampler is
}
// Overriden to point to a this contract.
function _getExchangeContract()
function _getDevUtilsAddress()
internal
view
returns (IExchange zeroex)
returns (address devUtilAddress)
{
return IExchange(address(this));
return address(this);
}
// Overriden to point to a custom contract.
function _getEth2DaiContract()
function _getEth2DaiAddress()
internal
view
returns (IEth2Dai eth2dai_)
returns (address eth2daiAddress)
{
return eth2Dai;
return address(eth2Dai);
}
// Overriden to point to a custom contract.
function _getUniswapExchangeFactoryContract()
function _getUniswapExchangeFactoryAddress()
internal
view
returns (IUniswapExchangeFactory uniswap_)
returns (address uniswapAddress)
{
return uniswap;
return address(uniswap);
}
// Overriden to point to a custom contract.
function _getKyberNetworkContract()
function _getKyberNetworkProxyAddress()
internal
view
returns (IKyberNetwork kyber_)
returns (address kyberAddress)
{
return kyber;
return address(kyber);
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc20-bridge-sampler",
"version": "1.0.0",
"version": "1.0.3",
"engines": {
"node": ">=6.12"
},
@@ -38,7 +38,7 @@
"config": {
"publicInterfaceContracts": "ERC20BridgeSampler,IERC20BridgeSampler",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(DeploymentConstants|ERC20BridgeSampler|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|IUniswapExchangeQuotes|TestERC20BridgeSampler).json"
"abis": "./test/generated-artifacts/@(ERC20BridgeSampler|IDevUtils|IERC20BridgeSampler|IEth2Dai|IKyberNetwork|IUniswapExchangeQuotes|TestERC20BridgeSampler).json"
},
"repository": {
"type": "git",
@@ -50,18 +50,18 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.0",
"@0x/contracts-asset-proxy": "^3.0.0",
"@0x/contracts-erc20": "^3.0.0",
"@0x/contracts-exchange": "^3.0.0",
"@0x/contracts-exchange-libs": "^4.0.0",
"@0x/contracts-gen": "^2.0.0",
"@0x/contracts-test-utils": "^4.0.0",
"@0x/contracts-utils": "^4.0.0",
"@0x/dev-utils": "^3.0.0",
"@0x/sol-compiler": "^4.0.0",
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-asset-proxy": "^3.1.0",
"@0x/contracts-erc20": "^3.0.3",
"@0x/contracts-exchange": "^3.0.3",
"@0x/contracts-exchange-libs": "^4.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/contracts-utils": "^4.0.3",
"@0x/dev-utils": "^3.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/tslint-config": "^4.0.0",
"@0x/web3-wrapper": "^7.0.0",
"@0x/web3-wrapper": "^7.0.3",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -79,10 +79,10 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.0",
"@0x/types": "^3.0.0",
"@0x/typescript-typings": "^5.0.0",
"@0x/utils": "^5.0.0",
"@0x/base-contract": "^6.0.3",
"@0x/types": "^3.1.1",
"@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.1.2",
"ethereum-types": "^3.0.0",
"lodash": "^4.17.11"
},

View File

@@ -5,16 +5,16 @@
*/
import { ContractArtifact } from 'ethereum-types';
import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json';
import * as ERC20BridgeSampler from '../test/generated-artifacts/ERC20BridgeSampler.json';
import * as IDevUtils from '../test/generated-artifacts/IDevUtils.json';
import * as IERC20BridgeSampler from '../test/generated-artifacts/IERC20BridgeSampler.json';
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
import * as IKyberNetwork from '../test/generated-artifacts/IKyberNetwork.json';
import * as IUniswapExchangeQuotes from '../test/generated-artifacts/IUniswapExchangeQuotes.json';
import * as TestERC20BridgeSampler from '../test/generated-artifacts/TestERC20BridgeSampler.json';
export const artifacts = {
DeploymentConstants: DeploymentConstants as ContractArtifact,
ERC20BridgeSampler: ERC20BridgeSampler as ContractArtifact,
IDevUtils: IDevUtils as ContractArtifact,
IERC20BridgeSampler: IERC20BridgeSampler as ContractArtifact,
IEth2Dai: IEth2Dai as ContractArtifact,
IKyberNetwork: IKyberNetwork as ContractArtifact,

View File

@@ -4,15 +4,10 @@ import {
expect,
getRandomInteger,
getRandomPortion,
hexConcat,
hexHash,
hexLeftPad,
hexRandom,
randomAddress,
toHex,
} from '@0x/contracts-test-utils';
import { Order, OrderInfo } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Order } from '@0x/types';
import { BigNumber, hexUtils } from '@0x/utils';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
@@ -31,16 +26,17 @@ blockchainTests('erc20-bridge-sampler', env => {
const ETH2DAI_SALT = '0xb713b61bb9bb2958a0f5d1534b21e94fc68c4c0c034b0902ed844f2f6cd1b4f7';
const UNISWAP_BASE_SALT = '0x1d6a6a0506b0b4a554b907a4c29d9f4674e461989d9c1921feb17b26716385ab';
const ERC20_PROXY_ID = '0xf47261b0';
const INVALID_ASSET_PROXY_ASSET_DATA = hexConcat('0xf47261b1', hexLeftPad(randomAddress()));
const INVALID_ASSET_DATA = hexRandom(37);
const INVALID_ASSET_PROXY_ASSET_DATA = hexUtils.concat('0xf47261b1', hexUtils.leftPad(randomAddress()));
const INVALID_ASSET_DATA = hexUtils.random(37);
const SELL_SOURCES = ['Eth2Dai', 'Kyber', 'Uniswap'];
const BUY_SOURCES = ['Eth2Dai', 'Uniswap'];
const EMPTY_ORDERS_ERROR = 'EMPTY_ORDERS';
const UNSUPPORTED_ASSET_PROXY_ERROR = 'UNSUPPORTED_ASSET_PROXY';
const INVALID_ASSET_DATA_ERROR = 'INVALID_ASSET_DATA';
const UNSUPPORTED_UNISWAP_EXCHANGE_ERROR = 'UNSUPPORTED_UNISWAP_EXCHANGE';
const UNSUPPORTED_SOURCE_ERROR = 'UNSUPPORTED_SOURCE';
const INVALID_TOKEN_PAIR_ERROR = 'INVALID_TOKEN_PAIR';
const EMPTY_ORDERS_ERROR = 'ERC20BridgeSampler/EMPTY_ORDERS';
const UNSUPPORTED_ASSET_PROXY_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY';
const INVALID_ASSET_DATA_ERROR = 'ERC20BridgeSampler/INVALID_ASSET_DATA';
const UNSUPPORTED_SOURCE_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_SOURCE';
const INVALID_TOKEN_PAIR_ERROR = 'ERC20BridgeSampler/INVALID_TOKEN_PAIR';
const MAKER_TOKEN = randomAddress();
const TAKER_TOKEN = randomAddress();
before(async () => {
testContract = await TestERC20BridgeSamplerContract.deployFrom0xArtifactAsync(
@@ -60,7 +56,7 @@ blockchainTests('erc20-bridge-sampler', env => {
});
function getPackedHash(...args: string[]): string {
return hexHash(hexConcat(...args.map(a => toHex(a))));
return hexUtils.hash(hexUtils.concat(...args.map(a => hexUtils.toHex(a))));
}
function getUniswapExchangeSalt(tokenAddress: string): string {
@@ -197,17 +193,26 @@ blockchainTests('erc20-bridge-sampler', env => {
return quotes;
}
function getDeterministicOrderInfo(order: Order): OrderInfo {
const hash = getPackedHash(toHex(order.salt, 32));
return {
orderHash: hash,
orderStatus: new BigNumber(hash).mod(255).toNumber(),
orderTakerAssetFilledAmount: new BigNumber(hash).mod(order.takerAssetAmount),
};
function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber {
const hash = getPackedHash(hexUtils.toHex(order.salt, 32));
const orderStatus = new BigNumber(hash).mod(255).toNumber();
const isValidSignature = !!new BigNumber(hash).mod(2).toNumber();
if (orderStatus !== 3 || !isValidSignature) {
return constants.ZERO_AMOUNT;
}
return order.takerAssetAmount.minus(new BigNumber(hash).mod(order.takerAssetAmount));
}
function getDeterministicFillableMakerAssetAmount(order: Order): BigNumber {
const takerAmount = getDeterministicFillableTakerAssetAmount(order);
return order.makerAssetAmount
.times(takerAmount)
.div(order.takerAssetAmount)
.integerValue(BigNumber.ROUND_DOWN);
}
function getERC20AssetData(tokenAddress: string): string {
return hexConcat(ERC20_PROXY_ID, hexLeftPad(tokenAddress));
return hexUtils.concat(ERC20_PROXY_ID, hexUtils.leftPad(tokenAddress));
}
function getSampleAmounts(tokenAddress: string, count?: number): BigNumber[] {
@@ -234,7 +239,7 @@ blockchainTests('erc20-bridge-sampler', env => {
takerAssetData: getERC20AssetData(takerToken),
makerFeeAssetData: getERC20AssetData(randomAddress()),
takerFeeAssetData: getERC20AssetData(randomAddress()),
salt: new BigNumber(hexRandom()),
salt: new BigNumber(hexUtils.random()),
expirationTimeSeconds: getRandomInteger(0, 2 ** 32),
};
}
@@ -243,57 +248,115 @@ blockchainTests('erc20-bridge-sampler', env => {
return _.times(count || _.random(1, 16), () => createOrder(makerToken, takerToken));
}
describe('queryOrders()', () => {
const MAKER_TOKEN = randomAddress();
const TAKER_TOKEN = randomAddress();
async function enableFailTriggerAsync(): Promise<void> {
await testContract.enableFailTrigger().awaitTransactionSuccessAsync({ value: 1 });
}
it('returns the results of `getOrderInfo()` for each order', async () => {
describe('getOrderFillableTakerAssetAmounts()', () => {
it('returns the expected amount for each order', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
const expected = orders.map(getDeterministicOrderInfo);
const actual = await testContract.queryOrders(orders).callAsync();
const signatures: string[] = _.times(orders.length, hexUtils.random);
const expected = orders.map(getDeterministicFillableTakerAssetAmount);
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq(expected);
});
it('returns empty for no orders', async () => {
const actual = await testContract.queryOrders([]).callAsync();
const actual = await testContract.getOrderFillableTakerAssetAmounts([], []).callAsync();
expect(actual).to.deep.eq([]);
});
it('returns zero for an order with zero maker asset amount', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
const signatures: string[] = _.times(orders.length, hexUtils.random);
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
});
it('returns zero for an order with zero taker asset amount', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
const signatures: string[] = _.times(orders.length, hexUtils.random);
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
});
it('returns zero for an order with an empty signature', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
const signatures: string[] = _.times(orders.length, () => constants.NULL_BYTES);
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
});
});
describe('getOrderFillableMakerAssetAmounts()', () => {
it('returns the expected amount for each order', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
const signatures: string[] = _.times(orders.length, hexUtils.random);
const expected = orders.map(getDeterministicFillableMakerAssetAmount);
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq(expected);
});
it('returns empty for no orders', async () => {
const actual = await testContract.getOrderFillableMakerAssetAmounts([], []).callAsync();
expect(actual).to.deep.eq([]);
});
it('returns zero for an order with zero maker asset amount', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
const signatures: string[] = _.times(orders.length, hexUtils.random);
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
});
it('returns zero for an order with zero taker asset amount', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
const signatures: string[] = _.times(orders.length, hexUtils.random);
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
});
it('returns zero for an order with an empty signature', async () => {
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
const signatures: string[] = _.times(orders.length, () => constants.NULL_BYTES);
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
});
});
describe('queryOrdersAndSampleSells()', () => {
const MAKER_TOKEN = randomAddress();
const TAKER_TOKEN = randomAddress();
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
const SIGNATURES: string[] = _.times(ORDERS.length, hexUtils.random);
before(async () => {
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
});
it('returns the results of `getOrderInfo()` for each order', async () => {
it('returns expected fillable amounts for each order', async () => {
const takerTokenAmounts = getSampleAmounts(TAKER_TOKEN);
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
const expectedOrderInfos = orders.map(getDeterministicOrderInfo);
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableTakerAssetAmount);
const [orderInfos] = await testContract
.queryOrdersAndSampleSells(orders, SELL_SOURCES.map(n => allSources[n]), takerTokenAmounts)
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => allSources[n]), takerTokenAmounts)
.callAsync();
expect(orderInfos).to.deep.eq(expectedOrderInfos);
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
});
it('can return quotes for all sources', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
const [, quotes] = await testContract
.queryOrdersAndSampleSells(
createOrders(MAKER_TOKEN, TAKER_TOKEN),
SELL_SOURCES.map(n => allSources[n]),
sampleAmounts,
)
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => allSources[n]), sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('throws if no orders are passed in', async () => {
const tx = testContract
.queryOrdersAndSampleSells([], SELL_SOURCES.map(n => allSources[n]), getSampleAmounts(TAKER_TOKEN))
.queryOrdersAndSampleSells([], [], SELL_SOURCES.map(n => allSources[n]), getSampleAmounts(TAKER_TOKEN))
.callAsync();
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
});
@@ -301,7 +364,8 @@ blockchainTests('erc20-bridge-sampler', env => {
it('throws with an unsupported source', async () => {
const tx = testContract
.queryOrdersAndSampleSells(
createOrders(MAKER_TOKEN, TAKER_TOKEN),
ORDERS,
SIGNATURES,
[...SELL_SOURCES.map(n => allSources[n]), randomAddress()],
getSampleAmounts(TAKER_TOKEN),
)
@@ -312,10 +376,11 @@ blockchainTests('erc20-bridge-sampler', env => {
it('throws with non-ERC20 maker asset data', async () => {
const tx = testContract
.queryOrdersAndSampleSells(
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
ORDERS.map(o => ({
...o,
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
})),
SIGNATURES,
SELL_SOURCES.map(n => allSources[n]),
getSampleAmounts(TAKER_TOKEN),
)
@@ -326,10 +391,11 @@ blockchainTests('erc20-bridge-sampler', env => {
it('throws with non-ERC20 taker asset data', async () => {
const tx = testContract
.queryOrdersAndSampleSells(
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
ORDERS.map(o => ({
...o,
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
})),
SIGNATURES,
SELL_SOURCES.map(n => allSources[n]),
getSampleAmounts(TAKER_TOKEN),
)
@@ -340,10 +406,11 @@ blockchainTests('erc20-bridge-sampler', env => {
it('throws with invalid maker asset data', async () => {
const tx = testContract
.queryOrdersAndSampleSells(
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
ORDERS.map(o => ({
...o,
makerAssetData: INVALID_ASSET_DATA,
})),
SIGNATURES,
SELL_SOURCES.map(n => allSources[n]),
getSampleAmounts(TAKER_TOKEN),
)
@@ -354,10 +421,11 @@ blockchainTests('erc20-bridge-sampler', env => {
it('throws with invalid taker asset data', async () => {
const tx = testContract
.queryOrdersAndSampleSells(
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
ORDERS.map(o => ({
...o,
takerAssetData: INVALID_ASSET_DATA,
})),
SIGNATURES,
SELL_SOURCES.map(n => allSources[n]),
getSampleAmounts(TAKER_TOKEN),
)
@@ -367,39 +435,34 @@ blockchainTests('erc20-bridge-sampler', env => {
});
describe('queryOrdersAndSampleBuys()', () => {
const MAKER_TOKEN = randomAddress();
const TAKER_TOKEN = randomAddress();
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
const SIGNATURES: string[] = _.times(ORDERS.length, hexUtils.random);
before(async () => {
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
});
it('returns the results of `getOrderInfo()` for each order', async () => {
it('returns expected fillable amounts for each order', async () => {
const takerTokenAmounts = getSampleAmounts(MAKER_TOKEN);
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
const expectedOrderInfos = orders.map(getDeterministicOrderInfo);
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableMakerAssetAmount);
const [orderInfos] = await testContract
.queryOrdersAndSampleBuys(orders, BUY_SOURCES.map(n => allSources[n]), takerTokenAmounts)
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => allSources[n]), takerTokenAmounts)
.callAsync();
expect(orderInfos).to.deep.eq(expectedOrderInfos);
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
});
it('can return quotes for all sources', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
const [, quotes] = await testContract
.queryOrdersAndSampleBuys(
createOrders(MAKER_TOKEN, TAKER_TOKEN),
BUY_SOURCES.map(n => allSources[n]),
sampleAmounts,
)
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => allSources[n]), sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('throws if no orders are passed in', async () => {
const tx = testContract
.queryOrdersAndSampleBuys([], BUY_SOURCES.map(n => allSources[n]), getSampleAmounts(MAKER_TOKEN))
.queryOrdersAndSampleBuys([], [], BUY_SOURCES.map(n => allSources[n]), getSampleAmounts(MAKER_TOKEN))
.callAsync();
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
});
@@ -407,7 +470,8 @@ blockchainTests('erc20-bridge-sampler', env => {
it('throws with an unsupported source', async () => {
const tx = testContract
.queryOrdersAndSampleBuys(
createOrders(MAKER_TOKEN, TAKER_TOKEN),
ORDERS,
SIGNATURES,
[...BUY_SOURCES.map(n => allSources[n]), randomAddress()],
getSampleAmounts(MAKER_TOKEN),
)
@@ -419,7 +483,8 @@ blockchainTests('erc20-bridge-sampler', env => {
const sources = [...BUY_SOURCES, 'Kyber'];
const tx = testContract
.queryOrdersAndSampleBuys(
createOrders(MAKER_TOKEN, TAKER_TOKEN),
ORDERS,
SIGNATURES,
sources.map(n => allSources[n]),
getSampleAmounts(MAKER_TOKEN),
)
@@ -430,10 +495,11 @@ blockchainTests('erc20-bridge-sampler', env => {
it('throws with non-ERC20 maker asset data', async () => {
const tx = testContract
.queryOrdersAndSampleBuys(
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
ORDERS.map(o => ({
...o,
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
})),
SIGNATURES,
BUY_SOURCES.map(n => allSources[n]),
getSampleAmounts(MAKER_TOKEN),
)
@@ -444,10 +510,11 @@ blockchainTests('erc20-bridge-sampler', env => {
it('throws with non-ERC20 taker asset data', async () => {
const tx = testContract
.queryOrdersAndSampleBuys(
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
ORDERS.map(o => ({
...o,
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
})),
SIGNATURES,
BUY_SOURCES.map(n => allSources[n]),
getSampleAmounts(MAKER_TOKEN),
)
@@ -458,10 +525,11 @@ blockchainTests('erc20-bridge-sampler', env => {
it('throws with invalid maker asset data', async () => {
const tx = testContract
.queryOrdersAndSampleBuys(
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
ORDERS.map(o => ({
...o,
makerAssetData: INVALID_ASSET_DATA,
})),
SIGNATURES,
BUY_SOURCES.map(n => allSources[n]),
getSampleAmounts(MAKER_TOKEN),
)
@@ -472,10 +540,11 @@ blockchainTests('erc20-bridge-sampler', env => {
it('throws with invalid taker asset data', async () => {
const tx = testContract
.queryOrdersAndSampleBuys(
createOrders(MAKER_TOKEN, TAKER_TOKEN).map(o => ({
ORDERS.map(o => ({
...o,
takerAssetData: INVALID_ASSET_DATA,
})),
SIGNATURES,
BUY_SOURCES.map(n => allSources[n]),
getSampleAmounts(MAKER_TOKEN),
)
@@ -485,9 +554,6 @@ blockchainTests('erc20-bridge-sampler', env => {
});
describe('sampleSells()', () => {
const MAKER_TOKEN = randomAddress();
const TAKER_TOKEN = randomAddress();
before(async () => {
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
});
@@ -533,9 +599,6 @@ blockchainTests('erc20-bridge-sampler', env => {
});
describe('sampleBuys()', () => {
const MAKER_TOKEN = randomAddress();
const TAKER_TOKEN = randomAddress();
before(async () => {
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
});
@@ -588,10 +651,7 @@ blockchainTests('erc20-bridge-sampler', env => {
});
});
describe('sampleSellsFromKyberNetwork()', () => {
const MAKER_TOKEN = randomAddress();
const TAKER_TOKEN = randomAddress();
blockchainTests.resets('sampleSellsFromKyberNetwork()', () => {
before(async () => {
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
});
@@ -606,7 +666,7 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq([]);
});
it('can return many quotes', async () => {
it('can quote token - token', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Kyber'], sampleAmounts);
const quotes = await testContract
@@ -615,6 +675,16 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> token fails', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleSellsFromKyberNetwork(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote token -> ETH', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Kyber'], sampleAmounts);
@@ -624,6 +694,16 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> ETH fails', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleSellsFromKyberNetwork(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote ETH -> token', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const [expectedQuotes] = getDeterministicSellQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Kyber'], sampleAmounts);
@@ -632,12 +712,19 @@ blockchainTests('erc20-bridge-sampler', env => {
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if ETH -> token fails', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleSellsFromKyberNetwork(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
});
describe('sampleSellsFromEth2Dai()', () => {
const MAKER_TOKEN = randomAddress();
const TAKER_TOKEN = randomAddress();
blockchainTests.resets('sampleSellsFromEth2Dai()', () => {
before(async () => {
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
});
@@ -652,7 +739,7 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq([]);
});
it('can return many quotes', async () => {
it('can quote token -> token', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Eth2Dai'], sampleAmounts);
const quotes = await testContract
@@ -661,6 +748,16 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> token fails', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleSellsFromEth2Dai(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote token -> ETH', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Eth2Dai'], sampleAmounts);
@@ -670,6 +767,16 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> ETH fails', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleSellsFromEth2Dai(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote ETH -> token', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const [expectedQuotes] = getDeterministicSellQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Eth2Dai'], sampleAmounts);
@@ -678,12 +785,19 @@ blockchainTests('erc20-bridge-sampler', env => {
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if ETH -> token fails', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleSellsFromEth2Dai(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
});
describe('sampleBuysFromEth2Dai()', () => {
const MAKER_TOKEN = randomAddress();
const TAKER_TOKEN = randomAddress();
blockchainTests.resets('sampleBuysFromEth2Dai()', () => {
before(async () => {
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
});
@@ -698,7 +812,7 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq([]);
});
it('can return many quotes', async () => {
it('can quote token -> token', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Eth2Dai'], sampleAmounts);
const quotes = await testContract
@@ -707,6 +821,16 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> token fails', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleBuysFromEth2Dai(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote token -> ETH', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Eth2Dai'], sampleAmounts);
@@ -716,6 +840,16 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> ETH fails', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleBuysFromEth2Dai(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote ETH -> token', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const [expectedQuotes] = getDeterministicBuyQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Eth2Dai'], sampleAmounts);
@@ -724,12 +858,19 @@ blockchainTests('erc20-bridge-sampler', env => {
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if ETH -> token fails', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleBuysFromEth2Dai(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
});
describe('sampleSellsFromUniswap()', () => {
const MAKER_TOKEN = randomAddress();
const TAKER_TOKEN = randomAddress();
blockchainTests.resets('sampleSellsFromUniswap()', () => {
before(async () => {
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
});
@@ -744,7 +885,7 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq([]);
});
it('can return many quotes', async () => {
it('can quote token -> token', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Uniswap'], sampleAmounts);
const quotes = await testContract
@@ -753,6 +894,16 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> token fails', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleSellsFromUniswap(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote token -> ETH', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const [expectedQuotes] = getDeterministicSellQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Uniswap'], sampleAmounts);
@@ -762,6 +913,16 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> ETH fails', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleSellsFromUniswap(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote ETH -> token', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const [expectedQuotes] = getDeterministicSellQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Uniswap'], sampleAmounts);
@@ -771,27 +932,38 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq(expectedQuotes);
});
it('throws if no exchange exists for the maker token', async () => {
const nonExistantToken = randomAddress();
const tx = testContract
.sampleSellsFromUniswap(TAKER_TOKEN, nonExistantToken, getSampleAmounts(TAKER_TOKEN))
it('returns zero if ETH -> token fails', async () => {
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleSellsFromUniswap(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
.callAsync();
return expect(tx).to.revertWith(UNSUPPORTED_UNISWAP_EXCHANGE_ERROR);
expect(quotes).to.deep.eq(expectedQuotes);
});
it('throws if no exchange exists for the taker token', async () => {
it('returns zero if no exchange exists for the maker token', async () => {
const nonExistantToken = randomAddress();
const tx = testContract
.sampleSellsFromUniswap(nonExistantToken, MAKER_TOKEN, getSampleAmounts(nonExistantToken))
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
const quotes = await testContract
.sampleSellsFromUniswap(TAKER_TOKEN, nonExistantToken, sampleAmounts)
.callAsync();
return expect(tx).to.revertWith(UNSUPPORTED_UNISWAP_EXCHANGE_ERROR);
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if no exchange exists for the taker token', async () => {
const nonExistantToken = randomAddress();
const sampleAmounts = getSampleAmounts(nonExistantToken);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
const quotes = await testContract
.sampleSellsFromUniswap(nonExistantToken, MAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
});
describe('sampleBuysFromUniswap()', () => {
const MAKER_TOKEN = randomAddress();
const TAKER_TOKEN = randomAddress();
blockchainTests.resets('sampleBuysFromUniswap()', () => {
before(async () => {
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
});
@@ -806,7 +978,7 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq([]);
});
it('can return many quotes', async () => {
it('can quote token -> token', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, ['Uniswap'], sampleAmounts);
const quotes = await testContract
@@ -815,6 +987,16 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> token fails', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleBuysFromUniswap(TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote token -> ETH', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const [expectedQuotes] = getDeterministicBuyQuotes(TAKER_TOKEN, WETH_ADDRESS, ['Uniswap'], sampleAmounts);
@@ -824,6 +1006,16 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if token -> ETH fails', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleBuysFromUniswap(TAKER_TOKEN, WETH_ADDRESS, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
it('can quote ETH -> token', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const [expectedQuotes] = getDeterministicBuyQuotes(WETH_ADDRESS, TAKER_TOKEN, ['Uniswap'], sampleAmounts);
@@ -833,20 +1025,34 @@ blockchainTests('erc20-bridge-sampler', env => {
expect(quotes).to.deep.eq(expectedQuotes);
});
it('throws if no exchange exists for the maker token', async () => {
const nonExistantToken = randomAddress();
const tx = testContract
.sampleBuysFromUniswap(TAKER_TOKEN, nonExistantToken, getSampleAmounts(TAKER_TOKEN))
it('returns zero if ETH -> token fails', async () => {
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
await enableFailTriggerAsync();
const quotes = await testContract
.sampleBuysFromUniswap(WETH_ADDRESS, TAKER_TOKEN, sampleAmounts)
.callAsync();
return expect(tx).to.revertWith(UNSUPPORTED_UNISWAP_EXCHANGE_ERROR);
expect(quotes).to.deep.eq(expectedQuotes);
});
it('throws if no exchange exists for the taker token', async () => {
it('returns zero if no exchange exists for the maker token', async () => {
const nonExistantToken = randomAddress();
const tx = testContract
.sampleBuysFromUniswap(nonExistantToken, MAKER_TOKEN, getSampleAmounts(nonExistantToken))
const sampleAmounts = getSampleAmounts(nonExistantToken);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
const quotes = await testContract
.sampleBuysFromUniswap(TAKER_TOKEN, nonExistantToken, sampleAmounts)
.callAsync();
return expect(tx).to.revertWith(UNSUPPORTED_UNISWAP_EXCHANGE_ERROR);
expect(quotes).to.deep.eq(expectedQuotes);
});
it('returns zero if no exchange exists for the taker token', async () => {
const nonExistantToken = randomAddress();
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
const expectedQuotes = _.times(sampleAmounts.length, () => constants.ZERO_AMOUNT);
const quotes = await testContract
.sampleBuysFromUniswap(nonExistantToken, MAKER_TOKEN, sampleAmounts)
.callAsync();
expect(quotes).to.deep.eq(expectedQuotes);
});
});
});

View File

@@ -3,8 +3,8 @@
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../test/generated-wrappers/deployment_constants';
export * from '../test/generated-wrappers/erc20_bridge_sampler';
export * from '../test/generated-wrappers/i_dev_utils';
export * from '../test/generated-wrappers/i_erc20_bridge_sampler';
export * from '../test/generated-wrappers/i_eth2_dai';
export * from '../test/generated-wrappers/i_kyber_network';

View File

@@ -5,8 +5,8 @@
"files": [
"generated-artifacts/ERC20BridgeSampler.json",
"generated-artifacts/IERC20BridgeSampler.json",
"test/generated-artifacts/DeploymentConstants.json",
"test/generated-artifacts/ERC20BridgeSampler.json",
"test/generated-artifacts/IDevUtils.json",
"test/generated-artifacts/IERC20BridgeSampler.json",
"test/generated-artifacts/IEth2Dai.json",
"test/generated-artifacts/IKyberNetwork.json",

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1578272714,
"version": "3.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"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": [

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.0.3 - _January 6, 2020_
* Dependencies updated
## v3.0.2 - _December 17, 2019_
* Dependencies updated
## v3.0.1 - _December 9, 2019_
* Dependencies updated
## v3.0.0 - _December 2, 2019_
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc20",
"version": "3.0.0",
"version": "3.0.3",
"engines": {
"node": ">=6.12"
},
@@ -51,18 +51,18 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.0",
"@0x/contracts-gen": "^2.0.0",
"@0x/contracts-test-utils": "^4.0.0",
"@0x/contracts-utils": "^4.0.0",
"@0x/dev-utils": "^3.0.0",
"@0x/sol-compiler": "^4.0.0",
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/contracts-utils": "^4.0.3",
"@0x/dev-utils": "^3.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.0.0",
"@0x/typescript-typings": "^5.0.0",
"@0x/utils": "^5.0.0",
"@0x/web3-wrapper": "^7.0.0",
"@0x/types": "^3.1.1",
"@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.1.2",
"@0x/web3-wrapper": "^7.0.3",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -82,7 +82,7 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.0"
"@0x/base-contract": "^6.0.3"
},
"publishConfig": {
"access": "public"

View File

@@ -3,6 +3,9 @@ export {
DummyMultipleReturnERC20TokenContract,
DummyNoReturnERC20TokenContract,
WETH9Contract,
WETH9Events,
WETH9DepositEventArgs,
WETH9TransferEventArgs,
ZRXTokenContract,
DummyERC20TokenTransferEventArgs,
ERC20TokenEventArgs,

View File

@@ -3,11 +3,10 @@ import {
constants,
expect,
getRandomInteger,
hexLeftPad,
randomAddress,
verifyEventsFromLogs,
} from '@0x/contracts-test-utils';
import { RawRevertError, StringRevertError } from '@0x/utils';
import { hexUtils, RawRevertError, StringRevertError } from '@0x/utils';
import { TestLibERC20TokenContract, TestLibERC20TokenTargetEvents } from './wrappers';
@@ -17,11 +16,11 @@ blockchainTests('LibERC20Token', env => {
let testContract: TestLibERC20TokenContract;
const REVERT_STRING = 'WHOOPSIE';
const ENCODED_REVERT = new StringRevertError(REVERT_STRING).encode();
const ENCODED_TRUE = hexLeftPad(1);
const ENCODED_FALSE = hexLeftPad(0);
const ENCODED_TWO = hexLeftPad(2);
const ENCODED_SHORT_TRUE = hexLeftPad(2, 31);
const ENCODED_LONG_TRUE = hexLeftPad(2, 33);
const ENCODED_TRUE = hexUtils.leftPad(1);
const ENCODED_FALSE = hexUtils.leftPad(0);
const ENCODED_TWO = hexUtils.leftPad(2);
const ENCODED_SHORT_TRUE = hexUtils.leftPad(2, 31);
const ENCODED_LONG_TRUE = hexUtils.leftPad(2, 33);
before(async () => {
testContract = await TestLibERC20TokenContract.deployFrom0xArtifactAsync(
@@ -301,14 +300,14 @@ blockchainTests('LibERC20Token', env => {
describe('decimals()', () => {
const DEFAULT_DECIMALS = 18;
const ENCODED_ZERO = hexLeftPad(0);
const ENCODED_SHORT_ZERO = hexLeftPad(0, 31);
const ENCODED_LONG_ZERO = hexLeftPad(0, 33);
const ENCODED_ZERO = hexUtils.leftPad(0);
const ENCODED_SHORT_ZERO = hexUtils.leftPad(0, 31);
const ENCODED_LONG_ZERO = hexUtils.leftPad(0, 33);
const randomDecimals = () => Math.floor(Math.random() * 256) + 1;
it('returns the number of decimals defined by the token', async () => {
const decimals = randomDecimals();
const encodedDecimals = hexLeftPad(decimals);
const encodedDecimals = hexUtils.leftPad(decimals);
const result = await testContract.testDecimals(false, ENCODED_REVERT, encodedDecimals).callAsync();
return expect(result).to.bignumber.eq(decimals);
});

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1578272714,
"version": "3.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"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": [

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.0.3 - _January 6, 2020_
* Dependencies updated
## v3.0.2 - _December 17, 2019_
* Dependencies updated
## v3.0.1 - _December 9, 2019_
* Dependencies updated
## v3.0.0 - _December 2, 2019_
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc721",
"version": "3.0.0",
"version": "3.0.3",
"engines": {
"node": ">=6.12"
},
@@ -52,18 +52,18 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.0",
"@0x/contracts-gen": "^2.0.0",
"@0x/contracts-test-utils": "^4.0.0",
"@0x/contracts-utils": "^4.0.0",
"@0x/dev-utils": "^3.0.0",
"@0x/sol-compiler": "^4.0.0",
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/contracts-utils": "^4.0.3",
"@0x/dev-utils": "^3.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.0.0",
"@0x/typescript-typings": "^5.0.0",
"@0x/utils": "^5.0.0",
"@0x/web3-wrapper": "^7.0.0",
"@0x/types": "^3.1.1",
"@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.1.2",
"@0x/web3-wrapper": "^7.0.3",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -84,7 +84,7 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.0"
"@0x/base-contract": "^6.0.3"
},
"publishConfig": {
"access": "public"

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1578272714,
"version": "4.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1576540892,
"version": "4.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1575931811,
"version": "4.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "4.0.0",
"changes": [

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.0.3 - _January 6, 2020_
* Dependencies updated
## v4.0.2 - _December 17, 2019_
* Dependencies updated
## v4.0.1 - _December 9, 2019_
* Dependencies updated
## v4.0.0 - _December 2, 2019_
* Added buy support for ERC20Bridge (#2356)

View File

@@ -109,6 +109,7 @@ contract MixinExchangeWrapper is
// Subtract fee from makerAssetFilledAmount for the net amount acquired.
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount
.safeSub(singleFillResults.takerFeePaid);
// WETH fee
} else if (_areUnderlyingAssetsEqual(order.takerFeeAssetData, order.takerAssetData)) {
@@ -132,6 +133,7 @@ contract MixinExchangeWrapper is
.safeAdd(singleFillResults.protocolFeePaid);
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
// Unsupported fee
} else {
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedFeeError(order.takerFeeAssetData));
@@ -146,7 +148,7 @@ contract MixinExchangeWrapper is
/// @param signatures Proofs that orders have been signed by makers.
/// @return totalWethSpentAmount Total amount of WETH spent on the given orders.
/// @return totalMakerAssetAcquiredAmount Total amount of maker asset acquired from the given orders.
function _marketSellWeth(
function _marketSellNoThrow(
LibOrder.Order[] memory orders,
uint256 wethSellAmount,
bytes[] memory signatures
@@ -256,6 +258,7 @@ contract MixinExchangeWrapper is
.safeAdd(singleFillResults.protocolFeePaid);
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount;
// Percentage fee
} else if (_areUnderlyingAssetsEqual(order.takerFeeAssetData, order.makerAssetData)) {
// Calculate the remaining amount of takerAsset to sell
@@ -278,6 +281,7 @@ contract MixinExchangeWrapper is
// Subtract fee from makerAssetFilledAmount for the net amount acquired.
makerAssetAcquiredAmount = singleFillResults.makerAssetFilledAmount
.safeSub(singleFillResults.takerFeePaid);
// Unsupported fee
} else {
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedFeeError(order.takerFeeAssetData));
@@ -295,7 +299,7 @@ contract MixinExchangeWrapper is
/// @param signatures Proofs that orders have been signed by makers.
/// @return totalWethSpentAmount Total amount of WETH spent on the given orders.
/// @return totalMakerAssetAcquiredAmount Total amount of maker asset acquired from the given orders.
function _marketBuyExactAmountWithWeth(
function _marketBuyFillOrKill(
LibOrder.Order[] memory orders,
uint256 makerAssetBuyAmount,
bytes[] memory signatures

View File

@@ -63,53 +63,42 @@ contract MixinForwarderCore is
/// as possible, accounting for order and forwarder fees.
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
/// @param signatures Proofs that orders have been created by makers.
/// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
/// @param feeRecipient Address that will receive ETH when orders are filled.
/// @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 wethSpentAmount Amount of WETH spent on the given set of orders.
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
/// @return ethFeePaid Amount of ETH spent on the given forwarder fee.
function marketSellOrdersWithEth(
LibOrder.Order[] memory orders,
bytes[] memory signatures,
uint256 feePercentage,
address payable feeRecipient
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount,
uint256 ethFeePaid
uint256 makerAssetAcquiredAmount
)
{
// Convert ETH to WETH.
_convertEthToWeth();
// Calculate amount of WETH that won't be spent on the forwarder fee.
uint256 wethSellAmount = LibMath.getPartialAmountFloor(
PERCENTAGE_DENOMINATOR,
feePercentage.safeAdd(PERCENTAGE_DENOMINATOR),
msg.value
// Pay ETH affiliate fees to all feeRecipient addresses
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
ethFeeAmounts,
feeRecipients
);
// Spends up to wethSellAmount to fill orders, transfers purchased assets to msg.sender,
// Spends up to wethRemaining to fill orders, transfers purchased assets to msg.sender,
// and pays WETH order fees.
(
wethSpentAmount,
makerAssetAcquiredAmount
) = _marketSellWeth(
) = _marketSellNoThrow(
orders,
wethSellAmount,
wethRemaining,
signatures
);
// Transfer feePercentage of total ETH spent on orders to feeRecipient.
// Refund remaining ETH to msg.sender.
ethFeePaid = _transferEthFeeAndRefund(
wethSpentAmount,
feePercentage,
feeRecipient
);
_transferEthRefund(wethRemaining, wethSpentAmount);
}
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
@@ -119,45 +108,41 @@ contract MixinForwarderCore is
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
/// @param signatures Proofs that orders have been created by makers.
/// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
/// @param feeRecipient Address that will receive ETH when orders are filled.
/// @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 wethSpentAmount Amount of WETH spent on the given set of orders.
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
/// @return ethFeePaid Amount of ETH spent on the given forwarder fee.
function marketBuyOrdersWithEth(
LibOrder.Order[] memory orders,
uint256 makerAssetBuyAmount,
bytes[] memory signatures,
uint256 feePercentage,
address payable feeRecipient
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount,
uint256 ethFeePaid
uint256 makerAssetAcquiredAmount
)
{
// Convert ETH to WETH.
_convertEthToWeth();
// Pay ETH affiliate fees to all feeRecipient addresses
uint256 wethRemaining = _transferEthFeesAndWrapRemaining(
ethFeeAmounts,
feeRecipients
);
// Attempts to fill the desired amount of makerAsset and trasnfer purchased assets to msg.sender.
(
wethSpentAmount,
makerAssetAcquiredAmount
) = _marketBuyExactAmountWithWeth(
) = _marketBuyFillOrKill(
orders,
makerAssetBuyAmount,
signatures
);
// Transfer feePercentage of total ETH spent on orders to feeRecipient.
// Refund remaining ETH to msg.sender.
ethFeePaid = _transferEthFeeAndRefund(
wethSpentAmount,
feePercentage,
feeRecipient
);
_transferEthRefund(wethRemaining, wethSpentAmount);
}
}

View File

@@ -20,7 +20,6 @@ pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "./libs/LibConstants.sol";
import "./libs/LibForwarderRichErrors.sol";
@@ -42,39 +41,61 @@ contract MixinWeth is
}
}
/// @dev Converts message call's ETH value into WETH.
function _convertEthToWeth()
internal
{
if (msg.value == 0) {
LibRichErrors.rrevert(LibForwarderRichErrors.MsgValueCannotEqualZeroError());
}
ETHER_TOKEN.deposit.value(msg.value)();
}
/// @dev Transfers feePercentage of WETH spent on primary orders to feeRecipient.
/// Refunds any excess ETH to msg.sender.
/// @param wethSpent Amount of WETH spent when filling orders.
/// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
/// @param feeRecipient Address that will receive ETH when orders are filled.
/// @return ethFee Amount paid to feeRecipient as a percentage fee on the total WETH sold.
function _transferEthFeeAndRefund(
uint256 wethSpent,
uint256 feePercentage,
address payable feeRecipient
/// @dev Transfers ETH denominated fees to all feeRecipient addresses
/// @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 ethRemaining msg.value minus the amount of ETH spent on affiliate fees.
function _transferEthFeesAndWrapRemaining(
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
internal
returns (uint256 ethFee)
returns (uint256 ethRemaining)
{
// Ensure feePercentage is less than 5%.
if (feePercentage > MAX_FEE_PERCENTAGE) {
LibRichErrors.rrevert(LibForwarderRichErrors.FeePercentageTooLargeError(
feePercentage
uint256 feesLen = ethFeeAmounts.length;
// ethFeeAmounts len must equal feeRecipients len
if (feesLen != feeRecipients.length) {
LibRichErrors.rrevert(LibForwarderRichErrors.EthFeeLengthMismatchError(
feesLen,
feeRecipients.length
));
}
// This function is always called before any other function, so we assume that
// the ETH remaining is the entire msg.value.
ethRemaining = msg.value;
for (uint256 i = 0; i != feesLen; i++) {
uint256 ethFeeAmount = ethFeeAmounts[i];
// Ensure there is enough ETH to pay the fee
if (ethRemaining < ethFeeAmount) {
LibRichErrors.rrevert(LibForwarderRichErrors.InsufficientEthForFeeError(
ethFeeAmount,
ethRemaining
));
}
// Decrease ethRemaining and transfer fee to corresponding feeRecipient
ethRemaining = ethRemaining.safeSub(ethFeeAmount);
feeRecipients[i].transfer(ethFeeAmount);
}
// Convert remaining ETH to WETH.
ETHER_TOKEN.deposit.value(ethRemaining)();
return ethRemaining;
}
/// @dev Refunds any excess ETH to msg.sender.
/// @param initialWethAmount Amount of WETH available after transferring affiliate fees.
/// @param wethSpent Amount of WETH spent when filling orders.
function _transferEthRefund(
uint256 initialWethAmount,
uint256 wethSpent
)
internal
{
// Ensure that no extra WETH owned by this contract has been spent.
if (wethSpent > msg.value) {
if (wethSpent > initialWethAmount) {
LibRichErrors.rrevert(LibForwarderRichErrors.OverspentWethError(
wethSpent,
msg.value
@@ -82,38 +103,15 @@ contract MixinWeth is
}
// Calculate amount of WETH that hasn't been spent.
uint256 wethRemaining = msg.value.safeSub(wethSpent);
// Calculate ETH fee to pay to feeRecipient.
ethFee = LibMath.getPartialAmountFloor(
feePercentage,
PERCENTAGE_DENOMINATOR,
wethSpent
);
// Ensure fee is less than amount of WETH remaining.
if (ethFee > wethRemaining) {
LibRichErrors.rrevert(LibForwarderRichErrors.InsufficientEthForFeeError(
ethFee,
wethRemaining
));
}
uint256 wethRemaining = initialWethAmount.safeSub(wethSpent);
// Do nothing if no WETH remaining
if (wethRemaining > 0) {
// Convert remaining WETH to ETH
ETHER_TOKEN.withdraw(wethRemaining);
// Pay ETH to feeRecipient
if (ethFee > 0) {
feeRecipient.transfer(ethFee);
}
// Refund remaining ETH to msg.sender.
uint256 ethRefund = wethRemaining.safeSub(ethFee);
if (ethRefund > 0) {
msg.sender.transfer(ethRefund);
}
// Transfer remaining ETH to sender
msg.sender.transfer(wethRemaining);
}
}
}

View File

@@ -29,23 +29,21 @@ contract IForwarderCore {
/// as possible, accounting for order and forwarder fees.
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
/// @param signatures Proofs that orders have been created by makers.
/// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
/// @param feeRecipient Address that will receive ETH when orders are filled.
/// @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 wethSpentAmount Amount of WETH spent on the given set of orders.
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
/// @return ethFeePaid Amount of ETH spent on the given forwarder fee.
function marketSellOrdersWithEth(
LibOrder.Order[] memory orders,
bytes[] memory signatures,
uint256 feePercentage,
address payable feeRecipient
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount,
uint256 ethFeePaid
uint256 makerAssetAcquiredAmount
);
/// @dev Attempt to buy makerAssetBuyAmount of makerAsset by selling ETH provided with transaction.
@@ -55,23 +53,21 @@ contract IForwarderCore {
/// @param orders Array of order specifications used containing desired makerAsset and WETH as takerAsset.
/// @param makerAssetBuyAmount Desired amount of makerAsset to purchase.
/// @param signatures Proofs that orders have been created by makers.
/// @param feePercentage Percentage of WETH sold that will payed as fee to forwarding contract feeRecipient.
/// @param feeRecipient Address that will receive ETH when orders are filled.
/// @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 wethSpentAmount Amount of WETH spent on the given set of orders.
/// @return makerAssetAcquiredAmount Amount of maker asset acquired from the given set of orders.
/// @return ethFeePaid Amount of ETH spent on the given forwarder fee.
function marketBuyOrdersWithEth(
LibOrder.Order[] memory orders,
uint256 makerAssetBuyAmount,
bytes[] memory signatures,
uint256 feePercentage,
address payable feeRecipient
uint256[] memory ethFeeAmounts,
address payable[] memory feeRecipients
)
public
payable
returns (
uint256 wethSpentAmount,
uint256 makerAssetAcquiredAmount,
uint256 ethFeePaid
uint256 makerAssetAcquiredAmount
);
}

View File

@@ -28,8 +28,6 @@ contract LibConstants {
using LibBytes for bytes;
uint256 constant internal MAX_UINT = 2**256 - 1;
uint256 constant internal PERCENTAGE_DENOMINATOR = 10**18;
uint256 constant internal MAX_FEE_PERCENTAGE = 5 * PERCENTAGE_DENOMINATOR / 100; // 5%
// solhint-disable var-name-mixedcase
IExchange internal EXCHANGE;

View File

@@ -37,10 +37,6 @@ library LibForwarderRichErrors {
bytes4 internal constant UNSUPPORTED_FEE_ERROR_SELECTOR =
0x31360af1;
// bytes4(keccak256("FeePercentageTooLargeError(uint256)"))
bytes4 internal constant FEE_PERCENTAGE_TOO_LARGE_ERROR_SELECTOR =
0x1174fb80;
// bytes4(keccak256("InsufficientEthForFeeError(uint256,uint256)"))
bytes4 internal constant INSUFFICIENT_ETH_FOR_FEE_ERROR_SELECTOR =
0xecf40fd9;
@@ -53,13 +49,13 @@ library LibForwarderRichErrors {
bytes4 internal constant DEFAULT_FUNCTION_WETH_CONTRACT_ONLY_ERROR_SELECTOR =
0x08b18698;
// bytes4(keccak256("MsgValueCannotEqualZeroError()"))
bytes4 internal constant MSG_VALUE_CANNOT_EQUAL_ZERO_ERROR_SELECTOR =
0x8c0e562b;
// bytes4(keccak256("Erc721AmountMustEqualOneError(uint256)"))
bytes4 internal constant ERC721_AMOUNT_MUST_EQUAL_ONE_ERROR_SELECTOR =
0xbaffa474;
// bytes4(keccak256("EthFeeLengthMismatchError(uint256,uint256)"))
bytes4 internal constant ETH_FEE_LENGTH_MISMATCH_ERROR_SELECTOR =
0x3ecb6ceb;
// solhint-disable func-name-mixedcase
function UnregisteredAssetProxyError()
@@ -111,19 +107,6 @@ library LibForwarderRichErrors {
);
}
function FeePercentageTooLargeError(
uint256 feePercentage
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
FEE_PERCENTAGE_TOO_LARGE_ERROR_SELECTOR,
feePercentage
);
}
function InsufficientEthForFeeError(
uint256 ethFeeRequired,
uint256 ethAvailable
@@ -167,14 +150,6 @@ library LibForwarderRichErrors {
);
}
function MsgValueCannotEqualZeroError()
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(MSG_VALUE_CANNOT_EQUAL_ZERO_ERROR_SELECTOR);
}
function Erc721AmountMustEqualOneError(
uint256 amount
)
@@ -188,4 +163,18 @@ library LibForwarderRichErrors {
);
}
function EthFeeLengthMismatchError(
uint256 ethFeesLength,
uint256 feeRecipientsLength
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
ETH_FEE_LENGTH_MISMATCH_ERROR_SELECTOR,
ethFeesLength,
feeRecipientsLength
);
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange-forwarder",
"version": "4.0.0",
"version": "4.0.3",
"engines": {
"node": ">=6.12"
},
@@ -52,24 +52,24 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.0",
"@0x/contracts-asset-proxy": "^3.0.0",
"@0x/contracts-dev-utils": "^1.0.0",
"@0x/contracts-erc20": "^3.0.0",
"@0x/contracts-erc721": "^3.0.0",
"@0x/contracts-exchange": "^3.0.0",
"@0x/contracts-exchange-libs": "^4.0.0",
"@0x/contracts-gen": "^2.0.0",
"@0x/contracts-test-utils": "^4.0.0",
"@0x/contracts-utils": "^4.0.0",
"@0x/dev-utils": "^3.0.0",
"@0x/order-utils": "^9.0.0",
"@0x/sol-compiler": "^4.0.0",
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-asset-proxy": "^3.1.0",
"@0x/contracts-dev-utils": "^1.0.3",
"@0x/contracts-erc20": "^3.0.3",
"@0x/contracts-erc721": "^3.0.3",
"@0x/contracts-exchange": "^3.0.3",
"@0x/contracts-exchange-libs": "^4.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/contracts-utils": "^4.0.3",
"@0x/dev-utils": "^3.1.0",
"@0x/order-utils": "^10.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.0.0",
"@0x/utils": "^5.0.0",
"@0x/web3-wrapper": "^7.0.0",
"@0x/types": "^3.1.1",
"@0x/utils": "^5.1.2",
"@0x/web3-wrapper": "^7.0.3",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -89,8 +89,8 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.0",
"@0x/typescript-typings": "^5.0.0",
"@0x/base-contract": "^6.0.3",
"@0x/typescript-typings": "^5.0.1",
"ethereum-types": "^3.0.0"
},
"publishConfig": {

View File

@@ -16,12 +16,10 @@ import {
constants,
expect,
getRandomInteger,
hexRandom,
hexSlice,
randomAddress,
verifyEventsFromLogs,
} from '@0x/contracts-test-utils';
import { BigNumber, ExchangeForwarderRevertErrors } from '@0x/utils';
import { BigNumber, ExchangeForwarderRevertErrors, hexUtils } from '@0x/utils';
import { artifacts } from './artifacts';
import { TestForwarderContract } from './wrappers';
@@ -76,7 +74,7 @@ blockchainTests('Supported asset type unit tests', env => {
erc721AssetData = assetDataEncoder.ERC721Token(erc721Token.address, nftId).getABIEncodedTransactionData();
bridgeAddress = randomAddress();
bridgeData = hexRandom();
bridgeData = hexUtils.random();
erc20BridgeAssetData = assetDataEncoder
.ERC20Bridge(erc20Token.address, bridgeAddress, bridgeData)
.getABIEncodedTransactionData();
@@ -171,12 +169,12 @@ blockchainTests('Supported asset type unit tests', env => {
);
});
it('reverts if assetData is unsupported', async () => {
const randomBytes = hexRandom();
const randomBytes = hexUtils.random();
const tx = forwarder
.transferAssetToSender(randomBytes, TRANSFER_AMOUNT)
.awaitTransactionSuccessAsync({ from: receiver });
const expectedError = new ExchangeForwarderRevertErrors.UnsupportedAssetProxyError(
hexSlice(randomBytes, 0, 4),
hexUtils.slice(randomBytes, 0, 4),
);
return expect(tx).to.revertWith(expectedError);
});

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1578272714,
"version": "4.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1576540892,
"version": "4.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1575931811,
"version": "4.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "4.0.0",
"changes": [

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.0.3 - _January 6, 2020_
* Dependencies updated
## v4.0.2 - _December 17, 2019_
* Dependencies updated
## v4.0.1 - _December 9, 2019_
* Dependencies updated
## v4.0.0 - _December 2, 2019_
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)

View File

@@ -29,9 +29,11 @@ contract LibEIP712ExchangeDomain {
// EIP712 Exchange Domain Version value
string constant internal _EIP712_EXCHANGE_DOMAIN_VERSION = "3.0.0";
// Hash of the EIP712 Domain Separator data
// solhint-disable-next-line var-name-mixedcase
// solhint-disable var-name-mixedcase
/// @dev Hash of the EIP712 Domain Separator data
/// @return 0 Domain hash.
bytes32 public EIP712_EXCHANGE_DOMAIN_HASH;
// solhint-enable var-name-mixedcase
/// @param chainId Chain ID of the network this contract is deployed on.
/// @param verifyingContractAddressIfExists Address of the verifying contract (null if the address of this contract)

View File

@@ -60,6 +60,7 @@ library LibOrder {
}
// solhint-disable max-line-length
/// @dev Canonical order structure.
struct Order {
address makerAddress; // Address that created the order.
address takerAddress; // Address that is allowed to fill the order. If set to 0, any address is allowed to fill the order.
@@ -78,8 +79,9 @@ library LibOrder {
}
// solhint-enable max-line-length
/// @dev Order information returned by `getOrderInfo()`.
struct OrderInfo {
uint8 orderStatus; // Status that describes order's validity and fillability.
OrderStatus orderStatus; // Status that describes order's validity and fillability.
bytes32 orderHash; // EIP712 typed data hash of the order (see LibOrder.getTypedDataHash).
uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled.
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange-libs",
"version": "4.0.0",
"version": "4.0.3",
"engines": {
"node": ">=6.12"
},
@@ -52,15 +52,15 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/libs/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.0",
"@0x/contracts-gen": "^2.0.0",
"@0x/contracts-test-utils": "^4.0.0",
"@0x/dev-utils": "^3.0.0",
"@0x/sol-compiler": "^4.0.0",
"@0x/subproviders": "^6.0.0",
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/dev-utils": "^3.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/subproviders": "^6.0.3",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/web3-wrapper": "^7.0.0",
"@0x/web3-wrapper": "^7.0.3",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -81,12 +81,12 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.0",
"@0x/contracts-utils": "^4.0.0",
"@0x/order-utils": "^9.0.0",
"@0x/types": "^3.0.0",
"@0x/typescript-typings": "^5.0.0",
"@0x/utils": "^5.0.0",
"@0x/base-contract": "^6.0.3",
"@0x/contracts-utils": "^4.0.3",
"@0x/order-utils": "^10.1.0",
"@0x/types": "^3.1.1",
"@0x/typescript-typings": "^5.0.1",
"@0x/utils": "^5.1.2",
"ethereum-types": "^3.0.0"
},
"publishConfig": {

View File

@@ -103,7 +103,7 @@ export function calculateFillResults(
order.takerAssetAmount,
order.makerAssetAmount,
);
const makerFeePaid = safeGetPartialAmountFloor(makerAssetFilledAmount, order.makerAssetAmount, order.makerFee);
const makerFeePaid = safeGetPartialAmountFloor(takerAssetFilledAmount, order.takerAssetAmount, order.makerFee);
const takerFeePaid = safeGetPartialAmountFloor(takerAssetFilledAmount, order.takerAssetAmount, order.takerFee);
return {
makerAssetFilledAmount,
@@ -113,3 +113,30 @@ export function calculateFillResults(
protocolFeePaid: safeMul(protocolFeeMultiplier, gasPrice),
};
}
export const LibFractions = {
add: (n1: BigNumber, d1: BigNumber, n2: BigNumber, d2: BigNumber): [BigNumber, BigNumber] => {
if (n1.isZero()) {
return [n2, d2];
}
if (n2.isZero()) {
return [n1, d1];
}
const numerator = safeAdd(safeMul(n1, d2), safeMul(n2, d1));
const denominator = safeMul(d1, d2);
return [numerator, denominator];
},
normalize: (
numerator: BigNumber,
denominator: BigNumber,
maxValue: BigNumber = new BigNumber(2).exponentiatedBy(127),
): [BigNumber, BigNumber] => {
if (numerator.isGreaterThan(maxValue) || denominator.isGreaterThan(maxValue)) {
let rescaleBase = numerator.isGreaterThanOrEqualTo(denominator) ? numerator : denominator;
rescaleBase = safeDiv(rescaleBase, maxValue);
return [safeDiv(numerator, rescaleBase), safeDiv(denominator, rescaleBase)];
} else {
return [numerator, denominator];
}
},
};

View File

@@ -3,13 +3,12 @@ import {
constants,
describe,
expect,
hexRandom,
testCombinatoriallyWithReferenceFunc,
uint256Values,
} from '@0x/contracts-test-utils';
import { SafeMathRevertErrors } from '@0x/contracts-utils';
import { FillResults, MatchedFillResults, Order } from '@0x/types';
import { BigNumber, LibMathRevertErrors } from '@0x/utils';
import { BigNumber, hexUtils, LibMathRevertErrors } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
@@ -46,9 +45,9 @@ blockchainTests('LibFillResults', env => {
exchangeAddress: constants.NULL_ADDRESS,
};
const randomAddress = () => hexRandom(constants.ADDRESS_LENGTH);
const randomAssetData = () => hexRandom(36);
const randomUint256 = () => new BigNumber(hexRandom(constants.WORD_LENGTH));
const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH);
const randomAssetData = () => hexUtils.random(36);
const randomUint256 = () => new BigNumber(hexUtils.random(constants.WORD_LENGTH));
let libsContract: TestLibFillResultsContract;
let makerAddressLeft: string;

View File

@@ -1,7 +1,7 @@
import { blockchainTests, constants, describe, expect, hexRandom, orderHashUtils } from '@0x/contracts-test-utils';
import { blockchainTests, constants, describe, expect, orderHashUtils } from '@0x/contracts-test-utils';
import { eip712Utils } from '@0x/order-utils';
import { Order } from '@0x/types';
import { BigNumber, signTypedDataUtils } from '@0x/utils';
import { BigNumber, hexUtils, signTypedDataUtils } from '@0x/utils';
import * as ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
@@ -12,10 +12,10 @@ import { artifacts } from './artifacts';
blockchainTests('LibOrder', env => {
let libOrderContract: TestLibOrderContract;
const randomAddress = () => hexRandom(constants.ADDRESS_LENGTH);
const randomHash = () => hexRandom(constants.WORD_LENGTH);
const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH);
const randomHash = () => hexUtils.random(constants.WORD_LENGTH);
const randomUint256 = () => new BigNumber(randomHash());
const randomAssetData = () => hexRandom(36);
const randomAssetData = () => hexUtils.random(36);
const EMPTY_ORDER: Order = {
exchangeAddress: constants.NULL_ADDRESS,

View File

@@ -1,14 +1,7 @@
import {
blockchainTests,
constants,
describe,
expect,
hexRandom,
transactionHashUtils,
} from '@0x/contracts-test-utils';
import { blockchainTests, constants, describe, expect, transactionHashUtils } from '@0x/contracts-test-utils';
import { eip712Utils } from '@0x/order-utils';
import { ZeroExTransaction } from '@0x/types';
import { BigNumber, signTypedDataUtils } from '@0x/utils';
import { BigNumber, hexUtils, signTypedDataUtils } from '@0x/utils';
import * as ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
@@ -19,10 +12,10 @@ import { artifacts } from './artifacts';
blockchainTests('LibZeroExTransaction', env => {
let libZeroExTransactionContract: TestLibZeroExTransactionContract;
const randomAddress = () => hexRandom(constants.ADDRESS_LENGTH);
const randomHash = () => hexRandom(constants.WORD_LENGTH);
const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH);
const randomHash = () => hexUtils.random(constants.WORD_LENGTH);
const randomUint256 = () => new BigNumber(randomHash());
const randomAssetData = () => hexRandom(36);
const randomAssetData = () => hexUtils.random(36);
const EMPTY_TRANSACTION: ZeroExTransaction = {
salt: constants.ZERO_AMOUNT,

View File

@@ -1,4 +1,31 @@
[
{
"timestamp": 1578272714,
"version": "3.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"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": [

View File

@@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.0.3 - _January 6, 2020_
* Dependencies updated
## v3.0.2 - _December 17, 2019_
* Dependencies updated
## v3.0.1 - _December 9, 2019_
* Dependencies updated
## v3.0.0 - _December 2, 2019_
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)

View File

@@ -29,6 +29,7 @@ import "./MixinTransferSimulator.sol";
// MixinAssetProxyDispatcher, MixinExchangeCore, MixinSignatureValidator,
// and MixinTransactions are all inherited via the other Mixins that are
// used.
/// @dev The 0x Exchange contract.
contract Exchange is
LibEIP712ExchangeDomain,
MixinMatchOrders,

View File

@@ -62,11 +62,11 @@ contract MixinAssetProxyDispatcher is
/// @dev Gets an asset proxy.
/// @param assetProxyId Id of the asset proxy.
/// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
/// @return assetProxy The asset proxy address registered to assetProxyId. Returns 0x0 if no proxy is registered.
function getAssetProxy(bytes4 assetProxyId)
external
view
returns (address)
returns (address assetProxy)
{
return _assetProxies[assetProxyId];
}

View File

@@ -45,14 +45,21 @@ contract MixinExchangeCore is
using LibSafeMath for uint256;
using LibBytes for bytes;
// Mapping of orderHash => amount of takerAsset already bought by maker
/// @dev Mapping of orderHash => amount of takerAsset already bought by maker
/// @param 0 Order hash.
/// @return 0 The amount of taker asset filled.
mapping (bytes32 => uint256) public filled;
// Mapping of orderHash => cancelled
/// @dev Mapping of orderHash => cancelled
/// @param 0 Order hash.
/// @return 0 Whether the order was cancelled.
mapping (bytes32 => bool) public cancelled;
// Mapping of makerAddress => senderAddress => lowest salt an order can have in order to be fillable
// Orders with specified senderAddress and with a salt less than their epoch are considered cancelled
/// @dev Mapping of makerAddress => senderAddress => lowest salt an order can have in order to be fillable
/// Orders with specified senderAddress and with a salt less than their epoch are considered cancelled
/// @param 0 Address of the order's maker.
/// @param 1 Address of the order's sender.
/// @return 0 Minimum valid order epoch.
mapping (address => mapping (address => uint256)) public orderEpoch;
/// @dev Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch
@@ -94,7 +101,7 @@ contract MixinExchangeCore is
/// @param order Order struct containing order specifications.
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
/// @param signature Proof that order has been created by maker.
/// @return Amounts filled and fees paid by maker and taker.
/// @return fillResults Amounts filled and fees paid by maker and taker.
function fillOrder(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
@@ -125,7 +132,7 @@ contract MixinExchangeCore is
/// @dev Gets information about an order: status, hash, and amount filled.
/// @param order Order to gather information on.
/// @return OrderInfo Information about the order and its state.
/// @return orderInfo Information about the order and its state.
/// See LibOrder.OrderInfo for a complete description.
function getOrderInfo(LibOrder.Order memory order)
public
@@ -140,7 +147,7 @@ contract MixinExchangeCore is
// edge cases in the supporting infrastructure because they have
// an 'infinite' price when computed by a simple division.
if (order.makerAssetAmount == 0) {
orderInfo.orderStatus = uint8(LibOrder.OrderStatus.INVALID_MAKER_ASSET_AMOUNT);
orderInfo.orderStatus = LibOrder.OrderStatus.INVALID_MAKER_ASSET_AMOUNT;
return orderInfo;
}
@@ -149,35 +156,35 @@ contract MixinExchangeCore is
// Instead of distinguishing between unfilled and filled zero taker
// amount orders, we choose not to support them.
if (order.takerAssetAmount == 0) {
orderInfo.orderStatus = uint8(LibOrder.OrderStatus.INVALID_TAKER_ASSET_AMOUNT);
orderInfo.orderStatus = LibOrder.OrderStatus.INVALID_TAKER_ASSET_AMOUNT;
return orderInfo;
}
// Validate order availability
if (orderInfo.orderTakerAssetFilledAmount >= order.takerAssetAmount) {
orderInfo.orderStatus = uint8(LibOrder.OrderStatus.FULLY_FILLED);
orderInfo.orderStatus = LibOrder.OrderStatus.FULLY_FILLED;
return orderInfo;
}
// Validate order expiration
// solhint-disable-next-line not-rely-on-time
if (block.timestamp >= order.expirationTimeSeconds) {
orderInfo.orderStatus = uint8(LibOrder.OrderStatus.EXPIRED);
orderInfo.orderStatus = LibOrder.OrderStatus.EXPIRED;
return orderInfo;
}
// Check if order has been cancelled
if (cancelled[orderInfo.orderHash]) {
orderInfo.orderStatus = uint8(LibOrder.OrderStatus.CANCELLED);
orderInfo.orderStatus = LibOrder.OrderStatus.CANCELLED;
return orderInfo;
}
if (orderEpoch[order.makerAddress][order.senderAddress] > order.salt) {
orderInfo.orderStatus = uint8(LibOrder.OrderStatus.CANCELLED);
orderInfo.orderStatus = LibOrder.OrderStatus.CANCELLED;
return orderInfo;
}
// All other statuses are ruled out: order is Fillable
orderInfo.orderStatus = uint8(LibOrder.OrderStatus.FILLABLE);
orderInfo.orderStatus = LibOrder.OrderStatus.FILLABLE;
return orderInfo;
}
@@ -185,7 +192,7 @@ contract MixinExchangeCore is
/// @param order Order struct containing order specifications.
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
/// @param signature Proof that order has been created by maker.
/// @return Amounts filled and fees paid by maker and taker.
/// @return fillResults Amounts filled and fees paid by maker and taker.
function _fillOrder(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
@@ -255,7 +262,7 @@ contract MixinExchangeCore is
_assertValidCancel(order, orderInfo);
// Noop if order is already unfillable
if (orderInfo.orderStatus != uint8(LibOrder.OrderStatus.FILLABLE)) {
if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) {
return;
}
@@ -337,7 +344,7 @@ contract MixinExchangeCore is
view
{
// An order can only be filled if its status is FILLABLE.
if (orderInfo.orderStatus != uint8(LibOrder.OrderStatus.FILLABLE)) {
if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) {
LibRichErrors.rrevert(LibExchangeRichErrors.OrderStatusError(
orderInfo.orderHash,
LibOrder.OrderStatus(orderInfo.orderStatus)

View File

@@ -29,10 +29,12 @@ contract MixinProtocolFees is
IProtocolFees,
Ownable
{
// The protocol fee multiplier -- the owner can update this field.
/// @dev The protocol fee multiplier -- the owner can update this field.
/// @return 0 Gas multplier.
uint256 public protocolFeeMultiplier;
// The address of the registered protocolFeeCollector contract -- the owner can update this field.
/// @dev The address of the registered protocolFeeCollector contract -- the owner can update this field.
/// @return 0 Contract to forward protocol fees to.
address public protocolFeeCollector;
/// @dev Allows the owner to update the protocol fee multiplier.

View File

@@ -47,10 +47,16 @@ contract MixinSignatureValidator is
// bytes4(keccak256("isValidWalletSignature(bytes32,address,bytes)"))
bytes4 private constant LEGACY_WALLET_MAGIC_VALUE = 0xb0671381;
// Mapping of hash => signer => signed
/// @dev Mapping of hash => signer => signed
/// @param 0 Order hash.
/// @param 1 Signer address.
/// @return 0 Whether the hash is presigned.
mapping (bytes32 => mapping (address => bool)) public preSigned;
// Mapping of signer => validator => approved
/// @dev Mapping of signer => validator => approved
/// @param 0 Signer address.
/// @param 1 Signature validator address.
/// @return 0 Whether the validator is allowed to validate on behalf of the signer.
mapping (address => mapping (address => bool)) public allowedValidators;
/// @dev Approves a hash on-chain.

View File

@@ -36,11 +36,14 @@ contract MixinTransactions is
{
using LibZeroExTransaction for LibZeroExTransaction.ZeroExTransaction;
// Mapping of transaction hash => executed
// This prevents transactions from being executed more than once.
/// @dev Mapping of transaction hash => executed
/// This prevents transactions from being executed more than once.
/// @param 0 The transaction hash.
/// @return 0 Whether the transation was executed.
mapping (bytes32 => bool) public transactionsExecuted;
// Address of current transaction signer
/// @dev Address of current transaction signer.
/// @return 0 The address associated with the the current transaction.
address public currentContextAddress;
/// @dev Executes an Exchange method call in the context of signer.
@@ -62,7 +65,7 @@ contract MixinTransactions is
/// @dev Executes a batch of Exchange method calls in the context of signer(s).
/// @param transactions Array of 0x transaction structures.
/// @param signatures Array of proofs that transactions have been signed by signer(s).
/// @return Array containing ABI encoded return data for each of the underlying Exchange function calls.
/// @return returnData Array containing ABI encoded return data for each of the underlying Exchange function calls.
function batchExecuteTransactions(
LibZeroExTransaction.ZeroExTransaction[] memory transactions,
bytes[] memory signatures
@@ -70,10 +73,10 @@ contract MixinTransactions is
public
payable
disableRefundUntilEnd
returns (bytes[] memory)
returns (bytes[] memory returnData)
{
uint256 length = transactions.length;
bytes[] memory returnData = new bytes[](length);
returnData = new bytes[](length);
for (uint256 i = 0; i != length; i++) {
returnData[i] = _executeTransaction(transactions[i], signatures[i]);
}
@@ -117,7 +120,7 @@ contract MixinTransactions is
_setCurrentContextAddressIfRequired(signerAddress, address(0));
emit TransactionExecution(transactionHash);
return returnData;
}

View File

@@ -36,10 +36,11 @@ contract MixinWrapperFunctions is
{
using LibSafeMath for uint256;
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
/// @dev Fills the input order. Reverts if exact `takerAssetFillAmount` not filled.
/// @param order Order struct containing order specifications.
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
/// @param signature Proof that order has been created by maker.
/// @return fillResults Amounts filled and fees paid.
function fillOrKillOrder(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
@@ -62,7 +63,7 @@ contract MixinWrapperFunctions is
/// @param orders Array of order specifications.
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
/// @param signatures Proofs that orders have been created by makers.
/// @return Array of amounts filled and fees paid by makers and taker.
/// @return fillResults Array of amounts filled and fees paid by makers and taker.
function batchFillOrders(
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
@@ -89,7 +90,7 @@ contract MixinWrapperFunctions is
/// @param orders Array of order specifications.
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
/// @param signatures Proofs that orders have been created by makers.
/// @return Array of amounts filled and fees paid by makers and taker.
/// @return fillResults Array of amounts filled and fees paid by makers and taker.
function batchFillOrKillOrders(
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
@@ -116,7 +117,7 @@ contract MixinWrapperFunctions is
/// @param orders Array of order specifications.
/// @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell in orders.
/// @param signatures Proofs that orders have been created by makers.
/// @return Array of amounts filled and fees paid by makers and taker.
/// @return fillResults Array of amounts filled and fees paid by makers and taker.
function batchFillOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
@@ -145,7 +146,7 @@ contract MixinWrapperFunctions is
/// @param orders Array of order specifications.
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
/// @return fillResults Amounts filled and fees paid by makers and taker.
function marketSellOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256 takerAssetFillAmount,
@@ -186,7 +187,7 @@ contract MixinWrapperFunctions is
/// @param orders Array of order specifications.
/// @param makerAssetFillAmount Desired amount of makerAsset to buy.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
/// @return fillResults Amounts filled and fees paid by makers and taker.
function marketBuyOrdersNoThrow(
LibOrder.Order[] memory orders,
uint256 makerAssetFillAmount,
@@ -234,7 +235,7 @@ contract MixinWrapperFunctions is
/// @param orders Array of order specifications.
/// @param takerAssetFillAmount Minimum amount of takerAsset to sell.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
/// @return fillResults Amounts filled and fees paid by makers and taker.
function marketSellOrdersFillOrKill(
LibOrder.Order[] memory orders,
uint256 takerAssetFillAmount,
@@ -259,7 +260,7 @@ contract MixinWrapperFunctions is
/// @param orders Array of order specifications.
/// @param makerAssetFillAmount Minimum amount of makerAsset to buy.
/// @param signatures Proofs that orders have been signed by makers.
/// @return Amounts filled and fees paid by makers and taker.
/// @return fillResults Amounts filled and fees paid by makers and taker.
function marketBuyOrdersFillOrKill(
LibOrder.Order[] memory orders,
uint256 makerAssetFillAmount,
@@ -295,7 +296,7 @@ contract MixinWrapperFunctions is
/// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled.
/// @param order Order struct containing order specifications.
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
/// @param signature Proof that order has been created by maker.
/// @param fillResults ignature Proof that order has been created by maker.
function _fillOrKillOrder(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,
@@ -324,7 +325,7 @@ contract MixinWrapperFunctions is
/// @param order Order struct containing order specifications.
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
/// @param signature Proof that order has been created by maker.
/// @return Amounts filled and fees paid by maker and taker.
/// @return fillResults Amounts filled and fees paid by maker and taker.
function _fillOrderNoThrow(
LibOrder.Order memory order,
uint256 takerAssetFillAmount,

View File

@@ -30,7 +30,7 @@ import "../src/Exchange.sol";
contract TestWrapperFunctions is
Exchange
{
uint8 internal constant MAX_ORDER_STATUS = uint8(LibOrder.OrderStatus.CANCELLED);
LibOrder.OrderStatus internal constant MAX_ORDER_STATUS = LibOrder.OrderStatus.CANCELLED;
uint256 internal constant ALWAYS_FAILING_SALT = uint256(-1);
string internal constant ALWAYS_FAILING_SALT_REVERT_REASON = "ALWAYS_FAILING_SALT";
@@ -61,7 +61,7 @@ contract TestWrapperFunctions is
// Lower uint128 of `order.salt` is the `orderTakerAssetFilledAmount`.
orderInfo.orderTakerAssetFilledAmount = uint128(order.salt);
// High byte of `order.salt` is the `orderStatus`.
orderInfo.orderStatus = uint8(order.salt >> 248) % (MAX_ORDER_STATUS + 1);
orderInfo.orderStatus = LibOrder.OrderStatus(uint8(order.salt >> 248) % (uint8(MAX_ORDER_STATUS) + 1));
orderInfo.orderHash = order.getTypedDataHash(EIP712_EXCHANGE_DOMAIN_HASH);
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-exchange",
"version": "3.0.0",
"version": "3.0.3",
"engines": {
"node": ">=6.12"
},
@@ -52,21 +52,21 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.0",
"@0x/contracts-asset-proxy": "^3.0.0",
"@0x/contracts-exchange-libs": "^4.0.0",
"@0x/contracts-gen": "^2.0.0",
"@0x/contracts-multisig": "^4.0.0",
"@0x/contracts-staking": "^2.0.0",
"@0x/contracts-test-utils": "^4.0.0",
"@0x/contracts-utils": "^4.0.0",
"@0x/dev-utils": "^3.0.0",
"@0x/sol-compiler": "^4.0.0",
"@0x/abi-gen": "^5.0.3",
"@0x/contracts-asset-proxy": "^3.1.0",
"@0x/contracts-exchange-libs": "^4.0.3",
"@0x/contracts-gen": "^2.0.3",
"@0x/contracts-multisig": "^4.0.3",
"@0x/contracts-staking": "^2.0.3",
"@0x/contracts-test-utils": "^5.1.0",
"@0x/contracts-utils": "^4.0.3",
"@0x/dev-utils": "^3.1.0",
"@0x/sol-compiler": "^4.0.3",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.0.0",
"@0x/typescript-typings": "^5.0.0",
"@0x/web3-wrapper": "^7.0.0",
"@0x/types": "^3.1.1",
"@0x/typescript-typings": "^5.0.1",
"@0x/web3-wrapper": "^7.0.3",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -88,13 +88,13 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.0",
"@0x/contracts-dev-utils": "^1.0.0",
"@0x/contracts-erc1155": "^2.0.0",
"@0x/contracts-erc20": "^3.0.0",
"@0x/contracts-erc721": "^3.0.0",
"@0x/order-utils": "^9.0.0",
"@0x/utils": "^5.0.0",
"@0x/base-contract": "^6.0.3",
"@0x/contracts-dev-utils": "^1.0.3",
"@0x/contracts-erc1155": "^2.0.3",
"@0x/contracts-erc20": "^3.0.3",
"@0x/contracts-erc721": "^3.0.3",
"@0x/order-utils": "^10.1.0",
"@0x/utils": "^5.1.2",
"lodash": "^4.17.11"
},
"publishConfig": {

View File

@@ -1,8 +1,8 @@
import { ReferenceFunctions as LibReferenceFunctions } from '@0x/contracts-exchange-libs';
import { blockchainTests, constants, expect, hexRandom, orderHashUtils } from '@0x/contracts-test-utils';
import { blockchainTests, constants, expect, orderHashUtils } from '@0x/contracts-test-utils';
import { SafeMathRevertErrors } from '@0x/contracts-utils';
import { Order } from '@0x/types';
import { BigNumber, ExchangeRevertErrors } from '@0x/utils';
import { BigNumber, ExchangeRevertErrors, hexUtils } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { LogWithDecodedArgs } from 'ethereum-types';
import * as _ from 'lodash';
@@ -16,9 +16,9 @@ import {
blockchainTests('Exchange core internal functions', env => {
const CHAIN_ID = 1337;
const ONE_ETHER = constants.ONE_ETHER;
const randomAddress = () => hexRandom(constants.ADDRESS_LENGTH);
const randomHash = () => hexRandom(constants.WORD_LENGTH);
const randomAssetData = () => hexRandom(36);
const randomAddress = () => hexUtils.random(constants.ADDRESS_LENGTH);
const randomHash = () => hexUtils.random(constants.WORD_LENGTH);
const randomAssetData = () => hexUtils.random(36);
let testExchange: TestExchangeInternalsContract;
let senderAddress: string;
const DEFAULT_PROTOCOL_MULTIPLIER = new BigNumber(150000);

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