Compare commits

...

438 Commits

Author SHA1 Message Date
Jacob Evans
7742901e5c Publish
- @0x/contracts-asset-proxy@3.2.4
 - @0x/contracts-broker@1.1.3
 - @0x/contracts-coordinator@3.1.4
 - @0x/contracts-dev-utils@1.3.2
 - @0x/contracts-erc1155@2.1.4
 - @0x/contracts-erc20-bridge-sampler@1.5.0
 - @0x/contracts-erc20@3.1.4
 - @0x/contracts-erc721@3.1.4
 - @0x/contracts-exchange-forwarder@4.2.4
 - @0x/contracts-exchange-libs@4.3.4
 - @0x/contracts-exchange@3.2.4
 - @0x/contracts-extensions@6.1.4
 - @0x/contracts-integrations@2.5.0
 - @0x/contracts-multisig@4.1.4
 - @0x/contracts-staking@2.0.11
 - @0x/contracts-test-utils@5.3.1
 - @0x/contracts-utils@4.4.2
 - 0x.js@9.1.4
 - @0x/asset-swapper@4.3.2
 - @0x/contract-addresses@4.8.0
 - @0x/contract-wrappers-test@12.2.12
 - @0x/contract-wrappers@13.6.2
 - @0x/instant@1.0.49
 - @0x/migrations@6.2.3
 - @0x/order-utils@10.2.3
 - @0x/orderbook@2.2.4
