chore: Prune old contracts (#304)

Prune exchange-libs
deploy migrations at specific address
remove exchange-libs, moving LibMath into Utils
Remove staking order-utils multisig and remaining asset-proxy
This commit is contained in:
Jacob Evans 2021-08-18 10:33:47 +10:00 committed by GitHub
parent aae46bef84
commit 68656b4a4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
741 changed files with 586 additions and 121272 deletions

View File

@ -2,7 +2,7 @@
--- ---
[0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. For more information on how it works, check out the [0x protocol specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md). [0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. For more information on how it works, check out the [0x protocol specification](https://protocol.0x.org/).
This repository is a monorepo including the 0x protocol smart contracts and numerous developer tools. Each public sub-package is independently published to NPM. This repository is a monorepo including the 0x protocol smart contracts and numerous developer tools. Each public sub-package is independently published to NPM.
@ -15,38 +15,29 @@ This repository is a monorepo including the 0x protocol smart contracts and nume
## Packages ## Packages
Visit our [developer portal](https://0x.org/docs/tools/order-utils) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below. Visit our [developer portal](https://0x.org/docs/) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below.
### Solidity Packages ### Solidity Packages
These packages are all under development. See [/contracts/README.md](/contracts/README.md) for a list of deployed packages. These packages are all under development. See [/contracts/README.md](/contracts/README.md) for a list of deployed packages.
| Package | Version | Description | | Package | Version | Description |
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| [`@0x/contracts-asset-proxy`](/contracts/asset-proxy) | [![npm](https://img.shields.io/npm/v/@0x/contracts-asset-proxy.svg)](https://www.npmjs.com/package/@0x/contracts-asset-proxy) | [`AssetProxy`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy) contracts used within the protocol | | [`@0x/contracts-zero-ex`](/contracts/zero-ex) | [![npm](https://img.shields.io/npm/v/@0x/contracts-zero-ex.svg)](https://www.npmjs.com/package/@0x/contracts-zero-ex) | The contracts used for settling trades within the protocol |
| [`@0x/contracts-erc20`](/contracts/erc20) | [![npm](https://img.shields.io/npm/v/@0x/contracts-erc20.svg)](https://www.npmjs.com/package/@0x/contracts-erc20) | Implementations of various ERC20 tokens | | [`@0x/contracts-erc20`](/contracts/erc20) | [![npm](https://img.shields.io/npm/v/@0x/contracts-erc20.svg)](https://www.npmjs.com/package/@0x/contracts-erc20) | Implementations of various ERC20 tokens |
| [`@0x/contracts-erc721`](/contracts/erc721) | [![npm](https://img.shields.io/npm/v/@0x/contracts-erc721.svg)](https://www.npmjs.com/package/@0x/contracts-erc721) | Implementations of various ERC721 tokens |
| [`@0x/contracts-erc1155`](/contracts/erc1155) | [![npm](https://img.shields.io/npm/v/@0x/contracts-erc1155.svg)](https://www.npmjs.com/package/@0x/contracts-erc1155) | Implementations of various ERC1155 tokens |
| [`@0x/contracts-exchange`](/contracts/exchange) | [![npm](https://img.shields.io/npm/v/@0x/contracts-exchange.svg)](https://www.npmjs.com/package/@0x/contracts-exchange) | The [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange) contract used for settling trades within the protocol |
| [`@0x/contracts-exchange-forwarder`](/contracts/exchange-forwarder) | [![npm](https://img.shields.io/npm/v/@0x/contracts-exchange-forwarder.svg)](https://www.npmjs.com/package/@0x/contracts-exchange-forwarder) | A [`Forwarder`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md) contract used to simplify UX for interacting with the protocol |
| [`@0x/contracts-exchange-libs`](/contracts/exchange-libs) | [![npm](https://img.shields.io/npm/v/@0x/contracts-exchange-libs.svg)](https://www.npmjs.com/package/@0x/contracts-exchange-libs) | Protocol specific libraries used within the [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange) contract |
| [`@0x/contracts-extensions`](/contracts/extensions) | [![npm](https://img.shields.io/npm/v/@0x/contracts-extensions.svg)](https://www.npmjs.com/package/@0x/contracts-extensions) | Contracts that interact with and extend the functionality of the core protocol |
| [`@0x/contracts-multisig`](/contracts/multisig) | [![npm](https://img.shields.io/npm/v/@0x/contracts-multisig.svg)](https://www.npmjs.com/package/@0x/contracts-multisig) | Various implementations of multisignature wallets, including the [`AssetProxyOwner`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxyowner) contract that has permissions to upgrade the protocol |
| [`@0x/contracts-test-utils`](/contracts/test-utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-test-utils.svg)](https://www.npmjs.com/package/@0x/contracts-test-utils) | TypeScript/Javascript shared utilities used for testing contracts | | [`@0x/contracts-test-utils`](/contracts/test-utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-test-utils.svg)](https://www.npmjs.com/package/@0x/contracts-test-utils) | TypeScript/Javascript shared utilities used for testing contracts |
| [`@0x/contracts-utils`](/contracts/utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-utils.svg)](https://www.npmjs.com/package/@0x/contracts-utils) | Generic libraries and utilities used throughout all of the contracts | | [`@0x/contracts-utils`](/contracts/utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-utils.svg)](https://www.npmjs.com/package/@0x/contracts-utils) | Generic libraries and utilities used throughout all of the contracts |
| [`@0x/contracts-coordinator`](/contracts/coordinator) | [![npm](https://img.shields.io/npm/v/@0x/contracts-coordinator.svg)](https://www.npmjs.com/package/@0x/contracts-coordinator) | A contract that allows users to execute 0x transactions with permission from a Coordinator |
| [`@0x/contracts-dev-utils`](/contracts/dev-utils) | [![npm](https://img.shields.io/npm/v/@0x/contracts-dev-utils.svg)](https://www.npmjs.com/package/@0x/contracts-dev-utils) | A contract contains utility functions for developers (such as validating many orders using a single eth_call) |
| [`@0x/contracts-staking`](/contracts/staking) | [![npm](https://img.shields.io/npm/v/@0x/contracts-staking.svg)](https://www.npmjs.com/package/@0x/contracts-staking) | Implements the stake-based liquidity incentives defined by [`ZEIP-31`](https://github.com/0xProject/ZEIPs/issues/31) |
### TypeScript/Javascript Packages ### TypeScript/Javascript Packages
#### 0x-specific packages #### 0x-specific packages
| Package | Version | Description | | Package | Version | Description |
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [`@0x/asset-swapper`](/packages/asset-swapper) | [![npm](https://img.shields.io/npm/v/@0x/asset-swapper.svg)](https://www.npmjs.com/package/@0x/asset-swapper) | Package used to find and create aggregated swaps |
| [`@0x/protocol-utils`](/packages/protocol-utils) | [![npm](https://img.shields.io/npm/v/@0x/protocol-utils.svg)](https://www.npmjs.com/package/@0x/protocol-utils) | A set of utilities for generating, parsing, signing and validating 0x orders |
| [`@0x/contract-addresses`](/packages/contract-addresses) | [![npm](https://img.shields.io/npm/v/@0x/contract-addresses.svg)](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. | | [`@0x/contract-addresses`](/packages/contract-addresses) | [![npm](https://img.shields.io/npm/v/@0x/contract-addresses.svg)](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. |
| [`@0x/contract-wrappers`](/packages/contract-wrappers) | [![npm](https://img.shields.io/npm/v/@0x/contract-wrappers.svg)](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts | | [`@0x/contract-wrappers`](/packages/contract-wrappers) | [![npm](https://img.shields.io/npm/v/@0x/contract-wrappers.svg)](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts |
| [`@0x/order-utils`](/packages/order-utils) | [![npm](https://img.shields.io/npm/v/@0x/order-utils.svg)](https://www.npmjs.com/package/@0x/order-utils) | A set of utilities for generating, parsing, signing and validating 0x orders |
| [`@0x/migrations`](/packages/migrations) | [![npm](https://img.shields.io/npm/v/@0x/migrations.svg)](https://www.npmjs.com/package/@0x/migrations) | Migration tool for deploying 0x smart contracts on private testnets | | [`@0x/migrations`](/packages/migrations) | [![npm](https://img.shields.io/npm/v/@0x/migrations.svg)](https://www.npmjs.com/package/@0x/migrations) | Migration tool for deploying 0x smart contracts on private testnets |
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [![npm](https://img.shields.io/npm/v/@0x/contract-artifacts.svg)](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts | | | [`@0x/contract-artifacts`](/packages/contract-artifacts) | [![npm](https://img.shields.io/npm/v/@0x/contract-artifacts.svg)](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts | |
@ -92,7 +83,7 @@ yarn build
To build a specific package: To build a specific package:
```bash ```bash
PKG=@0x/contract-wrappers yarn build PKG=@0x/asset-swapper yarn build
``` ```
To build all contracts packages: To build all contracts packages:
@ -115,7 +106,7 @@ To watch a specific package and all it's dependent packages:
PKG=[NPM_PACKAGE_NAME] yarn watch PKG=[NPM_PACKAGE_NAME] yarn watch
e.g e.g
PKG=@0x/contract-wrappers yarn watch PKG=@0x/asset-swapper yarn watch
``` ```
### Clean ### Clean
@ -129,7 +120,7 @@ yarn clean
Clean a specific package Clean a specific package
```bash ```bash
PKG=0x.js yarn clean PKG=@0x/asset-swapper yarn clean
``` ```
### Rebuild ### Rebuild
@ -143,7 +134,7 @@ yarn rebuild
To re-build (clean & build) a specific package & it's deps: To re-build (clean & build) a specific package & it's deps:
```bash ```bash
PKG=@0x/contract-wrappers yarn rebuild PKG=@0x/asset-swapper yarn rebuild
``` ```
### Lint ### Lint
@ -157,7 +148,7 @@ yarn lint
Lint a specific package: Lint a specific package:
```bash ```bash
PKG=@0x/contract-wrappers yarn lint PKG=@0x/asset-swapper yarn lint
``` ```
### Run Tests ### Run Tests
@ -171,7 +162,7 @@ yarn test
Run a specific package's test: Run a specific package's test:
```bash ```bash
PKG=@0x/contract-wrappers yarn test PKG=@0x/asset-swapper yarn test
``` ```
Run all contracts packages tests: Run all contracts packages tests:

View File

@ -1,16 +1,3 @@
#### Deployed Contract Packages
| Contract | Package | Version | Git Tag |
| --------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| AssetProxyOwner | [`@0x/contracts-multisig`](/contracts/multisig) | [v1.0.2](https://www.npmjs.com/package/@0x/contracts-multisig/v/1.0.2) | [@0x/contracts-multisig@1.0.2](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-multisig@1.0.2) |
| ERC20Proxy | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1) | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1) |
| ERC721Proxy | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1) | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1) |
| Exchange | [`@0x/contracts-exchange`](/contracts/exchange) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-exchange/v/1.0.1) | [@0x/contracts-exchange@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-exchange@1.0.1) |
| DutchAuction | [`@0x/contracts-extensions`](/contracts/extensions) | [v1.0.2](https://www.npmjs.com/package/@0x/contracts-extensions/v/1.0.2) | [@0x/contracts-extensions@1.0.2](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-extensions@1.0.2) |
| Forwarder | [`@0x/contracts-exchange-forwarder`](/contracts/exchange-forwarder) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-exchange-forwarder/v/1.0.1) | [@0x/contracts-exchange-forwarder@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-exchange-forwarder@1.0.1) |
| MultiAssetProxy | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1) | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1) |
| ZRXToken | [`@0x/contracts-erc20`](/contracts/erc20) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-erc20/v/1.0.1) | [@0x/contracts-erc20@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-erc20@1.0.1) |
#### Development #### Development
Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `contract-artifacts` or `contract-wrappers` packages, which are generated from the artifact JSON. See `contract-artifacts/README.md` for instructions on updating these packages. Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `contract-artifacts` or `contract-wrappers` packages, which are generated from the artifact JSON. See `contract-artifacts/README.md` for instructions on updating these packages.

View File

@ -1,48 +0,0 @@
# Contracts testing options
## Revert stack traces
If you want to see helpful stack traces (incl. line number, code snippet) for smart contract reverts, run the tests with:
```
yarn test:trace
```
**Note:** This currently slows down the test runs and is therefore not enabled by default.
## Backing Ethereum node
By default, our tests run against an in-process [Ganache](https://github.com/trufflesuite/ganache-core) instance. In order to run the tests against [Geth](https://github.com/ethereum/go-ethereum), first follow the instructions in the README for the devnet package to start the devnet Geth node. Then run:
```bash
TEST_PROVIDER=geth yarn test
```
## Code coverage
In order to see the Solidity code coverage output generated by `@0x/sol-coverage`, run:
```
yarn test:coverage
```
## Gas profiler
In order to profile the gas costs for a specific smart contract call/transaction, you can run the tests in `profiler` mode.
**Note:** Traces emitted by ganache have incorrect gas costs so we recommend using Geth for profiling.
```
TEST_PROVIDER=geth yarn test:profiler
```
You'll see a warning that you need to explicitly enable and disable the profiler before and after the block of code you want to profile.
```typescript
import { profiler } from './utils/profiler';
profiler.start();
// Some call to a smart contract
profiler.stop();
```
Without explicitly starting and stopping the profiler, the profiler output will be too busy, and therefore unusable.

View File

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

View File

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

View File

@ -1,904 +0,0 @@
[
{
"timestamp": 1629079369,
"version": "3.7.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1628665757,
"version": "3.7.18",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1628225642,
"version": "3.7.17",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1624356181,
"version": "3.7.16",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1623382456,
"version": "3.7.15",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1622609597,
"version": "3.7.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1621944788,
"version": "3.7.13",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1621600614,
"version": "3.7.12",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1620214333,
"version": "3.7.11",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "3.7.10",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1617311315,
"version": "3.7.9",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "3.7.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "3.7.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "3.7.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "3.7.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1610510890,
"version": "3.7.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1609802516,
"version": "3.7.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "3.7.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "3.7.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.7.0",
"changes": [
{
"note": "Fix Bancor support of ETH",
"pr": 88
}
],
"timestamp": 1608105788
},
{
"timestamp": 1607485227,
"version": "3.6.9",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607381756,
"version": "3.6.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1606961263,
"version": "3.6.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1605763885,
"version": "3.6.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1605302002,
"version": "3.6.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "3.6.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "3.6.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604355662,
"version": "3.6.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1603851023,
"version": "3.6.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.6.0",
"changes": [
{
"note": "Add `SwerveBridge` and `SnowSwapBridge` (duplicate of `CurveBridge`)",
"pr": 2707
}
],
"timestamp": 1603833198
},
{
"version": "3.5.0",
"changes": [
{
"note": "Update `CurveBridge` to support more varied curves",
"pr": 2633
},
{
"note": "Export DexForwarderBridgeContract",
"pr": 2656
},
{
"note": "Add BancorBridge and IBancorNetwork, ",
"pr": 2650
},
{
"note": "Added `MStableBridge`",
"pr": 2662
},
{
"note": "Added `MooniswapBridge`",
"pr": 2675
},
{
"note": "Reworked `KyberBridge`",
"pr": 2683
},
{
"note": "Added `CreamBridge`",
"pr": 2715
},
{
"note": "Added `ShellBridge`",
"pr": 2722
},
{
"note": "Added `DODOBridge`",
"pr": 2701
}
],
"timestamp": 1603265572
},
{
"version": "3.4.0",
"changes": [
{
"note": "Fix instability with DFB.",
"pr": 2616
},
{
"note": "Add `BalancerBridge`",
"pr": 2613
}
],
"timestamp": 1594788383
},
{
"version": "3.3.0",
"changes": [
{
"note": "Use `LibERC20Token.approveIfBelow()` in DEX bridges for for approvals.",
"pr": 2512
},
{
"note": "Emit `ERC20BridgeTransfer` events in bridges.",
"pr": 2512
},
{
"note": "Change names of `ERC20BridgeTransfer` args to be less ambiguous.",
"pr": 2524
},
{
"note": "Added `MixinGasToken` allowing Gas Tokens to be freed",
"pr": 2523
},
{
"note": "Add `DexForwaderBridge` bridge contract.",
"pr": 2525
},
{
"note": "Add `UniswapV2Bridge` bridge contract.",
"pr": 2590
},
{
"note": "Add Gas Token freeing to `DexForwarderBridge` contract.",
"pr": 2536
}
],
"timestamp": 1592969527
},
{
"timestamp": 1583220306,
"version": "3.2.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"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": 2462
}
],
"timestamp": 1581204851
},
{
"timestamp": 1580988106,
"version": "3.1.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1580811564,
"version": "3.1.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1579682890,
"version": "3.1.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.1.0",
"changes": [
{
"note": "Integration tests for DydxBridge with ERC20BridgeProxy.",
"pr": 2401
},
{
"note": "Fix `UniswapBridge` token -> token transfer call.",
"pr": 2412
},
{
"note": "Fix `KyberBridge` incorrect `minConversionRate` calculation.",
"pr": 2412
}
],
"timestamp": 1578272714
},
{
"timestamp": 1576540892,
"version": "3.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1575931811,
"version": "3.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "3.0.0",
"changes": [
{
"note": "Implement `KyberBridge`.",
"pr": 2352
},
{
"note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils",
"pr": 2330
},
{
"note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract",
"pr": 2034
},
{
"note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable",
"pr": 2019
},
{
"note": "Remove `LibAssetProxyIds` contract",
"pr": 2055
},
{
"note": "Compile and export all contracts, artifacts, and wrappers by default",
"pr": 2055
},
{
"note": "Remove unused dependency on IAuthorizable in IAssetProxy",
"pr": 1910
},
{
"note": "Add `ERC20BridgeProxy`",
"pr": 2220
},
{
"note": "Add `Eth2DaiBridge`",
"pr": 2221
},
{
"note": "Add `UniswapBridge`",
"pr": 2233
},
{
"note": "Replaced `SafeMath` with `LibSafeMath`",
"pr": 2254
}
],
"timestamp": 1575296764
},
{
"version": "2.3.0-beta.4",
"changes": [
{
"note": "Implement `KyberBridge`.",
"pr": 2352
},
{
"note": "Implement `DydxBridge`.",
"pr": 2365
}
],
"timestamp": 1575290197
},
{
"version": "2.3.0-beta.3",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1574238768
},
{
"version": "2.3.0-beta.2",
"changes": [
{
"note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils",
"pr": 2330
}
],
"timestamp": 1574030254
},
{
"version": "2.3.0-beta.1",
"changes": [
{
"note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract",
"pr": 2034
}
],
"timestamp": 1573159180
},
{
"version": "2.3.0-beta.0",
"changes": [
{
"note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable",
"pr": 2019
},
{
"note": "Remove `LibAssetProxyIds` contract",
"pr": 2055
},
{
"note": "Compile and export all contracts, artifacts, and wrappers by default",
"pr": 2055
},
{
"note": "Remove unused dependency on IAuthorizable in IAssetProxy",
"pr": 1910
},
{
"note": "Add `ERC20BridgeProxy`",
"pr": 2220
},
{
"note": "Add `Eth2DaiBridge`",
"pr": 2221
},
{
"note": "Add `UniswapBridge`",
"pr": 2233
},
{
"note": "Replaced `SafeMath` with `LibSafeMath`",
"pr": 2254
}
],
"timestamp": 1570135330
},
{
"timestamp": 1568744790,
"version": "2.2.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1567521715,
"version": "2.2.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1566446343,
"version": "2.2.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1565296576,
"version": "2.2.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "2.2.4",
"changes": [
{
"note": "Updated calls to <contract wrapper>.deployFrom0xArtifactAsync to include artifact dependencies.",
"pr": 1995
}
],
"timestamp": 1564607468
},
{
"timestamp": 1563957393,
"version": "2.2.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1563193019,
"version": "2.2.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1563047529,
"version": "2.2.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "2.2.0",
"changes": [
{
"note": "Add `LibAssetProxyIds` contract",
"pr": 1835
},
{
"note": "Updated ERC1155 Asset Proxy. Less optimization. More explicit handling of edge cases.",
"pr": 1852
},
{
"note": "Implement StaticCallProxy",
"pr": 1863
}
],
"timestamp": 1563006338
},
{
"timestamp": 1558712885,
"version": "2.1.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1557961111,
"version": "2.1.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1557799313,
"version": "2.1.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "2.1.2",
"changes": [
{
"note": "Update tests to use contract-built-in `awaitTransactionSuccessAsync`",
"pr": 1797
},
{
"note": "Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID",
"pr": 1819
},
{
"note": "Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()`",
"pr": 1819
},
{
"note": "Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`.",
"pr": 1819
}
],
"timestamp": 1557507213
},
{
"version": "2.1.1",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1554997931
},
{
"version": "2.1.0",
"changes": [
{
"note": "Run Web3ProviderEngine without excess block polling",
"pr": 1695
}
],
"timestamp": 1553183790
},
{
"version": "2.0.0",
"changes": [
{
"note": "Do not reexport external dependencies",
"pr": 1682
},
{
"note": "Add ERC1155Proxy",
"pr": 1661
},
{
"note": "Bumped solidity version to ^0.5.5",
"pr": 1701
},
{
"note": "Integration testing for ERC1155Proxy",
"pr": 1673
}
],
"timestamp": 1553091633
},
{
"timestamp": 1551479279,
"version": "1.0.9",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1551299797,
"version": "1.0.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1551220833,
"version": "1.0.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1551130135,
"version": "1.0.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1549733923,
"version": "1.0.5",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
],
"timestamp": 1549547375
},
{
"version": "1.0.3",
"changes": [
{
"note": "Fake publish to enable pinning"
}
],
"timestamp": 1549504360
},
{
"timestamp": 1549452781,
"version": "1.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1549373905,
"version": "1.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.0.0",
"changes": [
{
"note": "Move all AssetProxy contracts out of contracts-protocol to new package",
"pr": 1539
}
]
}
]

View File

@ -1,362 +0,0 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v3.7.19 - _August 16, 2021_
* Dependencies updated
## v3.7.18 - _August 11, 2021_
* Dependencies updated
## v3.7.17 - _August 6, 2021_
* Dependencies updated
## v3.7.16 - _June 22, 2021_
* Dependencies updated
## v3.7.15 - _June 11, 2021_
* Dependencies updated
## v3.7.14 - _June 2, 2021_
* Dependencies updated
## v3.7.13 - _May 25, 2021_
* Dependencies updated
## v3.7.12 - _May 21, 2021_
* Dependencies updated
## v3.7.11 - _May 5, 2021_
* Dependencies updated
## v3.7.10 - _April 28, 2021_
* Dependencies updated
## v3.7.9 - _April 1, 2021_
* Dependencies updated
## v3.7.8 - _March 17, 2021_
* Dependencies updated
## v3.7.7 - _February 24, 2021_
* Dependencies updated
## v3.7.6 - _February 10, 2021_
* Dependencies updated
## v3.7.5 - _January 26, 2021_
* Dependencies updated
## v3.7.4 - _January 13, 2021_
* Dependencies updated
## v3.7.3 - _January 4, 2021_
* Dependencies updated
## v3.7.2 - _December 23, 2020_
* Dependencies updated
## v3.7.1 - _December 17, 2020_
* Dependencies updated
## v3.7.0 - _December 16, 2020_
* Fix Bancor support of ETH (#88)
## v3.6.9 - _December 9, 2020_
* Dependencies updated
## v3.6.8 - _December 7, 2020_
* Dependencies updated
## v3.6.7 - _December 3, 2020_
* Dependencies updated
## v3.6.6 - _November 19, 2020_
* Dependencies updated
## v3.6.5 - _November 13, 2020_
* Dependencies updated
## v3.6.4 - _November 3, 2020_
* Dependencies updated
## v3.6.3 - _November 3, 2020_
* Dependencies updated
## v3.6.2 - _November 2, 2020_
* Dependencies updated
## v3.6.1 - _October 28, 2020_
* Dependencies updated
## v3.6.0 - _October 27, 2020_
* Add `SwerveBridge` and `SnowSwapBridge` (duplicate of `CurveBridge`) (#2707)
## v3.5.0 - _October 21, 2020_
* Update `CurveBridge` to support more varied curves (#2633)
* Export DexForwarderBridgeContract (#2656)
* Add BancorBridge and IBancorNetwork, (#2650)
* Added `MStableBridge` (#2662)
* Added `MooniswapBridge` (#2675)
* Reworked `KyberBridge` (#2683)
* Added `CreamBridge` (#2715)
* Added `ShellBridge` (#2722)
* Added `DODOBridge` (#2701)
## v3.4.0 - _July 15, 2020_
* Fix instability with DFB. (#2616)
* Add `BalancerBridge` (#2613)
## v3.3.0 - _June 24, 2020_
* Use `LibERC20Token.approveIfBelow()` in DEX bridges for for approvals. (#2512)
* Emit `ERC20BridgeTransfer` events in bridges. (#2512)
* Change names of `ERC20BridgeTransfer` args to be less ambiguous. (#2524)
* Added `MixinGasToken` allowing Gas Tokens to be freed (#2523)
* Add `DexForwaderBridge` bridge contract. (#2525)
* Add `UniswapV2Bridge` bridge contract. (#2590)
* Add Gas Token freeing to `DexForwarderBridge` contract. (#2536)
## v3.2.5 - _March 3, 2020_
* Dependencies updated
## 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` (#2462)
## v3.1.3 - _February 6, 2020_
* Dependencies updated
## v3.1.2 - _February 4, 2020_
* Dependencies updated
## v3.1.1 - _January 22, 2020_
* Dependencies updated
## v3.1.0 - _January 6, 2020_
* Integration tests for DydxBridge with ERC20BridgeProxy. (#2401)
* Fix `UniswapBridge` token -> token transfer call. (#2412)
* Fix `KyberBridge` incorrect `minConversionRate` calculation. (#2412)
## v3.0.2 - _December 17, 2019_
* Dependencies updated
## v3.0.1 - _December 9, 2019_
* Dependencies updated
## v3.0.0 - _December 2, 2019_
* Implement `KyberBridge`. (#2352)
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
* ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034)
* Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019)
* Remove `LibAssetProxyIds` contract (#2055)
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
* Remove unused dependency on IAuthorizable in IAssetProxy (#1910)
* Add `ERC20BridgeProxy` (#2220)
* Add `Eth2DaiBridge` (#2221)
* Add `UniswapBridge` (#2233)
* Replaced `SafeMath` with `LibSafeMath` (#2254)
## v2.3.0-beta.4 - _December 2, 2019_
* Implement `KyberBridge`. (#2352)
* Implement `DydxBridge`. (#2365)
## v2.3.0-beta.3 - _November 20, 2019_
* Dependencies updated
## v2.3.0-beta.2 - _November 17, 2019_
* Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
## v2.3.0-beta.1 - _November 7, 2019_
* ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034)
## v2.3.0-beta.0 - _October 3, 2019_
* Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019)
* Remove `LibAssetProxyIds` contract (#2055)
* Compile and export all contracts, artifacts, and wrappers by default (#2055)
* Remove unused dependency on IAuthorizable in IAssetProxy (#1910)
* Add `ERC20BridgeProxy` (#2220)
* Add `Eth2DaiBridge` (#2221)
* Add `UniswapBridge` (#2233)
* Replaced `SafeMath` with `LibSafeMath` (#2254)
## v2.2.8 - _September 17, 2019_
* Dependencies updated
## v2.2.7 - _September 3, 2019_
* Dependencies updated
## v2.2.6 - _August 22, 2019_
* Dependencies updated
## v2.2.5 - _August 8, 2019_
* Dependencies updated
## v2.2.4 - _July 31, 2019_
* Updated calls to <contract wrapper>.deployFrom0xArtifactAsync to include artifact dependencies. (#1995)
## v2.2.3 - _July 24, 2019_
* Dependencies updated
## v2.2.2 - _July 15, 2019_
* Dependencies updated
## v2.2.1 - _July 13, 2019_
* Dependencies updated
## v2.2.0 - _July 13, 2019_
* Add `LibAssetProxyIds` contract (#1835)
* Updated ERC1155 Asset Proxy. Less optimization. More explicit handling of edge cases. (#1852)
* Implement StaticCallProxy (#1863)
## v2.1.5 - _May 24, 2019_
* Dependencies updated
## v2.1.4 - _May 15, 2019_
* Dependencies updated
## v2.1.3 - _May 14, 2019_
* Dependencies updated
## v2.1.2 - _May 10, 2019_
* Update tests to use contract-built-in `awaitTransactionSuccessAsync` (#1797)
* Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID (#1819)
* Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()` (#1819)
* Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`. (#1819)
## v2.1.1 - _April 11, 2019_
* Dependencies updated
## v2.1.0 - _March 21, 2019_
* Run Web3ProviderEngine without excess block polling (#1695)
## v2.0.0 - _March 20, 2019_
* Do not reexport external dependencies (#1682)
* Add ERC1155Proxy (#1661)
* Bumped solidity version to ^0.5.5 (#1701)
* Integration testing for ERC1155Proxy (#1673)
## v1.0.9 - _March 1, 2019_
* Dependencies updated
## v1.0.8 - _February 27, 2019_
* Dependencies updated
## v1.0.7 - _February 26, 2019_
* Dependencies updated
## v1.0.6 - _February 25, 2019_
* Dependencies updated
## v1.0.5 - _February 9, 2019_
* Dependencies updated
## v1.0.4 - _February 7, 2019_
* Dependencies updated
## v1.0.3 - _February 7, 2019_
* Fake publish to enable pinning
## v1.0.2 - _February 6, 2019_
* Dependencies updated
## v1.0.1 - _February 5, 2019_
* Dependencies updated
## v1.0.0 - _Invalid date_
* Move all AssetProxy contracts out of contracts-protocol to new package (#1539)

View File

@ -1,47 +0,0 @@
[
{
"name": "MultiAssetProxy",
"version": "1.0.0",
"changes": [
{
"note": "Add MultiAssetProxy implementation",
"pr": 1224,
"networks": {
"3": "0xab8fbd189c569ccdee3a4d929bb7f557be4028f6",
"4": "0xb34cde0ad3a83d04abebc0b66e75196f22216621",
"42": "0xf6313a772c222f51c28f2304c0703b8cf5428fd8"
}
}
]
},
{
"name": "ERC20Proxy",
"version": "1.0.0",
"changes": [
{
"note": "protocol v2 deploy",
"networks": {
"1": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e",
"3": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa",
"4": "0x3e809c563c15a295e832e37053798ddc8d6c8dab",
"42": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e"
}
}
]
},
{
"name": "ERC721Proxy",
"version": "1.0.0",
"changes": [
{
"note": "protocol v2 deploy",
"networks": {
"1": "0x208e41fb445f1bb1b6780d58356e81405f3e6127",
"3": "0xe654aac058bfbf9f83fcaee7793311dd82f6ddb4",
"4": "0x8e1ff02637cb5e39f2fa36c14706aa348b065b09",
"42": "0x2a9127c745688a165106c11cd4d647d2220af821"
}
}
]
}
]

View File

@ -1,73 +0,0 @@
## AssetProxy
This package contains the implementations of all of the [`AssetProxy`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy) contracts available within the 0x protocol. These contracts are responsible for decoding the `assetData` sent to them and performing the actual transfer of assets. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package.
## Installation
**Install**
```bash
npm install @0x/contracts-asset-proxy --save
```
## Bug bounty
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program).
## Contributing
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
yarn config set workspaces-experimental true
```
Then install dependencies
```bash
yarn install
```
### Build
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
```bash
PKG=@0x/contracts-asset-proxy yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0x/contracts-asset-proxy yarn watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```
#### Testing options
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).

View File

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

View File

@ -1,172 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "../archive/Ownable.sol";
import "../src/interfaces/IAssetProxy.sol";
import "../src/interfaces/IAssetProxyDispatcher.sol";
contract MixinAssetProxyDispatcher is
Ownable,
IAssetProxyDispatcher
{
// Mapping from Asset Proxy Id's to their respective Asset Proxy
mapping (bytes4 => address) public assetProxies;
/// @dev Registers an asset proxy to its asset proxy id.
/// Once an asset proxy is registered, it cannot be unregistered.
/// @param assetProxy Address of new asset proxy to register.
function registerAssetProxy(address assetProxy)
external
onlyOwner
{
// Ensure that no asset proxy exists with current id.
bytes4 assetProxyId = IAssetProxy(assetProxy).getProxyId();
address currentAssetProxy = assetProxies[assetProxyId];
require(
currentAssetProxy == address(0),
"ASSET_PROXY_ALREADY_EXISTS"
);
// Add asset proxy and log registration.
assetProxies[assetProxyId] = assetProxy;
emit AssetProxyRegistered(
assetProxyId,
assetProxy
);
}
/// @dev Gets an asset proxy.
/// @param assetProxyId Id of the asset proxy.
/// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
function getAssetProxy(bytes4 assetProxyId)
external
view
returns (address)
{
return assetProxies[assetProxyId];
}
/// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
/// @param assetData Byte array encoded for the asset.
/// @param from Address to transfer token from.
/// @param to Address to transfer token to.
/// @param amount Amount of token to transfer.
function _dispatchTransferFrom(
bytes memory assetData,
address from,
address to,
uint256 amount
)
internal
{
// Do nothing if no amount should be transferred.
if (amount > 0 && from != to) {
// Ensure assetData length is valid
require(
assetData.length > 3,
"LENGTH_GREATER_THAN_3_REQUIRED"
);
// Lookup assetProxy. We do not use `LibBytes.readBytes4` for gas efficiency reasons.
bytes4 assetProxyId;
assembly {
assetProxyId := and(mload(
add(assetData, 32)),
0xFFFFFFFF00000000000000000000000000000000000000000000000000000000
)
}
address assetProxy = assetProxies[assetProxyId];
// Ensure that assetProxy exists
require(
assetProxy != address(0),
"ASSET_PROXY_DOES_NOT_EXIST"
);
// We construct calldata for the `assetProxy.transferFrom` ABI.
// The layout of this calldata is in the table below.
//
// | Area | Offset | Length | Contents |
// | -------- |--------|---------|-------------------------------------------- |
// | Header | 0 | 4 | function selector |
// | Params | | 4 * 32 | function parameters: |
// | | 4 | | 1. offset to assetData (*) |
// | | 36 | | 2. from |
// | | 68 | | 3. to |
// | | 100 | | 4. amount |
// | Data | | | assetData: |
// | | 132 | 32 | assetData Length |
// | | 164 | ** | assetData Contents |
assembly {
/////// Setup State ///////
// `cdStart` is the start of the calldata for `assetProxy.transferFrom` (equal to free memory ptr).
let cdStart := mload(64)
// `dataAreaLength` is the total number of words needed to store `assetData`
// As-per the ABI spec, this value is padded up to the nearest multiple of 32,
// and includes 32-bytes for length.
let dataAreaLength := and(add(mload(assetData), 63), 0xFFFFFFFFFFFE0)
// `cdEnd` is the end of the calldata for `assetProxy.transferFrom`.
let cdEnd := add(cdStart, add(132, dataAreaLength))
/////// Setup Header Area ///////
// This area holds the 4-byte `transferFromSelector`.
// bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
mstore(cdStart, 0xa85e59e400000000000000000000000000000000000000000000000000000000)
/////// Setup Params Area ///////
// Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes.
// Notes:
// 1. The offset to `assetData` is the length of the Params Area (128 bytes).
// 2. A 20-byte mask is applied to addresses to zero-out the unused bytes.
mstore(add(cdStart, 4), 128)
mstore(add(cdStart, 36), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(cdStart, 68), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(cdStart, 100), amount)
/////// Setup Data Area ///////
// This area holds `assetData`.
let dataArea := add(cdStart, 132)
// solhint-disable-next-line no-empty-blocks
for {} lt(dataArea, cdEnd) {} {
mstore(dataArea, mload(assetData))
dataArea := add(dataArea, 32)
assetData := add(assetData, 32)
}
/////// Call `assetProxy.transferFrom` using the constructed calldata ///////
let success := call(
gas, // forward all gas
assetProxy, // call address of asset proxy
0, // don't send any ETH
cdStart, // pointer to start of input
sub(cdEnd, cdStart), // length of input
cdStart, // write output over input
512 // reserve 512 bytes for output
)
if iszero(success) {
revert(cdStart, returndatasize())
}
}
}
}
}

View File

@ -1,117 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "../archive/Ownable.sol";
import "../src/interfaces/IAuthorizable.sol";
contract MixinAuthorizable is
Ownable,
IAuthorizable
{
/// @dev Only authorized addresses can invoke functions with this modifier.
modifier onlyAuthorized {
require(
authorized[msg.sender],
"SENDER_NOT_AUTHORIZED"
);
_;
}
mapping (address => bool) public authorized;
address[] public authorities;
/// @dev Authorizes an address.
/// @param target Address to authorize.
function addAuthorizedAddress(address target)
external
onlyOwner
{
require(
!authorized[target],
"TARGET_ALREADY_AUTHORIZED"
);
authorized[target] = true;
authorities.push(target);
emit AuthorizedAddressAdded(target, msg.sender);
}
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
function removeAuthorizedAddress(address target)
external
onlyOwner
{
require(
authorized[target],
"TARGET_NOT_AUTHORIZED"
);
delete authorized[target];
for (uint256 i = 0; i < authorities.length; i++) {
if (authorities[i] == target) {
authorities[i] = authorities[authorities.length - 1];
authorities.length -= 1;
break;
}
}
emit AuthorizedAddressRemoved(target, msg.sender);
}
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
/// @param index Index of target in authorities array.
function removeAuthorizedAddressAtIndex(
address target,
uint256 index
)
external
onlyOwner
{
require(
authorized[target],
"TARGET_NOT_AUTHORIZED"
);
require(
index < authorities.length,
"INDEX_OUT_OF_BOUNDS"
);
require(
authorities[index] == target,
"AUTHORIZED_ADDRESS_MISMATCH"
);
delete authorized[target];
authorities[index] = authorities[authorities.length - 1];
authorities.length -= 1;
emit AuthorizedAddressRemoved(target, msg.sender);
}
/// @dev Gets all authorized addresses.
/// @return Array of authorized addresses.
function getAuthorizedAddresses()
external
view
returns (address[] memory)
{
return authorities;
}
}

View File

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

View File

@ -1,97 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
import "../archive/MixinAuthorizable.sol";
import "./interfaces/IAssetProxy.sol";
contract ERC1155Proxy is
MixinAuthorizable,
IAssetProxy
{
using LibBytes for bytes;
using LibSafeMath for uint256;
// Id of this proxy.
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC1155Assets(address,uint256[],uint256[],bytes)"));
/// @dev Transfers batch of ERC1155 assets. Either succeeds or throws.
/// @param assetData Byte array encoded with ERC1155 token address, array of ids, array of values, and callback data.
/// @param from Address to transfer assets from.
/// @param to Address to transfer assets to.
/// @param amount Amount that will be multiplied with each element of `assetData.values` to scale the
/// values that will be transferred.
function transferFrom(
bytes calldata assetData,
address from,
address to,
uint256 amount
)
external
onlyAuthorized
{
// Decode params from `assetData`
// solhint-disable indent
(
address erc1155TokenAddress,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) = abi.decode(
assetData.sliceDestructive(4, assetData.length),
(address, uint256[], uint256[], bytes)
);
// solhint-enable indent
// Scale values up by `amount`
uint256 length = values.length;
uint256[] memory scaledValues = new uint256[](length);
for (uint256 i = 0; i != length; i++) {
// We write the scaled values to an unused location in memory in order
// to avoid copying over `ids` or `data`. This is possible if they are
// identical to `values` and the offsets for each are pointing to the
// same location in the ABI encoded calldata.
scaledValues[i] = values[i].safeMul(amount);
}
// Execute `safeBatchTransferFrom` call
// Either succeeds or throws
IERC1155(erc1155TokenAddress).safeBatchTransferFrom(
from,
to,
ids,
scaledValues,
data
);
}
/// @dev Gets the proxy id associated with the proxy address.
/// @return Proxy id.
function getProxyId()
external
pure
returns (bytes4)
{
return PROXY_ID;
}
}

View File

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

View File

@ -1,184 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "../archive/MixinAuthorizable.sol";
contract ERC20Proxy is
MixinAuthorizable
{
// Id of this proxy.
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
// solhint-disable-next-line payable-fallback
function ()
external
{
assembly {
// The first 4 bytes of calldata holds the function selector
let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
// `transferFrom` will be called with the following parameters:
// assetData Encoded byte array.
// from Address to transfer asset from.
// to Address to transfer asset to.
// amount Amount of asset to transfer.
// bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
// To lookup a value in a mapping, we load from the storage location keccak256(k, p),
// where k is the key left padded to 32 bytes and p is the storage slot
let start := mload(64)
mstore(start, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(start, 32), authorized_slot)
// Revert if authorized[msg.sender] == false
if iszero(sload(keccak256(start, 64))) {
// Revert with `Error("SENDER_NOT_AUTHORIZED")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000)
mstore(96, 0)
revert(0, 100)
}
// `transferFrom`.
// The function is marked `external`, so no abi decodeding is done for
// us. Instead, we expect the `calldata` memory to contain the
// following:
//
// | Area | Offset | Length | Contents |
// |----------|--------|---------|-------------------------------------|
// | Header | 0 | 4 | function selector |
// | Params | | 4 * 32 | function parameters: |
// | | 4 | | 1. offset to assetData (*) |
// | | 36 | | 2. from |
// | | 68 | | 3. to |
// | | 100 | | 4. amount |
// | Data | | | assetData: |
// | | 132 | 32 | assetData Length |
// | | 164 | ** | assetData Contents |
//
// (*): offset is computed from start of function parameters, so offset
// by an additional 4 bytes in the calldata.
//
// (**): see table below to compute length of assetData Contents
//
// WARNING: The ABIv2 specification allows additional padding between
// the Params and Data section. This will result in a larger
// offset to assetData.
// Asset data itself is encoded as follows:
//
// | Area | Offset | Length | Contents |
// |----------|--------|---------|-------------------------------------|
// | Header | 0 | 4 | function selector |
// | Params | | 1 * 32 | function parameters: |
// | | 4 | 12 + 20 | 1. token address |
// We construct calldata for the `token.transferFrom` ABI.
// The layout of this calldata is in the table below.
//
// | Area | Offset | Length | Contents |
// |----------|--------|---------|-------------------------------------|
// | Header | 0 | 4 | function selector |
// | Params | | 3 * 32 | function parameters: |
// | | 4 | | 1. from |
// | | 36 | | 2. to |
// | | 68 | | 3. amount |
/////// Read token address from calldata ///////
// * The token address is stored in `assetData`.
//
// * The "offset to assetData" is stored at offset 4 in the calldata (table 1).
// [assetDataOffsetFromParams = calldataload(4)]
//
// * Notes that the "offset to assetData" is relative to the "Params" area of calldata;
// add 4 bytes to account for the length of the "Header" area (table 1).
// [assetDataOffsetFromHeader = assetDataOffsetFromParams + 4]
//
// * The "token address" is offset 32+4=36 bytes into "assetData" (tables 1 & 2).
// [tokenOffset = assetDataOffsetFromHeader + 36 = calldataload(4) + 4 + 36]
let token := calldataload(add(calldataload(4), 40))
/////// Setup Header Area ///////
// This area holds the 4-byte `transferFrom` selector.
// Any trailing data in transferFromSelector will be
// overwritten in the next `mstore` call.
mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
/////// Setup Params Area ///////
// We copy the fields `from`, `to` and `amount` in bulk
// from our own calldata to the new calldata.
calldatacopy(4, 36, 96)
/////// Call `token.transferFrom` using the calldata ///////
let success := call(
gas, // forward all gas
token, // call address of token contract
0, // don't send any ETH
0, // pointer to start of input
100, // length of input
0, // write output over input
32 // output size should be 32 bytes
)
/////// Check return data. ///////
// If there is no return data, we assume the token incorrectly
// does not return a bool. In this case we expect it to revert
// on failure, which was handled above.
// If the token does return data, we require that it is a single
// nonzero 32 bytes value.
// So the transfer succeeded if the call succeeded and either
// returned nothing, or returned a non-zero 32 byte value.
success := and(success, or(
iszero(returndatasize),
and(
eq(returndatasize, 32),
gt(mload(0), 0)
)
))
if success {
return(0, 0)
}
// Revert with `Error("TRANSFER_FAILED")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000)
mstore(96, 0)
revert(0, 100)
}
// Revert if undefined function is called
revert(0, 0)
}
}
/// @dev Gets the proxy id associated with the proxy address.
/// @return Proxy id.
function getProxyId()
external
pure
returns (bytes4)
{
return PROXY_ID;
}
}

View File

@ -1,171 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "../archive/MixinAuthorizable.sol";
contract ERC721Proxy is
MixinAuthorizable
{
// Id of this proxy.
bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
// solhint-disable-next-line payable-fallback
function ()
external
{
assembly {
// The first 4 bytes of calldata holds the function selector
let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
// `transferFrom` will be called with the following parameters:
// assetData Encoded byte array.
// from Address to transfer asset from.
// to Address to transfer asset to.
// amount Amount of asset to transfer.
// bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
// To lookup a value in a mapping, we load from the storage location keccak256(k, p),
// where k is the key left padded to 32 bytes and p is the storage slot
let start := mload(64)
mstore(start, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(start, 32), authorized_slot)
// Revert if authorized[msg.sender] == false
if iszero(sload(keccak256(start, 64))) {
// Revert with `Error("SENDER_NOT_AUTHORIZED")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000)
mstore(96, 0)
revert(0, 100)
}
// `transferFrom`.
// The function is marked `external`, so no abi decodeding is done for
// us. Instead, we expect the `calldata` memory to contain the
// following:
//
// | Area | Offset | Length | Contents |
// |----------|--------|---------|-------------------------------------|
// | Header | 0 | 4 | function selector |
// | Params | | 4 * 32 | function parameters: |
// | | 4 | | 1. offset to assetData (*) |
// | | 36 | | 2. from |
// | | 68 | | 3. to |
// | | 100 | | 4. amount |
// | Data | | | assetData: |
// | | 132 | 32 | assetData Length |
// | | 164 | ** | assetData Contents |
//
// (*): offset is computed from start of function parameters, so offset
// by an additional 4 bytes in the calldata.
//
// (**): see table below to compute length of assetData Contents
//
// WARNING: The ABIv2 specification allows additional padding between
// the Params and Data section. This will result in a larger
// offset to assetData.
// Asset data itself is encoded as follows:
//
// | Area | Offset | Length | Contents |
// |----------|--------|---------|-------------------------------------|
// | Header | 0 | 4 | function selector |
// | Params | | 2 * 32 | function parameters: |
// | | 4 | 12 + 20 | 1. token address |
// | | 36 | | 2. tokenId |
// We construct calldata for the `token.transferFrom` ABI.
// The layout of this calldata is in the table below.
//
// | Area | Offset | Length | Contents |
// |----------|--------|---------|-------------------------------------|
// | Header | 0 | 4 | function selector |
// | Params | | 3 * 32 | function parameters: |
// | | 4 | | 1. from |
// | | 36 | | 2. to |
// | | 68 | | 3. tokenId |
// There exists only 1 of each token.
// require(amount == 1, "INVALID_AMOUNT")
if sub(calldataload(100), 1) {
// Revert with `Error("INVALID_AMOUNT")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000000e494e56414c49445f414d4f554e540000000000000000000000000000)
mstore(96, 0)
revert(0, 100)
}
/////// Setup Header Area ///////
// This area holds the 4-byte `transferFrom` selector.
// Any trailing data in transferFromSelector will be
// overwritten in the next `mstore` call.
mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
/////// Setup Params Area ///////
// We copy the fields `from` and `to` in bulk
// from our own calldata to the new calldata.
calldatacopy(4, 36, 64)
// Copy `tokenId` field from our own calldata to the new calldata.
let assetDataOffset := calldataload(4)
calldatacopy(68, add(assetDataOffset, 72), 32)
/////// Call `token.transferFrom` using the calldata ///////
let token := calldataload(add(assetDataOffset, 40))
let success := call(
gas, // forward all gas
token, // call address of token contract
0, // don't send any ETH
0, // pointer to start of input
100, // length of input
0, // write output to null
0 // output size is 0 bytes
)
if success {
return(0, 0)
}
// Revert with `Error("TRANSFER_FAILED")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000)
mstore(96, 0)
revert(0, 100)
}
// Revert if undefined function is called
revert(0, 0)
}
}
/// @dev Gets the proxy id associated with the proxy address.
/// @return Proxy id.
function getProxyId()
external
pure
returns (bytes4)
{
return PROXY_ID;
}
}

View File

@ -1,335 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "../archive/MixinAssetProxyDispatcher.sol";
import "../archive/MixinAuthorizable.sol";
contract MultiAssetProxy is
MixinAssetProxyDispatcher,
MixinAuthorizable
{
// Id of this proxy.
bytes4 constant internal PROXY_ID = bytes4(keccak256("MultiAsset(uint256[],bytes[])"));
// solhint-disable-next-line payable-fallback
function ()
external
{
// NOTE: The below assembly assumes that clients do some input validation and that the input is properly encoded according to the AbiV2 specification.
// It is technically possible for inputs with very large lengths and offsets to cause overflows. However, this would make the calldata prohibitively
// expensive and we therefore do not check for overflows in these scenarios.
assembly {
// The first 4 bytes of calldata holds the function selector
let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
// `transferFrom` will be called with the following parameters:
// assetData Encoded byte array.
// from Address to transfer asset from.
// to Address to transfer asset to.
// amount Amount of asset to transfer.
// bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
// To lookup a value in a mapping, we load from the storage location keccak256(k, p),
// where k is the key left padded to 32 bytes and p is the storage slot
mstore(0, caller)
mstore(32, authorized_slot)
// Revert if authorized[msg.sender] == false
if iszero(sload(keccak256(0, 64))) {
// Revert with `Error("SENDER_NOT_AUTHORIZED")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000)
mstore(96, 0)
revert(0, 100)
}
// `transferFrom`.
// The function is marked `external`, so no abi decoding is done for
// us. Instead, we expect the `calldata` memory to contain the
// following:
//
// | Area | Offset | Length | Contents |
// |----------|--------|---------|-------------------------------------|
// | Header | 0 | 4 | function selector |
// | Params | | 4 * 32 | function parameters: |
// | | 4 | | 1. offset to assetData (*) |
// | | 36 | | 2. from |
// | | 68 | | 3. to |
// | | 100 | | 4. amount |
// | Data | | | assetData: |
// | | 132 | 32 | assetData Length |
// | | 164 | ** | assetData Contents |
//
// (*): offset is computed from start of function parameters, so offset
// by an additional 4 bytes in the calldata.
//
// (**): see table below to compute length of assetData Contents
//
// WARNING: The ABIv2 specification allows additional padding between
// the Params and Data section. This will result in a larger
// offset to assetData.
// Load offset to `assetData`
let assetDataOffset := add(calldataload(4), 4)
// Load length in bytes of `assetData`
let assetDataLength := calldataload(assetDataOffset)
// Asset data itself is encoded as follows:
//
// | Area | Offset | Length | Contents |
// |----------|-------------|---------|-------------------------------------|
// | Header | 0 | 4 | assetProxyId |
// | Params | | 2 * 32 | function parameters: |
// | | 4 | | 1. offset to amounts (*) |
// | | 36 | | 2. offset to nestedAssetData (*) |
// | Data | | | amounts: |
// | | 68 | 32 | amounts Length |
// | | 100 | a | amounts Contents |
// | | | | nestedAssetData: |
// | | 100 + a | 32 | nestedAssetData Length |
// | | 132 + a | b | nestedAssetData Contents (offsets) |
// | | 132 + a + b | | nestedAssetData[0, ..., len] |
// Assert that the length of asset data:
// 1. Must be at least 68 bytes (see table above)
// 2. Must be a multiple of 32 (excluding the 4-byte selector)
if or(lt(assetDataLength, 68), mod(sub(assetDataLength, 4), 32)) {
// Revert with `Error("INVALID_ASSET_DATA_LENGTH")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x00000019494e56414c49445f41535345545f444154415f4c454e475448000000)
mstore(96, 0)
revert(0, 100)
}
// End of asset data in calldata
// assetDataOffset
// + 32 (assetData len)
let assetDataEnd := add(assetDataOffset, add(assetDataLength, 32))
if gt(assetDataEnd, calldatasize()) {
// Revert with `Error("INVALID_ASSET_DATA_END")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x00000016494e56414c49445f41535345545f444154415f454e44000000000000)
mstore(96, 0)
revert(0, 100)
}
// In order to find the offset to `amounts`, we must add:
// assetDataOffset
// + 32 (assetData len)
// + 4 (assetProxyId)
let amountsOffset := calldataload(add(assetDataOffset, 36))
// In order to find the offset to `nestedAssetData`, we must add:
// assetDataOffset
// + 32 (assetData len)
// + 4 (assetProxyId)
// + 32 (amounts offset)
let nestedAssetDataOffset := calldataload(add(assetDataOffset, 68))
// In order to find the start of the `amounts` contents, we must add:
// assetDataOffset
// + 32 (assetData len)
// + 4 (assetProxyId)
// + amountsOffset
// + 32 (amounts len)
let amountsContentsStart := add(assetDataOffset, add(amountsOffset, 68))
// Load number of elements in `amounts`
let amountsLen := calldataload(sub(amountsContentsStart, 32))
// In order to find the start of the `nestedAssetData` contents, we must add:
// assetDataOffset
// + 32 (assetData len)
// + 4 (assetProxyId)
// + nestedAssetDataOffset
// + 32 (nestedAssetData len)
let nestedAssetDataContentsStart := add(assetDataOffset, add(nestedAssetDataOffset, 68))
// Load number of elements in `nestedAssetData`
let nestedAssetDataLen := calldataload(sub(nestedAssetDataContentsStart, 32))
// Revert if number of elements in `amounts` differs from number of elements in `nestedAssetData`
if sub(amountsLen, nestedAssetDataLen) {
// Revert with `Error("LENGTH_MISMATCH")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000000f4c454e4754485f4d49534d4154434800000000000000000000000000)
mstore(96, 0)
revert(0, 100)
}
// Copy `transferFrom` selector, offset to `assetData`, `from`, and `to` from calldata to memory
calldatacopy(
0, // memory can safely be overwritten from beginning
0, // start of calldata
100 // length of selector (4) and 3 params (32 * 3)
)
// Overwrite existing offset to `assetData` with our own
mstore(4, 128)
// Load `amount`
let amount := calldataload(100)
// Calculate number of bytes in `amounts` contents
let amountsByteLen := mul(amountsLen, 32)
// Initialize `assetProxyId` and `assetProxy` to 0
let assetProxyId := 0
let assetProxy := 0
// Loop through `amounts` and `nestedAssetData`, calling `transferFrom` for each respective element
for {let i := 0} lt(i, amountsByteLen) {i := add(i, 32)} {
// Calculate the total amount
let amountsElement := calldataload(add(amountsContentsStart, i))
let totalAmount := mul(amountsElement, amount)
// Revert if `amount` != 0 and multiplication resulted in an overflow
if iszero(or(
iszero(amount),
eq(div(totalAmount, amount), amountsElement)
)) {
// Revert with `Error("UINT256_OVERFLOW")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000001055494e543235365f4f564552464c4f57000000000000000000000000)
mstore(96, 0)
revert(0, 100)
}
// Write `totalAmount` to memory
mstore(100, totalAmount)
// Load offset to `nestedAssetData[i]`
let nestedAssetDataElementOffset := calldataload(add(nestedAssetDataContentsStart, i))
// In order to find the start of the `nestedAssetData[i]` contents, we must add:
// assetDataOffset
// + 32 (assetData len)
// + 4 (assetProxyId)
// + nestedAssetDataOffset
// + 32 (nestedAssetData len)
// + nestedAssetDataElementOffset
// + 32 (nestedAssetDataElement len)
let nestedAssetDataElementContentsStart := add(
assetDataOffset,
add(
nestedAssetDataOffset,
add(nestedAssetDataElementOffset, 100)
)
)
// Load length of `nestedAssetData[i]`
let nestedAssetDataElementLenStart := sub(nestedAssetDataElementContentsStart, 32)
let nestedAssetDataElementLen := calldataload(nestedAssetDataElementLenStart)
// Revert if the `nestedAssetData` does not contain a 4 byte `assetProxyId`
if lt(nestedAssetDataElementLen, 4) {
// Revert with `Error("LENGTH_GREATER_THAN_3_REQUIRED")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000001e4c454e4754485f475245415445525f5448414e5f335f524551554952)
mstore(96, 0x4544000000000000000000000000000000000000000000000000000000000000)
revert(0, 100)
}
// Load AssetProxy id
let currentAssetProxyId := and(
calldataload(nestedAssetDataElementContentsStart),
0xffffffff00000000000000000000000000000000000000000000000000000000
)
// Only load `assetProxy` if `currentAssetProxyId` does not equal `assetProxyId`
// We do not need to check if `currentAssetProxyId` is 0 since `assetProxy` is also initialized to 0
if sub(currentAssetProxyId, assetProxyId) {
// Update `assetProxyId`
assetProxyId := currentAssetProxyId
// To lookup a value in a mapping, we load from the storage location keccak256(k, p),
// where k is the key left padded to 32 bytes and p is the storage slot
mstore(132, assetProxyId)
mstore(164, assetProxies_slot)
assetProxy := sload(keccak256(132, 64))
}
// Revert if AssetProxy with given id does not exist
if iszero(assetProxy) {
// Revert with `Error("ASSET_PROXY_DOES_NOT_EXIST")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000001a41535345545f50524f58595f444f45535f4e4f545f45584953540000)
mstore(96, 0)
revert(0, 100)
}
// Copy `nestedAssetData[i]` from calldata to memory
calldatacopy(
132, // memory slot after `amounts[i]`
nestedAssetDataElementLenStart, // location of `nestedAssetData[i]` in calldata
add(nestedAssetDataElementLen, 32) // `nestedAssetData[i].length` plus 32 byte length
)
// call `assetProxy.transferFrom`
let success := call(
gas, // forward all gas
assetProxy, // call address of asset proxy
0, // don't send any ETH
0, // pointer to start of input
add(164, nestedAssetDataElementLen), // length of input
0, // write output over memory that won't be reused
0 // don't copy output to memory
)
// Revert with reason given by AssetProxy if `transferFrom` call failed
if iszero(success) {
returndatacopy(
0, // copy to memory at 0
0, // copy from return data at 0
returndatasize() // copy all return data
)
revert(0, returndatasize())
}
}
// Return if no `transferFrom` calls reverted
return(0, 0)
}
// Revert if undefined function is called
revert(0, 0)
}
}
/// @dev Gets the proxy id associated with the proxy address.
/// @return Proxy id.
function getProxyId()
external
pure
returns (bytes4)
{
return PROXY_ID;
}
}

View File

@ -1,83 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
// solhint-disable no-unused-vars
contract StaticCallProxy {
using LibBytes for bytes;
// Id of this proxy.
bytes4 constant internal PROXY_ID = bytes4(keccak256("StaticCall(address,bytes,bytes32)"));
/// @dev Makes a staticcall to a target address and verifies that the data returned matches the expected return data.
/// @param assetData Byte array encoded with staticCallTarget, staticCallData, and expectedCallResultHash
/// @param from This value is ignored.
/// @param to This value is ignored.
/// @param amount This value is ignored.
function transferFrom(
bytes calldata assetData,
address from,
address to,
uint256 amount
)
external
view
{
// Decode params from `assetData`
(
address staticCallTarget,
bytes memory staticCallData,
bytes32 expectedReturnDataHash
) = abi.decode(
assetData.sliceDestructive(4, assetData.length),
(address, bytes, bytes32)
);
// Execute staticcall
(bool success, bytes memory returnData) = staticCallTarget.staticcall(staticCallData);
// Revert with returned data if staticcall is unsuccessful
if (!success) {
assembly {
revert(add(returnData, 32), mload(returnData))
}
}
// Revert if hash of return data is not as expected
bytes32 returnDataHash = keccak256(returnData);
require(
expectedReturnDataHash == returnDataHash,
"UNEXPECTED_STATIC_CALL_RESULT"
);
}
/// @dev Gets the proxy id associated with the proxy address.
/// @return Proxy id.
function getProxyId()
external
pure
returns (bytes4)
{
return PROXY_ID;
}
}

View File

@ -1,103 +0,0 @@
/*
Copyright 2020 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/IBalancerPool.sol";
contract BalancerBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
/// token encoded in the bridge data, then transfers the bought
/// tokens to `to`.
/// @param toTokenAddress The token to buy and transfer to `to`.
/// @param from The maker (this contract).
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoded addresses of the "from" token and Balancer pool.
/// @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.
(address fromTokenAddress, address poolAddress) = abi.decode(
bridgeData,
(address, address)
);
require(toTokenAddress != fromTokenAddress, "BalancerBridge/INVALID_PAIR");
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
LibERC20Token.approveIfBelow(fromTokenAddress, poolAddress, fromTokenBalance);
// Sell all of this contract's `fromTokenAddress` token balance.
(uint256 boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn(
fromTokenAddress, // tokenIn
fromTokenBalance, // tokenAmountIn
toTokenAddress, // tokenOut
amount, // minAmountOut
uint256(-1) // maxPrice
);
// Transfer the converted `toToken`s to `to`.
LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
emit ERC20BridgeTransfer(
fromTokenAddress,
toTokenAddress,
fromTokenBalance,
boughtAmount,
from,
to
);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Magic success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@ -1,144 +0,0 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IERC20Bridge.sol";
import "../interfaces/IBancorNetwork.sol";
contract BancorBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
struct TransferState {
address bancorNetworkAddress;
address[] path;
IEtherToken weth;
}
/// @dev Bancor ETH pseudo-address.
address constant public BANCOR_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
// solhint-disable no-empty-blocks
/// @dev Payable fallback to receive ETH from Bancor/WETH.
function ()
external
payable
{
// Poor man's receive in 0.5.9
require(msg.data.length == 0);
}
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
/// token encoded in the bridge data, then transfers the bought
/// tokens to `to`.
/// @param toTokenAddress The token to buy and transfer to `to`.
/// @param from The maker (this contract).
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoded conversion path addresses and Bancor network 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)
{
// hold variables to get around stack depth limitations
TransferState memory state;
// Decode the bridge data.
(
state.path,
state.bancorNetworkAddress
// solhint-disable indent
) = abi.decode(bridgeData, (address[], address));
// solhint-enable indent
state.weth = IEtherToken(_getWethAddress());
require(state.path.length >= 2, "BancorBridge/PATH_LENGTH_MUST_BE_GREATER_THAN_TWO");
// Grant an allowance to the Bancor Network to spend `fromTokenAddress` token.
uint256 fromTokenBalance;
uint256 payableAmount = 0;
// If it's ETH in the path then withdraw from WETH
// The Bancor path will have ETH as the 0xeee address
// Bancor expects to be paid in ETH not WETH
if (state.path[0] == BANCOR_ETH_ADDRESS) {
fromTokenBalance = state.weth.balanceOf(address(this));
state.weth.withdraw(fromTokenBalance);
payableAmount = fromTokenBalance;
} else {
fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
LibERC20Token.approveIfBelow(state.path[0], state.bancorNetworkAddress, fromTokenBalance);
}
// Convert the tokens
uint256 boughtAmount = IBancorNetwork(state.bancorNetworkAddress).convertByPath.value(payableAmount)(
state.path, // path originating with source token and terminating in destination token
fromTokenBalance, // amount of source token to trade
amount, // minimum amount of destination token expected to receive
state.path[state.path.length-1] == BANCOR_ETH_ADDRESS ? address(this) : to, // beneficiary
address(0), // affiliateAccount; no fee paid
0 // affiliateFee; no fee paid
);
if (state.path[state.path.length-1] == BANCOR_ETH_ADDRESS) {
state.weth.deposit.value(boughtAmount)();
state.weth.transfer(to, boughtAmount);
}
emit ERC20BridgeTransfer(
state.path[0] == BANCOR_ETH_ADDRESS ? address(state.weth) : state.path[0],
toTokenAddress,
fromTokenBalance,
boughtAmount,
from,
to
);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Magic success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

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

View File

@ -1,103 +0,0 @@
/*
Copyright 2020 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/IBalancerPool.sol";
contract CreamBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
/// token encoded in the bridge data, then transfers the bought
/// tokens to `to`.
/// @param toTokenAddress The token to buy and transfer to `to`.
/// @param from The maker (this contract).
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoded addresses of the "from" token and Balancer pool.
/// @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.
(address fromTokenAddress, address poolAddress) = abi.decode(
bridgeData,
(address, address)
);
require(toTokenAddress != fromTokenAddress, "CreamBridge/INVALID_PAIR");
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
LibERC20Token.approveIfBelow(fromTokenAddress, poolAddress, fromTokenBalance);
// Sell all of this contract's `fromTokenAddress` token balance.
(uint256 boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn(
fromTokenAddress, // tokenIn
fromTokenBalance, // tokenAmountIn
toTokenAddress, // tokenOut
amount, // minAmountOut
uint256(-1) // maxPrice
);
// Transfer the converted `toToken`s to `to`.
LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
emit ERC20BridgeTransfer(
fromTokenAddress,
toTokenAddress,
fromTokenBalance,
boughtAmount,
from,
to
);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Magic success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@ -1,136 +0,0 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IUniswapV2Router01.sol";
import "../interfaces/IERC20Bridge.sol";
// solhint-disable space-after-comma
// solhint-disable not-rely-on-time
contract CryptoComBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
struct TransferState {
address[] path;
address router;
uint256 fromTokenBalance;
}
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
/// token encoded in the bridge data.
/// @param toTokenAddress The token to buy and transfer to `to`.
/// @param from The maker (this contract).
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
/// @return success The magic bytes if successful.
function bridgeTransferFrom(
address toTokenAddress,
address from,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success)
{
// hold variables to get around stack depth limitations
TransferState memory state;
// Decode the bridge data to get the `fromTokenAddress`.
// solhint-disable indent
(state.path, state.router) = abi.decode(bridgeData, (address[], address));
// solhint-enable indent
require(state.path.length >= 2, "CryptoComBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(state.path[state.path.length - 1] == toTokenAddress, "CryptoComBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
// Just transfer the tokens if they're the same.
if (state.path[0] == toTokenAddress) {
LibERC20Token.transfer(state.path[0], to, amount);
return BRIDGE_SUCCESS;
}
// Get our balance of `fromTokenAddress` token.
state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
// Grant the SushiSwap router an allowance.
LibERC20Token.approveIfBelow(
state.path[0],
state.router,
state.fromTokenBalance
);
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
// and transfer it to `to`.
IUniswapV2Router01 router = IUniswapV2Router01(state.router);
uint[] memory amounts = router.swapExactTokensForTokens(
// Sell all tokens we hold.
state.fromTokenBalance,
// Minimum buy amount.
amount,
// Convert `fromTokenAddress` to `toTokenAddress`.
state.path,
// Recipient is `to`.
to,
// Expires after this block.
block.timestamp
);
emit ERC20BridgeTransfer(
// input token
state.path[0],
// output token
toTokenAddress,
// input token amount
state.fromTokenBalance,
// output token amount
amounts[amounts.length - 1],
from,
to
);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@ -1,119 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IERC20Bridge.sol";
import "../interfaces/ICurve.sol";
// solhint-disable not-rely-on-time
// solhint-disable space-after-comma
contract CurveBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
struct CurveBridgeData {
address curveAddress;
bytes4 exchangeFunctionSelector;
address fromTokenAddress;
int128 fromCoinIdx;
int128 toCoinIdx;
}
/// @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 from The maker (this contract).
/// @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.
CurveBridgeData memory data = abi.decode(bridgeData, (CurveBridgeData));
require(toTokenAddress != data.fromTokenAddress, "CurveBridge/INVALID_PAIR");
uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this));
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance);
// Try to sell all of this contract's `fromTokenAddress` token balance.
{
(bool didSucceed, bytes memory resultData) =
data.curveAddress.call(abi.encodeWithSelector(
data.exchangeFunctionSelector,
data.fromCoinIdx,
data.toCoinIdx,
// dx
fromTokenBalance,
// min dy
amount
));
if (!didSucceed) {
assembly { revert(add(resultData, 32), mload(resultData)) }
}
}
uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this));
// Transfer the converted `toToken`s to `to`.
LibERC20Token.transfer(toTokenAddress, to, toTokenBalance);
emit ERC20BridgeTransfer(
data.fromTokenAddress,
toTokenAddress,
fromTokenBalance,
toTokenBalance,
from,
to
);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Magic success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@ -1,147 +0,0 @@
/*
Copyright 2020 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";
interface IDODOHelper {
function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256);
}
interface IDODO {
function sellBaseToken(uint256 amount, uint256 minReceiveQuote, bytes calldata data) external returns (uint256);
function buyBaseToken(uint256 amount, uint256 maxPayQuote, bytes calldata data) external returns (uint256);
}
contract DODOBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
struct TransferState {
address fromTokenAddress;
uint256 fromTokenBalance;
address pool;
bool isSellBase;
}
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
/// token encoded in the bridge data.
/// @param toTokenAddress The token to buy and transfer to `to`.
/// @param from The maker (this contract).
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
/// @return success The magic bytes if successful.
function bridgeTransferFrom(
address toTokenAddress,
address from,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success)
{
TransferState memory state;
// Decode the bridge data to get the `fromTokenAddress`.
(state.fromTokenAddress, state.pool, state.isSellBase) = abi.decode(bridgeData, (address, address, bool));
require(state.pool != address(0), "DODOBridge/InvalidPool");
IDODO exchange = IDODO(state.pool);
// Get our balance of `fromTokenAddress` token.
state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));
// Grant the pool an allowance.
LibERC20Token.approveIfBelow(
state.fromTokenAddress,
address(exchange),
state.fromTokenBalance
);
uint256 boughtAmount;
if (state.isSellBase) {
boughtAmount = exchange.sellBaseToken(
// amount to sell
state.fromTokenBalance,
// min receive amount
1,
new bytes(0)
);
} else {
// Need to re-calculate the sell quote amount into buyBase
boughtAmount = IDODOHelper(_getDODOHelperAddress()).querySellQuoteToken(
address(exchange),
state.fromTokenBalance
);
exchange.buyBaseToken(
// amount to buy
boughtAmount,
// max pay amount
state.fromTokenBalance,
new bytes(0)
);
}
// Transfer funds to `to`
IERC20Token(toTokenAddress).transfer(to, boughtAmount);
emit ERC20BridgeTransfer(
// input token
state.fromTokenAddress,
// output token
toTokenAddress,
// input token amount
state.fromTokenBalance,
// output token amount
boughtAmount,
from,
to
);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@ -1,200 +0,0 @@
/*
Copyright 2020 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-exchange-libs/contracts/src/LibMath.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "../interfaces/IERC20Bridge.sol";
import "./MixinGasToken.sol";
// solhint-disable space-after-comma, indent
contract DexForwarderBridge is
IERC20Bridge,
IWallet,
DeploymentConstants,
MixinGasToken
{
using LibSafeMath for uint256;
/// @dev Data needed to reconstruct a bridge call.
struct BridgeCall {
address target;
uint256 inputTokenAmount;
uint256 outputTokenAmount;
bytes bridgeData;
}
/// @dev Intermediate state variables used by `bridgeTransferFrom()`, in
/// struct form to get around stack limits.
struct TransferFromState {
address inputToken;
uint256 initialInputTokenBalance;
uint256 callInputTokenAmount;
uint256 callOutputTokenAmount;
uint256 totalInputTokenSold;
BridgeCall[] calls;
}
/// @dev Spends this contract's entire balance of input tokens by forwarding
/// them to other bridges. Reverts if the entire balance is not spent.
/// @param outputToken The token being bought.
/// @param to The recipient of the bought tokens.
/// @param bridgeData The abi-encoded input token address.
/// @return success The magic bytes if successful.
function bridgeTransferFrom(
address outputToken,
address /* from */,
address to,
uint256 /* amount */,
bytes calldata bridgeData
)
external
freesGasTokensFromCollector
returns (bytes4 success)
{
require(
msg.sender == _getERC20BridgeProxyAddress(),
"DexForwarderBridge/SENDER_NOT_AUTHORIZED"
);
TransferFromState memory state;
(
state.inputToken,
state.calls
) = abi.decode(bridgeData, (address, BridgeCall[]));
state.initialInputTokenBalance =
IERC20Token(state.inputToken).balanceOf(address(this));
for (uint256 i = 0; i < state.calls.length; ++i) {
// Stop if the we've sold all our input tokens.
if (state.totalInputTokenSold >= state.initialInputTokenBalance) {
break;
}
// Compute token amounts.
state.callInputTokenAmount = LibSafeMath.min256(
state.calls[i].inputTokenAmount,
state.initialInputTokenBalance.safeSub(state.totalInputTokenSold)
);
state.callOutputTokenAmount = LibMath.getPartialAmountFloor(
state.callInputTokenAmount,
state.calls[i].inputTokenAmount,
state.calls[i].outputTokenAmount
);
// Execute the call in a new context so we can recoup transferred
// funds by reverting.
(bool didSucceed, ) = address(this)
.call(abi.encodeWithSelector(
this.executeBridgeCall.selector,
state.calls[i].target,
to,
state.inputToken,
outputToken,
state.callInputTokenAmount,
state.callOutputTokenAmount,
state.calls[i].bridgeData
));
if (didSucceed) {
// Increase the amount of tokens sold.
state.totalInputTokenSold = state.totalInputTokenSold.safeAdd(
state.callInputTokenAmount
);
}
}
// Always succeed.
return BRIDGE_SUCCESS;
}
/// @dev Transfers `inputToken` token to a bridge contract then calls
/// its `bridgeTransferFrom()`. This is executed in separate context
/// so we can revert the transfer on error. This can only be called
// by this contract itself.
/// @param bridge The bridge contract.
/// @param to The recipient of `outputToken` tokens.
/// @param inputToken The input token.
/// @param outputToken The output token.
/// @param inputTokenAmount The amount of input tokens to transfer to `bridge`.
/// @param outputTokenAmount The amount of expected output tokens to be sent
/// to `to` by `bridge`.
function executeBridgeCall(
address bridge,
address to,
address inputToken,
address outputToken,
uint256 inputTokenAmount,
uint256 outputTokenAmount,
bytes calldata bridgeData
)
external
{
// Must be called through `bridgeTransferFrom()`.
require(msg.sender == address(this), "DexForwarderBridge/ONLY_SELF");
// `bridge` must not be this contract.
require(bridge != address(this));
// Get the starting balance of output tokens for `to`.
uint256 initialRecipientBalance = IERC20Token(outputToken).balanceOf(to);
// Transfer input tokens to the bridge.
LibERC20Token.transfer(inputToken, bridge, inputTokenAmount);
// Call the bridge.
(bool didSucceed, bytes memory resultData) =
bridge.call(abi.encodeWithSelector(
IERC20Bridge(0).bridgeTransferFrom.selector,
outputToken,
bridge,
to,
outputTokenAmount,
bridgeData
));
// Revert if the call failed or not enough tokens were bought.
// This will also undo the token transfer.
require(
didSucceed
&& resultData.length == 32
&& LibBytes.readBytes32(resultData, 0) == bytes32(BRIDGE_SUCCESS)
&& IERC20Token(outputToken).balanceOf(to).safeSub(initialRecipientBalance) >= outputTokenAmount
);
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Magic success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

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

View File

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

View File

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

View File

@ -1,94 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IERC20Bridge.sol";
import "../interfaces/IMStable.sol";
contract MStableBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
/// @dev Swaps specified tokens against the mStable mUSD contract
/// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
/// @param from The maker (this contract).
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoded "from" token address.
/// @return success The magic bytes if successful.
// solhint-disable no-unused-vars
function bridgeTransferFrom(
address toTokenAddress,
address from,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success)
{
// Decode the bridge data to get the `fromTokenAddress`.
(address fromTokenAddress) = abi.decode(bridgeData, (address));
IMStable exchange = IMStable(_getMUsdAddress());
uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
LibERC20Token.approveIfBelow(fromTokenAddress, address(exchange), fromTokenBalance);
// Try to sell all of this contract's `fromTokenAddress` token balance.
uint256 boughtAmount = exchange.swap(
fromTokenAddress,
toTokenAddress,
fromTokenBalance,
to
);
emit ERC20BridgeTransfer(
fromTokenAddress,
toTokenAddress,
fromTokenBalance,
boughtAmount,
from,
to
);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Magic success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@ -1,55 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.16;
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IGasToken.sol";
contract MixinGasToken is
DeploymentConstants
{
/// @dev Frees gas tokens based on the amount of gas consumed in the function
modifier freesGasTokens {
uint256 gasBefore = gasleft();
_;
IGasToken gst = IGasToken(_getGstAddress());
if (address(gst) != address(0)) {
// (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN)
// 14154 24000 6870
uint256 value = (gasBefore - gasleft() + 14154) / 41130;
gst.freeUpTo(value);
}
}
/// @dev Frees gas tokens using the balance of `from`. Amount freed is based
/// on the gas consumed in the function
modifier freesGasTokensFromCollector() {
uint256 gasBefore = gasleft();
_;
IGasToken gst = IGasToken(_getGstAddress());
if (address(gst) != address(0)) {
// (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN)
// 14154 24000 6870
uint256 value = (gasBefore - gasleft() + 14154) / 41130;
gst.freeFromUpTo(_getGstCollectorAddress(), value);
}
}
}

View File

@ -1,148 +0,0 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IERC20Bridge.sol";
import "../interfaces/IMooniswap.sol";
// solhint-disable space-after-comma
// solhint-disable not-rely-on-time
contract MooniswapBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
struct TransferState {
IMooniswap pool;
uint256 fromTokenBalance;
IEtherToken weth;
uint256 boughtAmount;
address fromTokenAddress;
address toTokenAddress;
}
// solhint-disable no-empty-blocks
/// @dev Payable fallback to receive ETH from uniswap.
function ()
external
payable
{}
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
/// token encoded in the bridge data.
/// @param toTokenAddress The token to buy and transfer to `to`.
/// @param from The maker (this contract).
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
/// @return success The magic bytes if successful.
function bridgeTransferFrom(
address toTokenAddress,
address from,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success)
{
// State memory object to avoid stack overflows.
TransferState memory state;
// Decode the bridge data to get the `fromTokenAddress`.
address fromTokenAddress = abi.decode(bridgeData, (address));
// Get the weth contract.
state.weth = IEtherToken(_getWethAddress());
// Get our balance of `fromTokenAddress` token.
state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
state.fromTokenAddress = fromTokenAddress == address(state.weth) ? address(0) : fromTokenAddress;
state.toTokenAddress = toTokenAddress == address(state.weth) ? address(0) : toTokenAddress;
state.pool = IMooniswap(
IMooniswapRegistry(_getMooniswapAddress()).pools(
state.fromTokenAddress,
state.toTokenAddress
)
);
// withdraw WETH to ETH
if (state.fromTokenAddress == address(0)) {
state.weth.withdraw(state.fromTokenBalance);
} else {
// Grant the pool an allowance.
LibERC20Token.approveIfBelow(
state.fromTokenAddress,
address(state.pool),
state.fromTokenBalance
);
}
uint256 ethValue = state.fromTokenAddress == address(0) ? state.fromTokenBalance : 0;
state.boughtAmount = state.pool.swap.value(ethValue)(
state.fromTokenAddress,
state.toTokenAddress,
state.fromTokenBalance,
amount,
address(0)
);
// Deposit to WETH
if (state.toTokenAddress == address(0)) {
state.weth.deposit.value(state.boughtAmount)();
}
// Transfer funds to `to`
LibERC20Token.transfer(toTokenAddress, to, state.boughtAmount);
emit ERC20BridgeTransfer(
// input token
fromTokenAddress,
// output token
toTokenAddress,
// input token amount
state.fromTokenBalance,
// output token amount
state.boughtAmount,
from,
to
);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

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

View File

@ -1,119 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IERC20Bridge.sol";
import "../interfaces/ICurve.sol";
// solhint-disable not-rely-on-time
// solhint-disable space-after-comma
contract SnowSwapBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
struct SnowSwapBridgeData {
address curveAddress;
bytes4 exchangeFunctionSelector;
address fromTokenAddress;
int128 fromCoinIdx;
int128 toCoinIdx;
}
/// @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 from The maker (this contract).
/// @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 SnowSwap metadata.
SnowSwapBridgeData memory data = abi.decode(bridgeData, (SnowSwapBridgeData));
require(toTokenAddress != data.fromTokenAddress, "SnowSwapBridge/INVALID_PAIR");
uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this));
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance);
// Try to sell all of this contract's `fromTokenAddress` token balance.
{
(bool didSucceed, bytes memory resultData) =
data.curveAddress.call(abi.encodeWithSelector(
data.exchangeFunctionSelector,
data.fromCoinIdx,
data.toCoinIdx,
// dx
fromTokenBalance,
// min dy
amount
));
if (!didSucceed) {
assembly { revert(add(resultData, 32), mload(resultData)) }
}
}
uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this));
// Transfer the converted `toToken`s to `to`.
LibERC20Token.transfer(toTokenAddress, to, toTokenBalance);
emit ERC20BridgeTransfer(
data.fromTokenAddress,
toTokenAddress,
fromTokenBalance,
toTokenBalance,
from,
to
);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Magic success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@ -1,136 +0,0 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IUniswapV2Router01.sol";
import "../interfaces/IERC20Bridge.sol";
// solhint-disable space-after-comma
// solhint-disable not-rely-on-time
contract SushiSwapBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
struct TransferState {
address[] path;
address router;
uint256 fromTokenBalance;
}
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
/// token encoded in the bridge data.
/// @param toTokenAddress The token to buy and transfer to `to`.
/// @param from The maker (this contract).
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
/// @return success The magic bytes if successful.
function bridgeTransferFrom(
address toTokenAddress,
address from,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success)
{
// hold variables to get around stack depth limitations
TransferState memory state;
// Decode the bridge data to get the `fromTokenAddress`.
// solhint-disable indent
(state.path, state.router) = abi.decode(bridgeData, (address[], address));
// solhint-enable indent
require(state.path.length >= 2, "SushiSwapBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(state.path[state.path.length - 1] == toTokenAddress, "SushiSwapBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
// Just transfer the tokens if they're the same.
if (state.path[0] == toTokenAddress) {
LibERC20Token.transfer(state.path[0], to, amount);
return BRIDGE_SUCCESS;
}
// Get our balance of `fromTokenAddress` token.
state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
// Grant the SushiSwap router an allowance.
LibERC20Token.approveIfBelow(
state.path[0],
state.router,
state.fromTokenBalance
);
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
// and transfer it to `to`.
IUniswapV2Router01 router = IUniswapV2Router01(state.router);
uint[] memory amounts = router.swapExactTokensForTokens(
// Sell all tokens we hold.
state.fromTokenBalance,
// Minimum buy amount.
amount,
// Convert `fromTokenAddress` to `toTokenAddress`.
state.path,
// Recipient is `to`.
to,
// Expires after this block.
block.timestamp
);
emit ERC20BridgeTransfer(
// input token
state.path[0],
// output token
toTokenAddress,
// input token amount
state.fromTokenBalance,
// output token amount
amounts[amounts.length - 1],
from,
to
);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@ -1,119 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IERC20Bridge.sol";
import "../interfaces/ICurve.sol";
// solhint-disable not-rely-on-time
// solhint-disable space-after-comma
contract SwerveBridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
struct SwerveBridgeData {
address curveAddress;
bytes4 exchangeFunctionSelector;
address fromTokenAddress;
int128 fromCoinIdx;
int128 toCoinIdx;
}
/// @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 from The maker (this contract).
/// @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 SwerveBridgeData metadata.
SwerveBridgeData memory data = abi.decode(bridgeData, (SwerveBridgeData));
require(toTokenAddress != data.fromTokenAddress, "SwerveBridge/INVALID_PAIR");
uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this));
// Grant an allowance to the exchange to spend `fromTokenAddress` token.
LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance);
// Try to sell all of this contract's `fromTokenAddress` token balance.
{
(bool didSucceed, bytes memory resultData) =
data.curveAddress.call(abi.encodeWithSelector(
data.exchangeFunctionSelector,
data.fromCoinIdx,
data.toCoinIdx,
// dx
fromTokenBalance,
// min dy
amount
));
if (!didSucceed) {
assembly { revert(add(resultData, 32), mload(resultData)) }
}
}
uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this));
// Transfer the converted `toToken`s to `to`.
LibERC20Token.transfer(toTokenAddress, to, toTokenBalance);
emit ERC20BridgeTransfer(
data.fromTokenAddress,
toTokenAddress,
fromTokenBalance,
toTokenBalance,
from,
to
);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Magic success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

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

View File

@ -1,135 +0,0 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
import "../interfaces/IUniswapV2Router01.sol";
import "../interfaces/IERC20Bridge.sol";
// solhint-disable space-after-comma
// solhint-disable not-rely-on-time
contract UniswapV2Bridge is
IERC20Bridge,
IWallet,
DeploymentConstants
{
struct TransferState {
address[] path;
uint256 fromTokenBalance;
}
/// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
/// `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
/// token encoded in the bridge data.
/// @param toTokenAddress The token to buy and transfer to `to`.
/// @param from The maker (this contract).
/// @param to The recipient of the bought tokens.
/// @param amount Minimum amount of `toTokenAddress` tokens to buy.
/// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
/// @return success The magic bytes if successful.
function bridgeTransferFrom(
address toTokenAddress,
address from,
address to,
uint256 amount,
bytes calldata bridgeData
)
external
returns (bytes4 success)
{
// hold variables to get around stack depth limitations
TransferState memory state;
// Decode the bridge data to get the `fromTokenAddress`.
// solhint-disable indent
state.path = abi.decode(bridgeData, (address[]));
// solhint-enable indent
require(state.path.length >= 2, "UniswapV2Bridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(state.path[state.path.length - 1] == toTokenAddress, "UniswapV2Bridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
// Just transfer the tokens if they're the same.
if (state.path[0] == toTokenAddress) {
LibERC20Token.transfer(state.path[0], to, amount);
return BRIDGE_SUCCESS;
}
// Get our balance of `fromTokenAddress` token.
state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
// Grant the Uniswap router an allowance.
LibERC20Token.approveIfBelow(
state.path[0],
_getUniswapV2Router01Address(),
state.fromTokenBalance
);
// Buy as much `toTokenAddress` token with `fromTokenAddress` token
// and transfer it to `to`.
IUniswapV2Router01 router = IUniswapV2Router01(_getUniswapV2Router01Address());
uint[] memory amounts = router.swapExactTokensForTokens(
// Sell all tokens we hold.
state.fromTokenBalance,
// Minimum buy amount.
amount,
// Convert `fromTokenAddress` to `toTokenAddress`.
state.path,
// Recipient is `to`.
to,
// Expires after this block.
block.timestamp
);
emit ERC20BridgeTransfer(
// input token
state.path[0],
// output token
toTokenAddress,
// input token amount
state.fromTokenBalance,
// output token amount
amounts[amounts.length - 1],
from,
to
);
return BRIDGE_SUCCESS;
}
/// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
/// and sign for itself in orders. Always succeeds.
/// @return magicValue Success bytes, always.
function isValidSignature(
bytes32,
bytes calldata
)
external
view
returns (bytes4 magicValue)
{
return LEGACY_WALLET_MAGIC_VALUE;
}
}

View File

@ -1,88 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// solhint-disable
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
// @dev Interface of the asset proxy's assetData.
// The asset proxies take an ABI encoded `bytes assetData` as argument.
// This argument is ABI encoded as one of the methods of this interface.
interface IAssetData {
/// @dev Function signature for encoding ERC20 assetData.
/// @param tokenAddress Address of ERC20Token contract.
function ERC20Token(address tokenAddress)
external;
/// @dev Function signature for encoding ERC721 assetData.
/// @param tokenAddress Address of ERC721 token contract.
/// @param tokenId Id of ERC721 token to be transferred.
function ERC721Token(
address tokenAddress,
uint256 tokenId
)
external;
/// @dev Function signature for encoding ERC1155 assetData.
/// @param tokenAddress Address of ERC1155 token contract.
/// @param tokenIds Array of ids of tokens to be transferred.
/// @param values Array of values that correspond to each token id to be transferred.
/// Note that each value will be multiplied by the amount being filled in the order before transferring.
/// @param callbackData Extra data to be passed to receiver's `onERC1155Received` callback function.
function ERC1155Assets(
address tokenAddress,
uint256[] calldata tokenIds,
uint256[] calldata values,
bytes calldata callbackData
)
external;
/// @dev Function signature for encoding MultiAsset assetData.
/// @param values Array of amounts that correspond to each asset to be transferred.
/// Note that each value will be multiplied by the amount being filled in the order before transferring.
/// @param nestedAssetData Array of assetData fields that will be be dispatched to their correspnding AssetProxy contract.
function MultiAsset(
uint256[] calldata values,
bytes[] calldata nestedAssetData
)
external;
/// @dev Function signature for encoding StaticCall assetData.
/// @param staticCallTargetAddress Address that will execute the staticcall.
/// @param staticCallData Data that will be executed via staticcall on the staticCallTargetAddress.
/// @param expectedReturnDataHash Keccak-256 hash of the expected staticcall return data.
function StaticCall(
address staticCallTargetAddress,
bytes calldata staticCallData,
bytes32 expectedReturnDataHash
)
external;
/// @dev Function signature for encoding ERC20Bridge assetData.
/// @param tokenAddress Address of token to transfer.
/// @param bridgeAddress Address of the bridge contract.
/// @param bridgeData Arbitrary data to be passed to the bridge contract.
function ERC20Bridge(
address tokenAddress,
address bridgeAddress,
bytes calldata bridgeData
)
external;
}

View File

@ -1,43 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
contract IAssetProxy {
/// @dev Transfers assets. Either succeeds or throws.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param from Address to transfer asset from.
/// @param to Address to transfer asset to.
/// @param amount Amount of asset to transfer.
function transferFrom(
bytes calldata assetData,
address from,
address to,
uint256 amount
)
external;
/// @dev Gets the proxy id associated with the proxy address.
/// @return Proxy id.
function getProxyId()
external
pure
returns (bytes4);
}

View File

@ -1,43 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
contract IAssetProxyDispatcher {
// Logs registration of new asset proxy
event AssetProxyRegistered(
bytes4 id, // Id of new registered AssetProxy.
address assetProxy // Address of new registered AssetProxy.
);
/// @dev Registers an asset proxy to its asset proxy id.
/// Once an asset proxy is registered, it cannot be unregistered.
/// @param assetProxy Address of new asset proxy to register.
function registerAssetProxy(address assetProxy)
external;
/// @dev Gets an asset proxy.
/// @param assetProxyId Id of the asset proxy.
/// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
function getAssetProxy(bytes4 assetProxyId)
external
view
returns (address);
}

View File

@ -1,64 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
contract IAuthorizable is
IOwnable
{
// Event logged when a new address is authorized.
event AuthorizedAddressAdded(
address indexed target,
address indexed caller
);
// Event logged when a currently authorized address is unauthorized.
event AuthorizedAddressRemoved(
address indexed target,
address indexed caller
);
/// @dev Authorizes an address.
/// @param target Address to authorize.
function addAuthorizedAddress(address target)
external;
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
function removeAuthorizedAddress(address target)
external;
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
/// @param index Index of target in authorities array.
function removeAuthorizedAddressAtIndex(
address target,
uint256 index
)
external;
/// @dev Gets all authorized addresses.
/// @return Array of authorized addresses.
function getAuthorizedAddresses()
external
view
returns (address[] memory);
}

View File

@ -1,39 +0,0 @@
/*
Copyright 2020 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 IBalancerPool {
/// @dev Sell `tokenAmountIn` of `tokenIn` and receive `tokenOut`.
/// @param tokenIn The token being sold
/// @param tokenAmountIn The amount of `tokenIn` to sell.
/// @param tokenOut The token being bought.
/// @param minAmountOut The minimum amount of `tokenOut` to buy.
/// @param maxPrice The maximum value for `spotPriceAfter`.
/// @return tokenAmountOut The amount of `tokenOut` bought.
/// @return spotPriceAfter The new marginal spot price of the given
/// token pair for this pool.
function swapExactAmountIn(
address tokenIn,
uint tokenAmountIn,
address tokenOut,
uint minAmountOut,
uint maxPrice
) external returns (uint tokenAmountOut, uint spotPriceAfter);
}

View File

@ -1,38 +0,0 @@
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
contract IContractRegistry {
function addressOf(
bytes32 contractName
) external returns(address);
}
contract IBancorNetwork {
function convertByPath(
address[] calldata _path,
uint256 _amount,
uint256 _minReturn,
address _beneficiary,
address _affiliateAccount,
uint256 _affiliateFee
) external payable returns (uint256);
}

View File

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

View File

@ -1,70 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
// solhint-disable func-name-mixedcase
interface ICurve {
/// @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`
/// @param i The token index being sold.
/// @param j The token index being bought.
/// @param buyAmount The amount of token being bought.
function get_dx_underlying(
int128 i,
int128 j,
uint256 buyAmount
)
external
returns (uint256 dx);
/// @dev Get the underlying token address from the token index
/// @param i The token index.
function underlying_coins(
int128 i
)
external
returns (address tokenAddress);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,40 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.15;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
contract IGasToken is IERC20Token {
/// @dev Frees up to `value` sub-tokens
/// @param value The amount of tokens to free
/// @return How many tokens were freed
function freeUpTo(uint256 value) external returns (uint256 freed);
/// @dev Frees up to `value` sub-tokens owned by `from`
/// @param from The owner of tokens to spend
/// @param value The amount of tokens to free
/// @return How many tokens were freed
function freeFromUpTo(address from, uint256 value) external returns (uint256 freed);
/// @dev Mints `value` amount of tokens
/// @param value The amount of tokens to mint
function mint(uint256 value) external;
}

View File

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

View File

@ -1,32 +0,0 @@
/*
Copyright 2020 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 IMStable {
function swap(
address _input,
address _output,
uint256 _quantity,
address _recipient
)
external
returns (uint256 output);
}

View File

@ -1,40 +0,0 @@
/*
Copyright 2020 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 IMooniswapRegistry {
function pools(address token1, address token2) external view returns(address);
}
interface IMooniswap {
function swap(
address fromToken,
address destToken,
uint256 amount,
uint256 minReturn,
address referral
)
external
payable
returns(uint256 returnAmount);
}

View File

@ -1,34 +0,0 @@
/*
Copyright 2020 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 IShell {
function originSwap(
address from,
address to,
uint256 fromAmount,
uint256 minTargetAmount,
uint256 deadline
)
external
returns (uint256 toAmount);
}

View File

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

View File

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

View File

@ -1,40 +0,0 @@
/*
Copyright 2020 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 IUniswapV2Router01 {
/// @dev Swaps an exact amount of input tokens for as many output tokens as possible, along the route determined by the path.
/// The first element of path is the input token, the last is the output token, and any intermediate elements represent
/// intermediate pairs to trade through (if, for example, a direct pair does not exist).
/// @param amountIn The amount of input tokens to send.
/// @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
/// @param path An array of token addresses. path.length must be >= 2. Pools for each consecutive pair of addresses must exist and have liquidity.
/// @param to Recipient of the output tokens.
/// @param deadline Unix timestamp after which the transaction will revert.
/// @return amounts The input token amount and all subsequent output token amounts.
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
}

View File

@ -1,247 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
import "../src/bridges/BancorBridge.sol";
import "../src/interfaces/IBancorNetwork.sol";
contract TestEventsRaiser {
event TokenTransfer(
address token,
address from,
address to,
uint256 amount
);
event TokenApprove(
address spender,
uint256 allowance
);
event ConvertByPathInput(
uint amountIn,
uint amountOutMin,
address toTokenAddress,
address to,
address feeRecipient,
uint256 feeAmount
);
function raiseTokenTransfer(
address from,
address to,
uint256 amount
)
external
{
emit TokenTransfer(
msg.sender,
from,
to,
amount
);
}
function raiseTokenApprove(address spender, uint256 allowance) external {
emit TokenApprove(spender, allowance);
}
function raiseConvertByPathInput(
uint amountIn,
uint amountOutMin,
address toTokenAddress,
address to,
address feeRecipient,
uint256 feeAmount
) external
{
emit ConvertByPathInput(
amountIn,
amountOutMin,
toTokenAddress,
to,
feeRecipient,
feeAmount
);
}
}
/// @dev A minimalist ERC20 token.
contract TestToken {
using LibSafeMath for uint256;
mapping (address => uint256) public balances;
string private _nextRevertReason;
/// @dev Set the balance for `owner`.
function setBalance(address owner, uint256 balance)
external
payable
{
balances[owner] = balance;
}
/// @dev Just emits a TokenTransfer event on the caller
function transfer(address to, uint256 amount)
external
returns (bool)
{
TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
return true;
}
/// @dev Just emits a TokenApprove event on the caller
function approve(address spender, uint256 allowance)
external
returns (bool)
{
TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance);
return true;
}
function allowance(address, address) external view returns (uint256) {
return 0;
}
/// @dev Retrieve the balance for `owner`.
function balanceOf(address owner)
external
view
returns (uint256)
{
return balances[owner];
}
}
/// @dev Mock the BancorNetwork contract
contract TestBancorNetwork is
IBancorNetwork
{
string private _nextRevertReason;
/// @dev Set the revert reason for `swapExactTokensForTokens`.
function setRevertReason(string calldata reason)
external
{
_nextRevertReason = reason;
}
function convertByPath(
address[] calldata _path,
uint256 _amount,
uint256 _minReturn,
address _beneficiary,
address _affiliateAccount,
uint256 _affiliateFee
) external payable returns (uint256)
{
_revertIfReasonExists();
TestEventsRaiser(msg.sender).raiseConvertByPathInput(
// tokens sold
_amount,
// tokens bought
_minReturn,
// output token
_path[_path.length - 1],
// recipient
_beneficiary,
// fee recipient
_affiliateAccount,
// fee amount
_affiliateFee
);
}
function _revertIfReasonExists()
private
view
{
if (bytes(_nextRevertReason).length != 0) {
revert(_nextRevertReason);
}
}
}
/// @dev BancorBridge overridden to mock tokens and BancorNetwork
contract TestBancorBridge is
BancorBridge,
TestEventsRaiser
{
// Token address to TestToken instance.
mapping (address => TestToken) private _testTokens;
// TestRouter instance.
TestBancorNetwork private _testNetwork;
constructor() public {
_testNetwork = new TestBancorNetwork();
}
function setNetworkRevertReason(string calldata revertReason)
external
{
_testNetwork.setRevertReason(revertReason);
}
/// @dev Sets the balance of this contract for an existing token.
function setTokenBalance(address tokenAddress, uint256 balance)
external
{
TestToken token = _testTokens[tokenAddress];
token.setBalance(address(this), balance);
}
/// @dev Create a new token
/// @param tokenAddress The token address. If zero, one will be created.
function createToken(
address tokenAddress
)
external
returns (TestToken token)
{
token = TestToken(tokenAddress);
if (tokenAddress == address(0)) {
token = new TestToken();
}
_testTokens[address(token)] = token;
return token;
}
function getNetworkAddress()
external
view
returns (address)
{
return address(_testNetwork);
}
}

View File

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

View File

@ -1,244 +0,0 @@
/*
Copyright 2020 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/DexForwarderBridge.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
interface ITestDexForwarderBridge {
event BridgeTransferFromCalled(
address caller,
uint256 inputTokenBalance,
address inputToken,
address outputToken,
address from,
address to,
uint256 amount
);
event TokenTransferCalled(
address from,
address to,
uint256 amount
);
function emitBridgeTransferFromCalled(
address caller,
uint256 inputTokenBalance,
address inputToken,
address outputToken,
address from,
address to,
uint256 amount
) external;
function emitTokenTransferCalled(
address from,
address to,
uint256 amount
) external;
}
interface ITestDexForwarderBridgeTestToken {
function transfer(address to, uint256 amount)
external
returns (bool);
function mint(address to, uint256 amount)
external;
function balanceOf(address owner) external view returns (uint256);
}
contract TestDexForwarderBridgeTestBridge {
bytes4 private _returnCode;
string private _revertError;
uint256 private _transferAmount;
ITestDexForwarderBridge private _testContract;
constructor(bytes4 returnCode, string memory revertError) public {
_testContract = ITestDexForwarderBridge(msg.sender);
_returnCode = returnCode;
_revertError = revertError;
}
function setTransferAmount(uint256 amount) external {
_transferAmount = amount;
}
function bridgeTransferFrom(
address outputToken,
address from,
address to,
uint256 amount,
bytes memory bridgeData
)
public
returns (bytes4 success)
{
if (bytes(_revertError).length != 0) {
revert(_revertError);
}
address inputToken = abi.decode(bridgeData, (address));
_testContract.emitBridgeTransferFromCalled(
msg.sender,
ITestDexForwarderBridgeTestToken(inputToken).balanceOf(address(this)),
inputToken,
outputToken,
from,
to,
amount
);
ITestDexForwarderBridgeTestToken(outputToken).mint(to, _transferAmount);
return _returnCode;
}
}
contract TestDexForwarderBridgeTestToken {
using LibSafeMath for uint256;
mapping(address => uint256) public balanceOf;
ITestDexForwarderBridge private _testContract;
constructor() public {
_testContract = ITestDexForwarderBridge(msg.sender);
}
function transfer(address to, uint256 amount)
external
returns (bool)
{
balanceOf[msg.sender] = balanceOf[msg.sender].safeSub(amount);
balanceOf[to] = balanceOf[to].safeAdd(amount);
_testContract.emitTokenTransferCalled(msg.sender, to, amount);
return true;
}
function mint(address owner, uint256 amount)
external
{
balanceOf[owner] = balanceOf[owner].safeAdd(amount);
}
function setBalance(address owner, uint256 amount)
external
{
balanceOf[owner] = amount;
}
}
contract TestDexForwarderBridge is
ITestDexForwarderBridge,
DexForwarderBridge
{
address private AUTHORIZED_ADDRESS; // solhint-disable-line var-name-mixedcase
function setAuthorized(address authorized)
public
{
AUTHORIZED_ADDRESS = authorized;
}
function createBridge(
bytes4 returnCode,
string memory revertError
)
public
returns (address bridge)
{
return address(new TestDexForwarderBridgeTestBridge(returnCode, revertError));
}
function createToken() public returns (address token) {
return address(new TestDexForwarderBridgeTestToken());
}
function setTokenBalance(address token, address owner, uint256 amount) public {
TestDexForwarderBridgeTestToken(token).setBalance(owner, amount);
}
function setBridgeTransferAmount(address bridge, uint256 amount) public {
TestDexForwarderBridgeTestBridge(bridge).setTransferAmount(amount);
}
function emitBridgeTransferFromCalled(
address caller,
uint256 inputTokenBalance,
address inputToken,
address outputToken,
address from,
address to,
uint256 amount
)
public
{
emit BridgeTransferFromCalled(
caller,
inputTokenBalance,
inputToken,
outputToken,
from,
to,
amount
);
}
function emitTokenTransferCalled(
address from,
address to,
uint256 amount
)
public
{
emit TokenTransferCalled(
from,
to,
amount
);
}
function balanceOf(address token, address owner) public view returns (uint256) {
return TestDexForwarderBridgeTestToken(token).balanceOf(owner);
}
function _getGstAddress()
internal
view
returns (address gst)
{
return address(0);
}
function _getERC20BridgeProxyAddress()
internal
view
returns (address erc20BridgeProxyAddress)
{
return AUTHORIZED_ADDRESS;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,82 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
contract TestStaticCallTarget {
using LibBytes for bytes;
uint256 internal _state;
function updateState()
external
{
_state++;
}
function assertEvenNumber(uint256 target)
external
pure
{
require(
target % 2 == 0,
"TARGET_NOT_EVEN"
);
}
function isOddNumber(uint256 target)
external
pure
returns (bool isOdd)
{
isOdd = target % 2 == 1;
return isOdd;
}
function noInputFunction()
external
pure
{
assert(msg.data.length == 4 && msg.data.readBytes4(0) == bytes4(keccak256("noInputFunction()")));
}
function dynamicInputFunction(bytes calldata a)
external
pure
{
bytes memory abiEncodedData = abi.encodeWithSignature("dynamicInputFunction(bytes)", a);
assert(msg.data.equals(abiEncodedData));
}
function returnComplexType(uint256 a, uint256 b)
external
view
returns (bytes memory result)
{
result = abi.encodePacked(
address(this),
a,
b
);
return result;
}
}

View File

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

View File

@ -1,253 +0,0 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
import "../src/bridges/UniswapV2Bridge.sol";
import "../src/interfaces/IUniswapV2Router01.sol";
contract TestEventsRaiser {
event TokenTransfer(
address token,
address from,
address to,
uint256 amount
);
event TokenApprove(
address spender,
uint256 allowance
);
event SwapExactTokensForTokensInput(
uint amountIn,
uint amountOutMin,
address toTokenAddress,
address to,
uint deadline
);
function raiseTokenTransfer(
address from,
address to,
uint256 amount
)
external
{
emit TokenTransfer(
msg.sender,
from,
to,
amount
);
}
function raiseTokenApprove(address spender, uint256 allowance) external {
emit TokenApprove(spender, allowance);
}
function raiseSwapExactTokensForTokensInput(
uint amountIn,
uint amountOutMin,
address toTokenAddress,
address to,
uint deadline
) external
{
emit SwapExactTokensForTokensInput(
amountIn,
amountOutMin,
toTokenAddress,
to,
deadline
);
}
}
/// @dev A minimalist ERC20 token.
contract TestToken {
using LibSafeMath for uint256;
mapping (address => uint256) public balances;
string private _nextRevertReason;
/// @dev Set the balance for `owner`.
function setBalance(address owner, uint256 balance)
external
payable
{
balances[owner] = balance;
}
/// @dev Just emits a TokenTransfer event on the caller
function transfer(address to, uint256 amount)
external
returns (bool)
{
TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
return true;
}
/// @dev Just emits a TokenApprove event on the caller
function approve(address spender, uint256 allowance)
external
returns (bool)
{
TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance);
return true;
}
function allowance(address, address) external view returns (uint256) {
return 0;
}
/// @dev Retrieve the balance for `owner`.
function balanceOf(address owner)
external
view
returns (uint256)
{
return balances[owner];
}
}
/// @dev Mock the UniswapV2Router01 contract
contract TestRouter is
IUniswapV2Router01
{
string private _nextRevertReason;
/// @dev Set the revert reason for `swapExactTokensForTokens`.
function setRevertReason(string calldata reason)
external
{
_nextRevertReason = reason;
}
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts)
{
_revertIfReasonExists();
amounts = new uint[](path.length);
amounts[0] = amountIn;
amounts[amounts.length - 1] = amountOutMin;
TestEventsRaiser(msg.sender).raiseSwapExactTokensForTokensInput(
// tokens sold
amountIn,
// tokens bought
amountOutMin,
// output token (toTokenAddress)
path[path.length - 1],
// recipient
to,
// deadline
deadline
);
}
function _revertIfReasonExists()
private
view
{
if (bytes(_nextRevertReason).length != 0) {
revert(_nextRevertReason);
}
}
}
/// @dev UniswapV2Bridge overridden to mock tokens and Uniswap router
contract TestUniswapV2Bridge is
UniswapV2Bridge,
TestEventsRaiser
{
// Token address to TestToken instance.
mapping (address => TestToken) private _testTokens;
// TestRouter instance.
TestRouter private _testRouter;
constructor() public {
_testRouter = new TestRouter();
}
function setRouterRevertReason(string calldata revertReason)
external
{
_testRouter.setRevertReason(revertReason);
}
/// @dev Sets the balance of this contract for an existing token.
/// The wei attached will be the balance.
function setTokenBalance(address tokenAddress, uint256 balance)
external
{
TestToken token = _testTokens[tokenAddress];
token.setBalance(address(this), balance);
}
/// @dev Create a new token
/// @param tokenAddress The token address. If zero, one will be created.
function createToken(
address tokenAddress
)
external
returns (TestToken token)
{
token = TestToken(tokenAddress);
if (tokenAddress == address(0)) {
token = new TestToken();
}
_testTokens[address(token)] = token;
return token;
}
function getRouterAddress()
external
view
returns (address)
{
return address(_testRouter);
}
function _getUniswapV2Router01Address()
internal
view
returns (address)
{
return address(_testRouter);
}
}

View File

@ -1,99 +0,0 @@
{
"name": "@0x/contracts-asset-proxy",
"version": "3.7.19",
"engines": {
"node": ">=6.12"
},
"description": "Smart contract components of 0x protocol",
"main": "lib/src/index.js",
"directories": {
"test": "test"
},
"scripts": {
"build": "yarn pre_build && 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",
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
"compile": "sol-compiler",
"watch": "sol-compiler -w",
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"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",
"coverage:report:lcov": "istanbul report lcov",
"test:circleci": "yarn test",
"contracts:gen": "contracts-gen generate",
"contracts:copy": "contracts-gen copy",
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
"compile:truffle": "truffle compile",
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
},
"config": {
"abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CreamBridge|CryptoComBridge|CurveBridge|DODOBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IShell|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|ShellBridge|SnowSwapBridge|StaticCallProxy|SushiSwapBridge|SwerveBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/protocol.git"
},
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/0xProject/protocol/issues"
},
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
"devDependencies": {
"@0x/abi-gen": "^5.6.0",
"@0x/contract-wrappers": "^13.17.4",
"@0x/contracts-gen": "^2.0.38",
"@0x/contracts-test-utils": "^5.4.8",
"@0x/contracts-utils": "^4.7.16",
"@0x/dev-utils": "^4.2.7",
"@0x/sol-compiler": "^4.7.3",
"@0x/ts-doc-gen": "^0.0.28",
"@0x/tslint-config": "^4.1.4",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "12.12.54",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^3.0.0",
"dirty-chai": "^2.0.1",
"ethereumjs-util": "^7.0.10",
"make-promises-safe": "^1.1.0",
"mocha": "^6.2.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"solhint": "^1.4.1",
"truffle": "^5.0.32",
"tslint": "5.11.0",
"typedoc": "~0.16.11",
"typescript": "4.2.2"
},
"dependencies": {
"@0x/base-contract": "^6.4.0",
"@0x/contracts-erc1155": "^2.1.37",
"@0x/contracts-erc20": "^3.3.16",
"@0x/contracts-erc721": "^3.1.37",
"@0x/contracts-exchange-libs": "^4.3.37",
"@0x/order-utils": "^10.4.28",
"@0x/types": "^3.3.3",
"@0x/typescript-typings": "^5.2.0",
"@0x/utils": "^6.4.3",
"@0x/web3-wrapper": "^7.5.3",
"ethereum-types": "^3.5.0",
"lodash": "^4.17.11"
},
"publishConfig": {
"access": "public"
},
"gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
}

View File

@ -1,127 +0,0 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
import { ContractArtifact } from 'ethereum-types';
import * as BalancerBridge from '../generated-artifacts/BalancerBridge.json';
import * as BancorBridge from '../generated-artifacts/BancorBridge.json';
import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json';
import * as CreamBridge from '../generated-artifacts/CreamBridge.json';
import * as CryptoComBridge from '../generated-artifacts/CryptoComBridge.json';
import * as CurveBridge from '../generated-artifacts/CurveBridge.json';
import * as DexForwarderBridge from '../generated-artifacts/DexForwarderBridge.json';
import * as DODOBridge from '../generated-artifacts/DODOBridge.json';
import * as DydxBridge from '../generated-artifacts/DydxBridge.json';
import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json';
import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json';
import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json';
import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json';
import * as Eth2DaiBridge from '../generated-artifacts/Eth2DaiBridge.json';
import * as IAssetData from '../generated-artifacts/IAssetData.json';
import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json';
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
import * as IBalancerPool from '../generated-artifacts/IBalancerPool.json';
import * as IBancorNetwork from '../generated-artifacts/IBancorNetwork.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 IGasToken from '../generated-artifacts/IGasToken.json';
import * as IKyberNetworkProxy from '../generated-artifacts/IKyberNetworkProxy.json';
import * as IMooniswap from '../generated-artifacts/IMooniswap.json';
import * as IMStable from '../generated-artifacts/IMStable.json';
import * as IShell from '../generated-artifacts/IShell.json';
import * as IUniswapExchange from '../generated-artifacts/IUniswapExchange.json';
import * as IUniswapExchangeFactory from '../generated-artifacts/IUniswapExchangeFactory.json';
import * as IUniswapV2Router01 from '../generated-artifacts/IUniswapV2Router01.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 MixinGasToken from '../generated-artifacts/MixinGasToken.json';
import * as MooniswapBridge from '../generated-artifacts/MooniswapBridge.json';
import * as MStableBridge from '../generated-artifacts/MStableBridge.json';
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
import * as Ownable from '../generated-artifacts/Ownable.json';
import * as ShellBridge from '../generated-artifacts/ShellBridge.json';
import * as SnowSwapBridge from '../generated-artifacts/SnowSwapBridge.json';
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
import * as SushiSwapBridge from '../generated-artifacts/SushiSwapBridge.json';
import * as SwerveBridge from '../generated-artifacts/SwerveBridge.json';
import * as TestBancorBridge from '../generated-artifacts/TestBancorBridge.json';
import * as TestChaiBridge from '../generated-artifacts/TestChaiBridge.json';
import * as TestDexForwarderBridge from '../generated-artifacts/TestDexForwarderBridge.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 TestUniswapV2Bridge from '../generated-artifacts/TestUniswapV2Bridge.json';
import * as UniswapBridge from '../generated-artifacts/UniswapBridge.json';
import * as UniswapV2Bridge from '../generated-artifacts/UniswapV2Bridge.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,
BalancerBridge: BalancerBridge as ContractArtifact,
BancorBridge: BancorBridge as ContractArtifact,
ChaiBridge: ChaiBridge as ContractArtifact,
CreamBridge: CreamBridge as ContractArtifact,
CryptoComBridge: CryptoComBridge as ContractArtifact,
CurveBridge: CurveBridge as ContractArtifact,
DODOBridge: DODOBridge as ContractArtifact,
DexForwarderBridge: DexForwarderBridge as ContractArtifact,
DydxBridge: DydxBridge as ContractArtifact,
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
KyberBridge: KyberBridge as ContractArtifact,
MStableBridge: MStableBridge as ContractArtifact,
MixinGasToken: MixinGasToken as ContractArtifact,
MooniswapBridge: MooniswapBridge as ContractArtifact,
ShellBridge: ShellBridge as ContractArtifact,
SnowSwapBridge: SnowSwapBridge as ContractArtifact,
SushiSwapBridge: SushiSwapBridge as ContractArtifact,
SwerveBridge: SwerveBridge as ContractArtifact,
UniswapBridge: UniswapBridge as ContractArtifact,
UniswapV2Bridge: UniswapV2Bridge as ContractArtifact,
IAssetData: IAssetData as ContractArtifact,
IAssetProxy: IAssetProxy as ContractArtifact,
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
IAuthorizable: IAuthorizable as ContractArtifact,
IBalancerPool: IBalancerPool as ContractArtifact,
IBancorNetwork: IBancorNetwork 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,
IGasToken: IGasToken as ContractArtifact,
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
IMStable: IMStable as ContractArtifact,
IMooniswap: IMooniswap as ContractArtifact,
IShell: IShell as ContractArtifact,
IUniswapExchange: IUniswapExchange as ContractArtifact,
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
TestBancorBridge: TestBancorBridge as ContractArtifact,
TestChaiBridge: TestChaiBridge as ContractArtifact,
TestDexForwarderBridge: TestDexForwarderBridge 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,
TestUniswapV2Bridge: TestUniswapV2Bridge as ContractArtifact,
};

View File

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

View File

@ -1,27 +0,0 @@
import { AbiEncoder, BigNumber } from '@0x/utils';
export interface DexForwarderBridgeCall {
target: string;
inputTokenAmount: BigNumber;
outputTokenAmount: BigNumber;
bridgeData: string;
}
export interface DexForwaderBridgeData {
inputToken: string;
calls: DexForwarderBridgeCall[];
}
export const dexForwarderBridgeDataEncoder = AbiEncoder.create([
{ name: 'inputToken', type: 'address' },
{
name: 'calls',
type: 'tuple[]',
components: [
{ name: 'target', type: 'address' },
{ name: 'inputTokenAmount', type: 'uint256' },
{ name: 'outputTokenAmount', type: 'uint256' },
{ name: 'bridgeData', type: 'bytes' },
],
},
]);

View File

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

View File

@ -1,410 +0,0 @@
import { artifacts as erc1155Artifacts, ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155';
import {
constants,
ERC1155FungibleHoldingsByOwner,
ERC1155HoldingsByOwner,
ERC1155NonFungibleHoldingsByOwner,
LogDecoder,
txDefaults,
} from '@0x/contracts-test-utils';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { ERC1155ProxyContract, IAssetDataContract, IAssetProxyContract } from './wrappers';
export class ERC1155ProxyWrapper {
private readonly _tokenOwnerAddresses: string[];
private readonly _fungibleTokenIds: string[];
private readonly _nonFungibleTokenIds: string[];
private readonly _nfts: Array<{ id: BigNumber; tokenId: BigNumber }>;
private readonly _contractOwnerAddress: string;
private readonly _web3Wrapper: Web3Wrapper;
private readonly _provider: Provider;
private readonly _logDecoder: LogDecoder;
private readonly _dummyTokenWrappers: Erc1155Wrapper[];
private readonly _assetProxyInterface: IAssetProxyContract;
private readonly _assetDataInterface: IAssetDataContract;
private _proxyContract?: ERC1155ProxyContract;
private _proxyIdIfExists?: string;
private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} };
constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
this._web3Wrapper = new Web3Wrapper(provider);
this._provider = provider;
const allArtifacts = _.merge(artifacts, erc1155Artifacts);
this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts);
this._dummyTokenWrappers = [];
this._assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider);
this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
this._tokenOwnerAddresses = tokenOwnerAddresses;
this._contractOwnerAddress = contractOwnerAddress;
this._fungibleTokenIds = [];
this._nonFungibleTokenIds = [];
this._nfts = [];
}
/**
* @dev Deploys dummy ERC1155 contracts
* @return An array of ERC1155 wrappers; one for each deployed contract.
*/
public async deployDummyContractsAsync(): Promise<Erc1155Wrapper[]> {
// tslint:disable-next-line:no-unused-variable
for (const i of _.times(constants.NUM_DUMMY_ERC1155_CONTRACTS_TO_DEPLOY)) {
const erc1155Contract = await ERC1155MintableContract.deployFrom0xArtifactAsync(
erc1155Artifacts.ERC1155Mintable,
this._provider,
txDefaults,
artifacts,
);
const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._contractOwnerAddress);
this._dummyTokenWrappers.push(erc1155Wrapper);
}
return this._dummyTokenWrappers;
}
/**
* @dev Deploys the ERC1155 proxy
* @return Deployed ERC1155 proxy contract instance
*/
public async deployProxyAsync(): Promise<ERC1155ProxyContract> {
this._proxyContract = await ERC1155ProxyContract.deployFrom0xArtifactAsync(
artifacts.ERC1155Proxy,
this._provider,
txDefaults,
artifacts,
);
this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync();
return this._proxyContract;
}
/**
* @dev Gets the ERC1155 proxy id
*/
public getProxyId(): string {
this._validateProxyContractExistsOrThrow();
return this._proxyIdIfExists as string;
}
/**
* @dev generates abi-encoded tx data for transferring erc1155 fungible/non-fungible tokens.
* @param from source address
* @param to destination address
* @param contractAddress address of erc155 contract
* @param tokensToTransfer array of erc1155 tokens to transfer
* @param valuesToTransfer array of corresponding values for each erc1155 token to transfer
* @param valueMultiplier each value in `valuesToTransfer` is multiplied by this
* @param receiverCallbackData callback data if `to` is a contract
* @param authorizedSender sender of `transferFrom` transaction
* @param extraData extra data to append to `transferFrom` transaction. Optional.
* @return abi encoded tx data.
*/
public async getTransferFromAbiEncodedTxDataAsync(
from: string,
to: string,
contractAddress: string,
tokensToTransfer: BigNumber[],
valuesToTransfer: BigNumber[],
valueMultiplier: BigNumber,
receiverCallbackData: string,
authorizedSender: string,
assetData_?: string,
): Promise<string> {
this._validateProxyContractExistsOrThrow();
const assetData =
assetData_ === undefined
? this._assetDataInterface
.ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData()
: assetData_;
const data = this._assetProxyInterface
.transferFrom(assetData, from, to, valueMultiplier)
.getABIEncodedTransactionData();
return data;
}
/**
* @dev transfers erc1155 fungible/non-fungible tokens.
* @param txData: abi-encoded tx data
* @param authorizedSender sender of `transferFrom` transaction
*/
public async transferFromRawAsync(
txData: string,
authorizedSender: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const txHash = await this._web3Wrapper.sendTransactionAsync({
to: (this._proxyContract as ERC1155ProxyContract).address,
data: txData,
from: authorizedSender,
gas: 300000,
});
const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return txReceipt;
}
/**
* @dev transfers erc1155 fungible/non-fungible tokens.
* @param from source address
* @param to destination address
* @param contractAddress address of erc155 contract
* @param tokensToTransfer array of erc1155 tokens to transfer
* @param valuesToTransfer array of corresponding values for each erc1155 token to transfer
* @param valueMultiplier each value in `valuesToTransfer` is multiplied by this
* @param receiverCallbackData callback data if `to` is a contract
* @param authorizedSender sender of `transferFrom` transaction
* @param extraData extra data to append to `transferFrom` transaction. Optional.
* @return tranasction hash.
*/
public async transferFromAsync(
from: string,
to: string,
contractAddress: string,
tokensToTransfer: BigNumber[],
valuesToTransfer: BigNumber[],
valueMultiplier: BigNumber,
receiverCallbackData: string,
authorizedSender: string,
assetData_?: string,
): Promise<TransactionReceiptWithDecodedLogs> {
this._validateProxyContractExistsOrThrow();
const assetData =
assetData_ === undefined
? this._assetDataInterface
.ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
.getABIEncodedTransactionData()
: assetData_;
const data = this._assetProxyInterface
.transferFrom(assetData, from, to, valueMultiplier)
.getABIEncodedTransactionData();
const txHash = await this._web3Wrapper.sendTransactionAsync({
to: (this._proxyContract as ERC1155ProxyContract).address,
data,
from: authorizedSender,
gas: 300000,
});
const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return txReceipt;
}
/**
* @dev For each deployed ERC1155 contract, this function mints a set of fungible/non-fungible
* tokens for each token owner address (`_tokenOwnerAddresses`).
* @return Balances of each token owner, across all ERC1155 contracts and tokens.
*/
public async setBalancesAndAllowancesAsync(): Promise<ERC1155HoldingsByOwner> {
this._validateDummyTokenContractsExistOrThrow();
this._validateProxyContractExistsOrThrow();
this._initialTokenIdsByOwner = {
fungible: {},
nonFungible: {},
};
const fungibleHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {};
const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {};
// Set balances accordingly
for (const dummyWrapper of this._dummyTokenWrappers) {
const dummyAddress = dummyWrapper.getContract().address;
// tslint:disable-next-line:no-unused-variable
for (const i of _.times(constants.NUM_ERC1155_FUNGIBLE_TOKENS_MINT)) {
// Create a fungible token
const tokenId = await dummyWrapper.mintFungibleTokensAsync(
this._tokenOwnerAddresses,
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
);
const tokenIdAsString = tokenId.toString();
this._fungibleTokenIds.push(tokenIdAsString);
// Mint tokens for each owner for this token
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
// tslint:disable-next-line:no-unused-variable
if (fungibleHoldingsByOwner[tokenOwnerAddress] === undefined) {
fungibleHoldingsByOwner[tokenOwnerAddress] = {};
}
if (fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] === undefined) {
fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {};
}
fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] =
constants.INITIAL_ERC1155_FUNGIBLE_BALANCE;
await dummyWrapper.setApprovalForAllAsync(
tokenOwnerAddress,
(this._proxyContract as ERC1155ProxyContract).address,
true,
);
}
}
// Non-fungible tokens
// tslint:disable-next-line:no-unused-variable
for (const j of _.times(constants.NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT)) {
const [tokenId, nftIds] = await dummyWrapper.mintNonFungibleTokensAsync(this._tokenOwnerAddresses);
const tokenIdAsString = tokenId.toString();
this._nonFungibleTokenIds.push(tokenIdAsString);
_.each(this._tokenOwnerAddresses, async (tokenOwnerAddress: string, i: number) => {
if (nonFungibleHoldingsByOwner[tokenOwnerAddress] === undefined) {
nonFungibleHoldingsByOwner[tokenOwnerAddress] = {};
}
if (nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] === undefined) {
nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {};
}
if (nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] === undefined) {
nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = [];
}
this._nfts.push({ id: nftIds[i], tokenId });
nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString].push(nftIds[i]);
await dummyWrapper.setApprovalForAllAsync(
tokenOwnerAddress,
(this._proxyContract as ERC1155ProxyContract).address,
true,
);
});
}
}
this._initialTokenIdsByOwner = {
fungible: fungibleHoldingsByOwner,
nonFungible: nonFungibleHoldingsByOwner,
};
return this._initialTokenIdsByOwner;
}
/**
* @dev For each deployed ERC1155 contract, this function quieries the set of fungible/non-fungible
* tokens for each token owner address (`_tokenOwnerAddresses`).
* @return Balances of each token owner, across all ERC1155 contracts and tokens.
*/
public async getBalancesAsync(): Promise<ERC1155HoldingsByOwner> {
this._validateDummyTokenContractsExistOrThrow();
this._validateBalancesAndAllowancesSetOrThrow();
const tokenHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {};
const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {};
for (const dummyTokenWrapper of this._dummyTokenWrappers) {
const tokenContract = dummyTokenWrapper.getContract();
const tokenAddress = tokenContract.address;
// Construct batch balance call
const tokenOwners: string[] = [];
const tokenIds: BigNumber[] = [];
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
for (const tokenId of this._fungibleTokenIds) {
tokenOwners.push(tokenOwnerAddress);
tokenIds.push(new BigNumber(tokenId));
}
for (const nft of this._nfts) {
tokenOwners.push(tokenOwnerAddress);
tokenIds.push(nft.id);
}
}
const balances = await dummyTokenWrapper.getBalancesAsync(tokenOwners, tokenIds);
// Parse out balances into fungible / non-fungible token holdings
let i = 0;
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
// Fungible tokens
for (const tokenId of this._fungibleTokenIds) {
if (tokenHoldingsByOwner[tokenOwnerAddress] === undefined) {
tokenHoldingsByOwner[tokenOwnerAddress] = {};
}
if (tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] === undefined) {
tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {};
}
tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress][tokenId] = balances[i++];
}
// Non-fungible tokens
for (const nft of this._nfts) {
if (nonFungibleHoldingsByOwner[tokenOwnerAddress] === undefined) {
nonFungibleHoldingsByOwner[tokenOwnerAddress] = {};
}
if (nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] === undefined) {
nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {};
}
if (
nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] ===
undefined
) {
nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] = [];
}
const isOwner = balances[i++];
if (isOwner.isEqualTo(1)) {
nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()].push(
nft.id,
);
}
}
}
}
const holdingsByOwner = {
fungible: tokenHoldingsByOwner,
nonFungible: nonFungibleHoldingsByOwner,
};
return holdingsByOwner;
}
/**
* @dev Set the approval for the proxy on behalf of `userAddress` .
* @param userAddress owner of ERC1155 tokens.
* @param contractAddress address of ERC1155 contract.
* @param isApproved Whether to approve the proxy for all or not.
*/
public async setProxyAllowanceForAllAsync(
userAddress: string,
contractAddress: string,
isApproved: boolean,
): Promise<void> {
this._validateProxyContractExistsOrThrow();
const tokenWrapper = this.getContractWrapper(contractAddress);
const operator = (this._proxyContract as ERC1155ProxyContract).address;
await tokenWrapper.setApprovalForAllAsync(userAddress, operator, isApproved);
}
/**
* @dev Checks if proxy is approved to transfer tokens on behalf of `userAddress`.
* @param userAddress owner of ERC1155 tokens.
* @param contractAddress address of ERC1155 contract.
* @return True iff the proxy is approved for all. False otherwise.
*/
public async isProxyApprovedForAllAsync(userAddress: string, contractAddress: string): Promise<boolean> {
this._validateProxyContractExistsOrThrow();
const tokenContract = this._getContractFromAddress(contractAddress);
const operator = (this._proxyContract as ERC1155ProxyContract).address;
const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync();
return didApproveAll;
}
public getFungibleTokenIds(): BigNumber[] {
const fungibleTokenIds = _.map(this._fungibleTokenIds, (tokenIdAsString: string) => {
return new BigNumber(tokenIdAsString);
});
return fungibleTokenIds;
}
public getNonFungibleTokenIds(): BigNumber[] {
const nonFungibleTokenIds = _.map(this._nonFungibleTokenIds, (tokenIdAsString: string) => {
return new BigNumber(tokenIdAsString);
});
return nonFungibleTokenIds;
}
public getTokenOwnerAddresses(): string[] {
return this._tokenOwnerAddresses;
}
public getContractWrapper(contractAddress: string): Erc1155Wrapper {
const tokenWrapper = _.find(this._dummyTokenWrappers, (wrapper: Erc1155Wrapper) => {
return wrapper.getContract().address === contractAddress;
});
if (tokenWrapper === undefined) {
throw new Error(`Contract: ${contractAddress} was not deployed through ERC1155ProxyWrapper`);
}
return tokenWrapper;
}
private _getContractFromAddress(tokenAddress: string): ERC1155MintableContract {
const tokenContractIfExists = _.find(this._dummyTokenWrappers, c => c.getContract().address === tokenAddress);
if (tokenContractIfExists === undefined) {
throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155ProxyWrapper`);
}
return tokenContractIfExists.getContract();
}
private _validateDummyTokenContractsExistOrThrow(): void {
if (this._dummyTokenWrappers === undefined) {
throw new Error('Dummy ERC1155 tokens not yet deployed, please call "deployDummyTokensAsync"');
}
}
private _validateProxyContractExistsOrThrow(): void {
if (this._proxyContract === undefined) {
throw new Error('ERC1155 proxy contract not yet deployed, please call "deployProxyAsync"');
}
}
private _validateBalancesAndAllowancesSetOrThrow(): void {
if (
_.keys(this._initialTokenIdsByOwner.fungible).length === 0 ||
_.keys(this._initialTokenIdsByOwner.nonFungible).length === 0
) {
throw new Error(
'Dummy ERC1155 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"',
);
}
}
}

View File

@ -1,164 +0,0 @@
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils';
import { BigNumber } from '@0x/utils';
import { ZeroExProvider } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
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 _assetDataInterface: IAssetDataContract;
private _proxyContract?: ERC20ProxyContract;
private _proxyIdIfExists?: string;
/**
* Instanitates an ERC20Wrapper
* @param provider Web3 provider to use for all JSON RPC requests
* @param tokenOwnerAddresses Addresses that we want to endow as owners for dummy ERC20 tokens
* @param contractOwnerAddress Desired owner of the contract
* Instance of ERC20Wrapper
*/
constructor(provider: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
this._dummyTokenContracts = [];
this._provider = provider;
this._tokenOwnerAddresses = tokenOwnerAddresses;
this._contractOwnerAddress = contractOwnerAddress;
this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
}
public async deployDummyTokensAsync(
numberToDeploy: number,
decimals: BigNumber,
): Promise<DummyERC20TokenContract[]> {
for (let i = 0; i < numberToDeploy; i++) {
this._dummyTokenContracts.push(
await DummyERC20TokenContract.deployFrom0xArtifactAsync(
erc20Artifacts.DummyERC20Token,
this._provider,
txDefaults,
artifacts,
constants.DUMMY_TOKEN_NAME,
constants.DUMMY_TOKEN_SYMBOL,
decimals,
constants.DUMMY_TOKEN_TOTAL_SUPPLY,
),
);
}
return this._dummyTokenContracts;
}
public async deployProxyAsync(): Promise<ERC20ProxyContract> {
this._proxyContract = await ERC20ProxyContract.deployFrom0xArtifactAsync(
artifacts.ERC20Proxy,
this._provider,
txDefaults,
artifacts,
);
this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync();
return this._proxyContract;
}
public getProxyId(): string {
this._validateProxyContractExistsOrThrow();
return this._proxyIdIfExists as string;
}
public async setBalancesAndAllowancesAsync(): Promise<void> {
this._validateDummyTokenContractsExistOrThrow();
this._validateProxyContractExistsOrThrow();
for (const dummyTokenContract of this._dummyTokenContracts) {
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
await dummyTokenContract
.setBalance(tokenOwnerAddress, constants.INITIAL_ERC20_BALANCE)
.awaitTransactionSuccessAsync({ from: this._contractOwnerAddress });
await dummyTokenContract
.approve((this._proxyContract as ERC20ProxyContract).address, constants.INITIAL_ERC20_ALLOWANCE)
.awaitTransactionSuccessAsync({ from: tokenOwnerAddress });
}
}
}
public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
const balance = new BigNumber(await tokenContract.balanceOf(userAddress).callAsync());
return balance;
}
public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
await tokenContract
.setBalance(userAddress, amount)
.awaitTransactionSuccessAsync(
{ from: this._contractOwnerAddress },
{ pollingIntervalMs: constants.AWAIT_TRANSACTION_MINED_MS },
);
}
public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
const allowance = new BigNumber(await tokenContract.allowance(userAddress, proxyAddress).callAsync());
return allowance;
}
public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
await tokenContract.approve(proxyAddress, amount).awaitTransactionSuccessAsync({ from: userAddress });
}
public async getBalancesAsync(): Promise<ERC20BalancesByOwner> {
this._validateDummyTokenContractsExistOrThrow();
const balancesByOwner: ERC20BalancesByOwner = {};
const balances: BigNumber[] = [];
const balanceInfo: Array<{ tokenOwnerAddress: string; tokenAddress: string }> = [];
for (const dummyTokenContract of this._dummyTokenContracts) {
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
balances.push(await dummyTokenContract.balanceOf(tokenOwnerAddress).callAsync());
balanceInfo.push({
tokenOwnerAddress,
tokenAddress: dummyTokenContract.address,
});
}
}
_.forEach(balances, (balance, balanceIndex) => {
const tokenAddress = balanceInfo[balanceIndex].tokenAddress;
const tokenOwnerAddress = balanceInfo[balanceIndex].tokenOwnerAddress;
if (balancesByOwner[tokenOwnerAddress] === undefined) {
balancesByOwner[tokenOwnerAddress] = {};
}
const wrappedBalance = new BigNumber(balance);
balancesByOwner[tokenOwnerAddress][tokenAddress] = wrappedBalance;
});
return balancesByOwner;
}
public addDummyTokenContract(dummy: DummyERC20TokenContract): void {
if (this._dummyTokenContracts !== undefined) {
this._dummyTokenContracts.push(dummy);
}
}
public addTokenOwnerAddress(address: string): void {
this._tokenOwnerAddresses.push(address);
}
public getTokenOwnerAddresses(): string[] {
return this._tokenOwnerAddresses;
}
public getTokenAddresses(): string[] {
const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address);
return tokenAddresses;
}
private async _getTokenContractFromAssetDataAsync(assetData: string): Promise<DummyERC20TokenContract> {
const tokenAddress = this._assetDataInterface.getABIDecodedTransactionData<string>('ERC20Token', assetData); // tslint:disable-line:no-unused-variable
const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
if (tokenContractIfExists === undefined) {
throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
}
return tokenContractIfExists;
}
private _validateDummyTokenContractsExistOrThrow(): void {
if (this._dummyTokenContracts === undefined) {
throw new Error('Dummy ERC20 tokens not yet deployed, please call "deployDummyTokensAsync"');
}
}
private _validateProxyContractExistsOrThrow(): void {
if (this._proxyContract === undefined) {
throw new Error('ERC20 proxy contract not yet deployed, please call "deployProxyAsync"');
}
}
}

View File

@ -1,220 +0,0 @@
import { artifacts as erc721Artifacts, DummyERC721TokenContract } from '@0x/contracts-erc721';
import { constants, ERC721TokenIdsByOwner, txDefaults } from '@0x/contracts-test-utils';
import { generatePseudoRandomSalt } from '@0x/order-utils';
import { BigNumber } from '@0x/utils';
import { ZeroExProvider } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { ERC721ProxyContract } from './wrappers';
export class ERC721Wrapper {
private readonly _tokenOwnerAddresses: string[];
private readonly _contractOwnerAddress: string;
private readonly _provider: ZeroExProvider;
private readonly _dummyTokenContracts: DummyERC721TokenContract[];
private _proxyContract?: ERC721ProxyContract;
private _proxyIdIfExists?: string;
private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {};
constructor(provider: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
this._provider = provider;
this._dummyTokenContracts = [];
this._tokenOwnerAddresses = tokenOwnerAddresses;
this._contractOwnerAddress = contractOwnerAddress;
}
public async deployDummyTokensAsync(): Promise<DummyERC721TokenContract[]> {
// tslint:disable-next-line:no-unused-variable
for (const i of _.times(constants.NUM_DUMMY_ERC721_TO_DEPLOY)) {
this._dummyTokenContracts.push(
await DummyERC721TokenContract.deployFrom0xArtifactAsync(
erc721Artifacts.DummyERC721Token,
this._provider,
txDefaults,
artifacts,
constants.DUMMY_TOKEN_NAME,
constants.DUMMY_TOKEN_SYMBOL,
),
);
}
return this._dummyTokenContracts;
}
public async deployProxyAsync(): Promise<ERC721ProxyContract> {
this._proxyContract = await ERC721ProxyContract.deployFrom0xArtifactAsync(
artifacts.ERC721Proxy,
this._provider,
txDefaults,
artifacts,
);
this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync();
return this._proxyContract;
}
public getProxyId(): string {
this._validateProxyContractExistsOrThrow();
return this._proxyIdIfExists as string;
}
public async setBalancesAndAllowancesAsync(): Promise<void> {
this._validateDummyTokenContractsExistOrThrow();
this._validateProxyContractExistsOrThrow();
this._initialTokenIdsByOwner = {};
for (const dummyTokenContract of this._dummyTokenContracts) {
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
// tslint:disable-next-line:no-unused-variable
for (const i of _.times(constants.NUM_ERC721_TOKENS_TO_MINT)) {
const tokenId = generatePseudoRandomSalt();
await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress);
if (this._initialTokenIdsByOwner[tokenOwnerAddress] === undefined) {
this._initialTokenIdsByOwner[tokenOwnerAddress] = {
[dummyTokenContract.address]: [],
};
}
if (this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] === undefined) {
this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] = [];
}
this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId);
await this.approveProxyForAllAsync(dummyTokenContract.address, tokenOwnerAddress, true);
}
}
}
}
public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const owner = await tokenContract.ownerOf(tokenId).callAsync();
const doesExist = owner !== constants.NULL_ADDRESS;
return doesExist;
}
public async approveProxyAsync(tokenAddress: string, tokenId: BigNumber): Promise<void> {
const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
await this.approveAsync(proxyAddress, tokenAddress, tokenId);
}
public async approveProxyForAllAsync(
tokenAddress: string,
ownerAddress: string,
isApproved: boolean,
): Promise<void> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
await tokenContract.setApprovalForAll(proxyAddress, isApproved).awaitTransactionSuccessAsync({
from: ownerAddress,
});
}
public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
await tokenContract.approve(to, tokenId).awaitTransactionSuccessAsync({ from: tokenOwner });
}
public async transferFromAsync(
tokenAddress: string,
tokenId: BigNumber,
currentOwner: string,
userAddress: string,
): Promise<void> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
await tokenContract.transferFrom(currentOwner, userAddress, tokenId).awaitTransactionSuccessAsync({
from: currentOwner,
});
}
public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
await tokenContract.mint(userAddress, tokenId).awaitTransactionSuccessAsync({
from: this._contractOwnerAddress,
});
}
public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
await tokenContract.burn(owner, tokenId).awaitTransactionSuccessAsync({ from: this._contractOwnerAddress });
}
public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise<string> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const owner = await tokenContract.ownerOf(tokenId).callAsync();
return owner;
}
public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const tokenOwner = await tokenContract.ownerOf(tokenId).callAsync();
const isOwner = tokenOwner === userAddress;
return isOwner;
}
public async isProxyApprovedForAllAsync(userAddress: string, tokenAddress: string): Promise<boolean> {
this._validateProxyContractExistsOrThrow();
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const operator = (this._proxyContract as ERC721ProxyContract).address;
const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync();
return didApproveAll;
}
public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
this._validateProxyContractExistsOrThrow();
const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
const approvedAddress = await tokenContract.getApproved(tokenId).callAsync();
const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
const isProxyAnApprovedOperator = approvedAddress === proxyAddress;
return isProxyAnApprovedOperator;
}
public async getBalancesAsync(): Promise<ERC721TokenIdsByOwner> {
this._validateDummyTokenContractsExistOrThrow();
this._validateBalancesAndAllowancesSetOrThrow();
const tokenIdsByOwner: ERC721TokenIdsByOwner = {};
const tokenOwnerAddresses: string[] = [];
const tokenInfo: Array<{ tokenId: BigNumber; tokenAddress: string }> = [];
for (const dummyTokenContract of this._dummyTokenContracts) {
for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
const initialTokenOwnerIds = this._initialTokenIdsByOwner[tokenOwnerAddress][
dummyTokenContract.address
];
for (const tokenId of initialTokenOwnerIds) {
tokenOwnerAddresses.push(await dummyTokenContract.ownerOf(tokenId).callAsync());
tokenInfo.push({
tokenId,
tokenAddress: dummyTokenContract.address,
});
}
}
}
_.forEach(tokenOwnerAddresses, (tokenOwnerAddress, ownerIndex) => {
const tokenAddress = tokenInfo[ownerIndex].tokenAddress;
const tokenId = tokenInfo[ownerIndex].tokenId;
if (tokenIdsByOwner[tokenOwnerAddress] === undefined) {
tokenIdsByOwner[tokenOwnerAddress] = {
[tokenAddress]: [],
};
}
if (tokenIdsByOwner[tokenOwnerAddress][tokenAddress] === undefined) {
tokenIdsByOwner[tokenOwnerAddress][tokenAddress] = [];
}
tokenIdsByOwner[tokenOwnerAddress][tokenAddress].push(tokenId);
});
return tokenIdsByOwner;
}
public getTokenOwnerAddresses(): string[] {
return this._tokenOwnerAddresses;
}
public getTokenAddresses(): string[] {
const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address);
return tokenAddresses;
}
private _getTokenContractFromAssetData(tokenAddress: string): DummyERC721TokenContract {
const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
if (tokenContractIfExists === undefined) {
throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
}
return tokenContractIfExists;
}
private _validateDummyTokenContractsExistOrThrow(): void {
if (this._dummyTokenContracts === undefined) {
throw new Error('Dummy ERC721 tokens not yet deployed, please call "deployDummyTokensAsync"');
}
}
private _validateProxyContractExistsOrThrow(): void {
if (this._proxyContract === undefined) {
throw new Error('ERC721 proxy contract not yet deployed, please call "deployProxyAsync"');
}
}
private _validateBalancesAndAllowancesSetOrThrow(): void {
if (_.keys(this._initialTokenIdsByOwner).length === 0) {
throw new Error(
'Dummy ERC721 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"',
);
}
}
}

View File

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

View File

@ -1,64 +0,0 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../generated-wrappers/balancer_bridge';
export * from '../generated-wrappers/bancor_bridge';
export * from '../generated-wrappers/chai_bridge';
export * from '../generated-wrappers/cream_bridge';
export * from '../generated-wrappers/crypto_com_bridge';
export * from '../generated-wrappers/curve_bridge';
export * from '../generated-wrappers/d_o_d_o_bridge';
export * from '../generated-wrappers/dex_forwarder_bridge';
export * from '../generated-wrappers/dydx_bridge';
export * from '../generated-wrappers/erc1155_proxy';
export * from '../generated-wrappers/erc20_bridge_proxy';
export * from '../generated-wrappers/erc20_proxy';
export * from '../generated-wrappers/erc721_proxy';
export * from '../generated-wrappers/eth2_dai_bridge';
export * from '../generated-wrappers/i_asset_data';
export * from '../generated-wrappers/i_asset_proxy';
export * from '../generated-wrappers/i_asset_proxy_dispatcher';
export * from '../generated-wrappers/i_authorizable';
export * from '../generated-wrappers/i_balancer_pool';
export * from '../generated-wrappers/i_bancor_network';
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_gas_token';
export * from '../generated-wrappers/i_kyber_network_proxy';
export * from '../generated-wrappers/i_m_stable';
export * from '../generated-wrappers/i_mooniswap';
export * from '../generated-wrappers/i_shell';
export * from '../generated-wrappers/i_uniswap_exchange';
export * from '../generated-wrappers/i_uniswap_exchange_factory';
export * from '../generated-wrappers/i_uniswap_v2_router01';
export * from '../generated-wrappers/kyber_bridge';
export * from '../generated-wrappers/m_stable_bridge';
export * from '../generated-wrappers/mixin_asset_proxy_dispatcher';
export * from '../generated-wrappers/mixin_authorizable';
export * from '../generated-wrappers/mixin_gas_token';
export * from '../generated-wrappers/mooniswap_bridge';
export * from '../generated-wrappers/multi_asset_proxy';
export * from '../generated-wrappers/ownable';
export * from '../generated-wrappers/shell_bridge';
export * from '../generated-wrappers/snow_swap_bridge';
export * from '../generated-wrappers/static_call_proxy';
export * from '../generated-wrappers/sushi_swap_bridge';
export * from '../generated-wrappers/swerve_bridge';
export * from '../generated-wrappers/test_bancor_bridge';
export * from '../generated-wrappers/test_chai_bridge';
export * from '../generated-wrappers/test_dex_forwarder_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/test_uniswap_v2_bridge';
export * from '../generated-wrappers/uniswap_bridge';
export * from '../generated-wrappers/uniswap_v2_bridge';

View File

@ -1,127 +0,0 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
import { ContractArtifact } from 'ethereum-types';
import * as BalancerBridge from '../test/generated-artifacts/BalancerBridge.json';
import * as BancorBridge from '../test/generated-artifacts/BancorBridge.json';
import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json';
import * as CreamBridge from '../test/generated-artifacts/CreamBridge.json';
import * as CryptoComBridge from '../test/generated-artifacts/CryptoComBridge.json';
import * as CurveBridge from '../test/generated-artifacts/CurveBridge.json';
import * as DexForwarderBridge from '../test/generated-artifacts/DexForwarderBridge.json';
import * as DODOBridge from '../test/generated-artifacts/DODOBridge.json';
import * as DydxBridge from '../test/generated-artifacts/DydxBridge.json';
import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json';
import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json';
import * as ERC20Proxy from '../test/generated-artifacts/ERC20Proxy.json';
import * as ERC721Proxy from '../test/generated-artifacts/ERC721Proxy.json';
import * as Eth2DaiBridge from '../test/generated-artifacts/Eth2DaiBridge.json';
import * as IAssetData from '../test/generated-artifacts/IAssetData.json';
import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json';
import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json';
import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json';
import * as IBalancerPool from '../test/generated-artifacts/IBalancerPool.json';
import * as IBancorNetwork from '../test/generated-artifacts/IBancorNetwork.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 IGasToken from '../test/generated-artifacts/IGasToken.json';
import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json';
import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json';
import * as IMStable from '../test/generated-artifacts/IMStable.json';
import * as IShell from '../test/generated-artifacts/IShell.json';
import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json';
import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json';
import * as IUniswapV2Router01 from '../test/generated-artifacts/IUniswapV2Router01.json';
import * as KyberBridge from '../test/generated-artifacts/KyberBridge.json';
import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json';
import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json';
import * as MixinGasToken from '../test/generated-artifacts/MixinGasToken.json';
import * as MooniswapBridge from '../test/generated-artifacts/MooniswapBridge.json';
import * as MStableBridge from '../test/generated-artifacts/MStableBridge.json';
import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json';
import * as Ownable from '../test/generated-artifacts/Ownable.json';
import * as ShellBridge from '../test/generated-artifacts/ShellBridge.json';
import * as SnowSwapBridge from '../test/generated-artifacts/SnowSwapBridge.json';
import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json';
import * as SushiSwapBridge from '../test/generated-artifacts/SushiSwapBridge.json';
import * as SwerveBridge from '../test/generated-artifacts/SwerveBridge.json';
import * as TestBancorBridge from '../test/generated-artifacts/TestBancorBridge.json';
import * as TestChaiBridge from '../test/generated-artifacts/TestChaiBridge.json';
import * as TestDexForwarderBridge from '../test/generated-artifacts/TestDexForwarderBridge.json';
import * as TestDydxBridge from '../test/generated-artifacts/TestDydxBridge.json';
import * as TestERC20Bridge from '../test/generated-artifacts/TestERC20Bridge.json';
import * as TestEth2DaiBridge from '../test/generated-artifacts/TestEth2DaiBridge.json';
import * as TestKyberBridge from '../test/generated-artifacts/TestKyberBridge.json';
import * as TestStaticCallTarget from '../test/generated-artifacts/TestStaticCallTarget.json';
import * as TestUniswapBridge from '../test/generated-artifacts/TestUniswapBridge.json';
import * as TestUniswapV2Bridge from '../test/generated-artifacts/TestUniswapV2Bridge.json';
import * as UniswapBridge from '../test/generated-artifacts/UniswapBridge.json';
import * as UniswapV2Bridge from '../test/generated-artifacts/UniswapV2Bridge.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,
BalancerBridge: BalancerBridge as ContractArtifact,
BancorBridge: BancorBridge as ContractArtifact,
ChaiBridge: ChaiBridge as ContractArtifact,
CreamBridge: CreamBridge as ContractArtifact,
CryptoComBridge: CryptoComBridge as ContractArtifact,
CurveBridge: CurveBridge as ContractArtifact,
DODOBridge: DODOBridge as ContractArtifact,
DexForwarderBridge: DexForwarderBridge as ContractArtifact,
DydxBridge: DydxBridge as ContractArtifact,
Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
KyberBridge: KyberBridge as ContractArtifact,
MStableBridge: MStableBridge as ContractArtifact,
MixinGasToken: MixinGasToken as ContractArtifact,
MooniswapBridge: MooniswapBridge as ContractArtifact,
ShellBridge: ShellBridge as ContractArtifact,
SnowSwapBridge: SnowSwapBridge as ContractArtifact,
SushiSwapBridge: SushiSwapBridge as ContractArtifact,
SwerveBridge: SwerveBridge as ContractArtifact,
UniswapBridge: UniswapBridge as ContractArtifact,
UniswapV2Bridge: UniswapV2Bridge as ContractArtifact,
IAssetData: IAssetData as ContractArtifact,
IAssetProxy: IAssetProxy as ContractArtifact,
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
IAuthorizable: IAuthorizable as ContractArtifact,
IBalancerPool: IBalancerPool as ContractArtifact,
IBancorNetwork: IBancorNetwork 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,
IGasToken: IGasToken as ContractArtifact,
IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
IMStable: IMStable as ContractArtifact,
IMooniswap: IMooniswap as ContractArtifact,
IShell: IShell as ContractArtifact,
IUniswapExchange: IUniswapExchange as ContractArtifact,
IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
TestBancorBridge: TestBancorBridge as ContractArtifact,
TestChaiBridge: TestChaiBridge as ContractArtifact,
TestDexForwarderBridge: TestDexForwarderBridge 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,
TestUniswapV2Bridge: TestUniswapV2Bridge as ContractArtifact,
};

View File

@ -1,128 +0,0 @@
import { blockchainTests, expect, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
import { RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { artifacts } from './artifacts';
import { MixinAuthorizableContract } from './wrappers';
blockchainTests.resets('Authorizable', () => {
let owner: string;
let notOwner: string;
let address: string;
let authorizable: MixinAuthorizableContract;
before(async () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
[owner, address, notOwner] = accounts.slice(0, 3);
authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
artifacts.MixinAuthorizable,
provider,
txDefaults,
artifacts,
);
});
describe('addAuthorizedAddress', () => {
it('should revert if not called by owner', async () => {
const tx = authorizable.addAuthorizedAddress(notOwner).sendTransactionAsync({ from: notOwner });
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
});
it('should allow owner to add an authorized address', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const isAuthorized = await authorizable.authorized(address).callAsync();
expect(isAuthorized).to.be.true();
});
it('should revert if owner attempts to authorize a duplicate address', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const tx = authorizable.addAuthorizedAddress(address).sendTransactionAsync({ from: owner });
return expect(tx).to.revertWith(RevertReason.TargetAlreadyAuthorized);
});
});
describe('removeAuthorizedAddress', () => {
it('should revert if not called by owner', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: notOwner });
return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
});
it('should allow owner to remove an authorized address', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const isAuthorized = await authorizable.authorized(address).callAsync();
expect(isAuthorized).to.be.false();
});
it('should revert if owner attempts to remove an address that is not authorized', async () => {
const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: owner });
return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized);
});
});
describe('removeAuthorizedAddressAtIndex', () => {
it('should revert if not called by owner', async () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const index = new BigNumber(0);
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);
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);
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 () => {
const address1 = address;
const address2 = notOwner;
await authorizable.addAuthorizedAddress(address1).awaitTransactionSuccessAsync({ from: owner });
await authorizable.addAuthorizedAddress(address2).awaitTransactionSuccessAsync({ from: owner });
const address1Index = new BigNumber(0);
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 () => {
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const index = new BigNumber(0);
await authorizable.removeAuthorizedAddressAtIndex(address, index).awaitTransactionSuccessAsync({
from: owner,
});
const isAuthorized = await authorizable.authorized(address).callAsync();
expect(isAuthorized).to.be.false();
});
});
describe('getAuthorizedAddresses', () => {
it('should return all authorized addresses', async () => {
const initial = await authorizable.getAuthorizedAddresses().callAsync();
expect(initial).to.have.length(0);
await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const afterAdd = await authorizable.getAuthorizedAddresses().callAsync();
expect(afterAdd).to.have.length(1);
expect(afterAdd).to.include(address);
await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
const afterRemove = await authorizable.getAuthorizedAddresses().callAsync();
expect(afterRemove).to.have.length(0);
});
});
});

View File

@ -1,185 +0,0 @@
import {
blockchainTests,
constants,
expect,
filterLogsToArguments,
getRandomInteger,
randomAddress,
} from '@0x/contracts-test-utils';
import { AssetProxyId } from '@0x/types';
import { AbiEncoder, BigNumber, hexUtils } from '@0x/utils';
import { DecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { TestBancorBridgeContract } from './generated-wrappers/test_bancor_bridge';
import {
TestBancorBridgeConvertByPathInputEventArgs as ConvertByPathArgs,
TestBancorBridgeEvents as ContractEvents,
TestBancorBridgeTokenApproveEventArgs as TokenApproveArgs,
} from './wrappers';
blockchainTests.resets('Bancor unit tests', env => {
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);
let testContract: TestBancorBridgeContract;
before(async () => {
testContract = await TestBancorBridgeContract.deployFrom0xArtifactAsync(
artifacts.TestBancorBridge,
env.provider,
env.txDefaults,
artifacts,
);
});
describe('isValidSignature()', () => {
it('returns success bytes', async () => {
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
const result = await testContract
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
.callAsync();
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
});
});
describe('bridgeTransferFrom()', () => {
interface TransferFromOpts {
tokenAddressesPath: string[];
toAddress: string;
// Amount to pass into `bridgeTransferFrom()`
amount: BigNumber;
// Token balance of the bridge.
fromTokenBalance: BigNumber;
// Router reverts with this reason
routerRevertReason: string;
}
interface TransferFromResult {
opts: TransferFromOpts;
result: string;
logs: DecodedLogs;
blocktime: number;
}
function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100));
return {
tokenAddressesPath: Array(3).fill(constants.NULL_ADDRESS),
amount,
toAddress: randomAddress(),
fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)),
routerRevertReason: '',
...opts,
};
}
const bridgeDataEncoder = AbiEncoder.create('(address[], address)');
async function transferFromAsync(opts?: Partial<TransferFromOpts>): Promise<TransferFromResult> {
const _opts = createTransferFromOpts(opts);
for (let i = 0; i < _opts.tokenAddressesPath.length; i++) {
const createFromTokenFn = testContract.createToken(_opts.tokenAddressesPath[i]);
_opts.tokenAddressesPath[i] = await createFromTokenFn.callAsync();
await createFromTokenFn.awaitTransactionSuccessAsync();
}
// Set the token balance for the token we're converting from.
await testContract
.setTokenBalance(_opts.tokenAddressesPath[0], _opts.fromTokenBalance)
.awaitTransactionSuccessAsync();
// Set revert reason for the router.
await testContract.setNetworkRevertReason(_opts.routerRevertReason).awaitTransactionSuccessAsync();
// Call bridgeTransferFrom().
const bridgeTransferFromFn = testContract.bridgeTransferFrom(
// Output token
_opts.tokenAddressesPath[_opts.tokenAddressesPath.length - 1],
// Random maker address.
randomAddress(),
// Recipient address.
_opts.toAddress,
// Transfer amount.
_opts.amount,
// ABI-encode the input token address as the bridge data.
bridgeDataEncoder.encode([
_opts.tokenAddressesPath,
await testContract.getNetworkAddress().callAsync(),
]),
);
const result = await bridgeTransferFromFn.callAsync();
const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
return {
opts: _opts,
result,
logs: (receipt.logs as any) as DecodedLogs,
blocktime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber),
};
}
it('returns magic bytes on success', async () => {
const { result } = await transferFromAsync();
expect(result).to.eq(AssetProxyId.ERC20Bridge);
});
describe('token -> token', async () => {
it('calls BancorNetwork.convertByPath()', async () => {
const { opts, result, logs } = await transferFromAsync();
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
const transfers = filterLogsToArguments<ConvertByPathArgs>(logs, ContractEvents.ConvertByPathInput);
expect(transfers.length).to.eq(1);
expect(transfers[0].toTokenAddress).to.eq(
opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1],
'output token address',
);
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount');
expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount');
expect(transfers[0].feeRecipient).to.eq(constants.NULL_ADDRESS);
expect(transfers[0].feeAmount).to.bignumber.eq(new BigNumber(0));
});
it('sets allowance for "from" token', async () => {
const { logs } = await transferFromAsync();
const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
const networkAddress = await testContract.getNetworkAddress().callAsync();
expect(approvals.length).to.eq(1);
expect(approvals[0].spender).to.eq(networkAddress);
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
});
it('fails if the router fails', async () => {
const revertReason = 'FOOBAR';
const tx = transferFromAsync({
routerRevertReason: revertReason,
});
return expect(tx).to.eventually.be.rejectedWith(revertReason);
});
});
describe('token -> token -> token', async () => {
it('calls BancorNetwork.convertByPath()', async () => {
const { opts, result, logs } = await transferFromAsync({
tokenAddressesPath: Array(5).fill(constants.NULL_ADDRESS),
});
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
const transfers = filterLogsToArguments<ConvertByPathArgs>(logs, ContractEvents.ConvertByPathInput);
expect(transfers.length).to.eq(1);
expect(transfers[0].toTokenAddress).to.eq(
opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1],
'output token address',
);
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount');
expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount');
expect(transfers[0].feeRecipient).to.eq(constants.NULL_ADDRESS);
expect(transfers[0].feeAmount).to.bignumber.eq(new BigNumber(0));
});
});
});
});

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -1,19 +0,0 @@
import { env, EnvVars } from '@0x/dev-utils';
import { coverage, profiler, provider } from '@0x/contracts-test-utils';
import { providerUtils } from '@0x/utils';
before('start web3 provider', () => {
providerUtils.startProviderEngine(provider);
});
after('generate coverage report', async () => {
if (env.parseBoolean(EnvVars.SolidityCoverage)) {
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
await coverageSubprovider.writeCoverageAsync();
}
if (env.parseBoolean(EnvVars.SolidityProfiler)) {
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
await profilerSubprovider.writeProfilerOutputAsync();
}
provider.stop();
});

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,245 +0,0 @@
import {
chaiSetup,
constants,
expectTransactionFailedWithoutReasonAsync,
provider,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { AssetProxyId, RevertReason } from '@0x/types';
import { AbiEncoder, BigNumber } from '@0x/utils';
import * as chai from 'chai';
import * as ethUtil from 'ethereumjs-util';
import { artifacts } from './artifacts';
import {
IAssetDataContract,
IAssetProxyContract,
StaticCallProxyContract,
TestStaticCallTargetContract,
} from './wrappers';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('StaticCallProxy', () => {
const amount = constants.ZERO_AMOUNT;
let fromAddress: string;
let toAddress: string;
let assetDataInterface: IAssetDataContract;
let staticCallProxy: IAssetProxyContract;
let staticCallTarget: TestStaticCallTargetContract;
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
[fromAddress, toAddress] = accounts.slice(0, 2);
const staticCallProxyWithoutTransferFrom = await StaticCallProxyContract.deployFrom0xArtifactAsync(
artifacts.StaticCallProxy,
provider,
txDefaults,
artifacts,
);
assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
staticCallProxy = new IAssetProxyContract(
staticCallProxyWithoutTransferFrom.address,
provider,
txDefaults,
{},
StaticCallProxyContract.deployedBytecode,
);
staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync(
artifacts.TestStaticCallTarget,
provider,
txDefaults,
artifacts,
);
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('general', () => {
it('should revert if undefined function is called', async () => {
const undefinedSelector = '0x01020304';
await expectTransactionFailedWithoutReasonAsync(
web3Wrapper.sendTransactionAsync({
from: fromAddress,
to: staticCallProxy.address,
value: constants.ZERO_AMOUNT,
data: undefinedSelector,
}),
);
});
it('should have an id of 0xc339d10a', async () => {
const proxyId = await staticCallProxy.getProxyId().callAsync();
const expectedProxyId = AssetProxyId.StaticCall;
expect(proxyId).to.equal(expectedProxyId);
});
});
describe('transferFrom', () => {
it('should revert if assetData lies outside the bounds of calldata', async () => {
const staticCallData = staticCallTarget.noInputFunction().getABIEncodedTransactionData();
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
const txData = staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.getABIEncodedTransactionData();
const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080';
const txDataEndBuffer = ethUtil.toBuffer((txData.length - 2) / 2 - 4);
const paddedTxDataEndBuffer = ethUtil.setLengthLeft(txDataEndBuffer, 32);
const invalidOffsetToAssetData = ethUtil.bufferToHex(paddedTxDataEndBuffer).slice(2);
const newAssetData = '0000000000000000000000000000000000000000000000000000000000000304';
const badTxData = `${txData.replace(offsetToAssetData, invalidOffsetToAssetData)}${newAssetData}`;
await expectTransactionFailedWithoutReasonAsync(
web3Wrapper.sendTransactionAsync({
to: staticCallProxy.address,
from: fromAddress,
data: badTxData,
}),
);
});
it('should revert if the length of assetData is less than 100 bytes', async () => {
const staticCallData = constants.NULL_BYTES;
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData()
.slice(0, -128);
const assetDataByteLen = (assetData.length - 2) / 2;
expect((assetDataByteLen - 4) % 32).to.equal(0);
await expectTransactionFailedWithoutReasonAsync(
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(),
);
});
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 = 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);
const invalidOffsetToStaticCallData = ethUtil.bufferToHex(paddedAssetDataEndBuffer).slice(2);
const newStaticCallData = '0000000000000000000000000000000000000000000000000000000000000304';
const badAssetData = `${assetData.replace(
offsetToStaticCallData,
invalidOffsetToStaticCallData,
)}${newStaticCallData}`;
await expectTransactionFailedWithoutReasonAsync(
staticCallProxy.transferFrom(badAssetData, fromAddress, toAddress, amount).sendTransactionAsync(),
);
});
it('should revert if the callTarget attempts to write to state', async () => {
const staticCallData = staticCallTarget.updateState().getABIEncodedTransactionData();
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await expectTransactionFailedWithoutReasonAsync(
staticCallProxy.transferFrom(assetData, fromAddress, toAddress, amount).sendTransactionAsync(),
);
});
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 = 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.keccak256(trueAsBuffer));
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 = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
});
it('should be successful if the staticCallTarget is not a contract and no return value is expected', async () => {
const staticCallData = '0x0102030405060708';
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = assetDataInterface
.StaticCall(toAddress, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
});
it('should be successful if a function call with one static input returns the correct value', async () => {
const staticCallData = staticCallTarget.isOddNumber(new BigNumber(1)).getABIEncodedTransactionData();
const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
const expectedResultHash = ethUtil.bufferToHex(ethUtil.keccak256(trueAsBuffer));
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
});
it('should be successful if a function with one dynamic input is successful', async () => {
const dynamicInput = '0x0102030405060708';
const staticCallData = staticCallTarget.dynamicInputFunction(dynamicInput).getABIEncodedTransactionData();
const expectedResultHash = constants.KECCAK256_NULL;
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
});
it('should be successful if a function call returns a complex type', async () => {
const a = new BigNumber(1);
const b = new BigNumber(2);
const staticCallData = staticCallTarget.returnComplexType(a, b).getABIEncodedTransactionData();
const abiEncoder = new AbiEncoder.DynamicBytes({
name: '',
type: 'bytes',
});
const aHex = '0000000000000000000000000000000000000000000000000000000000000001';
const bHex = '0000000000000000000000000000000000000000000000000000000000000002';
const expectedResults = `${staticCallTarget.address}${aHex}${bHex}`;
const offset = '0000000000000000000000000000000000000000000000000000000000000020';
const encodedExpectedResultWithOffset = `0x${offset}${abiEncoder.encode(expectedResults).slice(2)}`;
const expectedResultHash = ethUtil.bufferToHex(
ethUtil.keccak256(ethUtil.toBuffer(encodedExpectedResultWithOffset)),
);
const assetData = assetDataInterface
.StaticCall(staticCallTarget.address, staticCallData, expectedResultHash)
.getABIEncodedTransactionData();
await staticCallProxy
.transferFrom(assetData, fromAddress, toAddress, amount)
.awaitTransactionSuccessAsync();
});
});
});

View File

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

View File

@ -1,216 +0,0 @@
import {
blockchainTests,
constants,
expect,
filterLogsToArguments,
getRandomInteger,
randomAddress,
} from '@0x/contracts-test-utils';
import { AssetProxyId } from '@0x/types';
import { AbiEncoder, BigNumber, hexUtils } from '@0x/utils';
import { DecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import {
TestUniswapV2BridgeContract,
TestUniswapV2BridgeEvents as ContractEvents,
TestUniswapV2BridgeSwapExactTokensForTokensInputEventArgs as SwapExactTokensForTokensArgs,
TestUniswapV2BridgeTokenApproveEventArgs as TokenApproveArgs,
TestUniswapV2BridgeTokenTransferEventArgs as TokenTransferArgs,
} from './wrappers';
blockchainTests.resets('UniswapV2 unit tests', env => {
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);
let testContract: TestUniswapV2BridgeContract;
before(async () => {
testContract = await TestUniswapV2BridgeContract.deployFrom0xArtifactAsync(
artifacts.TestUniswapV2Bridge,
env.provider,
env.txDefaults,
artifacts,
);
});
describe('isValidSignature()', () => {
it('returns success bytes', async () => {
const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
const result = await testContract
.isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
.callAsync();
expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
});
});
describe('bridgeTransferFrom()', () => {
interface TransferFromOpts {
tokenAddressesPath: string[];
toAddress: string;
// Amount to pass into `bridgeTransferFrom()`
amount: BigNumber;
// Token balance of the bridge.
fromTokenBalance: BigNumber;
// Router reverts with this reason
routerRevertReason: string;
}
interface TransferFromResult {
opts: TransferFromOpts;
result: string;
logs: DecodedLogs;
blocktime: number;
}
function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100));
return {
tokenAddressesPath: Array(2).fill(constants.NULL_ADDRESS),
amount,
toAddress: randomAddress(),
fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)),
routerRevertReason: '',
...opts,
};
}
const bridgeDataEncoder = AbiEncoder.create('(address[])');
async function transferFromAsync(opts?: Partial<TransferFromOpts>): Promise<TransferFromResult> {
const _opts = createTransferFromOpts(opts);
for (let i = 0; i < _opts.tokenAddressesPath.length; i++) {
const createFromTokenFn = testContract.createToken(_opts.tokenAddressesPath[i]);
_opts.tokenAddressesPath[i] = await createFromTokenFn.callAsync();
await createFromTokenFn.awaitTransactionSuccessAsync();
}
// Set the token balance for the token we're converting from.
await testContract
.setTokenBalance(_opts.tokenAddressesPath[0], _opts.fromTokenBalance)
.awaitTransactionSuccessAsync();
// Set revert reason for the router.
await testContract.setRouterRevertReason(_opts.routerRevertReason).awaitTransactionSuccessAsync();
// Call bridgeTransferFrom().
const bridgeTransferFromFn = testContract.bridgeTransferFrom(
// Output token
_opts.tokenAddressesPath[_opts.tokenAddressesPath.length - 1],
// Random maker address.
randomAddress(),
// Recipient address.
_opts.toAddress,
// Transfer amount.
_opts.amount,
// ABI-encode the input token address as the bridge data. // FIXME
bridgeDataEncoder.encode([_opts.tokenAddressesPath]),
);
const result = await bridgeTransferFromFn.callAsync();
const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
return {
opts: _opts,
result,
logs: (receipt.logs as any) as DecodedLogs,
blocktime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber),
};
}
it('returns magic bytes on success', async () => {
const { result } = await transferFromAsync();
expect(result).to.eq(AssetProxyId.ERC20Bridge);
});
it('performs transfer when both tokens are the same', async () => {
const createTokenFn = testContract.createToken(constants.NULL_ADDRESS);
const tokenAddress = await createTokenFn.callAsync();
await createTokenFn.awaitTransactionSuccessAsync();
const { opts, result, logs } = await transferFromAsync({
tokenAddressesPath: [tokenAddress, tokenAddress],
});
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
const transfers = filterLogsToArguments<TokenTransferArgs>(logs, ContractEvents.TokenTransfer);
expect(transfers.length).to.eq(1);
expect(transfers[0].token).to.eq(tokenAddress, 'input token address');
expect(transfers[0].from).to.eq(testContract.address);
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
expect(transfers[0].amount).to.bignumber.eq(opts.amount, 'amount');
});
describe('token -> token', async () => {
it('calls UniswapV2Router01.swapExactTokensForTokens()', async () => {
const { opts, result, logs, blocktime } = await transferFromAsync();
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
const transfers = filterLogsToArguments<SwapExactTokensForTokensArgs>(
logs,
ContractEvents.SwapExactTokensForTokensInput,
);
expect(transfers.length).to.eq(1);
expect(transfers[0].toTokenAddress).to.eq(
opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1],
'output token address',
);
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount');
expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount');
expect(transfers[0].deadline).to.bignumber.eq(blocktime, 'deadline');
});
it('sets allowance for "from" token', async () => {
const { logs } = await transferFromAsync();
const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
const routerAddress = await testContract.getRouterAddress().callAsync();
expect(approvals.length).to.eq(1);
expect(approvals[0].spender).to.eq(routerAddress);
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
});
it('sets allowance for "from" token on subsequent calls', async () => {
const { opts } = await transferFromAsync();
const { logs } = await transferFromAsync(opts);
const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
const routerAddress = await testContract.getRouterAddress().callAsync();
expect(approvals.length).to.eq(1);
expect(approvals[0].spender).to.eq(routerAddress);
expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
});
it('fails if the router fails', async () => {
const revertReason = 'FOOBAR';
const tx = transferFromAsync({
routerRevertReason: revertReason,
});
return expect(tx).to.eventually.be.rejectedWith(revertReason);
});
});
describe('token -> token -> token', async () => {
it('calls UniswapV2Router01.swapExactTokensForTokens()', async () => {
const { opts, result, logs, blocktime } = await transferFromAsync({
tokenAddressesPath: Array(3).fill(constants.NULL_ADDRESS),
});
expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
const transfers = filterLogsToArguments<SwapExactTokensForTokensArgs>(
logs,
ContractEvents.SwapExactTokensForTokensInput,
);
expect(transfers.length).to.eq(1);
expect(transfers[0].toTokenAddress).to.eq(
opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1],
'output token address',
);
expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount');
expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount');
expect(transfers[0].deadline).to.bignumber.eq(blocktime, 'deadline');
});
});
});
});

View File

@ -1,64 +0,0 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../test/generated-wrappers/balancer_bridge';
export * from '../test/generated-wrappers/bancor_bridge';
export * from '../test/generated-wrappers/chai_bridge';
export * from '../test/generated-wrappers/cream_bridge';
export * from '../test/generated-wrappers/crypto_com_bridge';
export * from '../test/generated-wrappers/curve_bridge';
export * from '../test/generated-wrappers/d_o_d_o_bridge';
export * from '../test/generated-wrappers/dex_forwarder_bridge';
export * from '../test/generated-wrappers/dydx_bridge';
export * from '../test/generated-wrappers/erc1155_proxy';
export * from '../test/generated-wrappers/erc20_bridge_proxy';
export * from '../test/generated-wrappers/erc20_proxy';
export * from '../test/generated-wrappers/erc721_proxy';
export * from '../test/generated-wrappers/eth2_dai_bridge';
export * from '../test/generated-wrappers/i_asset_data';
export * from '../test/generated-wrappers/i_asset_proxy';
export * from '../test/generated-wrappers/i_asset_proxy_dispatcher';
export * from '../test/generated-wrappers/i_authorizable';
export * from '../test/generated-wrappers/i_balancer_pool';
export * from '../test/generated-wrappers/i_bancor_network';
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_gas_token';
export * from '../test/generated-wrappers/i_kyber_network_proxy';
export * from '../test/generated-wrappers/i_m_stable';
export * from '../test/generated-wrappers/i_mooniswap';
export * from '../test/generated-wrappers/i_shell';
export * from '../test/generated-wrappers/i_uniswap_exchange';
export * from '../test/generated-wrappers/i_uniswap_exchange_factory';
export * from '../test/generated-wrappers/i_uniswap_v2_router01';
export * from '../test/generated-wrappers/kyber_bridge';
export * from '../test/generated-wrappers/m_stable_bridge';
export * from '../test/generated-wrappers/mixin_asset_proxy_dispatcher';
export * from '../test/generated-wrappers/mixin_authorizable';
export * from '../test/generated-wrappers/mixin_gas_token';
export * from '../test/generated-wrappers/mooniswap_bridge';
export * from '../test/generated-wrappers/multi_asset_proxy';
export * from '../test/generated-wrappers/ownable';
export * from '../test/generated-wrappers/shell_bridge';
export * from '../test/generated-wrappers/snow_swap_bridge';
export * from '../test/generated-wrappers/static_call_proxy';
export * from '../test/generated-wrappers/sushi_swap_bridge';
export * from '../test/generated-wrappers/swerve_bridge';
export * from '../test/generated-wrappers/test_bancor_bridge';
export * from '../test/generated-wrappers/test_chai_bridge';
export * from '../test/generated-wrappers/test_dex_forwarder_bridge';
export * from '../test/generated-wrappers/test_dydx_bridge';
export * from '../test/generated-wrappers/test_erc20_bridge';
export * from '../test/generated-wrappers/test_eth2_dai_bridge';
export * from '../test/generated-wrappers/test_kyber_bridge';
export * from '../test/generated-wrappers/test_static_call_target';
export * from '../test/generated-wrappers/test_uniswap_bridge';
export * from '../test/generated-wrappers/test_uniswap_v2_bridge';
export * from '../test/generated-wrappers/uniswap_bridge';
export * from '../test/generated-wrappers/uniswap_v2_bridge';

View File

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

View File

@ -1,126 +0,0 @@
{
"extends": "../../tsconfig",
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"generated-artifacts/BalancerBridge.json",
"generated-artifacts/BancorBridge.json",
"generated-artifacts/ChaiBridge.json",
"generated-artifacts/CreamBridge.json",
"generated-artifacts/CryptoComBridge.json",
"generated-artifacts/CurveBridge.json",
"generated-artifacts/DODOBridge.json",
"generated-artifacts/DexForwarderBridge.json",
"generated-artifacts/DydxBridge.json",
"generated-artifacts/ERC1155Proxy.json",
"generated-artifacts/ERC20BridgeProxy.json",
"generated-artifacts/ERC20Proxy.json",
"generated-artifacts/ERC721Proxy.json",
"generated-artifacts/Eth2DaiBridge.json",
"generated-artifacts/IAssetData.json",
"generated-artifacts/IAssetProxy.json",
"generated-artifacts/IAssetProxyDispatcher.json",
"generated-artifacts/IAuthorizable.json",
"generated-artifacts/IBalancerPool.json",
"generated-artifacts/IBancorNetwork.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/IGasToken.json",
"generated-artifacts/IKyberNetworkProxy.json",
"generated-artifacts/IMStable.json",
"generated-artifacts/IMooniswap.json",
"generated-artifacts/IShell.json",
"generated-artifacts/IUniswapExchange.json",
"generated-artifacts/IUniswapExchangeFactory.json",
"generated-artifacts/IUniswapV2Router01.json",
"generated-artifacts/KyberBridge.json",
"generated-artifacts/MStableBridge.json",
"generated-artifacts/MixinAssetProxyDispatcher.json",
"generated-artifacts/MixinAuthorizable.json",
"generated-artifacts/MixinGasToken.json",
"generated-artifacts/MooniswapBridge.json",
"generated-artifacts/MultiAssetProxy.json",
"generated-artifacts/Ownable.json",
"generated-artifacts/ShellBridge.json",
"generated-artifacts/SnowSwapBridge.json",
"generated-artifacts/StaticCallProxy.json",
"generated-artifacts/SushiSwapBridge.json",
"generated-artifacts/SwerveBridge.json",
"generated-artifacts/TestBancorBridge.json",
"generated-artifacts/TestChaiBridge.json",
"generated-artifacts/TestDexForwarderBridge.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/TestUniswapV2Bridge.json",
"generated-artifacts/UniswapBridge.json",
"generated-artifacts/UniswapV2Bridge.json",
"test/generated-artifacts/BalancerBridge.json",
"test/generated-artifacts/BancorBridge.json",
"test/generated-artifacts/ChaiBridge.json",
"test/generated-artifacts/CreamBridge.json",
"test/generated-artifacts/CryptoComBridge.json",
"test/generated-artifacts/CurveBridge.json",
"test/generated-artifacts/DODOBridge.json",
"test/generated-artifacts/DexForwarderBridge.json",
"test/generated-artifacts/DydxBridge.json",
"test/generated-artifacts/ERC1155Proxy.json",
"test/generated-artifacts/ERC20BridgeProxy.json",
"test/generated-artifacts/ERC20Proxy.json",
"test/generated-artifacts/ERC721Proxy.json",
"test/generated-artifacts/Eth2DaiBridge.json",
"test/generated-artifacts/IAssetData.json",
"test/generated-artifacts/IAssetProxy.json",
"test/generated-artifacts/IAssetProxyDispatcher.json",
"test/generated-artifacts/IAuthorizable.json",
"test/generated-artifacts/IBalancerPool.json",
"test/generated-artifacts/IBancorNetwork.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/IGasToken.json",
"test/generated-artifacts/IKyberNetworkProxy.json",
"test/generated-artifacts/IMStable.json",
"test/generated-artifacts/IMooniswap.json",
"test/generated-artifacts/IShell.json",
"test/generated-artifacts/IUniswapExchange.json",
"test/generated-artifacts/IUniswapExchangeFactory.json",
"test/generated-artifacts/IUniswapV2Router01.json",
"test/generated-artifacts/KyberBridge.json",
"test/generated-artifacts/MStableBridge.json",
"test/generated-artifacts/MixinAssetProxyDispatcher.json",
"test/generated-artifacts/MixinAuthorizable.json",
"test/generated-artifacts/MixinGasToken.json",
"test/generated-artifacts/MooniswapBridge.json",
"test/generated-artifacts/MultiAssetProxy.json",
"test/generated-artifacts/Ownable.json",
"test/generated-artifacts/ShellBridge.json",
"test/generated-artifacts/SnowSwapBridge.json",
"test/generated-artifacts/StaticCallProxy.json",
"test/generated-artifacts/SushiSwapBridge.json",
"test/generated-artifacts/SwerveBridge.json",
"test/generated-artifacts/TestBancorBridge.json",
"test/generated-artifacts/TestChaiBridge.json",
"test/generated-artifacts/TestDexForwarderBridge.json",
"test/generated-artifacts/TestDydxBridge.json",
"test/generated-artifacts/TestERC20Bridge.json",
"test/generated-artifacts/TestEth2DaiBridge.json",
"test/generated-artifacts/TestKyberBridge.json",
"test/generated-artifacts/TestStaticCallTarget.json",
"test/generated-artifacts/TestUniswapBridge.json",
"test/generated-artifacts/TestUniswapV2Bridge.json",
"test/generated-artifacts/UniswapBridge.json",
"test/generated-artifacts/UniswapV2Bridge.json"
],
"exclude": ["./deploy/solc/solc_bin"]
}

View File

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

View File

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

View File

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

View File

@ -1,373 +0,0 @@
[
{
"timestamp": 1629079369,
"version": "1.1.37",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1628665757,
"version": "1.1.36",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1628225642,
"version": "1.1.35",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1624356181,
"version": "1.1.34",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1623382456,
"version": "1.1.33",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1622609597,
"version": "1.1.32",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1621944788,
"version": "1.1.31",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1621600614,
"version": "1.1.30",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1620214333,
"version": "1.1.29",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "1.1.28",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1617311315,
"version": "1.1.27",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1616005394,
"version": "1.1.26",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1614141718,
"version": "1.1.25",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1612950500,
"version": "1.1.24",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1611648096,
"version": "1.1.23",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1610510890,
"version": "1.1.22",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1609802516,
"version": "1.1.21",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608692071,
"version": "1.1.20",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608245516,
"version": "1.1.19",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1608105788,
"version": "1.1.18",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607485227,
"version": "1.1.17",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1607381756,
"version": "1.1.16",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1606961263,
"version": "1.1.15",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1605763885,
"version": "1.1.14",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1605302002,
"version": "1.1.13",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604385937,
"version": "1.1.12",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604376968,
"version": "1.1.11",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1604355662,
"version": "1.1.10",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1603851023,
"version": "1.1.9",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1603833198,
"version": "1.1.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1603265572,
"version": "1.1.7",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1594788383,
"version": "1.1.6",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.1.5",
"changes": [
{
"note": "Fix broken tests.",
"pr": 2591
}
],
"timestamp": 1592969527
},
{
"timestamp": 1583220306,
"version": "1.1.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"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"
}
]
}
]

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