2020-02-28 08:13:33 +11:00
Jacob Evans
de68cb25d0 Updated CHANGELOGS & MD docs 2020-02-28 08:13:09 +11:00
Daniel Pyrathon
68fb6c2c27 Merge pull request #2499 from 0xProject/feature/erc20-bridge-sampler/liquidity-provider-registry
`@0x/contracts-erc20-bridge-sampler`: LiquidityProviderRegistry
2020-02-27 12:37:10 -08:00
Michael Zhu
a47c031ad1 Catch reverts when calling registry 2020-02-27 11:23:25 -08:00
Michael Zhu
817049456c Get liquidity provider from registry in the sampler 2020-02-27 11:05:56 -08:00
Lawrence Forman
e1a061789f Merge pull request #2500 from 0xProject/fix/asset-swapper/native-order-prune
[asset-swapper] Fix native fill prune
2020-02-27 13:38:49 -05:00
Jacob Evans
28573ba772 [asset-swapper] Fix native fill prune 2020-02-27 16:42:20 +11:00
David Sun
880b9413f6 Merge pull request #2492 from 0xProject/fix/instant/constant-polling
[Fix] Instant call destroyAsync on unmount
2020-02-26 19:36:48 -05:00
mzhu25
9a7c4b21a9 @0x/contracts-erc20-bridge-sampler: Generic liquidity provider sampling (#2487)
* Add methods to Sampler contract to plug into generic on-chain liquidity provider
2020-02-26 11:54:48 -08:00
mzhu25
ac56038eca Add Broker, GodsUnchainedValidator, ChainlinkStopLimit to ContractAddresses interface (#2498) 2020-02-26 11:54:32 -08:00
Lawrence Forman
4dd2fb6903 Merge pull request #2478 from 0xProject/feat/contracts/integrations/chai-bridge-benchmarks
`@0x/contracts-integrations`: Add `ChaiBridge` and `DydxBridge` gas b…
2020-02-26 14:17:15 -05:00
Lawrence Forman
0baec61f06 @0x/contracts/integrations: Update wallets and add comments with last run gas costs to benchmarks. 2020-02-26 12:57:03 -05:00
Lawrence Forman
d4751788d1 @0x/contracts-integrations: Add ChaiBridge and DydxBridge gas benchmark tests. 2020-02-26 11:29:44 -05:00
Lawrence Forman
ae68c061d1 @0x/asset-proxy: Add more functions to IDydx.
`@0x/dev-utils`: Fix all the weird dydx base unit madness.
2020-02-26 11:29:26 -05:00
Lawrence Forman
b0387245f0 @0x/contracts-utils: Roll back additions to LibFractions.
`@0x/contracts-dev-utils`: Add `D18` library for working with base-10, 18-digit decimals.
`@0x/contracts-dev-utils`: Use `D18` library instead of `LibFractions` in `LibDydxBalance`.
2020-02-26 11:29:16 -05:00
Lawrence Forman
c2d06a4a23 Cherry pick dydx validation from #2456 2020-02-26 11:29:02 -05:00
Lawrence Forman
270108abb7 Cherry pick DevUtils refactor code from #2456 2020-02-26 11:26:57 -05:00
Lawrence Forman
e76c33232d Cherry-pick changes from feat/dev-utils/dydx-bridge-validation 2020-02-26 11:26:57 -05:00
Jacob Evans
58ff2dc492 Publish
- @0x/contracts-asset-proxy@3.2.3
 - @0x/contracts-broker@1.1.2
 - @0x/contracts-coordinator@3.1.3
 - @0x/contracts-dev-utils@1.3.1
 - @0x/contracts-erc1155@2.1.3
 - @0x/contracts-erc20-bridge-sampler@1.4.2
 - @0x/contracts-erc20@3.1.3
 - @0x/contracts-erc721@3.1.3
 - @0x/contracts-exchange-forwarder@4.2.3
 - @0x/contracts-exchange-libs@4.3.3
 - @0x/contracts-exchange@3.2.3
 - @0x/contracts-extensions@6.1.3
 - @0x/contracts-integrations@2.4.2
 - @0x/contracts-multisig@4.1.3
 - @0x/contracts-staking@2.0.10
 - @0x/contracts-utils@4.4.1
 - 0x.js@9.1.3
 - @0x/abi-gen@5.2.2
 - @0x/asset-swapper@4.3.1
 - @0x/contract-wrappers-test@12.2.11
 - @0x/instant@1.0.48
 - @0x/migrations@6.2.2
 - @0x/orderbook@2.2.3
 - @0x/sol-doc@3.1.6
2020-02-26 11:34:29 +11:00
Jacob Evans
13c45a0e96 Updated CHANGELOGS & MD docs 2020-02-26 11:34:00 +11:00
Jacob Evans
be7b1a1bd4 Include bin in npm publish (#2496)
* Include bin in npm publish

* Include bin in files

* Update CHANGELOG

* Changelog
2020-02-26 10:12:52 +11:00
Amir Bandeali
132a3c6705 Merge pull request #2495 from 0xProject/feat/defaults-should-save-standard-input
Update boilerplate
2020-02-25 10:56:26 -08:00
Amir
5e73257557 Set shouldSaveStandardInput to true in all compiler.json files 2020-02-25 10:04:19 -08:00
Amir
e83346fbbb Do not prettify Solidity 2020-02-25 10:04:19 -08:00
Jacob Evans
2dd47a2103 Publish
- @0x/contracts-asset-proxy@3.2.2
 - @0x/contracts-broker@1.1.1
 - @0x/contracts-coordinator@3.1.2
 - @0x/contracts-dev-utils@1.3.0
 - @0x/contracts-erc1155@2.1.2
 - @0x/contracts-erc20-bridge-sampler@1.4.1
 - @0x/contracts-erc20@3.1.2
 - @0x/contracts-erc721@3.1.2
 - @0x/contracts-exchange-forwarder@4.2.2
 - @0x/contracts-exchange-libs@4.3.2
 - @0x/contracts-exchange@3.2.2
 - @0x/contracts-extensions@6.1.2
 - @0x/contracts-integrations@2.4.1
 - @0x/contracts-multisig@4.1.2
 - @0x/contracts-staking@2.0.9
 - @0x/contracts-test-utils@5.3.0
 - @0x/contracts-utils@4.4.0
 - 0x.js@9.1.2
 - @0x/abi-gen@5.2.1
 - @0x/assert@3.0.7
 - @0x/asset-swapper@4.3.0
 - @0x/base-contract@6.2.1
 - @0x/connect@6.0.7
 - @0x/contract-addresses@4.7.0
 - @0x/contract-artifacts@3.6.1
 - @0x/contract-wrappers-test@12.2.10
 - @0x/contract-wrappers@13.6.1
 - @0x/contracts-gen@2.0.8
 - @0x/dev-utils@3.2.1
 - @0x/instant@1.0.47
 - @0x/json-schemas@5.0.7
 - @0x/migrations@6.2.1
 - @0x/monorepo-scripts@1.0.51
 - @0x/order-utils@10.2.2
 - @0x/orderbook@2.2.2
 - @0x/sol-compiler@4.0.8
 - @0x/sol-coverage@4.0.8
 - @0x/sol-doc@3.1.5
 - @0x/sol-profiler@4.0.8
 - @0x/sol-trace@3.0.8
 - @0x/sol-tracing-utils@7.0.8
 - @0x/sra-spec@3.0.7
 - @0x/subproviders@6.0.8
 - @0x/utils@5.4.1
 - @0x/web3-wrapper@7.0.7
2020-02-25 20:43:55 +11:00
Jacob Evans
f31e530b6e Updated CHANGELOGS & MD docs 2020-02-25 20:43:31 +11:00
Jacob Evans
eb50f3fa9c Xlab/fix/extra space (#2494)
* Fix extra space in `provider.send` signature from fabio. Fixes #2285.

* Fix style and update changelog.

Co-authored-by: Maxim <max@kc.vc>
2020-02-25 19:56:33 +11:00
Lawrence Forman
8417fe4fdb Merge pull request #2493 from 0xProject/feat/redeploy-devutils
Redeploy DevUtils
2020-02-25 00:40:58 -05:00
Lawrence Forman
0f1c15a6ca Asset-Swapper: Incorporate fees into fill path optimization (#2481)
* `@0x/asset-swapper`: Incorporate fees into fill optimization.

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

* `@0x/asset-swapper`: Rebase and update tests for curve.

* `@0x/asset-swapper`: Bring back a form of native order pruning.
`@0x/asset-swapper`: Bring back dust thresholds.
`@0x/asset-swapper`: Avoid calling `getMedianSellRate()` if output token is ETH.

* Update devdoc for `fees` option

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2020-02-25 14:47:33 +11:00
Lawrence Forman
9345c4fb7f @0x/contract-addresses: Update DevUtils addresses. 2020-02-24 12:47:33 -05:00
Lawrence Forman
5e0758917b @0x/contracts-utils: Update DevUtils address in DeploymentConstants. 2020-02-24 12:42:01 -05:00
David Sun
f56839ec6b call destroyAsync on unmount 2020-02-24 12:24:07 -05:00
Lawrence Forman
cbb23a42e2 Merge pull request #2466 from 0xProject/feat/contracts/dev-utils/dydx-validation
DevUtils: DydxBridge validation
2020-02-20 13:36:22 -07:00
Kim Persson
5a59c286d0 Merge pull request #2488 from 0xProject/kim/fix-readme-spelling
FIXES spelling in exchange readme
2020-02-20 17:27:32 +01:00
Kim Persson
2e8c600d7a FIXES spelling in exchange readme 2020-02-20 14:45:53 +01:00
Lawrence Forman
e851cb1cbc @0x/contracts-dev-utils: Move D18 out to @0x/contracts-utils. 2020-02-19 16:19:38 -05:00
Lawrence Forman
3da03da32a @0x/contracts-utils: Add D18 library. 2020-02-19 16:19:09 -05:00
Lawrence Forman
3ec8924e7f @0x/contracts-dev-utils: Rebase. 2020-02-19 16:02:35 -05:00
Lawrence Forman
a04722b612 @0x/contracts-integrations: Add USDC->DAI forked dydx bridge order validation. 2020-02-19 15:51:05 -05:00
Lawrence Forman
f9a7857a90 @0x/contracts-dev-utils: Address review comments. 2020-02-19 15:51:05 -05:00
Lawrence Forman
58f772c74e foo 2020-02-19 15:51:05 -05:00
Lawrence Forman
a425c7e260 Regenerate artifacts and wrappers 2020-02-19 15:50:10 -05:00
Lawrence Forman
809885afd0 @0x/contracts-asset-proxy: Add getMarketMarginPremium() to IDydx.
`@0x/contracts-dev-utils`: Handle dydx market premiums.
2020-02-19 15:49:41 -05:00
Lawrence Forman
bf9b4b993f @0x/contracts-test-utils: Fix blockchainTests fork config to work with other tests. 2020-02-19 15:49:41 -05:00
Lawrence Forman
d94a26f0f4 @0x/contracts-integrations: Add DydxBridge validation integration tests. 2020-02-19 15:49:41 -05:00
Lawrence Forman
bd9c9cedca @0x/contracts-test-utils: Add blockchainTests.config 2020-02-19 15:45:27 -05:00
Lawrence Forman
651e94bd94 @0x/asset-proxy: Add more functions to IDydx.
`@0x/dev-utils`: Fix all the weird dydx base unit madness.
2020-02-19 15:45:27 -05:00
Lawrence Forman
162b6f1a74 @0x/dev-utils: Fix dydx min CR not being +1.
`@0x/dev-utils`: Fix withdraw rate vs order conversion rate check .
2020-02-19 15:45:27 -05:00
Lawrence Forman
865a253eb5 @0x/contracts-utils: Roll back additions to LibFractions.
`@0x/contracts-dev-utils`: Add `D18` library for working with base-10, 18-digit decimals.
`@0x/contracts-dev-utils`: Use `D18` library instead of `LibFractions` in `LibDydxBalance`.
2020-02-19 15:45:27 -05:00
Lawrence Forman
9b3781abf1 Cherry pick dydx validation from #2456 2020-02-19 15:45:27 -05:00
Lawrence Forman
d89243a0d3 Cherry pick DevUtils refactor code from #2456 2020-02-19 15:44:59 -05:00
Lawrence Forman
b4cefc64b4 Cherry pick library linking code from #2456 2020-02-19 15:44:59 -05:00
Lawrence Forman
2fd26587e5 Cherry-pick changes from feat/dev-utils/dydx-bridge-validation 2020-02-19 15:44:59 -05:00
David Sun
282a351859 Merge pull request #2404 from 0xProject/feature/instant/fortmatic-integration
Formatic integration into instant
2020-02-18 13:58:10 -06:00
David Sun
a84b848ea9 prettier 2020-02-18 14:20:30 -05:00
David Sun
d329320fc2 linted 2020-02-18 14:02:48 -05:00
David Sun
bc096554b5 fixed webpack issues 2020-02-18 13:58:22 -05:00
David Sun
5902d878d8 fixed affiliate + fortmatic 2020-02-18 12:13:38 -05:00
Jacob Evans
4a133ca36f Publish
- @0x/contracts-asset-proxy@3.2.1
 - @0x/contracts-broker@1.1.0
 - @0x/contracts-coordinator@3.1.1
 - @0x/contracts-dev-utils@1.1.1
 - @0x/contracts-erc1155@2.1.1
 - @0x/contracts-erc20-bridge-sampler@1.4.0
 - @0x/contracts-erc20@3.1.1
 - @0x/contracts-erc721@3.1.1
 - @0x/contracts-exchange-forwarder@4.2.1
 - @0x/contracts-exchange-libs@4.3.1
 - @0x/contracts-exchange@3.2.1
 - @0x/contracts-extensions@6.1.1
 - @0x/contracts-integrations@2.4.0
 - @0x/contracts-multisig@4.1.1
 - @0x/contracts-staking@2.0.8
 - @0x/contracts-test-utils@5.1.5
 - @0x/contracts-utils@4.3.1
 - 0x.js@9.1.1
 - @0x/asset-swapper@4.2.0
 - @0x/contract-addresses@4.6.0
 - @0x/contract-artifacts@3.6.0
 - @0x/contract-wrappers-test@12.2.9
 - @0x/contract-wrappers@13.6.0
 - @0x/instant@1.0.46
 - @0x/migrations@6.2.0
 - @0x/order-utils@10.2.1
 - @0x/orderbook@2.2.1
2020-02-15 17:39:09 +11:00
Jacob Evans
f7252f919a Updated CHANGELOGS & MD docs 2020-02-15 17:38:47 +11:00
Jacob Evans
e05a03a842 Curve ERC20Bridge (#2480)
* Curve ERC20Bridge

* ERC20BridgeSampler Curve (#2483)

* ERC20Sampler Curve

* Use Bridge Sources for each Curve

* Support multiple versions of the Curve contract

* CHANGELOG and redeployed Curve (mainnet)

* Fix Market ops utils test

* Added Curve DAI USDC USDT TUSD

* Bump sampler gas limit default

* Decode the Curve in tests

* Disable Curve in Buy tests

* blockchainTests.fork.resets Curve and Sampler
2020-02-15 17:02:19 +11:00
mzhu25
dcce8276b8 Add decoders for broker and stop-limit data (#2484)
* Add decoders for broker and stop-limit data

* update changelogs

* Address comments
2020-02-14 17:38:43 -08:00
Alex Towle
fd47947e55 Merge pull request #2454 from 0xProject/fix/dev-utils/and-another-one
Another one...
2020-02-13 20:45:34 -08:00
Alex Towle
ae151df2eb Addressed amir's review feedback 2020-02-13 18:07:45 -08:00
Alex Towle
79de188683 Updated addresses again 2020-02-13 17:37:03 -08:00
Alex Towle
6e5c788e13 Added a test that fails for the old DevUtils 2020-02-13 17:37:03 -08:00
Alex Towle
f53606007d Updated DevUtils again 2020-02-13 17:37:03 -08:00
Greg Hysz
a4ac418bc9 Merge pull request #2479 from 0xProject/test/dydx-mainnet-tests/updateDeployment
Fixed dYdX Bridge Tests
2020-02-13 14:42:47 -08:00
Greg Hysen
a8c09d0bdb Updated contracts-integrations changelog. 2020-02-13 13:21:07 -08:00
Greg Hysen
871105a48a Fixed dYdX Bridge Tests 2020-02-13 13:19:26 -08:00
Fabio B
3b61129ade Update link to docs for web3-wrapper 2020-02-12 22:08:10 +01:00
mzhu25
f471c79b59 Chainlink stop-limit orders (#2473)
* Contracts for Chainlink stop-limit orders

* Tests and asset data utils

* Update contracts-integrations changelog

* Address comments

* Remove priceFreshness parameter

* Remove LibSafeMath

* fix typo

* Add ChainlinkStopLimit addresses to @0x/contract-addresses
2020-02-11 15:10:06 -08:00
Lawrence Forman
dfd9443f74 Merge pull request #2477 from 0xProject/feat/batched-sampler
ERC20BridgeSampler: batchCall()
2020-02-11 14:32:48 -07:00
Lawrence Forman
a36ff9e365 `@0x/asset-swapper: Address review comments. 2020-02-11 12:08:15 -07:00
Lawrence Forman
12e65bbf26 @0x/contracts-erc20-bridge-sampler: Fix failing tests. 2020-02-11 12:08:15 -07:00
Lawrence Forman
ab9841e60b @0x/contract-addresses: Update ERC20BridgeSampler addresses on mainnet and kovan. 2020-02-11 12:08:15 -07:00
Lawrence Forman
7a52f12e57 Rebase and update contract artifacts + wrappers. 2020-02-11 12:07:48 -07:00
Lawrence Forman
11fd4506ac @0x/asset-swapper: Fix failing asset-swapper test. 2020-02-11 12:07:48 -07:00
Lawrence Forman
0c9c68030e @0x/asset-swapper: Use batchCall() version of the ERC20BridgeSampler contract 2020-02-11 12:07:48 -07:00
Lawrence Forman
55d6eddbb2 @0x/contract-artifacts: Update IERC20BridgeSampler wrapper. 2020-02-11 12:07:48 -07:00
Lawrence Forman
8341e60edb @0x/contract-artifacts: Update ERC20BridgeSampler artifact. 2020-02-11 12:07:48 -07:00
Lawrence Forman
6273a1ca73 @0x/contracts-erc20-bridge-sampler: Remove wrapper functions and introduce batchCall(). 2020-02-11 12:07:48 -07:00
mzhu25
1b83ebdf89 Merge pull request #2469 from 0xProject/feature/broker/deployments
Broker-related updates to contract-artifacts, contract-wrappers, contract-addresses
2020-02-10 18:41:24 -08:00
Michael Zhu
fef7f0506f rebase 🙄 2020-02-10 17:38:16 -08:00
Michael Zhu
f44eb4e383 Update changelogs for Forwarder changes 2020-02-10 17:11:01 -08:00
Michael Zhu
05df485c4a Update Forwarder in contract-artifacts and contract-wrappers 2020-02-10 17:11:00 -08:00
Michael Zhu
44857c526b Remove DutchAuction and OrderValidator from python contract addresses 2020-02-10 17:10:36 -08:00
Michael Zhu
b8ad5d5d32 Update Forwarder addresses 2020-02-10 17:10:36 -08:00
Michael Zhu
e3e0d00e21 Add Broker and GodsUnchainedValidator to contract-wrappers 2020-02-10 17:10:14 -08:00
Michael Zhu
a9b1ea9690 Add Broker and GodsUnchainedValidator to contract-addresses 2020-02-10 17:09:34 -08:00
Michael Zhu
8e5dd0f8d9 Add Broker and GodsUnchainedValidator to contract-artifacts 2020-02-10 17:08:24 -08:00
David Sun
3b0c8f6d92 fortmatic patches 2020-02-09 21:08:46 -05:00
David Sun
21058c2227 changes to fetch account state behavior 2020-02-09 21:08:46 -05:00
David Sun
f3b8ae0781 fix for fortmatic 2020-02-09 21:08:46 -05:00
David Sun
d590b004c1 incomplete, fixes for heartbeater 2020-02-09 21:08:46 -05:00
David Sun
02e21141c6 added minor polish + bug fixes 2020-02-09 21:08:46 -05:00
David Sun
f839a3087d add yarn.lock 2020-02-09 21:08:46 -05:00
David Sun
f458815541 fixing + testing fortmatic integration 2020-02-09 21:08:46 -05:00
apane
7ba754d2a4 Fixs styling 2020-02-09 21:08:46 -05:00
apane
09706e4ae2 Fix metamask logo size on connect and on install 2020-02-09 21:08:46 -05:00
apane
d18de4c541 Fixs styling
Removes unused imports
2020-02-09 21:08:46 -05:00
apane
001c7bfdbc Fixs order details only when a wallet is connected 2020-02-09 21:08:46 -05:00
apane
d4e04dc712 Fix chevron icon
Fixs metamask icon size
2020-02-09 21:08:46 -05:00
apane
8650cb5217 Disables order details if no payment method is selected 2020-02-09 21:08:46 -05:00
apane
0eaaddeb95 Removes unused colors
Adds white background
Adds phone.svg
2020-02-09 21:08:46 -05:00
apane
1cf8663f20 Adds phone svg
Updates design of payment methods
2020-02-09 21:08:46 -05:00
apane
5130259552 Remove icon on connect button 2020-02-09 21:08:46 -05:00
apane
ba5e19a015 Fix lint errors
Remove icon
2020-02-09 21:08:46 -05:00
apane
c0400fa986 Removes onUnlockFormatic, just uses onUnlockGenericWallet
Removes unlockWalletWithFormaticProvider, now just uses unlockWalletAndDispatchToStore with getProviderStateBasedOnProviderType
Adds getProviderStateBasedOnProviderType
Adds orderSource to providerState type
2020-02-09 21:08:46 -05:00
apane
51179d10ce Adds webpack config to use env var
Updates env example
Adds unlockWalletWithFormaticProvider on connect
2020-02-09 21:08:46 -05:00
apane
78752f9178 Adds connect to formatic button if the user does not have metamask installed 2020-02-09 21:08:46 -05:00
apane
762db417d7 Adds setProviderState action
unlockWalletAndDispatchToStore now changes the provider state based on the provider type
Adds button to connect with fortmatic
Adds FORTMATIC_API_KEY constant
2020-02-09 21:08:45 -05:00
apane
85bdccbc06 Adds Fortmatic to providerType
Uses fortmatic as default provider
2020-02-09 21:08:45 -05:00
apane
9f8cb99340 Removes prompt formatic
Fixs wallet prompt, adds marginTop props, splits border into border and borderColor
Adds fortmaticPrimary and fortmaticSecondary prop colors
2020-02-09 21:08:45 -05:00
apane
87b90bb04b Adds fortmatic button
Adds fortmatic colors
2020-02-09 21:08:45 -05:00
apane
e961d88277 Adds fortmatic dependency 2020-02-09 21:08:45 -05:00
Jacob Evans
5754c11e34 Publish
- @0x/contracts-asset-proxy@3.2.0
 - @0x/contracts-broker@1.0.2
 - @0x/contracts-coordinator@3.1.0
 - @0x/contracts-dev-utils@1.1.0
 - @0x/contracts-erc1155@2.1.0
 - @0x/contracts-erc20-bridge-sampler@1.3.0
 - @0x/contracts-erc20@3.1.0
 - @0x/contracts-erc721@3.1.0
 - @0x/contracts-exchange-forwarder@4.2.0
 - @0x/contracts-exchange-libs@4.3.0
 - @0x/contracts-exchange@3.2.0
 - @0x/contracts-extensions@6.1.0
 - @0x/contracts-integrations@2.3.0
 - @0x/contracts-multisig@4.1.0
 - @0x/contracts-staking@2.0.7
 - @0x/contracts-test-utils@5.1.4
 - @0x/contracts-utils@4.3.0
 - 0x.js@9.1.0
 - @0x/abi-gen@5.2.0
 - @0x/assert@3.0.6
 - @0x/asset-swapper@4.1.2
 - @0x/base-contract@6.2.0
 - @0x/connect@6.0.6
 - @0x/contract-addresses@4.5.0
 - @0x/contract-artifacts@3.5.0
 - @0x/contract-wrappers-test@12.2.8
 - @0x/contract-wrappers@13.5.0
 - @0x/contracts-gen@2.0.7
 - @0x/dev-utils@3.2.0
 - ethereum-types@3.1.0
 - @0x/instant@1.0.45
 - @0x/json-schemas@5.0.6
 - @0x/migrations@6.1.0
 - @0x/monorepo-scripts@1.0.50
 - @0x/order-utils@10.2.0
 - @0x/orderbook@2.2.0
 - @0x/sol-compiler@4.0.7
 - @0x/sol-coverage@4.0.7
 - @0x/sol-doc@3.1.4
 - @0x/sol-profiler@4.0.7
 - @0x/sol-resolver@3.0.3
 - @0x/sol-trace@3.0.7
 - @0x/sol-tracing-utils@7.0.7
 - @0x/sra-spec@3.0.6
 - @0x/subproviders@6.0.7
 - @0x/types@3.1.2
 - @0x/typescript-typings@5.0.2
 - @0x/utils@5.4.0
 - @0x/web3-wrapper@7.0.6
2020-02-09 09:37:34 +10:00
Jacob Evans
7bd88c1bb8 Updated CHANGELOGS & MD docs 2020-02-09 09:37:04 +10:00
Lawrence Forman
445b686c6c Merge pull request #2463 from 0xProject/feat/abi-gen/library-linking
Support contracts with unlinked libraries
2020-02-08 00:23:57 -05:00
Lawrence Forman
0cb7b75214 Merge pull request #2464 from 0xProject/feat/contracts/dev-utils/public-libraries-refactor
DevUtils refactor into public libraries
2020-02-07 23:53:16 -05:00
Lawrence Forman
a08399dfee regenerate artifacts and wrappers 2020-02-07 23:23:23 -05:00
Lawrence Forman
4016808fa4 Cherry pick DevUtils refactor code from #2456 2020-02-07 23:23:23 -05:00
Lawrence Forman
8635849977 Address review comments and regenerate contract-wrappers 2020-02-07 23:22:58 -05:00
Lawrence Forman
1a9ed4d4fe Add es2018.promises tsconfig lib target. 2020-02-07 23:22:58 -05:00
Lawrence Forman
e7b3246dd0 Cherry pick library linking code from #2456 2020-02-07 23:22:58 -05:00
Lawrence Forman
19589aec57 Cherry-pick changes from feat/dev-utils/dydx-bridge-validation 2020-02-07 23:22:58 -05:00
Lawrence Forman
4d33ff0417 Cherry-pick changes from feat/dev-utils/dydx-bridge-validation 2020-02-07 23:22:58 -05:00
Lawrence Forman
93a5ab5b33 Merge pull request #2462 from 0xProject/fix-and-feat/restore-contract-tests-and-refactors
Fix contracts tests + refactors
2020-02-07 23:16:50 -05:00
Lawrence Forman
59ada06cdf Fix linter errors. 2020-02-07 22:39:56 -05:00
Lawrence Forman
ae650849b0 Rebase and address review comments. 2020-02-07 22:29:32 -05:00
Lawrence Forman
3e8f9a6b53 Cherry-pick changes from feat/dev-utils/dydx-bridge-validation 2020-02-07 22:10:10 -05:00
Lawrence Forman
79362b0dba Merge pull request #2476 from 0xProject/fix/erc20-bridge-sampler/dev-utils-gas-stipend
ERC20BridgeSampler: Catch DevUtils reverts
2020-02-07 10:08:40 -05:00
Lawrence Forman
3e3df06d57 @0x/contracts-erc20-bridge-sampler: Fix catching invalid opcode from DevUtils
`@0x/contract-addresses`: Update `ERC20BridgeSampler` mainnet and kovan addresses.
2020-02-07 03:07:33 -05:00
Lawrence Forman
6b220eb1c5 Merge pull request #2474 from 0xProject/feat/eth2dai-bridge/market-migration
Update Eth2Dai address
2020-02-07 02:42:29 -05:00
Lawrence Forman
a1c61cae11 @0x/contract-addresses: Redeploy ERC20BridgeSampler 2020-02-07 02:10:19 -05:00
Jacob Evans
d48a917bf3 [erc20-bridge-sampler] gas stipend for DevUtils 2020-02-07 16:57:11 +10:00
Lawrence Forman
646b6dafb2 @0x/contract-addresses Redeploy Eth2DaiBridge and ERC20BridgeSampler. 2020-02-07 01:56:59 -05:00
Lawrence Forman
8d10f33a3f @0x/contracts-utils: Update Eth2Dai address. 2020-02-07 01:56:59 -05:00
Jacob Evans
5d603b2f80 Publish
- @0x/contracts-asset-proxy@3.1.3
 - @0x/contracts-broker@1.0.1
 - @0x/contracts-coordinator@3.0.6
 - @0x/contracts-dev-utils@1.0.6
 - @0x/contracts-erc1155@2.0.6
 - @0x/contracts-erc20-bridge-sampler@1.2.1
 - @0x/contracts-erc20@3.0.6
 - @0x/contracts-erc721@3.0.6
 - @0x/contracts-exchange-forwarder@4.1.0
 - @0x/contracts-exchange-libs@4.2.0
 - @0x/contracts-exchange@3.1.2
 - @0x/contracts-extensions@6.0.0
 - @0x/contracts-integrations@2.2.3
 - @0x/contracts-multisig@4.0.6
 - @0x/contracts-staking@2.0.6
 - @0x/contracts-test-utils@5.1.3
 - @0x/contracts-utils@4.2.1
 - 0x.js@9.0.7
 - @0x/abi-gen@5.1.2
 - @0x/assert@3.0.5
 - @0x/asset-swapper@4.1.1
 - @0x/base-contract@6.1.2
 - @0x/connect@6.0.5
 - @0x/contract-artifacts@3.4.1
 - @0x/contract-wrappers-test@12.2.7
 - @0x/contract-wrappers@13.4.2
 - @0x/contracts-gen@2.0.6
 - @0x/dev-utils@3.1.3
 - @0x/instant@1.0.44
 - @0x/json-schemas@5.0.5
 - @0x/migrations@6.0.2
 - @0x/monorepo-scripts@1.0.49
 - @0x/order-utils@10.1.3
 - @0x/orderbook@2.1.2
 - @0x/sol-compiler@4.0.6
 - @0x/sol-coverage@4.0.6
 - @0x/sol-doc@3.1.3
 - @0x/sol-profiler@4.0.6
 - @0x/sol-trace@3.0.6
 - @0x/sol-tracing-utils@7.0.6
 - @0x/sra-spec@3.0.5
 - @0x/subproviders@6.0.6
 - @0x/utils@5.3.0
 - @0x/web3-wrapper@7.0.5
2020-02-06 21:24:29 +10:00
Jacob Evans
0e1b08ff54 Updated CHANGELOGS & MD docs 2020-02-06 21:24:05 +10:00
David Sun
befc22d718 [FIX] asset-swapper liquidity breakdown (#2472)
* changed divided

* added changelog

* prettier

Co-authored-by: Jacob Evans <dekz@dekz.net>
2020-02-06 15:09:39 +10:00
Jacob Evans
4a62e80967 [asset-swapper] Bump sampler gas limit and allow for override (#2471)
* [asset-swapper] Bump sampler gas limit and allow for override

* Fix imports

* Set to 36e6
2020-02-06 12:31:28 +10:00
Jacob Evans
ee9ef9f2c1 [asset-swapper] prune before dummy order creation (#2470) 2020-02-06 07:08:31 +10:00
mzhu25
93dcb68437 Merge pull request #2455 from 0xProject/feature/broker/gods-unchained
`@0x/contracts-broker`: Property-based Gods Unchained orders
2020-02-04 10:53:54 -08:00
Michael Zhu
0691cc7909 rename _transferEthRefund -> _unwrapAndTransferEth 2020-02-04 10:13:07 -08:00
Michael Zhu
d82f34fe59 add weth-related integration tests 2020-02-04 10:13:07 -08:00
Michael Zhu
d2313b30af Address PR feedback and add support for affiliate fees 2020-02-04 10:13:07 -08:00
Michael Zhu
329719472a Move LibAssetDataTransfer and MixinWeth(Utils) to contracts-extensions 2020-02-04 10:13:02 -08:00
Michael Zhu
a2fcab47d4 skip coordinator client test 2020-02-04 10:08:25 -08:00
Michael Zhu
4ab5951c25 Add comments 2020-02-04 10:08:25 -08:00
Michael Zhu
403cabb201 more integrations tests 2020-02-04 10:08:25 -08:00
Michael Zhu
3da7c5d3e2 Move LibAssetDataTransfer from forwarder to exchange-libs package 2020-02-04 10:08:21 -08:00
Michael Zhu
c5e0de51aa Add Broker rich errors 2020-02-04 10:06:12 -08:00
Michael Zhu
c581f1bba4 Update Broker README 2020-02-04 10:06:12 -08:00
Michael Zhu
b8ac9c2edd lint 2020-02-04 10:06:10 -08:00
Michael Zhu
1027ee2481 Broker integrations tests 2020-02-04 10:05:17 -08:00
Michael Zhu
2f311f7821 GodsUnchainedValidator unit tests 2020-02-04 10:04:19 -08:00
Michael Zhu
a98c95b514 Broker contracts 2020-02-04 10:04:19 -08:00
Michael Zhu
5bbbae5b23 create contracts-broker package 2020-02-04 10:04:19 -08:00
Jacob Evans
f9c9b9f924 Prevent docs dir from being completely removed 2020-02-04 20:29:16 +10:00
Jacob Evans
5921208ea6 Publish
- @0x/contracts-asset-proxy@3.1.2
 - @0x/contracts-coordinator@3.0.5
 - @0x/contracts-dev-utils@1.0.5
 - @0x/contracts-erc1155@2.0.5
 - @0x/contracts-erc20-bridge-sampler@1.2.0
 - @0x/contracts-erc20@3.0.5
 - @0x/contracts-erc721@3.0.5
 - @0x/contracts-exchange-forwarder@4.0.5
 - @0x/contracts-exchange-libs@4.1.1
 - @0x/contracts-exchange@3.1.1
 - @0x/contracts-extensions@5.1.4
 - @0x/contracts-integrations@2.2.2
 - @0x/contracts-multisig@4.0.5
 - @0x/contracts-staking@2.0.5
 - @0x/contracts-test-utils@5.1.2
 - @0x/contracts-utils@4.2.0
 - 0x.js@9.0.6
 - @0x/abi-gen@5.1.1
 - @0x/asset-swapper@4.1.0
 - @0x/base-contract@6.1.1
 - @0x/contract-addresses@4.4.0
 - @0x/contract-wrappers-test@12.2.6
 - @0x/contract-wrappers@13.4.1
 - @0x/contracts-gen@2.0.5
 - @0x/dev-utils@3.1.2
 - @0x/instant@1.0.43
 - @0x/migrations@6.0.1
 - @0x/monorepo-scripts@1.0.48
 - @0x/order-utils@10.1.2
 - @0x/orderbook@2.1.1
 - @0x/sol-compiler@4.0.5
 - @0x/sol-coverage@4.0.5
 - @0x/sol-doc@3.1.2
 - @0x/sol-profiler@4.0.5
 - @0x/sol-trace@3.0.5
 - @0x/sol-tracing-utils@7.0.5
 - @0x/subproviders@6.0.5
2020-02-04 20:22:07 +10:00
Jacob Evans
f89c78abd1 Updated CHANGELOGS & MD docs 2020-02-04 20:21:45 +10:00
David Sun
74d3b9334c Add liquidity source breakdown to asset-swapper (#2465)
* add liquidity source breakdown to asset-swapper

* remove debug line

* use OptimizedMarketOrder metadata

* updated change-log

* prettier + lint

* bug fixes

* fixes

* Prettier

* Fix types

Co-authored-by: Jacob Evans <dekz@dekz.net>
2020-02-04 19:03:28 +10:00
Xianny
919fc66b9d Stop hardcoding contract addresses (#2461)
* stop hardcoding contract addresses

* update changelog

* export ContractAddresses for docs
2020-02-04 17:49:45 +10:00
Francesco Agosti
400fb5a5bb Merge pull request #2468 from 0xProject/feat/fix-test-publish
Bump maxBuffer?
2020-02-03 19:59:03 -08:00
fragosti
3bb4f9085c Add post-instal step 2020-02-03 18:13:31 -08:00
Jacob Evans
714c6cec3c Bump maxBuffer? 2020-02-03 17:50:32 -08:00
Lawrence Forman
cb69921202 ERC20BridgeSampler: Unlock full sampling on Kovan (#2459)
* `@0x/contracts-utils`: Update kovan addresses in `DeploymentConstants`

* `@0x/contracts-erc20-bridge-sampler`: Make source IDs static on all networks, not inherited from `DeploymentConstants`.

* `@0x/contract-addresses`: Update `ERC20BridgeSampler` addresses on mainnet and kovan.

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2020-01-31 11:27:28 -05:00
Jacob Evans
277a0adac9 [base-contract] throw string revert error (#2453) 2020-01-24 07:48:26 +10:00
Jacob Evans
02d14f504f Remove docs from sol-doc gitignore 2020-01-23 12:10:42 +10:00
Jacob Evans
1ab7664a60 Publish
- @0x/contracts-integrations@2.2.1
 - 0x.js@9.0.5
 - @0x/asset-swapper@4.0.1
 - @0x/instant@1.0.42
2020-01-23 11:58:27 +10:00
Jacob Evans
1be46ffb7e Updated CHANGELOGS & MD docs 2020-01-23 11:58:10 +10:00
Lawrence Forman
6ca52aed0d @0x/asset-swapper: Fix understimated protocol fee in worst case quote. (#2452) 2020-01-22 18:22:56 -05:00
Jacob Evans
74e20970e2 Create docs folder for sol-doc 2020-01-22 18:56:10 +10:00
Jacob Evans
93f2b6b4d8 Publish
- @0x/contracts-asset-proxy@3.1.1
 - @0x/contracts-coordinator@3.0.4
 - @0x/contracts-dev-utils@1.0.4
 - @0x/contracts-erc1155@2.0.4
 - @0x/contracts-erc20-bridge-sampler@1.1.0
 - @0x/contracts-erc20@3.0.4
 - @0x/contracts-erc721@3.0.4
 - @0x/contracts-exchange-forwarder@4.0.4
 - @0x/contracts-exchange-libs@4.1.0
 - @0x/contracts-exchange@3.1.0
 - @0x/contracts-extensions@5.1.3
 - @0x/contracts-integrations@2.2.0
 - @0x/contracts-multisig@4.0.4
 - @0x/contracts-staking@2.0.4
 - @0x/contracts-test-utils@5.1.1
 - @0x/contracts-utils@4.1.0
 - 0x.js@9.0.4
 - @0x/abi-gen@5.1.0
 - @0x/assert@3.0.4
 - @0x/asset-swapper@4.0.0
 - @0x/base-contract@6.1.0
 - @0x/connect@6.0.4
 - @0x/contract-addresses@4.3.0
 - @0x/contract-artifacts@3.4.0
 - @0x/contract-wrappers-test@12.2.5
 - @0x/contract-wrappers@13.4.0
 - @0x/contracts-gen@2.0.4
 - @0x/dev-utils@3.1.1
 - @0x/instant@1.0.41
 - @0x/json-schemas@5.0.4
 - @0x/migrations@6.0.0
 - @0x/monorepo-scripts@1.0.47
 - @0x/order-utils@10.1.1
 - @0x/orderbook@2.1.0
 - @0x/sol-compiler@4.0.4
 - @0x/sol-coverage@4.0.4
 - @0x/sol-doc@3.1.1
 - @0x/sol-profiler@4.0.4
 - @0x/sol-trace@3.0.4
 - @0x/sol-tracing-utils@7.0.4
 - @0x/sra-spec@3.0.4
 - @0x/subproviders@6.0.4
 - @0x/utils@5.2.0
 - @0x/web3-wrapper@7.0.4
2020-01-22 18:49:46 +10:00
Jacob Evans
00e616b57a Updated CHANGELOGS & MD docs 2020-01-22 18:49:24 +10:00
Jacob Evans
e436673304 [asset-swapper] Change Exchange sell to marketSellOrdersFillOrKill (#2450)
* Change Exchange sell to marketSellOrdersFillOrKill

* Update Changelog
2020-01-22 18:25:09 +10:00
James Towle
ce04d3ce41 Fix regression in DevUtils (#2449)
* fix bug in OrderTransferSimulationUtils causing failures for 721 assets

* Patched the regression and added tests

* Added regression test for fillable order

* Created a test for in and out of process ganache

* Split up DevUtils into two contracts

* Updated migration

* Remove the in and out of process ganache test

* Fixed contract addresses

* Appease linter

* Addressed review comments and updated artifacts, wrappers, and snapshots

* Fixed regression after refactor

* Update DevUtils and libTransactionDecoder contracts on mainnet and testnets

* Addressed @mzhu's review feedback

* Addressed @hysz's review feedback

* Updated devUtils address on testnets and mainnet after deployment

Co-authored-by: mzhu25 <mchl.zhu.96@gmail.com>
Co-authored-by: Fabio B <kandinsky454@protonmail.ch>
2020-01-22 12:54:10 +10:00
Jacob Evans
4e46bf4697 Merge pull request #2427 from 0xProject/feature/erc20-bridge-sampler/query-multiple-buys-sells
ERC20BridgeSampler: Allow for batching multiple buy/sell samples
2020-01-22 11:54:45 +10:00
Jacob Evans
9b95508f99 Merge pull request #2445 from 0xProject/feat/asset-swapper/better-best-price-quote
asset-swapper: provide more accurate best quote price
2020-01-22 11:16:40 +10:00
Jacob Evans
c8c24456c1 Fix prettier 2020-01-22 10:01:18 +10:00
Lawrence Forman
80a6e82e1b @0x/contracts-erc20-bridge-sampler: Fix linter error. 2020-01-21 17:47:27 -05:00
Lawrence Forman
80cec20d38 Update packages/asset-swapper/src/utils/swap_quote_calculator.ts
Co-Authored-By: Jacob Evans <jacob@dekz.net>
2020-01-21 16:53:02 -05:00
Lawrence Forman
26cb22020d Update packages/asset-swapper/src/utils/swap_quote_calculator.ts
Co-Authored-By: Jacob Evans <jacob@dekz.net>
2020-01-21 16:52:54 -05:00
Lawrence Forman
09d05d09c9 @0x/asset-swapper: Provide more accurate best quote price. 2020-01-21 15:48:35 +10:00
Jacob Evans
160c91f908 Rename to Batch 2020-01-21 15:48:35 +10:00
Jacob Evans
58f41bcd42 Update asset-swapper WIP 2020-01-21 15:46:31 +10:00
Jacob Evans
0235429995 Update contract addresses 2020-01-21 09:15:47 +10:00
Lawrence Forman
f79697e117 @0x/contract-wrappers: Fix linter error. 2020-01-20 13:30:58 +10:00
Lawrence Forman
6f0019c71e @0x/contract-wrappers: Update IERC20BridgeSampler wrapper. 2020-01-20 13:30:58 +10:00
Lawrence Forman
1a04a18245 @0x/contract-artifacts: Update IERC20BridgeSampler artifact. 2020-01-20 13:30:57 +10:00
Lawrence Forman
0cf3ff8209 @0x/contracts-erc20-bridge-sampler: Increase gas forwarded to kyber and eth2dai.
`@0x/contracts-erc20-bridge-sampler`: Bail as soon as any quote from a DEX fails.

`@0x/contracts-erc20-bridge-sampler`: Fix broken tests.
2020-01-20 13:30:57 +10:00
Lawrence Forman
7f56091fbd @0x/asset-swapper: Add exponential sampling, exposed by sampleDistributionBase.
`@0x/asset-swapper`: Disable ethgasstation polling in tests.
`@0x/asset-swapper`: Tweak default hyper parameters to be friendlier to big fills.
2020-01-20 13:30:57 +10:00
F. Eugene Aumson
391f9b31f6 wrappers.py: satisfy linter (rm unnecessary pass) 2020-01-20 13:30:56 +10:00
F. Eugene Aumson
1d7c0f504a abi-gen: ran black on CLI test Python output 2020-01-20 13:30:56 +10:00
F. Eugene Aumson
9cdc62f918 abi-gen: fix bug w/ 2D arrays of UDT's in Python
Fix bug in handling 2-dimensional arrays of user defined data types in
generated Python code.
2020-01-20 13:30:56 +10:00
F. Eugene Aumson
6027d0481e wrappers.py: fix clean not rm'ing gen'd code 2020-01-20 13:30:55 +10:00
F. Eugene Aumson
277fb92f9e abi-gen: exit when black fails to parse Python
Note: this is not the same case as when the black executable can't be
found; that case is still just a (non-fatal) warning.
2020-01-20 13:30:55 +10:00
Jacob Evans
79b6c3c1af Update CHANGELOGs 2020-01-20 13:30:55 +10:00
Jacob Evans
ad17174119 Rename to Batch 2020-01-20 13:30:54 +10:00
Jacob Evans
6c2692eec0 Enable batch fetching from orderbook. Refactor 2020-01-20 13:30:54 +10:00
Jacob Evans
08640e8575 Update asset-swapper WIP 2020-01-20 13:30:54 +10:00
Jacob Evans
4a2575136f Allow for batching multiple buy/sell samples 2020-01-20 13:30:52 +10:00
Jacob Evans
e792afad17 Merge pull request #2441 from 0xProject/kroeger/fix_function_name_in_readme
Fixed function name in README, network -> chain
2020-01-20 13:29:45 +10:00
Jacob Evans
5ecc4b027d Merge pull request #2448 from 0xProject/fix/python-latest-ganache
Fix/python latest ganache
2020-01-20 13:25:26 +10:00
Jacob Evans
bc540f0cf0 [python] change gas estimate expected 2020-01-20 12:53:34 +10:00
Jacob Evans
a24b14c465 Pull 0xorg/ganache-cli:6.0.0 in circleci 2020-01-20 12:06:28 +10:00
Jacob Evans
c3f36c3123 Change python to use latest ganache 2020-01-20 11:50:43 +10:00
fabioberger
1d34da7557 Remove -v3-beta from snapshot name 2020-01-19 20:10:06 +01:00
fabioberger
27d74a4327 Update ganache-cli version to Istanbul-compatible version 2020-01-19 20:09:50 +01:00
mzhu25
8a20cc682c Merge pull request #2446 from 0xProject/feature/contract-addresses/update-dev-utils-1-17-20
`@0x/contract-addresses`: update DevUtils addresses
2020-01-17 13:38:04 -08:00
mzhu25
9b20359e7b Merge pull request #2431 from 0xProject/feature/fuzz/revert-assertions
`@0x/contracts-integrations`: Negative assertions for fuzzing
2020-01-17 13:10:00 -08:00
Michael Zhu
8866d0ccef update contract-addresses changelog 2020-01-17 12:42:56 -08:00
Michael Zhu
7fa91a9971 update dev-utils addresses 2020-01-17 12:39:07 -08:00
Amir Bandeali
28d1f3eef0 Merge pull request #2440 from 0xProject/feat/dev-utils/chai-bridge-validation
Add ChaiBridge order balance/allowance checks to DevUtils
2020-01-17 11:46:27 -08:00
Amir
f321cf6655 Update DevUtils contract wrapper 2020-01-17 11:08:04 -08:00
Amir
14ade737da Fix linting errors 2020-01-17 10:47:17 -08:00
Amir
41b1b1f141 Skip failing dydxBridge tests 2020-01-17 10:47:17 -08:00
Amir
25dfd47d32 Fix Ganache migrations 2020-01-17 10:47:17 -08:00
Amir
6afa9c8b92 Add mainnet integration tests for checking balances/allowances of ChaiBridge orders using DevUtils 2020-01-17 10:00:16 -08:00
Amir
2fc449da4c Fix integrations tests build 2020-01-17 10:00:16 -08:00
Amir
5dd3b8cf9d Special case unlimited allowance for Chai 2020-01-17 09:59:03 -08:00
Amir
e834fa0050 Split Dai calculation and erc20 balance checks into separate functions 2020-01-17 09:59:03 -08:00
Amir
9a97401606 Add ChaiBridge allowance checks 2020-01-17 09:59:03 -08:00
Amir
410a3fef18 Add ChaiBridge balance checks to DevUtils 2020-01-17 09:59:03 -08:00
Amir Bandeali
969b9814d5 Merge pull request #2442 from 0xProject/feat/forwarder/1155-support
Add 1155 support to Forwarder
2020-01-16 11:41:20 -08:00
Amir
2275e27b87 Rename internal functions in LibAssetDataTransfer and fix tests 2020-01-15 18:33:02 -08:00
Amir
62b06cd204 Add tests for transfering ERC1155 tokens out 2020-01-15 18:33:02 -08:00
Amir
350934ca21 Remove unused params 2020-01-15 18:32:57 -08:00
mzhu25
6332673434 Merge pull request #2436 from 0xProject/fix/dev-utils/map-fixes
`@0x/contracts-dev-utils`: LibAssetData fixes
2020-01-15 16:10:11 -08:00
Michael Zhu
f217840998 address comments 2020-01-15 13:22:53 -08:00
Michael Zhu
089ec35ceb update changelog 2020-01-15 13:22:53 -08:00
Michael Zhu
fecd0b809e tslint be trippin 2020-01-15 13:20:54 -08:00
Michael Zhu
4707a46561 Add negative assertions for endEpoch 2020-01-15 13:20:54 -08:00
Michael Zhu
616533c5a8 Add negative assertions for moveStake 2020-01-15 13:20:54 -08:00
Michael Zhu
c5b2991821 fix bug in finalizePool 2020-01-15 13:20:54 -08:00
Michael Zhu
c36d0fdc7c invalidWithdrawDelegatorRewardsAssertion 2020-01-15 13:20:54 -08:00
Michael Zhu
544e09cf4b invalidUnstakeAssertion 2020-01-15 13:20:54 -08:00
Michael Zhu
c110dc9e6a generic assertion for TRANSFER_FAILED reverts; _invalidStake generator 2020-01-15 13:20:54 -08:00
Michael Zhu
3bf37d6afd invalidDecreaseStakingPoolOperatorShareAssertion 2020-01-15 13:20:54 -08:00
Michael Zhu
b80ae5796b invalidCreateStakingPoolAssertion 2020-01-15 13:20:54 -08:00
Michael Zhu
2083632299 Update addresses, artifact, wrapper 2020-01-15 10:38:57 -08:00
Amir
3ca2f8ac9e Split out transfer logic into library, add 1155 support 2020-01-14 20:27:12 -08:00
Greg Hysz
7172432084 Merge pull request #2443 from 0xProject/fix/abiDecoder/LogDecodingDynamicData
Fixes log decoding of dynamic data
2020-01-14 18:33:57 -08:00
Greg Hysz
0e6afd147f Merge pull request #2437 from 0xProject/test/contracts-integrations/fuzzOrderMatching
Fuzz order matching
2020-01-14 18:04:27 -08:00
Greg Hysen
46275a4f43 Minor fixes to order matching fuzz code 2020-01-14 17:32:10 -08:00
Michael Zhu
1dca378e03 add division-by-zero check for ERC1155 too 2020-01-14 16:32:18 -08:00
Greg Hysen
06669594b1 Updated changelogs. 2020-01-14 16:18:50 -08:00
Greg Hysen
c09ac58ac0 Fuzz testing for matchOrders and matchOrdersWithMaximalFill. 2020-01-14 16:17:43 -08:00
Greg Hysen
e01d32ef1a added order matching functions to Taker actor. 2020-01-14 16:17:43 -08:00
Greg Hysen
5ea3bcf59e Added matchOrders and matchOrdersWithMaximalFill to the reference functions. 2020-01-14 16:17:43 -08:00
Greg Hysen
aa8b14b7ee Added order martching to Maker actor. Also fixed the joinStakingPool to record the pool id. 2020-01-14 16:17:43 -08:00
Greg Hysen
e1722cf739 Updated changelogs 2020-01-14 15:01:02 -08:00
Greg Hysen
7a7f70e15d Updating tests after fixing log decoding 2020-01-14 14:17:45 -08:00
Greg Hysen
b3c3ec16e5 Fixed log decoding. Dynamic structures were not decoding properly. Now uses AbiEncoder from utils package. 2020-01-14 14:17:42 -08:00
Michael Zhu
149f863951 unbreak migrations cli 2020-01-14 09:15:17 -08:00
Michael Zhu
684d09faac refactor LibAssetData tests 2020-01-13 15:29:37 -08:00
Michael Zhu
8a42691c80 Add test cases 2020-01-13 14:10:55 -08:00
Michael Zhu
d591b3dd98 LibAssetData fixes 2020-01-13 14:10:55 -08:00
Alex Kroeger
a90fb4d8b6 Fixed function name in README, network -> chain 2020-01-13 13:33:54 -08:00
Lawrence Forman
ebd08d9c63 Contract wrappers: Catch empty reverts on live networks (#2433)
* `@0x/utils`: Allow strict decoding of return values.

* `@0x/base-contract`: Catch empty call reverts on live networks.
`@0x/abi-gen`: Catch empty call reverts on live networks.

* `@0x/contracts-integrations`: Add mainnet contract wrapper `callAsync()` revert behavior tests.

* `@0x/contract-wrappers`: Regenerate wrappers to catch empty reverts on live networks.

* Update CHANGELOGs

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

* `@0x/abi-gen`: Regenerate test outputs.

* `@0x/base-contract`: Update CHANGELOG.

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2020-01-13 15:33:45 -05:00
Lawrence Forman
71731d223b Update contract wrappers (esp Forwarder + asset-swapper) (#2432)
* `@0x/contract-artifacts`: Update artifacts.

* `@0x/contract-wrappers`: Regenerate wrappers.

* `@0x/migrations`: Update Forwarder migration.

* `@0x/asset-swapper`: Update forwarder fees for new forwarder contract.

* `@0x/dev-utils`: Make `"istanbul"` the default `hardfork` when creating a ganache provider.

* `@0x/asset-swapper`: Remove debug code.

* `@0x/asset-swapper`: Remove `getSmartContractParamsOrThrowAsync()` because why does it even exist?
`@0x/asset-swapper`: Fix broken tests.
`@0x/asset-swapper`: Correctly handle affiliate fees in `getCalldataOrThrow()`.

* `@0x/contract-wrappers`: Export `ExchangeOwnershipTransferredEventArgs`.
`@0x/0x.js`: Export `ExchangeOwnershipTransferredEventArgs`.
`@0x/asset-swapper`: Unexport `MethodAbi`, `ConstructorStateMutability`, and `StateMutability`.

* Update changelogs

* Update packages/migrations/CHANGELOG.json

Co-Authored-By: Jacob Evans <jacob@dekz.net>

* Update packages/asset-swapper/CHANGELOG.json

Co-Authored-By: Jacob Evans <jacob@dekz.net>

Co-authored-by: Lawrence Forman <me@merklejerk.com>
Co-authored-by: Jacob Evans <dekz@dekz.net>
2020-01-09 15:35:22 -05:00
David Sun
726ea5e01e Merge pull request #2430 from 0xProject/feature/instant/enable-aggregator
Instant: whitelist tokens using bridge orders array
2020-01-08 16:50:40 -08:00
David Sun
16c7d2964b typo 2020-01-08 16:17:25 -08:00
David Sun
5a6e494bda lint + prettier 2020-01-08 16:16:29 -08:00
David Sun
88c6d89fbb whitelist constants array 2020-01-08 13:55:53 -08:00
Lawrence Forman
de12da18da Exchange signature validation fuzz tests (#2425)
* `@0x/contracts-integrations`: Add Exchange signature validation fuzz tests.

* `@0x/contracts-integrations`: Switch from actor pattern to just pure function generators.

Co-authored-by: Lawrence Forman <me@merklejerk.com>
2020-01-07 17:35:25 -05:00
Amir Bandeali
8d10736934 Merge pull request #2390 from 0xProject/feat/forwarder/v2-backwards-compatibility
Make Forwarder backwards compatible with v2
2020-01-07 13:04:27 -08:00
Amir
2328e02d82 Redeploy Forwarder 2020-01-07 11:03:18 -08:00
Michael Zhu
87cd5fca90 address comments 2020-01-07 11:03:18 -08:00
Michael Zhu
b70cb726c5 remove _noTakerFee (i.e. disallow StaticCall takerFeeAssetData) 2020-01-07 11:03:18 -08:00
Michael Zhu
295811ed5a add integrations tests 2020-01-07 11:03:18 -08:00
Michael Zhu
4bc55551c6 Add unit tests 2020-01-07 11:03:18 -08:00
Michael Zhu
2b8c6dc8f9 Forwarder StaticCall and MultiAsset buy support 2020-01-07 11:03:18 -08:00
Amir Bandeali
8b27380feb Fix dep version 2020-01-07 11:03:18 -08:00
Amir Bandeali
8de3a90851 Update CHANGELOG 2020-01-07 11:03:18 -08:00
Amir Bandeali
f8bb94d721 Remove unnecessary BigNumber cast 2020-01-06 22:12:05 -08:00
Amir Bandeali
0c6d06e7bb Redeploy bridges and Forwarder on mainnet 2020-01-06 22:12:05 -08:00
Amir Bandeali
b0aa5d3af2 Check makerFeeAssetData length before attempting to read id 2020-01-06 22:12:05 -08:00
Amir Bandeali
27d09713fd Add forwarder mainnet tests 2020-01-06 22:12:05 -08:00
Amir Bandeali
ff18852879 Fix build 2020-01-06 22:12:05 -08:00
Amir Bandeali
e515c91e5e Do not attempt to transfer asset if fill failed 2020-01-06 22:12:05 -08:00
Amir Bandeali
1d5800c4f7 Fix WETH compilation 2020-01-06 22:12:05 -08:00
Amir Bandeali
de8f190945 Change erc-20 package compiler target to istanbul 2020-01-06 22:12:05 -08:00
Amir Bandeali
f371e3c8d3 Regenerate boilerplate 2020-01-06 22:12:05 -08:00
Amir Bandeali
b15a6290a7 Handle v2 order edge cases 2020-01-06 22:12:05 -08:00
Amir Bandeali
0f151db355 Enable istanbul in Ganache 2020-01-06 22:12:05 -08:00
Amir Bandeali
fa99b75d1f Redeploy Forwarder and all bridges 2020-01-06 22:12:05 -08:00
Amir Bandeali
4a299c1f39 Change EVM target to istanbul for all contract packages except erc-20 2020-01-06 22:12:05 -08:00
Amir Bandeali
30a2015a68 Fix build 2020-01-06 22:12:05 -08:00
Amir Bandeali
c7c8a4891f Update TS boilerplate 2020-01-06 22:12:05 -08:00
Amir Bandeali
fe9fc6b459 Allow v2 orders to be filled if their makerAssetFeeData field uses a v2 order id 2020-01-06 22:12:05 -08:00
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
788 changed files with 48306 additions and 19407 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
@@ -47,7 +47,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-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-tests @0x/contracts-staking
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-staking
test-exchange-ganache-3.0:
resource_class: medium+
docker:
@@ -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-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:6.0.0
- 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:

33
.gitignore vendored
View File

@@ -79,6 +79,8 @@ TODO.md
.vscode
# generated contract artifacts/
contracts/broker/generated-artifacts/
contracts/broker/test/generated-artifacts/
contracts/erc20-bridge-sampler/generated-artifacts/
contracts/erc20-bridge-sampler/test/generated-artifacts/
contracts/integrations/generated-artifacts/
@@ -113,6 +115,7 @@ packages/sol-tracing-utils/test/fixtures/artifacts/
python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/
# generated truffle contract artifacts/
contracts/broker/build/
contracts/erc20-bridge-sampler/build/
contracts/staking/build/
contracts/coordinator/build/
@@ -129,6 +132,8 @@ contracts/exchange-forwarder/build/
contracts/dev-utils/build/
# generated contract wrappers
contracts/broker/generated-wrappers/
contracts/broker/test/generated-wrappers/
packages/python-contract-wrappers/generated/
contracts/erc20-bridge-sampler/generated-wrappers/
contracts/erc20-bridge-sampler/test/generated-wrappers/
@@ -160,33 +165,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

@@ -1,5 +1,9 @@
lib
.nyc_output
/contracts/broker/generated-wrappers
/contracts/broker/test/generated-wrappers
/contracts/broker/generated-artifacts
/contracts/broker/test/generated-artifacts
/contracts/integrations/generated-wrappers
/contracts/integrations/test/generated-wrappers
/contracts/integrations/generated-artifacts
@@ -87,3 +91,4 @@ packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json
packages/abi-gen/test-cli/fixtures/artifacts/LibDummy.json
packages/abi-gen/test-cli/fixtures/artifacts/TestLibDummy.json
packages/*/docs
*.sol

View File

@@ -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,133 @@
[
{
"timestamp": 1582837861,
"version": "3.2.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1582677073,
"version": "3.2.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1582623685,
"version": "3.2.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1581748629,
"version": "3.2.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.2.0",
"changes": [
{
"note": "Add more types and functions to `IDydx`",
"pr": 2466
},
{
"note": "Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx`",
"pr": 2466
},
{
"note": "Fix broken tests.",
"pr": 2462
},
{
"note": "Remove dependency on `@0x/contracts-dev-utils`",
"pr": 2462
},
{
"note": "Add asset data decoding functions",
"pr": 2462
},
{
"note": "Add `setOperators()` to `IDydx`",
"pr": "TODO"
}
],
"timestamp": 1581204851
},
{
"timestamp": 1580988106,
"version": "3.1.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1580811564,
"version": "3.1.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "3.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.1.0",
"changes": [
{
"note": "Integration tests for DydxBridge with ERC20BridgeProxy.",
"pr": 2401
},
{
"note": "Fix `UniswapBridge` token -> token transfer call.",
"pr": 2412
},
{
"note": "Fix `KyberBridge` incorrect `minConversionRate` calculation.",
"pr": 2412
}
],
"timestamp": 1578272714
},
{
"timestamp": 1576540892,
"version": "3.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1575931811,
"version": "3.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.0.0",
"changes": [
@@ -55,6 +184,10 @@
{
"note": "Implement `KyberBridge`.",
"pr": 2352
},
{
"note": "Implement `DydxBridge`.",
"pr": 2365
}
],
"timestamp": 1575290197

View File

@@ -5,6 +5,57 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.2.4 - _February 27, 2020_
* Dependencies updated
## v3.2.3 - _February 26, 2020_
* Dependencies updated
## v3.2.2 - _February 25, 2020_
* Dependencies updated
## v3.2.1 - _February 15, 2020_
* Dependencies updated
## v3.2.0 - _February 8, 2020_
* Add more types and functions to `IDydx` (#2466)
* Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx` (#2466)
* Fix broken tests. (#2462)
* Remove dependency on `@0x/contracts-dev-utils` (#2462)
* Add asset data decoding functions (#2462)
* Add `setOperators()` to `IDydx` (#TODO)
## v3.1.3 - _February 6, 2020_
* Dependencies updated
## v3.1.2 - _February 4, 2020_
* Dependencies updated
## v3.1.1 - _January 22, 2020_
* Dependencies updated
## v3.1.0 - _January 6, 2020_
* Integration tests for DydxBridge with ERC20BridgeProxy. (#2401)
* Fix `UniswapBridge` token -> token transfer call. (#2412)
* Fix `KyberBridge` incorrect `minConversionRate` calculation. (#2412)
## v3.0.2 - _December 17, 2019_
* Dependencies updated
## v3.0.1 - _December 9, 2019_
* Dependencies updated
## v3.0.0 - _December 2, 2019_
* Implement `KyberBridge`. (#2352)
@@ -22,6 +73,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

@@ -3,8 +3,9 @@
"contractsDir": "./contracts",
"useDockerisedSolc": false,
"isOfflineMode": false,
"shouldSaveStandardInput": true,
"compilerSettings": {
"evmVersion": "constantinople",
"evmVersion": "istanbul",
"optimizer": {
"enabled": true,
"runs": 1000000,

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 `0xdc1600f3` if successful.
function bridgeTransferFrom(
address /* tokenAddress */,
address from,
address to,
uint256 amount,
bytes calldata /* bridgeData */
)
external
returns (bytes4 success)
{
// Ensure that only the `ERC20BridgeProxy` can call this function.
require(
msg.sender == _getERC20BridgeProxyAddress(),
"ChaiBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY"
);
// Withdraw `from` address's Dai.
// NOTE: This contract must be approved to spend Chai on behalf of `from`.
bytes memory drawCalldata = abi.encodeWithSelector(
IChai(address(0)).draw.selector,
from,
amount
);
(bool success,) = _getChaiAddress().call(drawCalldata);
require(
success,
"ChaiBridge/DRAW_DAI_FAILED"
);
// Transfer Dai to `to`
// This will never fail if the `draw` call was successful
IERC20Token(_getDaiAddress()).transfer(to, amount);
return BRIDGE_SUCCESS;
}
}

View File

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

View File

@@ -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.
accountIdx: bridgeAction.accountIdx, // index in the `accounts` when calling `operate`.
primaryMarketId: bridgeAction.marketId, // indicates which token to deposit.
otherAddress: depositFrom, // deposit from the account owner.
// unused parameters
secondaryMarketId: 0,
otherAccountIdx: 0,
data: hex''
});
}
/// @dev Returns a dydx `WithdrawAction`.
/// @param withdrawTo Withdraw tokens to this address.
/// @param amount of tokens to withdraw.
/// @param bridgeAction A `BridgeAction` struct.
/// @return withdrawAction The encoded dydx action.
function _createWithdrawAction(
address withdrawTo,
uint256 amount,
BridgeAction memory bridgeAction
)
internal
pure
returns (
IDydx.ActionArgs memory withdrawAction
)
{
// Create dydx amount.
IDydx.AssetAmount memory amountToWithdraw = IDydx.AssetAmount({
sign: false, // false if negative.
denomination: IDydx.AssetDenomination.Wei, // Wei => actual token amount held in account.
ref: IDydx.AssetReference.Delta, // Delta => a relative amount.
value: amount // amount to withdraw.
});
// Create withdraw action.
withdrawAction = IDydx.ActionArgs({
actionType: IDydx.ActionType.Withdraw, // withdraw tokens.
amount: amountToWithdraw, // amount to withdraw.
accountIdx: bridgeAction.accountIdx, // index in the `accounts` when calling `operate`.
primaryMarketId: bridgeAction.marketId, // indicates which token to withdraw.
otherAddress: withdrawTo, // withdraw tokens to this address.
// unused parameters
secondaryMarketId: 0,
otherAccountIdx: 0,
data: hex''
});
}
}

View File

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

View File

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

View File

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

View File

@@ -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 accountIdx; // Index in `BridgeData.accountNumbers` for this action.
uint256 marketId; // Market to operate on.
uint256 conversionRateNumerator; // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator).
uint256 conversionRateDenominator; // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator).
}
struct BridgeData {
uint256[] accountNumbers; // Account number used to identify the owner's specific account.
BridgeAction[] actions; // Actions to carry out on the owner's accounts.
}
}

View File

@@ -30,7 +30,7 @@ contract IERC20Bridge {
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer.
/// @param bridgeData Arbitrary asset data needed by the bridge contract.
/// @return success The magic bytes `0x37708e9b` if successful.
/// @return success The magic bytes `0xdc1600f3` if successful.
function bridgeTransferFrom(
address tokenAddress,
address from,

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

View File

@@ -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.2.4",
"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|CurveBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IKyberNetworkProxy|IUniswapExchange|IUniswapExchangeFactory|KyberBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MultiAssetProxy|Ownable|StaticCallProxy|TestChaiBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|UniswapBridge).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
},
"repository": {
@@ -52,15 +51,14 @@
},
"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.2.2",
"@0x/contracts-gen": "^2.0.8",
"@0x/contracts-test-utils": "^5.3.1",
"@0x/contracts-utils": "^4.4.2",
"@0x/dev-utils": "^3.2.1",
"@0x/sol-compiler": "^4.0.8",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.0.0",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -80,16 +78,17 @@
"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",
"ethereum-types": "^3.0.0",
"@0x/base-contract": "^6.2.1",
"@0x/contracts-erc1155": "^2.1.4",
"@0x/contracts-erc20": "^3.1.4",
"@0x/contracts-erc721": "^3.1.4",
"@0x/contracts-exchange-libs": "^4.3.4",
"@0x/order-utils": "^10.2.3",
"@0x/types": "^3.1.2",
"@0x/typescript-typings": "^5.0.2",
"@0x/utils": "^5.4.1",
"@0x/web3-wrapper": "^7.0.7",
"ethereum-types": "^3.1.0",
"lodash": "^4.17.11"
},
"publishConfig": {

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,3 @@
import { DevUtilsContract } from '@0x/contracts-dev-utils';
import { artifacts as erc1155Artifacts, ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155';
import {
constants,
@@ -15,7 +14,7 @@ import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { ERC1155ProxyContract, IAssetProxyContract } from './wrappers';
import { ERC1155ProxyContract, IAssetDataContract, IAssetProxyContract } from './wrappers';
export class ERC1155ProxyWrapper {
private readonly _tokenOwnerAddresses: string[];
@@ -28,7 +27,7 @@ export class ERC1155ProxyWrapper {
private readonly _logDecoder: LogDecoder;
private readonly _dummyTokenWrappers: Erc1155Wrapper[];
private readonly _assetProxyInterface: IAssetProxyContract;
private readonly _devUtils: DevUtilsContract;
private readonly _assetDataInterface: IAssetDataContract;
private _proxyContract?: ERC1155ProxyContract;
private _proxyIdIfExists?: string;
private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} };
@@ -40,7 +39,7 @@ export class ERC1155ProxyWrapper {
this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts);
this._dummyTokenWrappers = [];
this._assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider);
this._devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider);
this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
this._tokenOwnerAddresses = tokenOwnerAddresses;
this._contractOwnerAddress = contractOwnerAddress;
this._fungibleTokenIds = [];
@@ -60,7 +59,7 @@ export class ERC1155ProxyWrapper {
txDefaults,
artifacts,
);
const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._provider, this._contractOwnerAddress);
const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._contractOwnerAddress);
this._dummyTokenWrappers.push(erc1155Wrapper);
}
return this._dummyTokenWrappers;
@@ -113,9 +112,9 @@ export class ERC1155ProxyWrapper {
this._validateProxyContractExistsOrThrow();
const assetData =
assetData_ === undefined
? await this._devUtils
.encodeERC1155AssetData(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.callAsync()
? this._assetDataInterface
.ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData()
: assetData_;
const data = this._assetProxyInterface
.transferFrom(assetData, from, to, valueMultiplier)
@@ -167,9 +166,9 @@ export class ERC1155ProxyWrapper {
this._validateProxyContractExistsOrThrow();
const assetData =
assetData_ === undefined
? await this._devUtils
.encodeERC1155AssetData(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.callAsync()
? this._assetDataInterface
.ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData()
: assetData_;
const data = this._assetProxyInterface
.transferFrom(assetData, from, to, valueMultiplier)

View File

@@ -1,4 +1,3 @@
import { DevUtilsContract } from '@0x/contracts-dev-utils';
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils';
import { BigNumber } from '@0x/utils';
@@ -7,14 +6,14 @@ import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { ERC20ProxyContract } from './wrappers';
import { ERC20ProxyContract, IAssetDataContract } from './wrappers';
export class ERC20Wrapper {
private readonly _tokenOwnerAddresses: string[];
private readonly _contractOwnerAddress: string;
private readonly _provider: ZeroExProvider;
private readonly _dummyTokenContracts: DummyERC20TokenContract[];
private readonly _devUtils: DevUtilsContract;
private readonly _assetDataInterface: IAssetDataContract;
private _proxyContract?: ERC20ProxyContract;
private _proxyIdIfExists?: string;
/**
@@ -29,7 +28,7 @@ export class ERC20Wrapper {
this._provider = provider;
this._tokenOwnerAddresses = tokenOwnerAddresses;
this._contractOwnerAddress = contractOwnerAddress;
this._devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider);
this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
}
public async deployDummyTokensAsync(
numberToDeploy: number,
@@ -145,7 +144,7 @@ export class ERC20Wrapper {
return tokenAddresses;
}
private async _getTokenContractFromAssetDataAsync(assetData: string): Promise<DummyERC20TokenContract> {
const [proxyId, tokenAddress] = await this._devUtils.decodeERC20AssetData(assetData).callAsync(); // tslint:disable-line:no-unused-variable
const tokenAddress = this._assetDataInterface.getABIDecodedTransactionData<string>('ERC20Token', assetData); // tslint:disable-line:no-unused-variable
const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
if (tokenContractIfExists === undefined) {
throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);

View File

@@ -1,14 +1,20 @@
export { artifacts } from './artifacts';
export {
ChaiBridgeContract,
ERC1155ProxyContract,
ERC20BridgeProxyContract,
ERC20ProxyContract,
ERC721ProxyContract,
Eth2DaiBridgeContract,
DydxBridgeContract,
IAssetDataContract,
IAssetProxyContract,
IChaiContract,
IDydxContract,
KyberBridgeContract,
MultiAssetProxyContract,
StaticCallProxyContract,
TestDydxBridgeContract,
TestStaticCallTargetContract,
UniswapBridgeContract,
} from './wrappers';
@@ -19,6 +25,7 @@ export { ERC1155ProxyWrapper } from './erc1155_proxy_wrapper';
export { ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155';
export { DummyERC20TokenContract } from '@0x/contracts-erc20';
export { DummyERC721TokenContract } from '@0x/contracts-erc721';
export { AssetProxyId } from '@0x/types';
export {
ERC1155HoldingsByOwner,
ERC20BalancesByOwner,
@@ -49,6 +56,7 @@ export {
OutputField,
ParamDescription,
EvmBytecodeOutput,
EvmBytecodeOutputLinkReferences,
AbiDefinition,
FunctionAbi,
EventAbi,
@@ -62,3 +70,21 @@ export {
TupleDataItem,
StateMutability,
} from 'ethereum-types';
export {
decodeERC1155AssetData,
decodeERC20AssetData,
decodeERC20BridgeAssetData,
decodeERC721AssetData,
decodeMultiAssetData,
decodeStaticCallAssetData,
encodeERC1155AssetData,
encodeERC20AssetData,
encodeERC20BridgeAssetData,
encodeERC721AssetData,
encodeMultiAssetData,
encodeStaticCallAssetData,
getAssetDataProxyId,
} from './asset_data';
export * from './dydx_bridge_encoder';

View File

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

View File

@@ -5,6 +5,9 @@
*/
import { ContractArtifact } from 'ethereum-types';
import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json';
import * as CurveBridge from '../test/generated-artifacts/CurveBridge.json';
import * as DydxBridge from '../test/generated-artifacts/DydxBridge.json';
import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json';
import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json';
import * as ERC20Proxy from '../test/generated-artifacts/ERC20Proxy.json';
@@ -14,6 +17,10 @@ import * as IAssetData from '../test/generated-artifacts/IAssetData.json';
import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json';
import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json';
import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json';
import * as IChai from '../test/generated-artifacts/IChai.json';
import * as ICurve from '../test/generated-artifacts/ICurve.json';
import * as IDydx from '../test/generated-artifacts/IDydx.json';
import * as IDydxBridge from '../test/generated-artifacts/IDydxBridge.json';
import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json';
@@ -25,6 +32,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 +50,9 @@ export const artifacts = {
ERC721Proxy: ERC721Proxy as ContractArtifact,
MultiAssetProxy: MultiAssetProxy as ContractArtifact,
StaticCallProxy: StaticCallProxy as ContractArtifact,
ChaiBridge: ChaiBridge as ContractArtifact,
CurveBridge: CurveBridge as ContractArtifact,
DydxBridge: DydxBridge as ContractArtifact,
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
KyberBridge: KyberBridge as ContractArtifact,
UniswapBridge: UniswapBridge as ContractArtifact,
@@ -48,11 +60,17 @@ export const artifacts = {
IAssetProxy: IAssetProxy as ContractArtifact,
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
IAuthorizable: IAuthorizable as ContractArtifact,
IChai: IChai as ContractArtifact,
ICurve: ICurve as ContractArtifact,
IDydx: IDydx as ContractArtifact,
IDydxBridge: IDydxBridge as ContractArtifact,
IERC20Bridge: IERC20Bridge as ContractArtifact,
IEth2Dai: IEth2Dai as ContractArtifact,
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
IUniswapExchange: IUniswapExchange as ContractArtifact,
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
TestChaiBridge: TestChaiBridge as ContractArtifact,
TestDydxBridge: TestDydxBridge as ContractArtifact,
TestERC20Bridge: TestERC20Bridge as ContractArtifact,
TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact,
TestKyberBridge: TestKyberBridge as ContractArtifact,

View File

@@ -1,35 +1,20 @@
import { chaiSetup, expectTransactionFailedAsync, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { blockchainTests, expect, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
import { RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { MixinAuthorizableContract } from './wrappers';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('Authorizable', () => {
blockchainTests.resets('Authorizable', () => {
let owner: string;
let notOwner: string;
let address: string;
let authorizable: MixinAuthorizableContract;
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
[owner, address, notOwner] = _.slice(accounts, 0, 3);
[owner, address, notOwner] = accounts.slice(0, 3);
authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
artifacts.MixinAuthorizable,
provider,
@@ -38,20 +23,10 @@ describe('Authorizable', () => {
);
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('addAuthorizedAddress', () => {
it('should revert if not called by owner', async () => {
await expectTransactionFailedAsync(
authorizable.addAuthorizedAddress(notOwner).sendTransactionAsync({ from: notOwner }),
RevertReason.OnlyContractOwner,
);
const tx = authorizable.addAuthorizedAddress(notOwner).sendTransactionAsync({ from: notOwner });
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
});
it('should allow owner to add an authorized address', async () => {
@@ -62,20 +37,16 @@ describe('Authorizable', () => {
it('should revert if owner attempts to authorize a duplicate address', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
return expectTransactionFailedAsync(
authorizable.addAuthorizedAddress(address).sendTransactionAsync({ from: owner }),
RevertReason.TargetAlreadyAuthorized,
);
const tx = authorizable.addAuthorizedAddress(address).sendTransactionAsync({ from: owner });
return expect(tx).to.revertWith(RevertReason.TargetAlreadyAuthorized);
});
});
describe('removeAuthorizedAddress', () => {
it('should revert if not called by owner', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
await expectTransactionFailedAsync(
authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: notOwner }),
RevertReason.OnlyContractOwner,
);
const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: notOwner });
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
});
it('should allow owner to remove an authorized address', async () => {
@@ -86,12 +57,8 @@ describe('Authorizable', () => {
});
it('should revert if owner attempts to remove an address that is not authorized', async () => {
return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddress(address).sendTransactionAsync({
from: owner,
}),
RevertReason.TargetNotAuthorized,
);
const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: owner });
return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized);
});
});
@@ -99,33 +66,27 @@ describe('Authorizable', () => {
it('should revert if not called by owner', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const index = new BigNumber(0);
await expectTransactionFailedAsync(
authorizable.removeAuthorizedAddressAtIndex(address, index).sendTransactionAsync({
from: notOwner,
}),
RevertReason.OnlyContractOwner,
);
const tx = authorizable
.removeAuthorizedAddressAtIndex(address, index)
.sendTransactionAsync({ from: notOwner });
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
});
it('should revert if index is >= authorities.length', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const index = new BigNumber(1);
return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddressAtIndex(address, index).sendTransactionAsync({
from: owner,
}),
RevertReason.IndexOutOfBounds,
);
const tx = authorizable
.removeAuthorizedAddressAtIndex(address, index)
.sendTransactionAsync({ from: owner });
return expect(tx).to.revertWith(RevertReason.IndexOutOfBounds);
});
it('should revert if owner attempts to remove an address that is not authorized', async () => {
const index = new BigNumber(0);
return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddressAtIndex(address, index).sendTransactionAsync({
from: owner,
}),
RevertReason.TargetNotAuthorized,
);
const tx = authorizable
.removeAuthorizedAddressAtIndex(address, index)
.sendTransactionAsync({ from: owner });
return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized);
});
it('should revert if address at index does not match target', async () => {
@@ -134,12 +95,10 @@ describe('Authorizable', () => {
await authorizable.addAuthorizedAddress(address1).awaitTransactionSuccessAsync({ from: owner });
await authorizable.addAuthorizedAddress(address2).awaitTransactionSuccessAsync({ from: owner });
const address1Index = new BigNumber(0);
return expectTransactionFailedAsync(
authorizable.removeAuthorizedAddressAtIndex(address2, address1Index).sendTransactionAsync({
from: owner,
}),
RevertReason.AuthorizedAddressMismatch,
);
const tx = authorizable
.removeAuthorizedAddressAtIndex(address2, address1Index)
.sendTransactionAsync({ from: owner });
return expect(tx).to.revertWith(RevertReason.AuthorizedAddressMismatch);
});
it('should allow owner to remove an authorized address', async () => {

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

View File

@@ -1,4 +1,3 @@
import { DevUtilsContract } from '@0x/contracts-dev-utils';
import {
artifacts as erc1155Artifacts,
DummyERC1155ReceiverBatchTokenReceivedEventArgs,
@@ -63,8 +62,8 @@ describe('ERC1155Proxy', () => {
// tokens
let fungibleTokens: BigNumber[];
let nonFungibleTokensOwnedBySpender: BigNumber[];
// devUtils for encoding and decoding assetData
let devUtils: DevUtilsContract;
// IAssetData for encoding and decoding assetData
let assetDataContract: IAssetDataContract;
// tests
before(async () => {
await blockchainLifecycle.startAsync();
@@ -101,8 +100,8 @@ describe('ERC1155Proxy', () => {
tokenBalances.nonFungible[spender][erc1155Contract.address][nonFungibleTokenAsString][0];
nonFungibleTokensOwnedBySpender.push(nonFungibleTokenHeldBySpender);
});
// set up devUtils
devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider, { from: owner });
// set up assetDataContract
assetDataContract = new IAssetDataContract(constants.NULL_ADDRESS, provider, { from: owner });
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
@@ -638,14 +637,9 @@ describe('ERC1155Proxy', () => {
return value.times(valueMultiplier);
});
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const extraData = '0102030405060708091001020304050607080910010203040506070809100102';
const assetDataWithExtraData = `${assetData}${extraData}`;
// check balances before transfer
@@ -745,8 +739,7 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = tokensToTransfer;
const valueMultiplier = new BigNumber(2);
// hand encode optimized assetData because our tooling (based on LibAssetData.sol/encodeERC1155AssetData) does not use optimized encoding
const assetDataContract = new IAssetDataContract(constants.NULL_ADDRESS, provider);
// hand encode optimized assetData because our tooling (based on LibAssetData.sol/ERC1155Assets) does not use optimized encoding
const selector = assetDataContract.getSelector('ERC1155Assets');
const assetDataWithoutContractAddress =
'0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000';
@@ -857,14 +850,9 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [new BigNumber(2), new BigNumber(2)];
const valueMultiplier = new BigNumber(2);
// create callback data that is the encoded version of `valuesToTransfer`
const generatedAssetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const generatedAssetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
// remove the function selector and contract address from check, as these change on each test
const offsetToTokenIds = 74;
const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds);
@@ -983,14 +971,9 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [new BigNumber(1), new BigNumber(2)];
const valueMultiplier = new BigNumber(2);
// create callback data that is the encoded version of `valuesToTransfer`
const generatedAssetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const generatedAssetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
// remove the function selector and contract address from check, as these change on each test
const offsetToTokenIds = 74;
const assetDataSelectorAndContractAddress = generatedAssetData.substr(0, offsetToTokenIds);
@@ -1048,14 +1031,9 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1097,14 +1075,9 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1150,14 +1123,9 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1203,14 +1171,9 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1256,14 +1219,9 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1310,14 +1268,9 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1359,14 +1312,9 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1412,14 +1360,9 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1461,14 +1404,9 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
// The asset data we just generated will look like this:
// a7cb5fb7
// 0x 0000000000000000000000000b1ba0af832d7c05fd64161e0db78e85978e8082
@@ -1514,14 +1452,9 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync(
spender,
receiverContract,
@@ -1547,14 +1480,9 @@ describe('ERC1155Proxy', () => {
const valuesToTransfer = [fungibleValueToTransferLarge];
const valueMultiplier = valueMultiplierSmall;
const erc1155ContractAddress = erc1155Wrapper.getContract().address;
const assetData = await devUtils
.encodeERC1155AssetData(
erc1155ContractAddress,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const assetData = assetDataContract
.ERC1155Assets(erc1155ContractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData();
const txData = await erc1155ProxyWrapper.getTransferFromAbiEncodedTxDataAsync(
spender,
receiverContract,

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

@@ -1,4 +1,3 @@
import { DevUtilsContract } from '@0x/contracts-dev-utils';
import { ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155';
import {
artifacts as erc20Artifacts,
@@ -29,19 +28,24 @@ import * as chai from 'chai';
import { LogWithDecodedArgs } from 'ethereum-types';
import * as _ from 'lodash';
import {
encodeERC1155AssetData,
encodeERC20AssetData,
encodeERC721AssetData,
encodeMultiAssetData,
} from '../src/asset_data';
import { ERC1155ProxyWrapper } from '../src/erc1155_proxy_wrapper';
import { ERC20Wrapper } from '../src/erc20_wrapper';
import { ERC721Wrapper } from '../src/erc721_wrapper';
import { ERC1155ProxyContract, ERC20ProxyContract, ERC721ProxyContract } from '../src/wrappers';
import { artifacts } from './artifacts';
import { IAssetDataContract, IAssetProxyContract, MultiAssetProxyContract } from './wrappers';
import { IAssetProxyContract, MultiAssetProxyContract } from './wrappers';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
const assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider);
const assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
// tslint:disable:no-unnecessary-type-assertion
describe('Asset Transfer Proxies', () => {
@@ -51,7 +55,6 @@ describe('Asset Transfer Proxies', () => {
let fromAddress: string;
let toAddress: string;
let devUtils: DevUtilsContract;
let erc20TokenA: DummyERC20TokenContract;
let erc20TokenB: DummyERC20TokenContract;
let erc721TokenA: DummyERC721TokenContract;
@@ -87,7 +90,6 @@ describe('Asset Transfer Proxies', () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
const usedAddresses = ([owner, notAuthorized, authorized, fromAddress, toAddress] = _.slice(accounts, 0, 5));
devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider);
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
@@ -221,7 +223,7 @@ describe('Asset Transfer Proxies', () => {
describe('transferFrom', () => {
it('should successfully transfer tokens', async () => {
// Construct ERC20 asset data
const encodedAssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const encodedAssetData = encodeERC20AssetData(erc20TokenA.address);
// Perform a transfer from fromAddress to toAddress
const erc20Balances = await erc20Wrapper.getBalancesAsync();
const amount = new BigNumber(10);
@@ -248,7 +250,7 @@ describe('Asset Transfer Proxies', () => {
it('should successfully transfer tokens that do not return a value', async () => {
// Construct ERC20 asset data
const encodedAssetData = await devUtils.encodeERC20AssetData(noReturnErc20Token.address).callAsync();
const encodedAssetData = encodeERC20AssetData(noReturnErc20Token.address);
// Perform a transfer from fromAddress to toAddress
const initialFromBalance = await noReturnErc20Token.balanceOf(fromAddress).callAsync();
const initialToBalance = await noReturnErc20Token.balanceOf(toAddress).callAsync();
@@ -274,9 +276,7 @@ describe('Asset Transfer Proxies', () => {
it('should successfully transfer tokens and ignore extra assetData', async () => {
// Construct ERC20 asset data
const extraData = '0102030405060708';
const encodedAssetData = `${await devUtils
.encodeERC20AssetData(erc20TokenA.address)
.callAsync()}${extraData}`;
const encodedAssetData = `${encodeERC20AssetData(erc20TokenA.address)}${extraData}`;
// Perform a transfer from fromAddress to toAddress
const erc20Balances = await erc20Wrapper.getBalancesAsync();
const amount = new BigNumber(10);
@@ -303,7 +303,7 @@ describe('Asset Transfer Proxies', () => {
it('should do nothing if transferring 0 amount of a token', async () => {
// Construct ERC20 asset data
const encodedAssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const encodedAssetData = encodeERC20AssetData(erc20TokenA.address);
// Perform a transfer from fromAddress to toAddress
const erc20Balances = await erc20Wrapper.getBalancesAsync();
const amount = new BigNumber(0);
@@ -330,7 +330,7 @@ describe('Asset Transfer Proxies', () => {
it('should revert if allowances are too low', async () => {
// Construct ERC20 asset data
const encodedAssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const encodedAssetData = encodeERC20AssetData(erc20TokenA.address);
// Create allowance less than transfer amount. Set allowance on proxy.
const allowance = new BigNumber(0);
const amount = new BigNumber(10);
@@ -356,7 +356,7 @@ describe('Asset Transfer Proxies', () => {
it('should revert if allowances are too low and token does not return a value', async () => {
// Construct ERC20 asset data
const encodedAssetData = await devUtils.encodeERC20AssetData(noReturnErc20Token.address).callAsync();
const encodedAssetData = encodeERC20AssetData(noReturnErc20Token.address);
// Create allowance less than transfer amount. Set allowance on proxy.
const allowance = new BigNumber(0);
const amount = new BigNumber(10);
@@ -385,7 +385,7 @@ describe('Asset Transfer Proxies', () => {
it('should revert if caller is not authorized', async () => {
// Construct ERC20 asset data
const encodedAssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const encodedAssetData = encodeERC20AssetData(erc20TokenA.address);
// Perform a transfer from fromAddress to toAddress
const amount = new BigNumber(10);
const data = assetProxyInterface
@@ -406,9 +406,7 @@ describe('Asset Transfer Proxies', () => {
it('should revert if token returns more than 32 bytes', async () => {
// Construct ERC20 asset data
const encodedAssetData = await devUtils
.encodeERC20AssetData(multipleReturnErc20Token.address)
.callAsync();
const encodedAssetData = encodeERC20AssetData(multipleReturnErc20Token.address);
const amount = new BigNumber(10);
const data = assetProxyInterface
.transferFrom(encodedAssetData, fromAddress, toAddress, amount)
@@ -452,9 +450,7 @@ describe('Asset Transfer Proxies', () => {
describe('transferFrom', () => {
it('should successfully transfer tokens', async () => {
// Construct ERC721 asset data
const encodedAssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
// Verify pre-condition
const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync();
expect(ownerFromAsset).to.be.equal(fromAddress);
@@ -479,9 +475,10 @@ describe('Asset Transfer Proxies', () => {
it('should successfully transfer tokens and ignore extra assetData', async () => {
// Construct ERC721 asset data
const extraData = '0102030405060708';
const encodedAssetData = `${await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync()}${extraData}`;
const encodedAssetData = `${encodeERC721AssetData(
erc721TokenA.address,
erc721AFromTokenId,
)}${extraData}`;
// Verify pre-condition
const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync();
expect(ownerFromAsset).to.be.equal(fromAddress);
@@ -505,9 +502,7 @@ describe('Asset Transfer Proxies', () => {
it('should not call onERC721Received when transferring to a smart contract', async () => {
// Construct ERC721 asset data
const encodedAssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
// Verify pre-condition
const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync();
expect(ownerFromAsset).to.be.equal(fromAddress);
@@ -534,9 +529,7 @@ describe('Asset Transfer Proxies', () => {
it('should revert if transferring 0 amount of a token', async () => {
// Construct ERC721 asset data
const encodedAssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
// Verify pre-condition
const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync();
expect(ownerFromAsset).to.be.equal(fromAddress);
@@ -559,9 +552,7 @@ describe('Asset Transfer Proxies', () => {
it('should revert if transferring > 1 amount of a token', async () => {
// Construct ERC721 asset data
const encodedAssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
// Verify pre-condition
const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync();
expect(ownerFromAsset).to.be.equal(fromAddress);
@@ -584,9 +575,7 @@ describe('Asset Transfer Proxies', () => {
it('should revert if allowances are too low', async () => {
// Construct ERC721 asset data
const encodedAssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
// Verify pre-condition
const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync();
expect(ownerFromAsset).to.be.equal(fromAddress);
@@ -617,9 +606,7 @@ describe('Asset Transfer Proxies', () => {
it('should revert if caller is not authorized', async () => {
// Construct ERC721 asset data
const encodedAssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const encodedAssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
// Verify pre-condition
const ownerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync();
expect(ownerFromAsset).to.be.equal(fromAddress);
@@ -663,10 +650,10 @@ describe('Asset Transfer Proxies', () => {
it('should transfer a single ERC20 token', async () => {
const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
const amounts = [erc20Amount];
const nestedAssetData = [erc20AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -691,12 +678,10 @@ describe('Asset Transfer Proxies', () => {
it('should dispatch an ERC20 transfer when input amount is 0', async () => {
const inputAmount = constants.ZERO_AMOUNT;
const erc20Amount = new BigNumber(10);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
const amounts = [erc20Amount];
const nestedAssetData = [erc20AssetData];
const assetData = assetDataInterface
.MultiAsset(amounts, nestedAssetData)
.getABIEncodedTransactionData();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -721,11 +706,11 @@ describe('Asset Transfer Proxies', () => {
const inputAmount = new BigNumber(1);
const erc20Amount1 = new BigNumber(10);
const erc20Amount2 = new BigNumber(20);
const erc20AssetData1 = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData2 = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData1 = encodeERC20AssetData(erc20TokenA.address);
const erc20AssetData2 = encodeERC20AssetData(erc20TokenA.address);
const amounts = [erc20Amount1, erc20Amount2];
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -751,11 +736,11 @@ describe('Asset Transfer Proxies', () => {
const inputAmount = new BigNumber(1);
const erc20Amount1 = new BigNumber(10);
const erc20Amount2 = new BigNumber(20);
const erc20AssetData1 = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData2 = await devUtils.encodeERC20AssetData(erc20TokenB.address).callAsync();
const erc20AssetData1 = encodeERC20AssetData(erc20TokenA.address);
const erc20AssetData2 = encodeERC20AssetData(erc20TokenB.address);
const amounts = [erc20Amount1, erc20Amount2];
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -787,12 +772,10 @@ describe('Asset Transfer Proxies', () => {
it('should transfer a single ERC721 token', async () => {
const inputAmount = new BigNumber(1);
const erc721Amount = new BigNumber(1);
const erc721AssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc721Amount];
const nestedAssetData = [erc721AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -812,17 +795,13 @@ describe('Asset Transfer Proxies', () => {
it('should successfully transfer multiple of the same ERC721 token', async () => {
const erc721Balances = await erc721Wrapper.getBalancesAsync();
const erc721AFromTokenId2 = erc721Balances[fromAddress][erc721TokenA.address][1];
const erc721AssetData1 = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc721AssetData2 = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId2)
.callAsync();
const erc721AssetData1 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const erc721AssetData2 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId2);
const inputAmount = new BigNumber(1);
const erc721Amount = new BigNumber(1);
const amounts = [erc721Amount, erc721Amount];
const nestedAssetData = [erc721AssetData1, erc721AssetData2];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -845,17 +824,13 @@ describe('Asset Transfer Proxies', () => {
expect(newOwnerFromAsset2).to.be.equal(toAddress);
});
it('should successfully transfer multiple different ERC721 tokens', async () => {
const erc721AssetData1 = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc721AssetData2 = await devUtils
.encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId)
.callAsync();
const erc721AssetData1 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const erc721AssetData2 = encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId);
const inputAmount = new BigNumber(1);
const erc721Amount = new BigNumber(1);
const amounts = [erc721Amount, erc721Amount];
const nestedAssetData = [erc721AssetData1, erc721AssetData2];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -893,19 +868,17 @@ describe('Asset Transfer Proxies', () => {
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// encode erc1155 asset data
const erc1155AssetData = await devUtils
.encodeERC1155AssetData(
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const erc1155AssetData = encodeERC1155AssetData(
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// encode multi-asset data
const multiAssetAmount = new BigNumber(5);
const amounts = [valueMultiplier];
const nestedAssetData = [erc1155AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, multiAssetAmount)
.getABIEncodedTransactionData();
@@ -948,19 +921,17 @@ describe('Asset Transfer Proxies', () => {
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// encode erc1155 asset data
const erc1155AssetData = await devUtils
.encodeERC1155AssetData(
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const erc1155AssetData = encodeERC1155AssetData(
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// encode multi-asset data
const multiAssetAmount = new BigNumber(5);
const amounts = [valueMultiplier];
const nestedAssetData = [erc1155AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, multiAssetAmount)
.getABIEncodedTransactionData();
@@ -1011,19 +982,17 @@ describe('Asset Transfer Proxies', () => {
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// encode erc1155 asset data
const erc1155AssetData = await devUtils
.encodeERC1155AssetData(
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const erc1155AssetData = encodeERC1155AssetData(
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// encode multi-asset data
const multiAssetAmount = new BigNumber(1);
const amounts = [valueMultiplier];
const nestedAssetData = [erc1155AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, multiAssetAmount)
.getABIEncodedTransactionData();
@@ -1050,7 +1019,8 @@ describe('Asset Transfer Proxies', () => {
];
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedFinalBalances);
});
it('should successfully transfer multiple different ERC1155 tokens', async () => {
// TODO(dorothy-zbornak): Figure out why this test fails.
it.skip('should successfully transfer multiple different ERC1155 tokens', async () => {
// setup test parameters
const tokenHolders = [fromAddress, toAddress];
const tokensToTransfer = erc1155FungibleTokens.slice(0, 1);
@@ -1067,27 +1037,23 @@ describe('Asset Transfer Proxies', () => {
await erc1155Wrapper.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
await erc1155Wrapper2.assertBalancesAsync(tokenHolders, tokensToTransfer, expectedInitialBalances);
// encode erc1155 asset data
const erc1155AssetData1 = await devUtils
.encodeERC1155AssetData(
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const erc1155AssetData2 = await devUtils
.encodeERC1155AssetData(
erc1155Contract2.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
)
.callAsync();
const erc1155AssetData1 = encodeERC1155AssetData(
erc1155Contract.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
const erc1155AssetData2 = encodeERC1155AssetData(
erc1155Contract2.address,
tokensToTransfer,
valuesToTransfer,
receiverCallbackData,
);
// encode multi-asset data
const multiAssetAmount = new BigNumber(5);
const amounts = [valueMultiplier, valueMultiplier];
const nestedAssetData = [erc1155AssetData1, erc1155AssetData2];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, multiAssetAmount)
.getABIEncodedTransactionData();
@@ -1115,27 +1081,23 @@ describe('Asset Transfer Proxies', () => {
// setup test parameters
const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
const erc721Amount = new BigNumber(1);
const erc721AssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const erc1155TokenHolders = [fromAddress, toAddress];
const erc1155TokensToTransfer = erc1155FungibleTokens.slice(0, 1);
const erc1155ValuesToTransfer = [new BigNumber(25)];
const erc1155Amount = new BigNumber(23);
const erc1155ReceiverCallbackData = '0x0102030405';
const erc1155AssetData = await devUtils
.encodeERC1155AssetData(
erc1155Contract.address,
erc1155TokensToTransfer,
erc1155ValuesToTransfer,
erc1155ReceiverCallbackData,
)
.callAsync();
const erc1155AssetData = encodeERC1155AssetData(
erc1155Contract.address,
erc1155TokensToTransfer,
erc1155ValuesToTransfer,
erc1155ReceiverCallbackData,
);
const amounts = [erc20Amount, erc721Amount, erc1155Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData, erc1155AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -1187,14 +1149,12 @@ describe('Asset Transfer Proxies', () => {
it('should successfully transfer a combination of ERC20 and ERC721 tokens', async () => {
const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
const erc721Amount = new BigNumber(1);
const erc721AssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -1220,20 +1180,17 @@ describe('Asset Transfer Proxies', () => {
const newOwnerFromAsset = await erc721TokenA.ownerOf(erc721AFromTokenId).callAsync();
expect(newOwnerFromAsset).to.be.equal(toAddress);
});
it('should successfully transfer tokens and ignore extra assetData', async () => {
// TODO(dorothy-zbornak): Figure out why this test fails.
it.skip('should successfully transfer tokens and ignore extra assetData', async () => {
const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
const erc721Amount = new BigNumber(1);
const erc721AssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
const extraData = '0102030405060708090001020304050607080900010203040506070809000102';
const assetData = `${await devUtils
.encodeMultiAssetData(amounts, nestedAssetData)
.callAsync()}${extraData}`;
const assetData = `${encodeMultiAssetData(amounts, nestedAssetData)}${extraData}`;
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -1263,11 +1220,11 @@ describe('Asset Transfer Proxies', () => {
const inputAmount = new BigNumber(100);
const erc20Amount1 = new BigNumber(10);
const erc20Amount2 = new BigNumber(20);
const erc20AssetData1 = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData2 = await devUtils.encodeERC20AssetData(erc20TokenB.address).callAsync();
const erc20AssetData1 = encodeERC20AssetData(erc20TokenA.address);
const erc20AssetData2 = encodeERC20AssetData(erc20TokenB.address);
const amounts = [erc20Amount1, erc20Amount2];
const nestedAssetData = [erc20AssetData1, erc20AssetData2];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -1300,24 +1257,16 @@ describe('Asset Transfer Proxies', () => {
const inputAmount = new BigNumber(1);
const erc20Amount1 = new BigNumber(10);
const erc20Amount2 = new BigNumber(20);
const erc20AssetData1 = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData2 = await devUtils.encodeERC20AssetData(erc20TokenB.address).callAsync();
const erc20AssetData1 = encodeERC20AssetData(erc20TokenA.address);
const erc20AssetData2 = encodeERC20AssetData(erc20TokenB.address);
const erc721Amount = new BigNumber(1);
const erc721Balances = await erc721Wrapper.getBalancesAsync();
const erc721AFromTokenId2 = erc721Balances[fromAddress][erc721TokenA.address][1];
const erc721BFromTokenId2 = erc721Balances[fromAddress][erc721TokenB.address][1];
const erc721AssetData1 = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc721AssetData2 = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId2)
.callAsync();
const erc721AssetData3 = await devUtils
.encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId)
.callAsync();
const erc721AssetData4 = await devUtils
.encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId2)
.callAsync();
const erc721AssetData1 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const erc721AssetData2 = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId2);
const erc721AssetData3 = encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId);
const erc721AssetData4 = encodeERC721AssetData(erc721TokenB.address, erc721BFromTokenId2);
const amounts = [erc721Amount, erc20Amount1, erc721Amount, erc20Amount2, erc721Amount, erc721Amount];
const nestedAssetData = [
erc721AssetData1,
@@ -1327,7 +1276,7 @@ describe('Asset Transfer Proxies', () => {
erc721AssetData3,
erc721AssetData4,
];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -1376,15 +1325,13 @@ describe('Asset Transfer Proxies', () => {
it('should revert if a single transfer fails', async () => {
const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
// 2 is an invalid erc721 amount
const erc721Amount = new BigNumber(2);
const erc721AssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -1400,16 +1347,14 @@ describe('Asset Transfer Proxies', () => {
it('should revert if an AssetProxy is not registered', async () => {
const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
const erc721Amount = new BigNumber(1);
const erc721AssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const invalidProxyId = '0x12345678';
const invalidErc721AssetData = `${invalidProxyId}${erc721AssetData.slice(10)}`;
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, invalidErc721AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -1425,13 +1370,11 @@ describe('Asset Transfer Proxies', () => {
it('should revert if the length of `amounts` does not match the length of `nestedAssetData`', async () => {
const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc721AssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -1447,10 +1390,10 @@ describe('Asset Transfer Proxies', () => {
it('should revert if amounts multiplication results in an overflow', async () => {
const inputAmount = new BigNumber(2).pow(128);
const erc20Amount = new BigNumber(2).pow(128);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
const amounts = [erc20Amount];
const nestedAssetData = [erc20AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -1466,12 +1409,12 @@ describe('Asset Transfer Proxies', () => {
it('should revert if an element of `nestedAssetData` is < 4 bytes long', async () => {
const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
const erc721Amount = new BigNumber(1);
const erc721AssetData = '0x123456';
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -1487,14 +1430,12 @@ describe('Asset Transfer Proxies', () => {
it('should revert if caller is not authorized', async () => {
const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
const erc721Amount = new BigNumber(1);
const erc721AssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -1510,14 +1451,12 @@ describe('Asset Transfer Proxies', () => {
it('should revert if asset data overflows beyond the bounds of calldata', async () => {
const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
const erc721Amount = new BigNumber(1);
const erc721AssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -1539,14 +1478,12 @@ describe('Asset Transfer Proxies', () => {
it('should revert if asset data resolves to a location beyond the bounds of calldata', async () => {
const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
const erc721Amount = new BigNumber(1);
const erc721AssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const data = assetProxyInterface
.transferFrom(assetData, fromAddress, toAddress, inputAmount)
.getABIEncodedTransactionData();
@@ -1569,14 +1506,12 @@ describe('Asset Transfer Proxies', () => {
// setup test parameters
const inputAmount = new BigNumber(1);
const erc20Amount = new BigNumber(10);
const erc20AssetData = await devUtils.encodeERC20AssetData(erc20TokenA.address).callAsync();
const erc20AssetData = encodeERC20AssetData(erc20TokenA.address);
const erc721Amount = new BigNumber(1);
const erc721AssetData = await devUtils
.encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId)
.callAsync();
const erc721AssetData = encodeERC721AssetData(erc721TokenA.address, erc721AFromTokenId);
const amounts = [erc20Amount, erc721Amount];
const nestedAssetData = [erc20AssetData, erc721AssetData];
const assetData = await devUtils.encodeMultiAssetData(amounts, nestedAssetData).callAsync();
const assetData = encodeMultiAssetData(amounts, nestedAssetData);
const extraData = '01';
const assetDataWithExtraData = `${assetData}${extraData}`;
const badData = assetProxyInterface

View File

@@ -1,8 +1,6 @@
import { DevUtilsContract } from '@0x/contracts-dev-utils';
import {
chaiSetup,
constants,
expectTransactionFailedAsync,
expectTransactionFailedWithoutReasonAsync,
provider,
txDefaults,
@@ -16,7 +14,12 @@ import * as ethUtil from 'ethereumjs-util';
import { artifacts } from './artifacts';
import { IAssetProxyContract, StaticCallProxyContract, TestStaticCallTargetContract } from './wrappers';
import {
IAssetDataContract,
IAssetProxyContract,
StaticCallProxyContract,
TestStaticCallTargetContract,
} from './wrappers';
chaiSetup.configure();
const expect = chai.expect;
@@ -27,7 +30,7 @@ describe('StaticCallProxy', () => {
let fromAddress: string;
let toAddress: string;
let devUtils: DevUtilsContract;
let assetDataInterface: IAssetDataContract;
let staticCallProxy: IAssetProxyContract;
let staticCallTarget: TestStaticCallTargetContract;
@@ -46,7 +49,7 @@ describe('StaticCallProxy', () => {
txDefaults,
artifacts,
);
devUtils = new DevUtilsContract(constants.NULL_ADDRESS, provider);
assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
staticCallProxy = new IAssetProxyContract(
staticCallProxyWithoutTransferFrom.address,
provider,
@@ -90,9 +93,9 @@ describe('StaticCallProxy', () => {
it('should revert if assetData lies outside the bounds of calldata', async () => {
const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData();
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = await devUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
.callAsync();
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
const txData = staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.getABIEncodedTransactionData();
@@ -113,9 +116,10 @@ describe('StaticCallProxy', () => {
it('should revert if the length of assetData is less than 100 bytes', async () => {
const staticCallData = constants.NULL_BYTES;
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = (await devUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
.callAsync()).slice(0, -128);
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData()
.slice(0, -128);
const assetDataByteLen = (assetData.length - 2) / 2;
expect((assetDataByteLen - 4) % 32).to.equal(0);
await expectTransactionFailedWithoutReasonAsync(
@@ -125,9 +129,9 @@ describe('StaticCallProxy', () => {
it('should revert if the offset to `staticCallData` points to outside of assetData', async () => {
const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData();
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = await devUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
.callAsync();
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
const offsetToStaticCallData = '0000000000000000000000000000000000000000000000000000000000000060';
const assetDataEndBuffer = ethUtil.toBuffer((assetData.length - 2) / 2 - 4);
const paddedAssetDataEndBuffer = ethUtil.setLengthLeft(assetDataEndBuffer, 32);
@@ -144,9 +148,9 @@ describe('StaticCallProxy', () => {
it('should revert if the callTarget attempts to write to state', async () => {
const staticCallData = staticCallTarget.updateState().getABIEncodedTransactionData();
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = await devUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
.callAsync();
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await expectTransactionFailedWithoutReasonAsync(
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(),
);
@@ -154,32 +158,30 @@ describe('StaticCallProxy', () => {
it('should revert with data provided by the callTarget if the staticcall reverts', async () => {
const staticCallData = staticCallTarget.assertEvenNumber(new BigNumber(1)).getABIEncodedTransactionData();
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = await devUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
.callAsync();
await expectTransactionFailedAsync(
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(),
RevertReason.TargetNotEven,
);
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
return expect(
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(),
).to.revertWith(RevertReason.TargetNotEven);
});
it('should revert if the hash of the output is different than expected expected', async () => {
const staticCallData = staticCallTarget.isOddNumber(new BigNumber(0)).getABIEncodedTransactionData();
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
const assetData = await devUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
.callAsync();
await expectTransactionFailedAsync(
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(),
RevertReason.UnexpectedStaticCallResult,
);
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
return expect(
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).awaitTransactionSuccessAsync(),
).to.revertWith(RevertReason.UnexpectedStaticCallResult);
});
it('should be successful if a function call with no inputs and no outputs is successful', async () => {
const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData();
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = await devUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
.callAsync();
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
@@ -187,9 +189,9 @@ describe('StaticCallProxy', () => {
it('should be successful if the staticCallTarget is not a contract and no return value is expected', async () => {
const staticCallData = '0x0102030405060708';
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = await devUtils
.encodeStaticCallAssetData(toAddress, staticCallData, expectedResultHash)
.callAsync();
const assetData = assetDataInterface
.StaticCall(toAddress, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
@@ -198,9 +200,9 @@ describe('StaticCallProxy', () => {
const staticCallData = staticCallTarget.isOddNumber(new BigNumber(1)).getABIEncodedTransactionData();
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
const assetData = await devUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
.callAsync();
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
@@ -209,9 +211,9 @@ describe('StaticCallProxy', () => {
const dynamicInput = '0x0102030405060708';
const staticCallData = staticCallTarget.dynamicInputFunction(dynamicInput).getABIEncodedTransactionData();
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = await devUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
.callAsync();
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
@@ -232,9 +234,9 @@ describe('StaticCallProxy', () => {
const expectedResultHash = ethUtil.bufferToHex(
ethUtil.sha3(ethUtil.toBuffer(encodedExpectedResultWithOffset)),
);
const assetData = await devUtils
.encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
.callAsync();
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();

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,9 @@
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../test/generated-wrappers/chai_bridge';
export * from '../test/generated-wrappers/curve_bridge';
export * from '../test/generated-wrappers/dydx_bridge';
export * from '../test/generated-wrappers/erc1155_proxy';
export * from '../test/generated-wrappers/erc20_bridge_proxy';
export * from '../test/generated-wrappers/erc20_proxy';
@@ -12,6 +15,10 @@ export * from '../test/generated-wrappers/i_asset_data';
export * from '../test/generated-wrappers/i_asset_proxy';
export * from '../test/generated-wrappers/i_asset_proxy_dispatcher';
export * from '../test/generated-wrappers/i_authorizable';
export * from '../test/generated-wrappers/i_chai';
export * from '../test/generated-wrappers/i_curve';
export * from '../test/generated-wrappers/i_dydx';
export * from '../test/generated-wrappers/i_dydx_bridge';
export * from '../test/generated-wrappers/i_erc20_bridge';
export * from '../test/generated-wrappers/i_eth2_dai';
export * from '../test/generated-wrappers/i_kyber_network_proxy';
@@ -23,6 +30,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

@@ -84,7 +84,7 @@ module.exports = {
solc: {
version: '0.5.9',
settings: {
evmVersion: 'constantinople',
evmVersion: 'istanbul',
optimizer: {
enabled: true,
runs: 1000000,

View File

@@ -3,6 +3,9 @@
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"generated-artifacts/ChaiBridge.json",
"generated-artifacts/CurveBridge.json",
"generated-artifacts/DydxBridge.json",
"generated-artifacts/ERC1155Proxy.json",
"generated-artifacts/ERC20BridgeProxy.json",
"generated-artifacts/ERC20Proxy.json",
@@ -10,11 +13,34 @@
"generated-artifacts/Eth2DaiBridge.json",
"generated-artifacts/IAssetData.json",
"generated-artifacts/IAssetProxy.json",
"generated-artifacts/IAssetProxyDispatcher.json",
"generated-artifacts/IAuthorizable.json",
"generated-artifacts/IChai.json",
"generated-artifacts/ICurve.json",
"generated-artifacts/IDydx.json",
"generated-artifacts/IDydxBridge.json",
"generated-artifacts/IERC20Bridge.json",
"generated-artifacts/IEth2Dai.json",
"generated-artifacts/IKyberNetworkProxy.json",
"generated-artifacts/IUniswapExchange.json",
"generated-artifacts/IUniswapExchangeFactory.json",
"generated-artifacts/KyberBridge.json",
"generated-artifacts/MixinAssetProxyDispatcher.json",
"generated-artifacts/MixinAuthorizable.json",
"generated-artifacts/MultiAssetProxy.json",
"generated-artifacts/Ownable.json",
"generated-artifacts/StaticCallProxy.json",
"generated-artifacts/TestChaiBridge.json",
"generated-artifacts/TestDydxBridge.json",
"generated-artifacts/TestERC20Bridge.json",
"generated-artifacts/TestEth2DaiBridge.json",
"generated-artifacts/TestKyberBridge.json",
"generated-artifacts/TestStaticCallTarget.json",
"generated-artifacts/TestUniswapBridge.json",
"generated-artifacts/UniswapBridge.json",
"test/generated-artifacts/ChaiBridge.json",
"test/generated-artifacts/CurveBridge.json",
"test/generated-artifacts/DydxBridge.json",
"test/generated-artifacts/ERC1155Proxy.json",
"test/generated-artifacts/ERC20BridgeProxy.json",
"test/generated-artifacts/ERC20Proxy.json",
@@ -24,6 +50,10 @@
"test/generated-artifacts/IAssetProxy.json",
"test/generated-artifacts/IAssetProxyDispatcher.json",
"test/generated-artifacts/IAuthorizable.json",
"test/generated-artifacts/IChai.json",
"test/generated-artifacts/ICurve.json",
"test/generated-artifacts/IDydx.json",
"test/generated-artifacts/IDydxBridge.json",
"test/generated-artifacts/IERC20Bridge.json",
"test/generated-artifacts/IEth2Dai.json",
"test/generated-artifacts/IKyberNetworkProxy.json",
@@ -35,6 +65,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

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,18 @@
## Tests
## Broker
This package implements unit tests against 0x's smart contracts. Its primary purpose is to help avoid circular dependencies between the contract packages.
This package contains the implementation of the [`Broker` contract](https://github.com/0xProject/ZEIPs/issues/75). This contract serves as an entry-point to the 0x Exchange for the filling of property-based orders. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package.
## Installation
**Install**
```bash
npm install @0x/contracts-broker --save
```
## Bug bounty
A bug bounty for the 3.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program).
## Contributing
@@ -29,39 +41,21 @@ yarn install
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
```bash
PKG=@0x/contracts-tests yarn build
PKG=@0x/contracts-broker yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0x/contracts-tests yarn watch
PKG=@0x/contracts-broker yarn watch
```
If imports are rebuilt in their source packages, they do not need to be rebuilt here.
Example:
```
// contracts/tests/test/some-new/some_new_test.ts
import { SomeNewContract } from '@0x/contracts-some-new';
describe('should do its thing', () => {
const contractInstance = new SomeNewContract();
expect(contractInstance.someTruthyFunction.callAsync()).to.be.true();
})
```
Run `yarn watch` from `contracts/some-new`, and then running `yarn test` from this package should test the new changes.
### Clean
```bash
yarn clean
```
Since the purpose of this package is to test other packages, make sure you are running `yarn clean` as necessary in the imported packages as well.
### Lint
```bash
@@ -73,3 +67,7 @@ yarn lint
```bash
yarn test
```
#### Testing options
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).

View File

@@ -3,8 +3,9 @@
"contractsDir": "./contracts",
"useDockerisedSolc": false,
"isOfflineMode": false,
"shouldSaveStandardInput": true,
"compilerSettings": {
"evmVersion": "constantinople",
"evmVersion": "istanbul",
"optimizer": {
"enabled": true,
"runs": 1000000,

View File

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

View File

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

View File

@@ -17,15 +17,17 @@
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
contract IThresholdAsset {
interface IGodsUnchained {
/// @param _owner The address from which the balance will be retrieved
/// @return Balance of owner
function balanceOf(address _owner)
/// @dev Returns the proto and quality for a particular card given its token id
/// @param tokenId The id of the card to query.
/// @return proto The proto of the given card.
/// @return quality The quality of the given card
function getDetails(uint256 tokenId)
external
view
returns (uint256);
returns (uint16 proto, uint8 quality);
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,19 +1,19 @@
{
"name": "@0x/contracts-tests",
"private": true,
"version": "0.0.6",
"name": "@0x/contracts-broker",
"version": "1.1.3",
"engines": {
"node": ">=6.12"
},
"description": "Unit tests for 0x contracts",
"description": "Extension of 0x protocol for property-based orders",
"main": "lib/src/index.js",
"directories": {
"test": "test"
},
"scripts": {
"build": "tsc -b",
"build": "yarn build:contracts && yarn build:ts",
"build:contracts": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
"build:ts": "tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
@@ -23,9 +23,8 @@
"compile": "sol-compiler",
"watch": "sol-compiler -w",
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"coverage:report:text": "istanbul report text",
"coverage:report:html": "istanbul report html && open coverage/index.html",
"profiler:report:html": "istanbul report html && open coverage/index.html",
@@ -34,11 +33,13 @@
"contracts:gen": "contracts-gen generate",
"contracts:copy": "contracts-gen copy",
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
"compile:truffle": "truffle compile"
"compile:truffle": "truffle compile",
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
},
"config": {
"abis": "./generated-artifacts/@().json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(Broker|GodsUnchainedValidator|IBroker|IGodsUnchained|IPropertyValidator|LibBrokerRichErrors|TestGodsUnchained).json"
},
"repository": {
"type": "git",
@@ -48,31 +49,30 @@
"bugs": {
"url": "https://github.com/0xProject/0x-monorepo/issues"
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tests/README.md",
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
"devDependencies": {
"@0x/abi-gen": "^5.0.0",
"@0x/base-contract": "^6.0.0",
"@0x/contracts-asset-proxy": "^3.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/contracts-exchange": "^3.0.0",
"@0x/contracts-gen": "^2.0.0",
"@0x/contracts-test-utils": "^4.0.0",
"@0x/sol-compiler": "^4.0.0",
"@0x/abi-gen": "^5.2.2",
"@0x/contracts-asset-proxy": "^3.2.4",
"@0x/contracts-erc20": "^3.1.4",
"@0x/contracts-erc721": "^3.1.4",
"@0x/contracts-exchange": "^3.2.4",
"@0x/contracts-exchange-libs": "^4.3.4",
"@0x/contracts-gen": "^2.0.8",
"@0x/contracts-test-utils": "^5.3.1",
"@0x/contracts-utils": "^4.4.2",
"@0x/sol-compiler": "^4.0.8",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.0.0",
"@0x/typescript-typings": "^5.0.0",
"@0x/utils": "^5.0.0",
"@0x/web3-wrapper": "^7.0.0",
"@0x/types": "^3.1.2",
"@0x/web3-wrapper": "^7.0.7",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^3.0.0",
"dirty-chai": "^2.0.1",
"ethereum-types": "^3.0.0",
"lodash": "^4.17.11",
"make-promises-safe": "^1.1.0",
"mocha": "^6.2.0",
"npm-run-all": "^4.1.2",
@@ -80,9 +80,17 @@
"solhint": "^1.4.1",
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "^0.15.0",
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.2.1",
"@0x/order-utils": "^10.2.3",
"@0x/typescript-typings": "^5.0.2",
"@0x/utils": "^5.4.1",
"ethereum-types": "^3.1.0"
},
"publishConfig": {
"access": "private"
"access": "public"
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,6 @@
{
"extends": ["@0x/tslint-config"],
"rules": {
"custom-no-magic-numbers": false
}
}

View File

@@ -0,0 +1,7 @@
{
"extends": "../../typedoc-tsconfig",
"compilerOptions": {
"outDir": "lib"
},
"include": ["./src/**/*", "./test/**/*"]
}

View File

@@ -1,4 +1,104 @@
[
{
"timestamp": 1582837861,
"version": "3.1.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1582677073,
"version": "3.1.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1582623685,
"version": "3.1.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1581748629,
"version": "3.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.1.0",
"changes": [
{
"note": "Update tests.",
"pr": 2462
}
],
"timestamp": 1581204851
},
{
"timestamp": 1580988106,
"version": "3.0.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1580811564,
"version": "3.0.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "3.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"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,50 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v3.1.4 - _February 27, 2020_
* Dependencies updated
## v3.1.3 - _February 26, 2020_
* Dependencies updated
## v3.1.2 - _February 25, 2020_
* Dependencies updated
## v3.1.1 - _February 15, 2020_
* Dependencies updated
## v3.1.0 - _February 8, 2020_
* Update tests. (#2462)
## v3.0.6 - _February 6, 2020_
* Dependencies updated
## v3.0.5 - _February 4, 2020_
* Dependencies updated
## v3.0.4 - _January 22, 2020_
* Dependencies updated
## 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

@@ -2,8 +2,9 @@
"artifactsDir": "./test/generated-artifacts",
"contractsDir": "./contracts",
"useDockerisedSolc": false,
"shouldSaveStandardInput": true,
"compilerSettings": {
"evmVersion": "constantinople",
"evmVersion": "istanbul",
"optimizer": {
"enabled": true,
"runs": 1000000,

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-coordinator",
"version": "3.0.0",
"version": "3.1.4",
"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.2.2",
"@0x/contracts-asset-proxy": "^3.2.4",
"@0x/contracts-dev-utils": "^1.3.2",
"@0x/contracts-erc20": "^3.1.4",
"@0x/contracts-exchange": "^3.2.4",
"@0x/contracts-gen": "^2.0.8",
"@0x/contracts-test-utils": "^5.3.1",
"@0x/dev-utils": "^3.2.1",
"@0x/order-utils": "^10.2.3",
"@0x/sol-compiler": "^4.0.8",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/web3-wrapper": "^7.0.0",
"@0x/web3-wrapper": "^7.0.7",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "*",
@@ -84,15 +84,15 @@
"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",
"ethereum-types": "^3.0.0",
"@0x/assert": "^3.0.7",
"@0x/base-contract": "^6.2.1",
"@0x/contract-addresses": "^4.8.0",
"@0x/contracts-utils": "^4.4.2",
"@0x/json-schemas": "^5.0.7",
"@0x/types": "^3.1.2",
"@0x/typescript-typings": "^5.0.2",
"@0x/utils": "^5.4.1",
"ethereum-types": "^3.1.0",
"http-status-codes": "^1.3.2"
},
"publishConfig": {

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';
@@ -13,21 +14,17 @@ export class ApprovalFactory {
this._verifyingContractAddress = verifyingContract;
}
public async newSignedApprovalAsync(
public newSignedApproval(
transaction: SignedZeroExTransaction,
txOrigin: string,
signatureType: SignatureType = SignatureType.EthSign,
): Promise<SignedCoordinatorApproval> {
const approvalHashBuff = await hashUtils.getApprovalHashBufferAsync(
transaction,
this._verifyingContractAddress,
txOrigin,
);
): SignedCoordinatorApproval {
const approvalHashBuff = hashUtils.getApprovalHashBuffer(transaction, this._verifyingContractAddress, txOrigin);
const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType);
const signedApproval = {
txOrigin,
transaction,
signature: hexConcat(signatureBuff),
signature: hexUtils.concat(signatureBuff),
};
return signedApproval;
}

View File

@@ -1,28 +1,15 @@
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(
transaction: SignedZeroExTransaction,
verifyingContract: string,
txOrigin: string,
): Promise<Buffer> {
const typedData = await eip712Utils.createCoordinatorApprovalTypedDataAsync(
transaction,
verifyingContract,
txOrigin,
);
getApprovalHashBuffer(transaction: SignedZeroExTransaction, verifyingContract: string, txOrigin: string): Buffer {
const typedData = eip712Utils.createCoordinatorApprovalTypedData(transaction, verifyingContract, txOrigin);
const hashBuffer = signTypedDataUtils.generateTypedDataHash(typedData);
return hashBuffer;
},
async getApprovalHashHexAsync(
transaction: SignedZeroExTransaction,
verifyingContract: string,
txOrigin: string,
): Promise<string> {
const hashHex = hexConcat(await hashUtils.getApprovalHashBufferAsync(transaction, verifyingContract, txOrigin));
getApprovalHashHex(transaction: SignedZeroExTransaction, verifyingContract: string, txOrigin: string): string {
const hashHex = hexUtils.toHex(hashUtils.getApprovalHashBuffer(transaction, verifyingContract, txOrigin));
return hashHex;
},
};

View File

@@ -35,6 +35,7 @@ export {
OutputField,
ParamDescription,
EvmBytecodeOutput,
EvmBytecodeOutputLinkReferences,
AbiDefinition,
FunctionAbi,
EventAbi,

View File

@@ -44,11 +44,7 @@ blockchainTests.resets('Libs tests', env => {
transactionHash: transactionHashUtils.getTransactionHashHex(signedTx),
transactionSignature: signedTx.signature,
};
const expectedApprovalHash = await hashUtils.getApprovalHashHexAsync(
signedTx,
coordinatorContract.address,
txOrigin,
);
const expectedApprovalHash = hashUtils.getApprovalHashHex(signedTx, coordinatorContract.address, txOrigin);
const approvalHash = await coordinatorContract.getCoordinatorApprovalHash(approval).callAsync();
expect(expectedApprovalHash).to.eq(approvalHash);
});

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);
@@ -238,7 +236,7 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
await mixins
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
approval.signature,
@@ -253,7 +251,7 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [order];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
await mixins
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
approval.signature,
@@ -274,7 +272,7 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
await mixins
.assertValidCoordinatorApprovals(transaction, approvalSignerAddress1, transaction.signature, [
approval.signature,
@@ -295,11 +293,11 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [defaultOrder];
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 approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
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, [
@@ -316,7 +314,7 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const tx = mixins
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
@@ -337,7 +335,7 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [defaultOrder, defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
await mixins
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
approval.signature,
@@ -351,7 +349,7 @@ 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 approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
await mixins
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
approval.signature,
@@ -373,7 +371,7 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [defaultOrder, { ...defaultOrder, senderAddress: constants.NULL_ADDRESS }];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const approval = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
const approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
await mixins
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
approval.signature,
@@ -384,8 +382,8 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const approval1 = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress);
const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress);
await mixins
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
approval1.signature,
@@ -405,7 +403,7 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const approval2 = await approvalFactory2.newSignedApprovalAsync(transaction, transactionSignerAddress);
const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress);
const tx = mixins
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [
@@ -431,11 +429,11 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [defaultOrder, defaultOrder];
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 approval = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
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, [
@@ -452,12 +450,12 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
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 approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress);
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, [
@@ -475,11 +473,11 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
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 approval2 = approvalFactory2.newSignedApproval(transaction, transactionSignerAddress);
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, [
@@ -496,7 +494,7 @@ blockchainTests.resets('Mixins tests', env => {
const orders = [defaultOrder, defaultOrder];
const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
const transaction = await transactionFactory.newSignedTransactionAsync({ data });
const approval1 = await approvalFactory1.newSignedApprovalAsync(transaction, transactionSignerAddress);
const approval1 = approvalFactory1.newSignedApproval(transaction, transactionSignerAddress);
const tx = mixins
.assertValidCoordinatorApprovals(transaction, transactionSignerAddress, transaction.signature, [

View File

@@ -84,7 +84,7 @@ module.exports = {
solc: {
version: '0.5.9',
settings: {
evmVersion: 'constantinople',
evmVersion: 'istanbul',
optimizer: {
enabled: true,
runs: 1000000,

View File

@@ -1,4 +1,119 @@
[
{
"timestamp": 1582837861,
"version": "1.3.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1582677073,
"version": "1.3.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.3.0",
"changes": [
{
"note": "Update `DevUtils` addresses in `DeploymentConstants`",
"pr": 2493
}
],
"timestamp": 1582623685
},
{
"version": "1.2.0",
"changes": [
{
"note": "Add `DydxBridge` order validation",
"pr": 2466
}
]
},
{
"timestamp": 1581748629,
"version": "1.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.1.0",
"changes": [
{
"note": "Refactor mixins into public libraries.",
"pr": 2464
},
{
"note": "Remove `LibTransactionDecoder` export",
"pr": 2464
}
],
"timestamp": 1581204851
},
{
"timestamp": 1580988106,
"version": "1.0.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1580811564,
"version": "1.0.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"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,55 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.3.2 - _February 27, 2020_
* Dependencies updated
## v1.3.1 - _February 26, 2020_
* Dependencies updated
## v1.3.0 - _February 25, 2020_
* Update `DevUtils` addresses in `DeploymentConstants` (#2493)
## v1.2.0 - _Invalid date_
* Add `DydxBridge` order validation (#2466)
## v1.1.1 - _February 15, 2020_
* Dependencies updated
## v1.1.0 - _February 8, 2020_
* Refactor mixins into public libraries. (#2464)
* Remove `LibTransactionDecoder` export (#2464)
## v1.0.6 - _February 6, 2020_
* Dependencies updated
## v1.0.5 - _February 4, 2020_
* Dependencies updated
## v1.0.4 - _January 22, 2020_
* Dependencies updated
## 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

@@ -41,13 +41,13 @@ yarn install
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
```bash
PKG=@0x/contracts-extensions yarn build
PKG=@0x/contracts-dev-utils yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0x/contracts-extensions yarn watch
PKG=@0x/contracts-dev-utils yarn watch
```
### Clean

View File

@@ -3,11 +3,12 @@
"contractsDir": "./contracts",
"useDockerisedSolc": false,
"isOfflineMode": false,
"shouldSaveStandardInput": true,
"compilerSettings": {
"evmVersion": "constantinople",
"evmVersion": "istanbul",
"optimizer": {
"enabled": true,
"runs": 1666,
"runs": 5000,
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
},
"outputSelection": {

View File

@@ -0,0 +1,54 @@
/*
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.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
// solhint-disable no-empty-blocks
contract Addresses is
DeploymentConstants
{
address public exchangeAddress;
address public erc20ProxyAddress;
address public erc721ProxyAddress;
address public erc1155ProxyAddress;
address public staticCallProxyAddress;
address public chaiBridgeAddress;
address public dydxBridgeAddress;
constructor (
address exchange_,
address chaiBridge_,
address dydxBridge_
)
public
{
exchangeAddress = exchange_;
chaiBridgeAddress = chaiBridge_;
dydxBridgeAddress = dydxBridge_;
erc20ProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).ERC20Token.selector);
erc721ProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).ERC721Token.selector);
erc1155ProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
staticCallProxyAddress = IExchange(exchange_).getAssetProxy(IAssetData(address(0)).StaticCall.selector);
}
}

View File

@@ -0,0 +1,388 @@
/*
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.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IChai.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
import "./Addresses.sol";
import "./LibDydxBalance.sol";
contract AssetBalance is
Addresses
{
// 2^256 - 1
uint256 constant internal _MAX_UINT256 = uint256(-1);
using LibBytes for bytes;
/// @dev Returns the owner's balance of the assets(s) specified in
/// assetData. When the asset data contains multiple assets (eg in
/// ERC1155 or Multi-Asset), the return value indicates how many
/// complete "baskets" of those assets are owned by owner.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
/// @return Number of assets (or asset baskets) held by owner.
function getBalance(address ownerAddress, bytes memory assetData)
public
returns (uint256 balance)
{
// Get id of AssetProxy contract
bytes4 assetProxyId = assetData.readBytes4(0);
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
// Get ERC20 token address
address tokenAddress = assetData.readAddress(16);
balance = LibERC20Token.balanceOf(tokenAddress, ownerAddress);
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
// Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = LibAssetData.decodeERC721AssetData(assetData);
// Check if id is owned by ownerAddress
bytes memory ownerOfCalldata = abi.encodeWithSelector(
IERC721Token(address(0)).ownerOf.selector,
tokenId
);
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
balance = currentOwnerAddress == ownerAddress ? 1 : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address, array of ids, and array of values
(, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = LibAssetData.decodeERC1155AssetData(assetData);
uint256 length = tokenIds.length;
for (uint256 i = 0; i != length; i++) {
// Skip over the token if the corresponding value is 0.
if (tokenValues[i] == 0) {
continue;
}
// Encode data for `balanceOf(ownerAddress, tokenIds[i])
bytes memory balanceOfData = abi.encodeWithSelector(
IERC1155(address(0)).balanceOf.selector,
ownerAddress,
tokenIds[i]
);
// Query balance
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
uint256 totalBalance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
// Scale total balance down by corresponding value in assetData
uint256 scaledBalance = totalBalance / tokenValues[i];
if (scaledBalance == 0) {
return 0;
}
if (scaledBalance < balance || balance == 0) {
balance = scaledBalance;
}
}
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// Encode data for `staticCallProxy.transferFrom(assetData,...)`
bytes memory transferFromData = abi.encodeWithSelector(
IAssetProxy(address(0)).transferFrom.selector,
assetData,
address(0), // `from` address is not used
address(0), // `to` address is not used
0 // `amount` is not used
);
// Check if staticcall would be successful
(bool success,) = staticCallProxyAddress.staticcall(transferFromData);
// Success means that the staticcall can be made an unlimited amount of times
balance = success ? _MAX_UINT256 : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
// Get address of ERC20 token and bridge contract
(, address tokenAddress, address bridgeAddress, ) = LibAssetData.decodeERC20BridgeAssetData(assetData);
if (tokenAddress == _getDaiAddress() && bridgeAddress == chaiBridgeAddress) {
uint256 chaiBalance = LibERC20Token.balanceOf(_getChaiAddress(), ownerAddress);
// Calculate Dai balance
balance = _convertChaiToDaiAmount(chaiBalance);
}
// Balance will be 0 if bridge is not supported
} else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
// Get array of values and array of assetDatas
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = LibAssetData.decodeMultiAssetData(assetData);
uint256 length = nestedAssetData.length;
for (uint256 i = 0; i != length; i++) {
// Skip over the asset if the corresponding amount is 0.
if (assetAmounts[i] == 0) {
continue;
}
// Query balance of individual assetData
uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]);
// Scale total balance down by corresponding value in assetData
uint256 scaledBalance = totalBalance / assetAmounts[i];
if (scaledBalance == 0) {
return 0;
}
if (scaledBalance < balance || balance == 0) {
balance = scaledBalance;
}
}
}
// Balance will be 0 if assetProxyId is unknown
return balance;
}
/// @dev Calls getBalance() for each element of assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
/// @return Array of asset balances from getBalance(), with each element
/// corresponding to the same-indexed element in the assetData input.
function getBatchBalances(address ownerAddress, bytes[] memory assetData)
public
returns (uint256[] memory balances)
{
uint256 length = assetData.length;
balances = new uint256[](length);
for (uint256 i = 0; i != length; i++) {
balances[i] = getBalance(ownerAddress, assetData[i]);
}
return balances;
}
/// @dev Returns the number of asset(s) (described by assetData) that
/// the corresponding AssetProxy contract is authorized to spend. When the asset data contains
/// multiple assets (eg for Multi-Asset), the return value indicates
/// how many complete "baskets" of those assets may be spent by all of the corresponding
/// AssetProxy contracts.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
/// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getAssetProxyAllowance(address ownerAddress, bytes memory assetData)
public
returns (uint256 allowance)
{
// Get id of AssetProxy contract
bytes4 assetProxyId = assetData.readBytes4(0);
if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
// Get array of values and array of assetDatas
(, uint256[] memory amounts, bytes[] memory nestedAssetData) = LibAssetData.decodeMultiAssetData(assetData);
uint256 length = nestedAssetData.length;
for (uint256 i = 0; i != length; i++) {
// Skip over the asset if the corresponding amount is 0.
if (amounts[i] == 0) {
continue;
}
// Query allowance of individual assetData
uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]);
// Scale total allowance down by corresponding value in assetData
uint256 scaledAllowance = totalAllowance / amounts[i];
if (scaledAllowance == 0) {
return 0;
}
if (scaledAllowance < allowance || allowance == 0) {
allowance = scaledAllowance;
}
}
return allowance;
}
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
// Get ERC20 token address
address tokenAddress = assetData.readAddress(16);
allowance = LibERC20Token.allowance(tokenAddress, ownerAddress, erc20ProxyAddress);
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
// Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = LibAssetData.decodeERC721AssetData(assetData);
// Encode data for `isApprovedForAll(ownerAddress, erc721ProxyAddress)`
bytes memory isApprovedForAllData = abi.encodeWithSelector(
IERC721Token(address(0)).isApprovedForAll.selector,
ownerAddress,
erc721ProxyAddress
);
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
// If not approved for all, call `getApproved(tokenId)`
if (!success || returnData.length != 32 || returnData.readUint256(0) != 1) {
// Encode data for `getApproved(tokenId)`
bytes memory getApprovedData = abi.encodeWithSelector(IERC721Token(address(0)).getApproved.selector, tokenId);
(success, returnData) = tokenAddress.staticcall(getApprovedData);
// Allowance is 1 if successful and the approved address is the ERC721Proxy
allowance = success && returnData.length == 32 && returnData.readAddress(12) == erc721ProxyAddress ? 1 : 0;
} else {
// Allowance is 2^256 - 1 if `isApprovedForAll` returned true
allowance = _MAX_UINT256;
}
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address
(, address tokenAddress, , , ) = LibAssetData.decodeERC1155AssetData(assetData);
// Encode data for `isApprovedForAll(ownerAddress, erc1155ProxyAddress)`
bytes memory isApprovedForAllData = abi.encodeWithSelector(
IERC1155(address(0)).isApprovedForAll.selector,
ownerAddress,
erc1155ProxyAddress
);
// Query allowance
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// The StaticCallProxy does not require any approvals
allowance = _MAX_UINT256;
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
// Get address of ERC20 token and bridge contract
(, address tokenAddress, address bridgeAddress,) =
LibAssetData.decodeERC20BridgeAssetData(assetData);
if (tokenAddress == _getDaiAddress() && bridgeAddress == chaiBridgeAddress) {
uint256 chaiAllowance = LibERC20Token.allowance(_getChaiAddress(), ownerAddress, chaiBridgeAddress);
// Dai allowance is unlimited if Chai allowance is unlimited
allowance = chaiAllowance == _MAX_UINT256 ? _MAX_UINT256 : _convertChaiToDaiAmount(chaiAllowance);
} else if (bridgeAddress == dydxBridgeAddress) {
allowance = LibDydxBalance.getDydxMakerAllowance(ownerAddress, bridgeAddress, _getDydxAddress());
}
// Allowance will be 0 if bridge is not supported
}
// Allowance will be 0 if the assetProxyId is unknown
return allowance;
}
/// @dev Calls getAssetProxyAllowance() for each element of assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
/// @return An array of asset allowances from getAllowance(), with each
/// element corresponding to the same-indexed element in the assetData input.
function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
public
returns (uint256[] memory allowances)
{
uint256 length = assetData.length;
allowances = new uint256[](length);
for (uint256 i = 0; i != length; i++) {
allowances[i] = getAssetProxyAllowance(ownerAddress, assetData[i]);
}
return allowances;
}
/// @dev Calls getBalance() and getAllowance() for assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
/// @return Number of assets (or asset baskets) held by owner, and number
/// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getBalanceAndAssetProxyAllowance(
address ownerAddress,
bytes memory assetData
)
public
returns (uint256 balance, uint256 allowance)
{
balance = getBalance(ownerAddress, assetData);
allowance = getAssetProxyAllowance(ownerAddress, assetData);
return (balance, allowance);
}
/// @dev Calls getBatchBalances() and getBatchAllowances() for each element of assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
/// @return An array of asset balances from getBalance(), and an array of
/// asset allowances from getAllowance(), with each element
/// corresponding to the same-indexed element in the assetData input.
function getBatchBalancesAndAssetProxyAllowances(
address ownerAddress,
bytes[] memory assetData
)
public
returns (uint256[] memory balances, uint256[] memory allowances)
{
balances = getBatchBalances(ownerAddress, assetData);
allowances = getBatchAssetProxyAllowances(ownerAddress, assetData);
return (balances, allowances);
}
/// @dev Converts an amount of Chai into its equivalent Dai amount.
/// Also accumulates Dai from DSR if called after the last time it was collected.
/// @param chaiAmount Amount of Chai to converts.
function _convertChaiToDaiAmount(uint256 chaiAmount)
internal
returns (uint256 daiAmount)
{
PotLike pot = IChai(_getChaiAddress()).pot();
// Accumulate savings if called after last time savings were collected
// solhint-disable-next-line not-rely-on-time
uint256 chiMultiplier = (now > pot.rho())
? pot.drip()
: pot.chi();
daiAmount = LibMath.getPartialAmountFloor(chiMultiplier, 10**27, chaiAmount);
return daiAmount;
}
/// @dev Returns an order MAKER's balance of the assets(s) specified in
/// makerAssetData. Unlike `getBalanceAndAssetProxyAllowance()`, this
/// can handle maker asset types that depend on taker tokens being
/// transferred to the maker first.
/// @param order The order.
/// @return balance Quantity of assets transferrable from maker to taker.
function _getConvertibleMakerBalanceAndAssetProxyAllowance(
LibOrder.Order memory order
)
internal
returns (uint256 balance, uint256 allowance)
{
if (order.makerAssetData.length < 4) {
return (0, 0);
}
bytes4 assetProxyId = order.makerAssetData.readBytes4(0);
// Handle dydx bridge assets.
if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
(, , address bridgeAddress, ) = LibAssetData.decodeERC20BridgeAssetData(order.makerAssetData);
if (bridgeAddress == dydxBridgeAddress) {
return (
LibDydxBalance.getDydxMakerBalance(order, _getDydxAddress()),
getAssetProxyAllowance(order.makerAddress, order.makerAssetData)
);
}
}
return (
getBalance(order.makerAddress, order.makerAssetData),
getAssetProxyAllowance(order.makerAddress, order.makerAssetData)
);
}
}

View File

@@ -16,7 +16,7 @@
*/
pragma solidity ^0.5.5;
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange-libs/contracts/src/LibEIP712ExchangeDomain.sol";
@@ -24,28 +24,39 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibZeroExTransaction.sol";
import "@0x/contracts-utils/contracts/src/LibEIP712.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "./Addresses.sol";
import "./OrderValidationUtils.sol";
import "./OrderTransferSimulationUtils.sol";
import "./LibTransactionDecoder.sol";
import "./EthBalanceChecker.sol";
import "./ExternalFunctions.sol";
// solhint-disable no-empty-blocks
contract DevUtils is
Addresses,
OrderValidationUtils,
LibTransactionDecoder,
LibEIP712ExchangeDomain,
EthBalanceChecker,
OrderTransferSimulationUtils
ExternalFunctions
{
constructor (address _exchange)
constructor (
address exchange_,
address chaiBridge_,
address dydxBridge_
)
public
OrderValidationUtils(_exchange)
OrderTransferSimulationUtils(_exchange)
Addresses(
exchange_,
chaiBridge_,
dydxBridge_
)
LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants
{}
function getOrderHash(LibOrder.Order memory order, uint256 chainId, address exchange)
function getOrderHash(
LibOrder.Order memory order,
uint256 chainId,
address exchange
)
public
pure
returns (bytes32 orderHash)

View File

@@ -16,7 +16,7 @@
*/
pragma solidity ^0.5.5;
pragma solidity ^0.5.16;
contract EthBalanceChecker {

View File

@@ -0,0 +1,322 @@
/*
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.16;
pragma experimental ABIEncoderV2;
import "./Addresses.sol";
import "./LibAssetData.sol";
import "./LibTransactionDecoder.sol";
import "./LibOrderTransferSimulation.sol";
contract ExternalFunctions is
Addresses
{
/// @dev Decodes the call data for an Exchange contract method call.
/// @param transactionData ABI-encoded calldata for an Exchange
/// contract method call.
/// @return The name of the function called, and the parameters it was
/// given. For single-order fills and cancels, the arrays will have
/// just one element.
function decodeZeroExTransactionData(bytes memory transactionData)
public
pure
returns(
string memory functionName,
LibOrder.Order[] memory orders,
uint256[] memory takerAssetFillAmounts,
bytes[] memory signatures
)
{
return LibTransactionDecoder.decodeZeroExTransactionData(transactionData);
}
/// @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)
public
pure
returns (
bytes4 assetProxyId
)
{
return LibAssetData.decodeAssetProxyId(assetData);
}
/// @dev Encode ERC-20 asset data into the format described in the AssetProxy contract specification.
/// @param tokenAddress The address of the ERC-20 contract hosting the asset to be traded.
/// @return AssetProxy-compliant data describing the asset.
function encodeERC20AssetData(address tokenAddress)
public
pure
returns (bytes memory assetData)
{
return LibAssetData.encodeERC20AssetData(tokenAddress);
}
/// @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
/// contract hosting this asset.
function decodeERC20AssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
address tokenAddress
)
{
return LibAssetData.decodeERC20AssetData(assetData);
}
/// @dev Encode ERC-721 asset data into the format described in the AssetProxy specification.
/// @param tokenAddress The address of the ERC-721 contract hosting the asset to be traded.
/// @param tokenId The identifier of the specific asset to be traded.
/// @return AssetProxy-compliant asset data describing the asset.
function encodeERC721AssetData(address tokenAddress, uint256 tokenId)
public
pure
returns (bytes memory assetData)
{
return LibAssetData.encodeERC721AssetData(tokenAddress, tokenId);
}
/// @dev Decode ERC-721 asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC-721 asset.
/// @return The ERC-721 AssetProxy identifier, the address of the ERC-721
/// contract hosting this asset, and the identifier of the specific
/// asset to be traded.
function decodeERC721AssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
address tokenAddress,
uint256 tokenId
)
{
return LibAssetData.decodeERC721AssetData(assetData);
}
/// @dev Encode ERC-1155 asset data into the format described in the AssetProxy contract specification.
/// @param tokenAddress The address of the ERC-1155 contract hosting the asset(s) to be traded.
/// @param tokenIds The identifiers of the specific assets to be traded.
/// @param tokenValues The amounts of each asset to be traded.
/// @param callbackData Data to be passed to receiving contracts when a transfer is performed.
/// @return AssetProxy-compliant asset data describing the set of assets.
function encodeERC1155AssetData(
address tokenAddress,
uint256[] memory tokenIds,
uint256[] memory tokenValues,
bytes memory callbackData
)
public
pure
returns (bytes memory assetData)
{
return LibAssetData.encodeERC1155AssetData(
tokenAddress,
tokenIds,
tokenValues,
callbackData
);
}
/// @dev Decode ERC-1155 asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC-1155 set of assets.
/// @return The ERC-1155 AssetProxy identifier, the address of the ERC-1155
/// contract hosting the assets, an array of the identifiers of the
/// assets to be traded, an array of asset amounts to be traded, and
/// callback data. Each element of the arrays corresponds to the
/// same-indexed element of the other array. Return values specified as
/// `memory` are returned as pointers to locations within the memory of
/// the input parameter `assetData`.
function decodeERC1155AssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
address tokenAddress,
uint256[] memory tokenIds,
uint256[] memory tokenValues,
bytes memory callbackData
)
{
return LibAssetData.decodeERC1155AssetData(assetData);
}
/// @dev Encode data for multiple assets, per the AssetProxy contract specification.
/// @param amounts The amounts of each asset to be traded.
/// @param nestedAssetData AssetProxy-compliant data describing each asset to be traded.
/// @return AssetProxy-compliant data describing the set of assets.
function encodeMultiAssetData(uint256[] memory amounts, bytes[] memory nestedAssetData)
public
pure
returns (bytes memory assetData)
{
return LibAssetData.encodeMultiAssetData(amounts, nestedAssetData);
}
/// @dev Decode multi-asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant data describing a multi-asset basket.
/// @return The Multi-Asset AssetProxy identifier, an array of the amounts
/// of the assets to be traded, and an array of the
/// AssetProxy-compliant data describing each asset to be traded. Each
/// element of the arrays corresponds to the same-indexed element of the other array.
function decodeMultiAssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
uint256[] memory amounts,
bytes[] memory nestedAssetData
)
{
return LibAssetData.decodeMultiAssetData(assetData);
}
/// @dev Encode StaticCall asset data into the format described in the AssetProxy contract specification.
/// @param staticCallTargetAddress Target address of StaticCall.
/// @param staticCallData Data that will be passed to staticCallTargetAddress in the StaticCall.
/// @param expectedReturnDataHash Expected Keccak-256 hash of the StaticCall return data.
/// @return AssetProxy-compliant asset data describing the set of assets.
function encodeStaticCallAssetData(
address staticCallTargetAddress,
bytes memory staticCallData,
bytes32 expectedReturnDataHash
)
public
pure
returns (bytes memory assetData)
{
return LibAssetData.encodeStaticCallAssetData(
staticCallTargetAddress,
staticCallData,
expectedReturnDataHash
);
}
/// @dev Decode StaticCall asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing a StaticCall asset
/// @return The StaticCall AssetProxy identifier, the target address of the StaticCAll, the data to be
/// passed to the target address, and the expected Keccak-256 hash of the static call return data.
function decodeStaticCallAssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
address staticCallTargetAddress,
bytes memory staticCallData,
bytes32 expectedReturnDataHash
)
{
return LibAssetData.decodeStaticCallAssetData(assetData);
}
/// @dev Decode ERC20Bridge asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC20Bridge asset
/// @return The ERC20BridgeProxy identifier, the address of the ERC20 token to transfer, the address
/// of the bridge contract, and extra data to be passed to the bridge contract.
function decodeERC20BridgeAssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
address tokenAddress,
address bridgeAddress,
bytes memory bridgeData
)
{
return LibAssetData.decodeERC20BridgeAssetData(assetData);
}
/// @dev Reverts if assetData is not of a valid format for its given proxy id.
/// @param assetData AssetProxy compliant asset data.
function revertIfInvalidAssetData(bytes memory assetData)
public
pure
{
return LibAssetData.revertIfInvalidAssetData(assetData);
}
/// @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 (LibOrderTransferSimulation.OrderTransferResults orderTransferResults)
{
return LibOrderTransferSimulation.getSimulatedOrderMakerTransferResults(
exchangeAddress,
order,
takerAddress,
takerAssetFillAmount
);
}
/// @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.
/// @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 getSimulatedOrderTransferResults(
LibOrder.Order memory order,
address takerAddress,
uint256 takerAssetFillAmount
)
public
returns (LibOrderTransferSimulation.OrderTransferResults orderTransferResults)
{
return LibOrderTransferSimulation.getSimulatedOrderTransferResults(
exchangeAddress,
order,
takerAddress,
takerAssetFillAmount
);
}
/// @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 (LibOrderTransferSimulation.OrderTransferResults[] memory orderTransferResults)
{
return LibOrderTransferSimulation.getSimulatedOrdersTransferResults(
exchangeAddress,
orders,
takerAddresses,
takerAssetFillAmounts
);
}
}

View File

@@ -16,307 +16,18 @@
*/
pragma solidity ^0.5.5;
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
contract LibAssetData {
// 2^256 - 1
uint256 constant internal _MAX_UINT256 = uint256(-1);
library LibAssetData {
using LibBytes for bytes;
// solhint-disable var-name-mixedcase
IExchange internal _EXCHANGE;
address internal _ERC20_PROXY_ADDRESS;
address internal _ERC721_PROXY_ADDRESS;
address internal _ERC1155_PROXY_ADDRESS;
address internal _STATIC_CALL_PROXY_ADDRESS;
// solhint-enable var-name-mixedcase
constructor (address _exchange)
public
{
_EXCHANGE = IExchange(_exchange);
_ERC20_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC20Token.selector);
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector);
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
_STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).StaticCall.selector);
}
/// @dev Returns the owner's balance of the assets(s) specified in
/// assetData. When the asset data contains multiple assets (eg in
/// ERC1155 or Multi-Asset), the return value indicates how many
/// complete "baskets" of those assets are owned by owner.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
/// @return Number of assets (or asset baskets) held by owner.
function getBalance(address ownerAddress, bytes memory assetData)
public
view
returns (uint256 balance)
{
// Get id of AssetProxy contract
bytes4 assetProxyId = assetData.readBytes4(0);
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
// Get ERC20 token address
address tokenAddress = assetData.readAddress(16);
// Encode data for `balanceOf(ownerAddress)`
bytes memory balanceOfData = abi.encodeWithSelector(
IERC20Token(address(0)).balanceOf.selector,
ownerAddress
);
// Query balance
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
// Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
// Check if id is owned by ownerAddress
bytes memory ownerOfCalldata = abi.encodeWithSelector(
IERC721Token(address(0)).ownerOf.selector,
tokenId
);
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
balance = currentOwnerAddress == ownerAddress ? 1 : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address, array of ids, and array of values
(, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData);
uint256 length = tokenIds.length;
for (uint256 i = 0; i != length; i++) {
// Encode data for `balanceOf(ownerAddress, tokenIds[i])
bytes memory balanceOfData = abi.encodeWithSelector(
IERC1155(address(0)).balanceOf.selector,
ownerAddress,
tokenIds[i]
);
// Query balance
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
uint256 totalBalance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
// Scale total balance down by corresponding value in assetData
uint256 scaledBalance = totalBalance / tokenValues[i];
if (scaledBalance < balance || balance == 0) {
balance = scaledBalance;
}
}
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// Encode data for `staticCallProxy.transferFrom(assetData,...)`
bytes memory transferFromData = abi.encodeWithSelector(
IAssetProxy(address(0)).transferFrom.selector,
assetData,
address(0), // `from` address is not used
address(0), // `to` address is not used
0 // `amount` is not used
);
// Check if staticcall would be successful
(bool success,) = _STATIC_CALL_PROXY_ADDRESS.staticcall(transferFromData);
// Success means that the staticcall can be made an unlimited amount of times
balance = success ? _MAX_UINT256 : 0;
} else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
// Get array of values and array of assetDatas
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
uint256 length = nestedAssetData.length;
for (uint256 i = 0; i != length; i++) {
// Query balance of individual assetData
uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]);
// Scale total balance down by corresponding value in assetData
uint256 scaledBalance = totalBalance / assetAmounts[i];
if (scaledBalance < balance || balance == 0) {
balance = scaledBalance;
}
}
}
// Balance will be 0 if assetProxyId is unknown
return balance;
}
/// @dev Calls getBalance() for each element of assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
/// @return Array of asset balances from getBalance(), with each element
/// corresponding to the same-indexed element in the assetData input.
function getBatchBalances(address ownerAddress, bytes[] memory assetData)
public
view
returns (uint256[] memory balances)
{
uint256 length = assetData.length;
balances = new uint256[](length);
for (uint256 i = 0; i != length; i++) {
balances[i] = getBalance(ownerAddress, assetData[i]);
}
return balances;
}
/// @dev Returns the number of asset(s) (described by assetData) that
/// the corresponding AssetProxy contract is authorized to spend. When the asset data contains
/// multiple assets (eg for Multi-Asset), the return value indicates
/// how many complete "baskets" of those assets may be spent by all of the corresponding
/// AssetProxy contracts.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
/// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getAssetProxyAllowance(address ownerAddress, bytes memory assetData)
public
view
returns (uint256 allowance)
{
// Get id of AssetProxy contract
bytes4 assetProxyId = assetData.readBytes4(0);
if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
// Get array of values and array of assetDatas
(, uint256[] memory amounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
uint256 length = nestedAssetData.length;
for (uint256 i = 0; i != length; i++) {
// Query allowance of individual assetData
uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]);
// Scale total allowance down by corresponding value in assetData
uint256 scaledAllowance = totalAllowance / amounts[i];
if (scaledAllowance < allowance || allowance == 0) {
allowance = scaledAllowance;
}
}
return allowance;
}
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
// Get ERC20 token address
address tokenAddress = assetData.readAddress(16);
// Encode data for `allowance(ownerAddress, _ERC20_PROXY_ADDRESS)`
bytes memory allowanceData = abi.encodeWithSelector(
IERC20Token(address(0)).allowance.selector,
ownerAddress,
_ERC20_PROXY_ADDRESS
);
// Query allowance
(bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData);
allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
// Get ERC721 token address and id
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
// Encode data for `isApprovedForAll(ownerAddress, _ERC721_PROXY_ADDRESS)`
bytes memory isApprovedForAllData = abi.encodeWithSelector(
IERC721Token(address(0)).isApprovedForAll.selector,
ownerAddress,
_ERC721_PROXY_ADDRESS
);
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
// If not approved for all, call `getApproved(tokenId)`
if (!success || returnData.length != 32 || returnData.readUint256(0) != 1) {
// Encode data for `getApproved(tokenId)`
bytes memory getApprovedData = abi.encodeWithSelector(IERC721Token(address(0)).getApproved.selector, tokenId);
(success, returnData) = tokenAddress.staticcall(getApprovedData);
// Allowance is 1 if successful and the approved address is the ERC721Proxy
allowance = success && returnData.length == 32 && returnData.readAddress(12) == _ERC721_PROXY_ADDRESS ? 1 : 0;
} else {
// Allowance is 2^256 - 1 if `isApprovedForAll` returned true
allowance = _MAX_UINT256;
}
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
// Get ERC1155 token address
(, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
// Encode data for `isApprovedForAll(ownerAddress, _ERC1155_PROXY_ADDRESS)`
bytes memory isApprovedForAllData = abi.encodeWithSelector(
IERC1155(address(0)).isApprovedForAll.selector,
ownerAddress,
_ERC1155_PROXY_ADDRESS
);
// Query allowance
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
// The StaticCallProxy does not require any approvals
allowance = _MAX_UINT256;
}
// Allowance will be 0 if the assetProxyId is unknown
return allowance;
}
/// @dev Calls getAssetProxyAllowance() for each element of assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
/// @return An array of asset allowances from getAllowance(), with each
/// element corresponding to the same-indexed element in the assetData input.
function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
public
view
returns (uint256[] memory allowances)
{
uint256 length = assetData.length;
allowances = new uint256[](length);
for (uint256 i = 0; i != length; i++) {
allowances[i] = getAssetProxyAllowance(ownerAddress, assetData[i]);
}
return allowances;
}
/// @dev Calls getBalance() and getAllowance() for assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Details of asset, encoded per the AssetProxy contract specification.
/// @return Number of assets (or asset baskets) held by owner, and number
/// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData)
public
view
returns (uint256 balance, uint256 allowance)
{
balance = getBalance(ownerAddress, assetData);
allowance = getAssetProxyAllowance(ownerAddress, assetData);
return (balance, allowance);
}
/// @dev Calls getBatchBalances() and getBatchAllowances() for each element of assetData.
/// @param ownerAddress Owner of the assets specified by assetData.
/// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
/// @return An array of asset balances from getBalance(), and an array of
/// asset allowances from getAllowance(), with each element
/// corresponding to the same-indexed element in the assetData input.
function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
public
view
returns (uint256[] memory balances, uint256[] memory allowances)
{
balances = getBatchBalances(ownerAddress, assetData);
allowances = getBatchAssetProxyAllowances(ownerAddress, assetData);
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 +64,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
@@ -589,9 +300,38 @@ contract LibAssetData {
);
}
/// @dev Decode ERC20Bridge asset data from the format described in the AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC20Bridge asset
/// @return The ERC20BridgeProxy identifier, the address of the ERC20 token to transfer, the address
/// of the bridge contract, and extra data to be passed to the bridge contract.
function decodeERC20BridgeAssetData(bytes memory assetData)
public
pure
returns (
bytes4 assetProxyId,
address tokenAddress,
address bridgeAddress,
bytes memory bridgeData
)
{
assetProxyId = assetData.readBytes4(0);
require(
assetProxyId == IAssetData(address(0)).ERC20Bridge.selector,
"WRONG_PROXY_ID"
);
(tokenAddress, bridgeAddress, bridgeData) = abi.decode(
assetData.slice(4, assetData.length),
(address, address, bytes)
);
}
/// @dev Reverts if assetData is not of a valid format for its given proxy id.
/// @param assetData AssetProxy compliant asset data.
function revertIfInvalidAssetData(bytes memory assetData)
public
pure
pure
{
bytes4 assetProxyId = assetData.readBytes4(0);
@@ -605,6 +345,8 @@ contract LibAssetData {
decodeMultiAssetData(assetData);
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
decodeStaticCallAssetData(assetData);
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
decodeERC20BridgeAssetData(assetData);
} else {
revert("WRONG_PROXY_ID");
}

View File

@@ -0,0 +1,436 @@
/*
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.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IDydxBridge.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IDydx.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-utils/contracts/src/D18.sol";
import "./LibAssetData.sol";
library LibDydxBalance {
using LibBytes for bytes;
using LibSafeMath for uint256;
/// @dev Padding % added to the minimum collateralization ratio to
/// prevent withdrawing exactly the amount that would make an account
/// insolvent. 1 bps.
int256 private constant MARGIN_RATIO_PADDING = 0.0001e18;
/// @dev Structure that holds all pertinent info needed to perform a balance
/// check.
struct BalanceCheckInfo {
IDydx dydx;
address bridgeAddress;
address makerAddress;
address makerTokenAddress;
address takerTokenAddress;
int256 orderMakerToTakerRate;
uint256[] accounts;
IDydxBridge.BridgeAction[] actions;
}
/// @dev Gets the maker asset allowance for a Dydx bridge order.
/// @param makerAddress The maker of the order.
/// @param bridgeAddress The address of the Dydx bridge.
/// @param dydx The Dydx contract address.
/// @return allowance The maker asset allowance.
function getDydxMakerAllowance(address makerAddress, address bridgeAddress, address dydx)
public
view
returns (uint256 allowance)
{
// Allowance is infinite if the dydx bridge is an operator for the maker.
return IDydx(dydx).getIsLocalOperator(makerAddress, bridgeAddress)
? uint256(-1) : 0;
}
/// @dev Gets the maker allowance for a
/// @dev Get the maker asset balance of an order with a `DydxBridge` maker asset.
/// @param order An order with a dydx maker asset.
/// @param dydx The address of the dydx contract.
/// @return balance The maker asset balance.
function getDydxMakerBalance(LibOrder.Order memory order, address dydx)
public
view
returns (uint256 balance)
{
BalanceCheckInfo memory info = _getBalanceCheckInfo(order, dydx);
// Actions must be well-formed.
if (!_areActionsWellFormed(info)) {
return 0;
}
// If the rate we withdraw maker tokens is less than one, the asset
// proxy will throw because we will always transfer less maker tokens
// than asked.
if (_getMakerTokenWithdrawRate(info) < D18.one()) {
return 0;
}
// The maker balance is the smaller of:
return LibSafeMath.min256(
// How many times we can execute all the deposit actions.
_getDepositableMakerAmount(info),
// How many times we can execute all the actions before the an
// account becomes undercollateralized.
_getSolventMakerAmount(info)
);
}
/// @dev Checks that:
/// 1. Actions are arranged as [...deposits, withdraw].
/// 2. There is only one deposit for each market ID.
/// 3. Every action has a valid account index.
/// 4. There is exactly one withdraw at the end and it is for the
/// maker token.
/// @param info State from `_getBalanceCheckInfo()`.
/// @return areWellFormed Whether the actions are well-formed.
function _areActionsWellFormed(BalanceCheckInfo memory info)
internal
view
returns (bool areWellFormed)
{
if (info.actions.length == 0) {
return false;
}
uint256 depositCount = 0;
// Count the number of deposits.
for (; depositCount < info.actions.length; ++depositCount) {
IDydxBridge.BridgeAction memory action = info.actions[depositCount];
if (action.actionType != IDydxBridge.BridgeActionType.Deposit) {
break;
}
// Search all prior actions for the same market ID.
uint256 marketId = action.marketId;
for (uint256 j = 0; j < depositCount; ++j) {
if (info.actions[j].marketId == marketId) {
// Market ID is not unique.
return false;
}
}
// Check that the account index is within the valid range.
if (action.accountIdx >= info.accounts.length) {
return false;
}
}
// There must be exactly one withdraw action at the end.
if (depositCount + 1 != info.actions.length) {
return false;
}
IDydxBridge.BridgeAction memory withdraw = info.actions[depositCount];
if (withdraw.actionType != IDydxBridge.BridgeActionType.Withdraw) {
return false;
}
// And it must be for the maker token.
if (info.dydx.getMarketTokenAddress(withdraw.marketId) != info.makerTokenAddress) {
return false;
}
// Check the account index.
return withdraw.accountIdx < info.accounts.length;
}
/// @dev Returns the rate at which we withdraw maker tokens.
/// @param info State from `_getBalanceCheckInfo()`.
/// @return makerTokenWithdrawRate Maker token withdraw rate.
function _getMakerTokenWithdrawRate(BalanceCheckInfo memory info)
internal
pure
returns (int256 makerTokenWithdrawRate)
{
// The last action is always a withdraw for the maker token.
IDydxBridge.BridgeAction memory withdraw = info.actions[info.actions.length - 1];
return _getActionRate(withdraw);
}
/// @dev Get how much maker asset we can transfer before a deposit fails.
/// @param info State from `_getBalanceCheckInfo()`.
function _getDepositableMakerAmount(BalanceCheckInfo memory info)
internal
view
returns (uint256 depositableMakerAmount)
{
depositableMakerAmount = uint256(-1);
// Take the minimum maker amount from all deposits.
for (uint256 i = 0; i < info.actions.length; ++i) {
IDydxBridge.BridgeAction memory action = info.actions[i];
// Only looking at deposit actions.
if (action.actionType != IDydxBridge.BridgeActionType.Deposit) {
continue;
}
// `depositRate` is the rate at which we convert a maker token into
// a taker token for deposit.
int256 depositRate = _getActionRate(action);
// Taker tokens will be transferred to the maker for every fill, so
// we reduce the effective deposit rate if we're depositing the taker
// token.
address depositToken = info.dydx.getMarketTokenAddress(action.marketId);
if (info.takerTokenAddress != address(0) && depositToken == info.takerTokenAddress) {
depositRate = D18.sub(depositRate, info.orderMakerToTakerRate);
}
// If the deposit rate is > 0, we are limited by the transferrable
// token balance of the maker.
if (depositRate > 0) {
uint256 supply = _getTransferabeTokenAmount(
depositToken,
info.makerAddress,
address(info.dydx)
);
depositableMakerAmount = LibSafeMath.min256(
depositableMakerAmount,
uint256(D18.div(supply, depositRate))
);
}
}
}
/// @dev Get how much maker asset we can transfer before an account
/// becomes insolvent.
/// @param info State from `_getBalanceCheckInfo()`.
function _getSolventMakerAmount(BalanceCheckInfo memory info)
internal
view
returns (uint256 solventMakerAmount)
{
solventMakerAmount = uint256(-1);
assert(info.actions.length >= 1);
IDydxBridge.BridgeAction memory withdraw = info.actions[info.actions.length - 1];
assert(withdraw.actionType == IDydxBridge.BridgeActionType.Withdraw);
int256 minCr = D18.add(_getMinimumCollateralizationRatio(info.dydx), MARGIN_RATIO_PADDING);
// Loop through the accounts.
for (uint256 accountIdx = 0; accountIdx < info.accounts.length; ++accountIdx) {
(uint256 supplyValue, uint256 borrowValue) =
_getAccountMarketValues(info, info.accounts[accountIdx]);
// All accounts must currently be solvent.
if (borrowValue != 0 && D18.div(supplyValue, borrowValue) < minCr) {
return 0;
}
// If this is the same account used to in the withdraw/borrow action,
// compute the maker amount at which it will become insolvent.
if (accountIdx != withdraw.accountIdx) {
continue;
}
// Compute the deposit/collateralization rate, which is the rate at
// which (USD) value is added to the account across all markets.
int256 dd = 0;
for (uint256 i = 0; i < info.actions.length - 1; ++i) {
IDydxBridge.BridgeAction memory deposit = info.actions[i];
assert(deposit.actionType == IDydxBridge.BridgeActionType.Deposit);
if (deposit.accountIdx == accountIdx) {
dd = D18.add(
dd,
_getActionRateValue(
info,
deposit
)
);
}
}
// Compute the borrow/withdraw rate, which is the rate at which
// (USD) value is deducted from the account.
int256 db = _getActionRateValue(
info,
withdraw
);
// If the deposit to withdraw ratio is >= the minimum collateralization
// ratio, then we will never become insolvent at these prices.
if (D18.div(dd, db) >= minCr) {
continue;
}
// If the adjusted deposit rates are equal, the account will remain
// at the same level of collateralization.
if (D18.mul(minCr, db) == dd) {
continue;
}
// The collateralization ratio for this account, parameterized by
// `t` (maker amount), is given by:
// `cr = (supplyValue + t * dd) / (borrowValue + t * db)`
// Solving for `t` gives us:
// `t = (supplyValue - cr * borrowValue) / (cr * db - dd)`
int256 t = D18.div(
D18.sub(supplyValue, D18.mul(minCr, borrowValue)),
D18.sub(D18.mul(minCr, db), dd)
);
solventMakerAmount = LibSafeMath.min256(
solventMakerAmount,
// `t` is in maker token units, so convert it to maker wei.
_toWei(info.makerTokenAddress, uint256(D18.clip(t)))
);
}
}
/// @dev Create a `BalanceCheckInfo` struct.
/// @param order An order with a `DydxBridge` maker asset.
/// @param dydx The address of the Dydx contract.
/// @return info The `BalanceCheckInfo` struct.
function _getBalanceCheckInfo(LibOrder.Order memory order, address dydx)
private
pure
returns (BalanceCheckInfo memory info)
{
bytes memory rawBridgeData;
(, info.makerTokenAddress, info.bridgeAddress, rawBridgeData) =
LibAssetData.decodeERC20BridgeAssetData(order.makerAssetData);
info.dydx = IDydx(dydx);
info.makerAddress = order.makerAddress;
if (order.takerAssetData.length == 36) {
if (order.takerAssetData.readBytes4(0) == IAssetData(0).ERC20Token.selector) {
(, info.takerTokenAddress) =
LibAssetData.decodeERC20AssetData(order.takerAssetData);
}
}
info.orderMakerToTakerRate = D18.div(order.takerAssetAmount, order.makerAssetAmount);
(IDydxBridge.BridgeData memory bridgeData) =
abi.decode(rawBridgeData, (IDydxBridge.BridgeData));
info.accounts = bridgeData.accountNumbers;
info.actions = bridgeData.actions;
}
/// @dev Returns the conversion rate for an action.
/// @param action A `BridgeAction`.
function _getActionRate(IDydxBridge.BridgeAction memory action)
private
pure
returns (int256 rate)
{
rate = action.conversionRateDenominator == 0
? D18.one()
: D18.div(
action.conversionRateNumerator,
action.conversionRateDenominator
);
}
/// @dev Returns the USD value of an action based on its conversion rate
/// and market prices.
/// @param info State from `_getBalanceCheckInfo()`.
/// @param action A `BridgeAction`.
function _getActionRateValue(
BalanceCheckInfo memory info,
IDydxBridge.BridgeAction memory action
)
private
view
returns (int256 value)
{
address toToken = info.dydx.getMarketTokenAddress(action.marketId);
uint256 fromTokenDecimals = LibERC20Token.decimals(info.makerTokenAddress);
uint256 toTokenDecimals = LibERC20Token.decimals(toToken);
// First express the rate as 18-decimal units.
value = toTokenDecimals > fromTokenDecimals
? int256(
uint256(_getActionRate(action))
.safeDiv(10 ** (toTokenDecimals - fromTokenDecimals))
)
: int256(
uint256(_getActionRate(action))
.safeMul(10 ** (fromTokenDecimals - toTokenDecimals))
);
// Prices have 18 + (18 - TOKEN_DECIMALS) decimal places because
// consistency is stupid.
uint256 price = info.dydx.getMarketPrice(action.marketId).value;
// Make prices have 18 decimals.
if (toTokenDecimals > 18) {
price = price.safeMul(10 ** (toTokenDecimals - 18));
} else {
price = price.safeDiv(10 ** (18 - toTokenDecimals));
}
// The action value is the action rate times the price.
value = D18.mul(price, value);
// Scale by the market premium.
int256 marketPremium = D18.add(
D18.one(),
info.dydx.getMarketMarginPremium(action.marketId).value
);
if (action.actionType == IDydxBridge.BridgeActionType.Deposit) {
value = D18.div(value, marketPremium);
} else {
value = D18.mul(value, marketPremium);
}
}
/// @dev Convert a `D18` fraction of 1 token to the equivalent integer wei.
/// @param token Address the of the token.
/// @param units Token units expressed with 18 digit precision.
function _toWei(address token, uint256 units)
private
view
returns (uint256 rate)
{
uint256 decimals = LibERC20Token.decimals(token);
rate = decimals > 18
? units.safeMul(10 ** (decimals - 18))
: units.safeDiv(10 ** (18 - decimals));
}
/// @dev Get the global minimum collateralization ratio required for
/// an account to be considered solvent.
/// @param dydx The Dydx interface.
function _getMinimumCollateralizationRatio(IDydx dydx)
private
view
returns (int256 ratio)
{
IDydx.RiskParams memory riskParams = dydx.getRiskParams();
return D18.add(D18.one(), D18.toSigned(riskParams.marginRatio.value));
}
/// @dev Get the total supply and borrow values for an account across all markets.
/// @param info State from `_getBalanceCheckInfo()`.
/// @param account The Dydx account identifier.
function _getAccountMarketValues(BalanceCheckInfo memory info, uint256 account)
private
view
returns (uint256 supplyValue, uint256 borrowValue)
{
(IDydx.Value memory supplyValue_, IDydx.Value memory borrowValue_) =
info.dydx.getAdjustedAccountValues(IDydx.AccountInfo(
info.makerAddress,
account
));
// Account values have 36 decimal places because dydx likes to make sure
// you're paying attention.
return (supplyValue_.value / 1e18, borrowValue_.value / 1e18);
}
/// @dev Get the amount of an ERC20 token held by `owner` that can be transferred
/// by `spender`.
/// @param tokenAddress The address of the ERC20 token.
/// @param owner The address of the token holder.
/// @param spender The address of the token spender.
function _getTransferabeTokenAmount(
address tokenAddress,
address owner,
address spender
)
private
view
returns (uint256 transferableAmount)
{
return LibSafeMath.min256(
LibERC20Token.allowance(tokenAddress, owner, spender),
LibERC20Token.balanceOf(tokenAddress, owner)
);
}
}

View File

@@ -0,0 +1,227 @@
/*
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.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
import "@0x/contracts-exchange/contracts/src/libs/LibExchangeRichErrorDecoder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibExchangeRichErrors.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
library LibOrderTransferSimulation {
using LibBytes for bytes;
enum OrderTransferResults {
TakerAssetDataFailed, // Transfer of takerAsset failed
MakerAssetDataFailed, // Transfer of makerAsset failed
TakerFeeAssetDataFailed, // Transfer of takerFeeAsset failed
MakerFeeAssetDataFailed, // Transfer of makerFeeAsset failed
TransfersSuccessful // All transfers in the order were successful
}
// NOTE(jalextowle): This is a random address that we use to avoid issues that addresses like `address(1)`
// may cause later.
address constant internal UNUSED_ADDRESS = address(0x377f698C4c287018D09b516F415317aEC5919332);
// keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL"));
bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0;
/// @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(
address exchange,
LibOrder.Order memory order,
address takerAddress,
uint256 takerAssetFillAmount
)
public
returns (OrderTransferResults orderTransferResults)
{
LibFillResults.FillResults memory fillResults = LibFillResults.calculateFillResults(
order,
takerAssetFillAmount,
IExchange(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 == address(0) ? UNUSED_ADDRESS : takerAddress;
amounts[0] = fillResults.makerAssetFilledAmount;
// Transfer `makerFeeAsset` from maker to feeRecipient
assetData[1] = order.makerFeeAssetData;
fromAddresses[1] = order.makerAddress;
toAddresses[1] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[1] = fillResults.makerFeePaid;
return _simulateTransferFromCalls(
exchange,
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.
/// @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 getSimulatedOrderTransferResults(
address exchange,
LibOrder.Order memory order,
address takerAddress,
uint256 takerAssetFillAmount
)
public
returns (OrderTransferResults orderTransferResults)
{
LibFillResults.FillResults memory fillResults = LibFillResults.calculateFillResults(
order,
takerAssetFillAmount,
IExchange(exchange).protocolFeeMultiplier(),
tx.gasprice
);
// Create input arrays
bytes[] memory assetData = new bytes[](4);
address[] memory fromAddresses = new address[](4);
address[] memory toAddresses = new address[](4);
uint256[] memory amounts = new uint256[](4);
// Transfer `takerAsset` from taker to maker
assetData[0] = order.takerAssetData;
fromAddresses[0] = takerAddress;
toAddresses[0] = order.makerAddress;
amounts[0] = takerAssetFillAmount;
// Transfer `makerAsset` from maker to taker
assetData[1] = order.makerAssetData;
fromAddresses[1] = order.makerAddress;
toAddresses[1] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress;
amounts[1] = fillResults.makerAssetFilledAmount;
// Transfer `takerFeeAsset` from taker to feeRecipient
assetData[2] = order.takerFeeAssetData;
fromAddresses[2] = takerAddress;
toAddresses[2] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[2] = fillResults.takerFeePaid;
// Transfer `makerFeeAsset` from maker to feeRecipient
assetData[3] = order.makerFeeAssetData;
fromAddresses[3] = order.makerAddress;
toAddresses[3] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[3] = fillResults.makerFeePaid;
return _simulateTransferFromCalls(
exchange,
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(
address exchange,
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(
exchange,
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(
address exchange,
bytes[] memory assetData,
address[] memory fromAddresses,
address[] memory toAddresses,
uint256[] memory amounts
)
private
returns (OrderTransferResults orderTransferResults)
{
// Encode data for `simulateDispatchTransferFromCalls(assetData, fromAddresses, toAddresses, amounts)`
bytes memory simulateDispatchTransferFromCallsData = abi.encodeWithSelector(
IExchange(address(0)).simulateDispatchTransferFromCalls.selector,
assetData,
fromAddresses,
toAddresses,
amounts
);
// Perform call and catch revert
(, bytes memory returnData) = address(exchange).call(simulateDispatchTransferFromCallsData);
bytes4 selector = returnData.readBytes4(0);
if (selector == LibExchangeRichErrors.AssetProxyDispatchErrorSelector()) {
// Decode AssetProxyDispatchError and return index of failed transfer
(, bytes32 failedTransferIndex,) = LibExchangeRichErrorDecoder.decodeAssetProxyDispatchError(returnData);
return OrderTransferResults(uint8(uint256(failedTransferIndex)));
} else if (selector == LibExchangeRichErrors.AssetProxyTransferErrorSelector()) {
// Decode AssetProxyTransferError and return index of failed transfer
(bytes32 failedTransferIndex, ,) = LibExchangeRichErrorDecoder.decodeAssetProxyTransferError(returnData);
return OrderTransferResults(uint8(uint256(failedTransferIndex)));
} else if (keccak256(returnData) == _TRANSFERS_SUCCESSFUL_RESULT_HASH) {
// All transfers were successful
return OrderTransferResults.TransfersSuccessful;
} else {
revert("UNKNOWN_RETURN_DATA");
}
}
}

View File

@@ -16,7 +16,7 @@
*/
pragma solidity ^0.5.5;
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
@@ -24,7 +24,7 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
contract LibTransactionDecoder {
library LibTransactionDecoder {
using LibBytes for bytes;

View File

@@ -28,9 +28,8 @@ import "@0x/contracts-exchange-libs/contracts/src/LibFillResults.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
contract OrderTransferSimulationUtils is
LibExchangeRichErrorDecoder
{
contract OrderTransferSimulationUtils {
using LibBytes for bytes;
enum OrderTransferResults {
@@ -41,6 +40,10 @@ contract OrderTransferSimulationUtils is
TransfersSuccessful // All transfers in the order were successful
}
// NOTE(jalextowle): This is a random address that we use to avoid issues that addresses like `address(1)`
// may cause later.
address constant internal UNUSED_ADDRESS = address(0x377f698C4c287018D09b516F415317aEC5919332);
// keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL"));
bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0;
@@ -54,6 +57,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 == address(0) ? UNUSED_ADDRESS : takerAddress;
amounts[0] = fillResults.makerAssetFilledAmount;
// Transfer `makerFeeAsset` from maker to feeRecipient
assetData[1] = order.makerFeeAssetData;
fromAddresses[1] = order.makerAddress;
toAddresses[1] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : 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.
@@ -89,48 +137,27 @@ contract OrderTransferSimulationUtils is
// Transfer `makerAsset` from maker to taker
assetData[1] = order.makerAssetData;
fromAddresses[1] = order.makerAddress;
toAddresses[1] = takerAddress;
toAddresses[1] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress;
amounts[1] = fillResults.makerAssetFilledAmount;
// Transfer `takerFeeAsset` from taker to feeRecipient
assetData[2] = order.takerFeeAssetData;
fromAddresses[2] = takerAddress;
toAddresses[2] = order.feeRecipientAddress;
toAddresses[2] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[2] = fillResults.takerFeePaid;
// Transfer `makerFeeAsset` from maker to feeRecipient
assetData[3] = order.makerFeeAssetData;
fromAddresses[3] = order.makerAddress;
toAddresses[3] = order.feeRecipientAddress;
toAddresses[3] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
amounts[3] = fillResults.makerFeePaid;
// Encode data for `simulateDispatchTransferFromCalls(assetData, fromAddresses, toAddresses, amounts)`
bytes memory simulateDispatchTransferFromCallsData = abi.encodeWithSelector(
IExchange(address(0)).simulateDispatchTransferFromCalls.selector,
return _simulateTransferFromCalls(
assetData,
fromAddresses,
toAddresses,
amounts
);
// Perform call and catch revert
(, bytes memory returnData) = address(_EXCHANGE).call(simulateDispatchTransferFromCallsData);
bytes4 selector = returnData.readBytes4(0);
if (selector == LibExchangeRichErrors.AssetProxyDispatchErrorSelector()) {
// Decode AssetProxyDispatchError and return index of failed transfer
(, bytes32 failedTransferIndex,) = decodeAssetProxyDispatchError(returnData);
return OrderTransferResults(uint8(uint256(failedTransferIndex)));
} else if (selector == LibExchangeRichErrors.AssetProxyTransferErrorSelector()) {
// Decode AssetProxyTransferError and return index of failed transfer
(bytes32 failedTransferIndex, ,) = decodeAssetProxyTransferError(returnData);
return OrderTransferResults(uint8(uint256(failedTransferIndex)));
} else if (keccak256(returnData) == _TRANSFERS_SUCCESSFUL_RESULT_HASH) {
// All transfers were successful
return OrderTransferResults.TransfersSuccessful;
} else {
revert("UNKNOWN_RETURN_DATA");
}
}
/// @dev Simulates all of the transfers for each given order and returns the indices of each first failed transfer.
@@ -157,4 +184,50 @@ contract OrderTransferSimulationUtils is
}
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,
assetData,
fromAddresses,
toAddresses,
amounts
);
// Perform call and catch revert
(, bytes memory returnData) = address(_EXCHANGE).call(simulateDispatchTransferFromCallsData);
bytes4 selector = returnData.readBytes4(0);
if (selector == LibExchangeRichErrors.AssetProxyDispatchErrorSelector()) {
// Decode AssetProxyDispatchError and return index of failed transfer
(, bytes32 failedTransferIndex,) = LibExchangeRichErrorDecoder
.decodeAssetProxyDispatchError(returnData);
return OrderTransferResults(uint8(uint256(failedTransferIndex)));
} else if (selector == LibExchangeRichErrors.AssetProxyTransferErrorSelector()) {
// Decode AssetProxyTransferError and return index of failed transfer
(bytes32 failedTransferIndex, ,) = LibExchangeRichErrorDecoder
.decodeAssetProxyTransferError(returnData);
return OrderTransferResults(uint8(uint256(failedTransferIndex)));
} else if (keccak256(returnData) == _TRANSFERS_SUCCESSFUL_RESULT_HASH) {
// All transfers were successful
return OrderTransferResults.TransfersSuccessful;
} else {
revert("UNKNOWN_RETURN_DATA");
}
}
}

View File

@@ -16,28 +16,26 @@
*/
pragma solidity ^0.5.5;
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;
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/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "./Addresses.sol";
import "./AssetBalance.sol";
import "./LibAssetData.sol";
import "./LibOrderTransferSimulation.sol";
contract OrderValidationUtils is
LibAssetData
Addresses,
AssetBalance
{
using LibBytes for bytes;
using LibSafeMath for uint256;
constructor (address _exchange)
public
LibAssetData(_exchange)
{}
/// @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.
@@ -50,7 +48,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,
@@ -58,23 +55,22 @@ contract OrderValidationUtils is
)
{
// Get info specific to order
orderInfo = _EXCHANGE.getOrderInfo(order);
orderInfo = IExchange(exchangeAddress).getOrderInfo(order);
// Validate the maker's signature
address makerAddress = order.makerAddress;
isValidSignature = _EXCHANGE.isValidOrderSignature(
isValidSignature = IExchange(exchangeAddress).isValidOrderSignature(
order,
signature
);
// Get the transferable amount of the `makerAsset`
uint256 transferableMakerAssetAmount = getTransferableAssetAmount(makerAddress, order.makerAssetData);
uint256 transferableMakerAssetAmount = _getTransferableConvertedMakerAssetAmount(
order
);
// Assign to stack variables to reduce redundant mloads/sloads
uint256 takerAssetAmount = order.takerAssetAmount;
uint256 makerFee = order.makerFee;
// Get the amount of `takerAsset` that is transferable to maker given the transferability of `makerAsset`, `makerFeeAsset`,
// Get the amount of `takerAsset` that is transferable to maker given the
// transferability of `makerAsset`, `makerFeeAsset`,
// and the total amounts specified in the order
uint256 transferableTakerAssetAmount;
if (order.makerAssetData.equals(order.makerFeeAssetData)) {
@@ -82,33 +78,35 @@ contract OrderValidationUtils is
// transferableMakerAssetAmount / (makerAssetAmount + makerFee)
transferableTakerAssetAmount = LibMath.getPartialAmountFloor(
transferableMakerAssetAmount,
order.makerAssetAmount.safeAdd(makerFee),
takerAssetAmount
order.makerAssetAmount.safeAdd(order.makerFee),
order.takerAssetAmount
);
} else {
// If `makerFee` is 0, the % that can be filled is (transferableMakerAssetAmount / makerAssetAmount)
if (makerFee == 0) {
if (order.makerFee == 0) {
transferableTakerAssetAmount = LibMath.getPartialAmountFloor(
transferableMakerAssetAmount,
order.makerAssetAmount,
takerAssetAmount
order.takerAssetAmount
);
// If `makerAsset` does not equal `makerFeeAsset`, the % that can be filled is the lower of
// (transferableMakerAssetAmount / makerAssetAmount) and (transferableMakerAssetFeeAmount / makerFee)
} else {
// Get the transferable amount of the `makerFeeAsset`
uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount(makerAddress, order.makerFeeAssetData);
uint256 transferableMakerFeeAssetAmount = getTransferableAssetAmount(
makerAddress,
order.makerFeeAssetData
);
uint256 transferableMakerToTakerAmount = LibMath.getPartialAmountFloor(
transferableMakerAssetAmount,
order.makerAssetAmount,
takerAssetAmount
order.takerAssetAmount
);
uint256 transferableMakerFeeToTakerAmount = LibMath.getPartialAmountFloor(
transferableMakerFeeAssetAmount,
makerFee,
takerAssetAmount
order.makerFee,
order.takerAssetAmount
);
transferableTakerAssetAmount = LibSafeMath.min256(transferableMakerToTakerAmount, transferableMakerFeeToTakerAmount);
}
@@ -116,10 +114,22 @@ contract OrderValidationUtils is
// `fillableTakerAssetAmount` is the lower of the order's remaining `takerAssetAmount` and the `transferableTakerAssetAmount`
fillableTakerAssetAmount = LibSafeMath.min256(
takerAssetAmount.safeSub(orderInfo.orderTakerAssetFilledAmount),
order.takerAssetAmount.safeSub(orderInfo.orderTakerAssetFilledAmount),
transferableTakerAssetAmount
);
// Ensure that all of the asset data is valid. Fee asset data only needs
// to be valid if the fees are nonzero.
if (!_areOrderAssetDatasValid(order)) {
fillableTakerAssetAmount = 0;
}
// If the order is not fillable, then the fillable taker asset amount is
// zero by definition.
if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) {
fillableTakerAssetAmount = 0;
}
return (orderInfo, fillableTakerAssetAmount, isValidSignature);
}
@@ -135,7 +145,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,
@@ -157,7 +166,7 @@ contract OrderValidationUtils is
return (ordersInfo, fillableTakerAssetAmounts, isValidSignature);
}
/// @dev Gets the amount of an asset transferable by the owner.
/// @dev Gets the amount of an asset transferable by the maker of an order.
/// @param ownerAddress Address of the owner of the asset.
/// @param assetData Description of tokens, per the AssetProxy contract specification.
/// @return The amount of the asset tranferable by the owner.
@@ -167,11 +176,104 @@ contract OrderValidationUtils is
/// the individual asset amounts located within the `assetData`.
function getTransferableAssetAmount(address ownerAddress, bytes memory assetData)
public
view
returns (uint256 transferableAssetAmount)
{
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData);
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(
ownerAddress,
assetData
);
transferableAssetAmount = LibSafeMath.min256(balance, allowance);
return transferableAssetAmount;
}
/// @dev Gets the amount of an asset transferable by the maker of an order.
/// Similar to `getTransferableAssetAmount()`, but can handle maker asset
/// types that depend on taker assets being transferred first (e.g., Dydx bridge).
/// @param order The order.
/// @return transferableAssetAmount Amount of maker asset that can be transferred.
function _getTransferableConvertedMakerAssetAmount(
LibOrder.Order memory order
)
internal
returns (uint256 transferableAssetAmount)
{
(uint256 balance, uint256 allowance) = _getConvertibleMakerBalanceAndAssetProxyAllowance(order);
transferableAssetAmount = LibSafeMath.min256(balance, allowance);
return LibSafeMath.min256(transferableAssetAmount, order.makerAssetAmount);
}
/// @dev Checks that the asset data contained in a ZeroEx is valid and returns
/// a boolean that indicates whether or not the asset data was found to be valid.
/// @param order A ZeroEx order to validate.
/// @return The validatity of the asset data.
function _areOrderAssetDatasValid(LibOrder.Order memory order)
internal
pure
returns (bool)
{
return _isAssetDataValid(order.makerAssetData) &&
(order.makerFee == 0 || _isAssetDataValid(order.makerFeeAssetData)) &&
_isAssetDataValid(order.takerAssetData) &&
(order.takerFee == 0 || _isAssetDataValid(order.takerFeeAssetData));
}
/// @dev This function handles the edge cases around taker validation. This function
/// currently attempts to find duplicate ERC721 token's in the taker
/// multiAssetData.
/// @param assetData The asset data that should be validated.
/// @return Whether or not the order should be considered valid.
function _isAssetDataValid(bytes memory assetData)
internal
pure
returns (bool)
{
// Asset data must be composed of an asset proxy Id and a bytes segment with
// a length divisible by 32.
if (assetData.length % 32 != 4) {
return false;
}
// Only process the taker asset data if it is multiAssetData.
bytes4 assetProxyId = assetData.readBytes4(0);
if (assetProxyId != IAssetData(address(0)).MultiAsset.selector) {
return true;
}
// Get array of values and array of assetDatas
(, , bytes[] memory nestedAssetData) =
LibAssetData.decodeMultiAssetData(assetData);
uint256 length = nestedAssetData.length;
for (uint256 i = 0; i != length; i++) {
// TODO(jalextowle): Implement similar validation for non-fungible ERC1155 asset data.
bytes4 nestedAssetProxyId = nestedAssetData[i].readBytes4(0);
if (nestedAssetProxyId == IAssetData(address(0)).ERC721Token.selector) {
if (_isAssetDataDuplicated(nestedAssetData, i)) {
return false;
}
}
}
return true;
}
/// Determines whether or not asset data is duplicated later in the nested asset data.
/// @param nestedAssetData The asset data to scan for duplication.
/// @param startIdx The index where the scan should begin.
/// @return A boolean reflecting whether or not the starting asset data was duplicated.
function _isAssetDataDuplicated(
bytes[] memory nestedAssetData,
uint256 startIdx
)
internal
pure
returns (bool)
{
uint256 length = nestedAssetData.length;
for (uint256 i = startIdx + 1; i < length; i++) {
if (nestedAssetData[startIdx].equals(nestedAssetData[i])) {
return true;
}
}
}
}

View File

@@ -0,0 +1,181 @@
/*
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.16;
pragma experimental ABIEncoderV2;
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IDydx.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
// solhint-disable separate-by-one-line-in-contract
contract TestDydx {
struct OperatorConfig {
address owner;
address operator;
}
struct AccountConfig {
address owner;
uint256 accountId;
int256[] balances;
}
struct MarketInfo {
address token;
uint256 price;
}
struct TestConfig {
uint256 marginRatio;
OperatorConfig[] operators;
AccountConfig[] accounts;
MarketInfo[] markets;
}
mapping (bytes32 => bool) private _operators;
mapping (bytes32 => int256) private _balance;
MarketInfo[] private _markets;
uint256 private _marginRatio;
constructor(TestConfig memory config) public {
_marginRatio = config.marginRatio;
for (uint256 marketId = 0; marketId < config.markets.length; ++marketId) {
_markets.push(config.markets[marketId]);
}
for (uint256 i = 0; i < config.operators.length; ++i) {
OperatorConfig memory op = config.operators[i];
_operators[_getOperatorHash(op.owner, op.operator)] = true;
}
for (uint256 i = 0; i < config.accounts.length; ++i) {
AccountConfig memory acct = config.accounts[i];
for (uint256 marketId = 0; marketId < acct.balances.length; ++marketId) {
_balance[_getBalanceHash(acct.owner, acct.accountId, marketId)] =
acct.balances[marketId];
}
}
}
function getIsLocalOperator(
address owner,
address operator
)
external
view
returns (bool isLocalOperator)
{
return _operators[_getOperatorHash(owner, operator)];
}
function getMarketTokenAddress(
uint256 marketId
)
external
view
returns (address tokenAddress)
{
return _markets[marketId].token;
}
function getRiskParams()
external
view
returns (IDydx.RiskParams memory riskParams)
{
return IDydx.RiskParams({
marginRatio: IDydx.D256(_marginRatio),
liquidationSpread: IDydx.D256(0),
earningsRate: IDydx.D256(0),
minBorrowedValue: IDydx.Value(0)
});
}
function getAdjustedAccountValues(
IDydx.AccountInfo calldata account
)
external
view
returns (IDydx.Value memory supplyValue, IDydx.Value memory borrowValue)
{
for (uint256 marketId = 0; marketId < _markets.length; ++marketId) {
int256 balance =
_balance[_getBalanceHash(account.owner, account.number, marketId)];
// Account values have 36 decimal places.
// `getMarketPrice()` returns a unit with
// 18 + (18 - TOKEN_DECIMALS) decimal places so multiplying the price
// with the wei balance will result in a 36 decimal value.
balance = balance * int256(getMarketPrice(marketId).value);
if (balance >= 0) {
supplyValue.value += uint256(balance);
} else {
borrowValue.value += uint256(-balance);
}
}
}
function getMarketMarginPremium(uint256)
external
view
returns (IDydx.D256 memory premium)
{
// Return 0.
return premium;
}
function getMarketPrice(
uint256 marketId
)
public
view
returns (IDydx.Price memory price)
{
MarketInfo memory market = _markets[marketId];
uint256 decimals = LibERC20Token.decimals(market.token);
price.value = _markets[marketId].price;
// Market prices have 18 + (18 - TOKEN_DECIMALS)
if (decimals > 18) {
price.value /= 10 ** (decimals - 18);
} else {
price.value *= 10 ** (18 - decimals);
}
}
function _getOperatorHash(address owner, address operator)
private
pure
returns (bytes32 operatorHash)
{
return keccak256(abi.encode(
owner,
operator
));
}
function _getBalanceHash(address owner, uint256 accountId, uint256 marketId)
private
pure
returns (bytes32 balanceHash)
{
return keccak256(abi.encode(
owner,
accountId,
marketId
));
}
}

View File

@@ -0,0 +1,116 @@
/*
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.16;
pragma experimental ABIEncoderV2;
import "../src/LibDydxBalance.sol";
contract TestLibDydxBalanceToken {
uint8 public decimals;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
constructor(uint8 decimals_) public {
decimals = decimals_;
}
function setBalance(address owner, uint256 balance) external {
balanceOf[owner] = balance;
}
function setApproval(
address owner,
address spender,
uint256 allowance_
)
external
{
allowance[owner][spender] = allowance_;
}
}
contract TestLibDydxBalance {
mapping (address => TestLibDydxBalanceToken) private tokens;
function createToken(uint8 decimals) external returns (address) {
TestLibDydxBalanceToken token = new TestLibDydxBalanceToken(decimals);
return address(tokens[address(token)] = token);
}
function setTokenBalance(
address tokenAddress,
address owner,
uint256 balance
)
external
{
tokens[tokenAddress].setBalance(owner, balance);
}
function setTokenApproval(
address tokenAddress,
address owner,
address spender,
uint256 allowance
)
external
{
tokens[tokenAddress].setApproval(owner, spender, allowance);
}
function getDydxMakerBalance(LibOrder.Order memory order, address dydx)
public
view
returns (uint256 balance)
{
return LibDydxBalance.getDydxMakerBalance(order, dydx);
}
function getSolventMakerAmount(
LibDydxBalance.BalanceCheckInfo memory info
)
public
view
returns (uint256 solventMakerAmount)
{
return LibDydxBalance._getSolventMakerAmount(info);
}
function getDepositableMakerAmount(
LibDydxBalance.BalanceCheckInfo memory info
)
public
view
returns (uint256 depositableMakerAmount)
{
return LibDydxBalance._getDepositableMakerAmount(info);
}
function areActionsWellFormed(LibDydxBalance.BalanceCheckInfo memory info)
public
view
returns (bool areWellFormed)
{
return LibDydxBalance._areActionsWellFormed(info);
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-dev-utils",
"version": "1.0.0",
"version": "1.3.2",
"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 && yarn mocha -t 10000 -b ./lib/test/**_test.js",
"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",
@@ -27,8 +27,8 @@
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
},
"config": {
"publicInterfaceContracts": "DevUtils,LibAssetData,LibTransactionDecoder",
"abis": "./test/generated-artifacts/@(DevUtils|EthBalanceChecker|LibAssetData|LibTransactionDecoder|OrderTransferSimulationUtils|OrderValidationUtils).json",
"publicInterfaceContracts": "DevUtils,LibAssetData,LibDydxBalance,LibOrderTransferSimulation,LibTransactionDecoder",
"abis": "./test/generated-artifacts/@(Addresses|AssetBalance|DevUtils|EthBalanceChecker|ExternalFunctions|LibAssetData|LibDydxBalance|LibOrderTransferSimulation|LibTransactionDecoder|OrderTransferSimulationUtils|OrderValidationUtils|TestDydx|TestLibDydxBalance).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
},
"repository": {
@@ -41,14 +41,19 @@
},
"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.2.2",
"@0x/assert": "^3.0.7",
"@0x/contracts-asset-proxy": "^3.2.4",
"@0x/contracts-erc20": "^3.1.4",
"@0x/contracts-gen": "^2.0.8",
"@0x/contracts-test-utils": "^5.3.1",
"@0x/sol-compiler": "^4.0.8",
"@0x/ts-doc-gen": "^0.0.22",
"@0x/tslint-config": "^4.0.0",
"@0x/types": "^3.1.2",
"@0x/utils": "^5.4.1",
"@types/node": "*",
"ethereum-types": "^3.0.0",
"ethereum-types": "^3.1.0",
"ethers": "~4.0.4",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
@@ -59,7 +64,7 @@
"typescript": "3.0.1"
},
"dependencies": {
"@0x/base-contract": "^6.0.0"
"@0x/base-contract": "^6.2.1"
},
"publishConfig": {
"access": "public"

View File

@@ -7,9 +7,13 @@ import { ContractArtifact } from 'ethereum-types';
import * as DevUtils from '../generated-artifacts/DevUtils.json';
import * as LibAssetData from '../generated-artifacts/LibAssetData.json';
import * as LibDydxBalance from '../generated-artifacts/LibDydxBalance.json';
import * as LibOrderTransferSimulation from '../generated-artifacts/LibOrderTransferSimulation.json';
import * as LibTransactionDecoder from '../generated-artifacts/LibTransactionDecoder.json';
export const artifacts = {
DevUtils: DevUtils as ContractArtifact,
LibAssetData: LibAssetData as ContractArtifact,
LibDydxBalance: LibDydxBalance as ContractArtifact,
LibOrderTransferSimulation: LibOrderTransferSimulation as ContractArtifact,
LibTransactionDecoder: LibTransactionDecoder as ContractArtifact,
};

View File

@@ -1,5 +1,5 @@
export { artifacts } from './artifacts';
export { DevUtilsContract, LibAssetDataContract, LibTransactionDecoderContract } from './wrappers';
export { DevUtilsContract } from './wrappers';
export {
ContractArtifact,
ContractChains,
@@ -15,6 +15,7 @@ export {
OutputField,
ParamDescription,
EvmBytecodeOutput,
EvmBytecodeOutputLinkReferences,
AbiDefinition,
FunctionAbi,
EventAbi,

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