Compare commits
132 Commits
@0x/contra
...
@0x/contra
Author | SHA1 | Date | |
---|---|---|---|
|
5921208ea6 | ||
|
f89c78abd1 | ||
|
74d3b9334c | ||
|
919fc66b9d | ||
|
400fb5a5bb | ||
|
3bb4f9085c | ||
|
714c6cec3c | ||
|
cb69921202 | ||
|
277a0adac9 | ||
|
02d14f504f | ||
|
1ab7664a60 | ||
|
1be46ffb7e | ||
|
6ca52aed0d | ||
|
74e20970e2 | ||
|
93f2b6b4d8 | ||
|
00e616b57a | ||
|
e436673304 | ||
|
ce04d3ce41 | ||
|
4e46bf4697 | ||
|
9b95508f99 | ||
|
c8c24456c1 | ||
|
80a6e82e1b | ||
|
80cec20d38 | ||
|
26cb22020d | ||
|
09d05d09c9 | ||
|
160c91f908 | ||
|
58f41bcd42 | ||
|
0235429995 | ||
|
f79697e117 | ||
|
6f0019c71e | ||
|
1a04a18245 | ||
|
0cf3ff8209 | ||
|
7f56091fbd | ||
|
391f9b31f6 | ||
|
1d7c0f504a | ||
|
9cdc62f918 | ||
|
6027d0481e | ||
|
277fb92f9e | ||
|
79b6c3c1af | ||
|
ad17174119 | ||
|
6c2692eec0 | ||
|
08640e8575 | ||
|
4a2575136f | ||
|
e792afad17 | ||
|
5ecc4b027d | ||
|
bc540f0cf0 | ||
|
a24b14c465 | ||
|
c3f36c3123 | ||
|
1d34da7557 | ||
|
27d74a4327 | ||
|
8a20cc682c | ||
|
9b20359e7b | ||
|
8866d0ccef | ||
|
7fa91a9971 | ||
|
28d1f3eef0 | ||
|
f321cf6655 | ||
|
14ade737da | ||
|
41b1b1f141 | ||
|
25dfd47d32 | ||
|
6afa9c8b92 | ||
|
2fc449da4c | ||
|
5dd3b8cf9d | ||
|
e834fa0050 | ||
|
9a97401606 | ||
|
410a3fef18 | ||
|
969b9814d5 | ||
|
2275e27b87 | ||
|
62b06cd204 | ||
|
350934ca21 | ||
|
6332673434 | ||
|
f217840998 | ||
|
089ec35ceb | ||
|
fecd0b809e | ||
|
4707a46561 | ||
|
616533c5a8 | ||
|
c5b2991821 | ||
|
c36d0fdc7c | ||
|
544e09cf4b | ||
|
c110dc9e6a | ||
|
3bf37d6afd | ||
|
b80ae5796b | ||
|
2083632299 | ||
|
3ca2f8ac9e | ||
|
7172432084 | ||
|
0e6afd147f | ||
|
46275a4f43 | ||
|
1dca378e03 | ||
|
06669594b1 | ||
|
c09ac58ac0 | ||
|
e01d32ef1a | ||
|
5ea3bcf59e | ||
|
aa8b14b7ee | ||
|
e1722cf739 | ||
|
7a7f70e15d | ||
|
b3c3ec16e5 | ||
|
149f863951 | ||
|
684d09faac | ||
|
8a42691c80 | ||
|
d591b3dd98 | ||
|
a90fb4d8b6 | ||
|
ebd08d9c63 | ||
|
71731d223b | ||
|
726ea5e01e | ||
|
16c7d2964b | ||
|
5a6e494bda | ||
|
88c6d89fbb | ||
|
de12da18da | ||
|
8d10736934 | ||
|
2328e02d82 | ||
|
87cd5fca90 | ||
|
b70cb726c5 | ||
|
295811ed5a | ||
|
4bc55551c6 | ||
|
2b8c6dc8f9 | ||
|
8b27380feb | ||
|
8de3a90851 | ||
|
f8bb94d721 | ||
|
0c6d06e7bb | ||
|
b0aa5d3af2 | ||
|
27d09713fd | ||
|
ff18852879 | ||
|
e515c91e5e | ||
|
1d5800c4f7 | ||
|
de8f190945 | ||
|
f371e3c8d3 | ||
|
b15a6290a7 | ||
|
0f151db355 | ||
|
fa99b75d1f | ||
|
4a299c1f39 | ||
|
30a2015a68 | ||
|
c7c8a4891f | ||
|
fe9fc6b459 |
@@ -193,7 +193,7 @@ jobs:
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: nikolaik/python-nodejs:python3.7-nodejs8
|
||||
- image: 0xorg/ganache-cli
|
||||
- image: 0xorg/ganache-cli:6.0.0
|
||||
- image: 0xorg/mesh:0xV3
|
||||
environment:
|
||||
ETHEREUM_RPC_URL: 'http://localhost:8545'
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"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": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## 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)
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
|
@@ -18,10 +18,22 @@
|
||||
|
||||
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 {
|
||||
|
||||
contract IChai is
|
||||
IERC20Token
|
||||
{
|
||||
/// @dev Withdraws Dai owned by `src`
|
||||
/// @param src Address that owns Dai.
|
||||
/// @param wad Amount of Dai to withdraw.
|
||||
@@ -30,4 +42,25 @@ contract IChai {
|
||||
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;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-asset-proxy",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.2",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -51,12 +51,12 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.3",
|
||||
"@0x/contracts-gen": "^2.0.3",
|
||||
"@0x/contracts-test-utils": "^5.1.0",
|
||||
"@0x/contracts-utils": "^4.0.3",
|
||||
"@0x/dev-utils": "^3.1.0",
|
||||
"@0x/sol-compiler": "^4.0.3",
|
||||
"@0x/abi-gen": "^5.1.1",
|
||||
"@0x/contracts-gen": "^2.0.5",
|
||||
"@0x/contracts-test-utils": "^5.1.2",
|
||||
"@0x/contracts-utils": "^4.2.0",
|
||||
"@0x/dev-utils": "^3.1.2",
|
||||
"@0x/sol-compiler": "^4.0.5",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
@@ -79,16 +79,16 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.3",
|
||||
"@0x/contracts-dev-utils": "^1.0.3",
|
||||
"@0x/contracts-erc1155": "^2.0.3",
|
||||
"@0x/contracts-erc20": "^3.0.3",
|
||||
"@0x/contracts-erc721": "^3.0.3",
|
||||
"@0x/contracts-exchange-libs": "^4.0.3",
|
||||
"@0x/order-utils": "^10.1.0",
|
||||
"@0x/base-contract": "^6.1.1",
|
||||
"@0x/contracts-dev-utils": "^1.0.5",
|
||||
"@0x/contracts-erc1155": "^2.0.5",
|
||||
"@0x/contracts-erc20": "^3.0.5",
|
||||
"@0x/contracts-erc721": "^3.0.5",
|
||||
"@0x/contracts-exchange-libs": "^4.1.1",
|
||||
"@0x/order-utils": "^10.1.2",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.1.2",
|
||||
"@0x/web3-wrapper": "^7.0.3",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"ethereum-types": "^3.0.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -60,7 +60,7 @@ export class ERC1155ProxyWrapper {
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._provider, this._contractOwnerAddress);
|
||||
const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._contractOwnerAddress);
|
||||
this._dummyTokenWrappers.push(erc1155Wrapper);
|
||||
}
|
||||
return this._dummyTokenWrappers;
|
||||
|
@@ -13,6 +13,9 @@ export {
|
||||
StaticCallProxyContract,
|
||||
TestStaticCallTargetContract,
|
||||
UniswapBridgeContract,
|
||||
KyberBridgeContract,
|
||||
ChaiBridgeContract,
|
||||
IChaiContract,
|
||||
} from './wrappers';
|
||||
|
||||
export { ERC20Wrapper } from './erc20_wrapper';
|
||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
evmVersion: 'istanbul',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "3.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "3.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1578272714,
|
||||
"version": "3.0.3",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.5 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.4 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.3 - _January 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -3,7 +3,7 @@
|
||||
"contractsDir": "./contracts",
|
||||
"useDockerisedSolc": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-coordinator",
|
||||
"version": "3.0.3",
|
||||
"version": "3.0.5",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,19 +52,19 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.3",
|
||||
"@0x/contracts-asset-proxy": "^3.1.0",
|
||||
"@0x/contracts-dev-utils": "^1.0.3",
|
||||
"@0x/contracts-erc20": "^3.0.3",
|
||||
"@0x/contracts-exchange": "^3.0.3",
|
||||
"@0x/contracts-gen": "^2.0.3",
|
||||
"@0x/contracts-test-utils": "^5.1.0",
|
||||
"@0x/dev-utils": "^3.1.0",
|
||||
"@0x/order-utils": "^10.1.0",
|
||||
"@0x/sol-compiler": "^4.0.3",
|
||||
"@0x/abi-gen": "^5.1.1",
|
||||
"@0x/contracts-asset-proxy": "^3.1.2",
|
||||
"@0x/contracts-dev-utils": "^1.0.5",
|
||||
"@0x/contracts-erc20": "^3.0.5",
|
||||
"@0x/contracts-exchange": "^3.1.1",
|
||||
"@0x/contracts-gen": "^2.0.5",
|
||||
"@0x/contracts-test-utils": "^5.1.2",
|
||||
"@0x/dev-utils": "^3.1.2",
|
||||
"@0x/order-utils": "^10.1.2",
|
||||
"@0x/sol-compiler": "^4.0.5",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.3",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -84,14 +84,14 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.3",
|
||||
"@0x/base-contract": "^6.0.3",
|
||||
"@0x/contract-addresses": "^4.2.0",
|
||||
"@0x/contracts-utils": "^4.0.3",
|
||||
"@0x/json-schemas": "^5.0.3",
|
||||
"@0x/assert": "^3.0.4",
|
||||
"@0x/base-contract": "^6.1.1",
|
||||
"@0x/contract-addresses": "^4.4.0",
|
||||
"@0x/contracts-utils": "^4.2.0",
|
||||
"@0x/json-schemas": "^5.0.4",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.1.2",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"ethereum-types": "^3.0.0",
|
||||
"http-status-codes": "^1.3.2"
|
||||
},
|
||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
evmVersion: 'istanbul',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "1.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "1.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.3",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.0.5 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.4 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v1.0.3 - _January 6, 2020_
|
||||
|
||||
* Fixed ERC721 duplicate token ID bug (#2400)
|
||||
|
@@ -4,10 +4,10 @@
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 200,
|
||||
"runs": 5000,
|
||||
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
|
||||
},
|
||||
"outputSelection": {
|
||||
|
@@ -26,25 +26,33 @@ import "@0x/contracts-utils/contracts/src/LibEIP712.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "./OrderValidationUtils.sol";
|
||||
import "./OrderTransferSimulationUtils.sol";
|
||||
import "./LibTransactionDecoder.sol";
|
||||
import "./EthBalanceChecker.sol";
|
||||
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
contract DevUtils is
|
||||
OrderValidationUtils,
|
||||
LibTransactionDecoder,
|
||||
LibEIP712ExchangeDomain,
|
||||
EthBalanceChecker
|
||||
{
|
||||
constructor (address _exchange)
|
||||
constructor (
|
||||
address _exchange,
|
||||
address _chaiBridge
|
||||
)
|
||||
public
|
||||
OrderValidationUtils(_exchange)
|
||||
OrderValidationUtils(
|
||||
_exchange,
|
||||
_chaiBridge
|
||||
)
|
||||
OrderTransferSimulationUtils(_exchange)
|
||||
LibEIP712ExchangeDomain(uint256(0), address(0)) // null args because because we only use constants
|
||||
{}
|
||||
|
||||
function getOrderHash(LibOrder.Order memory order, uint256 chainId, address exchange)
|
||||
function getOrderHash(
|
||||
LibOrder.Order memory order,
|
||||
uint256 chainId,
|
||||
address exchange
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes32 orderHash)
|
||||
|
@@ -26,10 +26,14 @@ import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
|
||||
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IChai.sol";
|
||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
|
||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
|
||||
|
||||
|
||||
contract LibAssetData {
|
||||
|
||||
contract LibAssetData is
|
||||
DeploymentConstants
|
||||
{
|
||||
// 2^256 - 1
|
||||
uint256 constant internal _MAX_UINT256 = uint256(-1);
|
||||
|
||||
@@ -41,9 +45,13 @@ contract LibAssetData {
|
||||
address internal _ERC721_PROXY_ADDRESS;
|
||||
address internal _ERC1155_PROXY_ADDRESS;
|
||||
address internal _STATIC_CALL_PROXY_ADDRESS;
|
||||
address internal _CHAI_BRIDGE_ADDRESS;
|
||||
// solhint-enable var-name-mixedcase
|
||||
|
||||
constructor (address _exchange)
|
||||
constructor (
|
||||
address _exchange,
|
||||
address _chaiBridge
|
||||
)
|
||||
public
|
||||
{
|
||||
_EXCHANGE = IExchange(_exchange);
|
||||
@@ -51,6 +59,7 @@ contract LibAssetData {
|
||||
_ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC721Token.selector);
|
||||
_ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).ERC1155Assets.selector);
|
||||
_STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(IAssetData(address(0)).StaticCall.selector);
|
||||
_CHAI_BRIDGE_ADDRESS = _chaiBridge;
|
||||
}
|
||||
|
||||
/// @dev Returns the owner's balance of the assets(s) specified in
|
||||
@@ -62,7 +71,6 @@ contract LibAssetData {
|
||||
/// @return Number of assets (or asset baskets) held by owner.
|
||||
function getBalance(address ownerAddress, bytes memory assetData)
|
||||
public
|
||||
view
|
||||
returns (uint256 balance)
|
||||
{
|
||||
// Get id of AssetProxy contract
|
||||
@@ -71,16 +79,8 @@ contract LibAssetData {
|
||||
if (assetProxyId == IAssetData(address(0)).ERC20Token.selector) {
|
||||
// Get ERC20 token address
|
||||
address tokenAddress = assetData.readAddress(16);
|
||||
balance = _erc20BalanceOf(tokenAddress, ownerAddress);
|
||||
|
||||
// Encode data for `balanceOf(ownerAddress)`
|
||||
bytes memory balanceOfData = abi.encodeWithSelector(
|
||||
IERC20Token(address(0)).balanceOf.selector,
|
||||
ownerAddress
|
||||
);
|
||||
|
||||
// Query balance
|
||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
|
||||
balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
||||
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
|
||||
// Get ERC721 token address and id
|
||||
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
||||
@@ -94,12 +94,18 @@ contract LibAssetData {
|
||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
|
||||
address currentOwnerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
|
||||
balance = currentOwnerAddress == ownerAddress ? 1 : 0;
|
||||
|
||||
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
|
||||
// Get ERC1155 token address, array of ids, and array of values
|
||||
(, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData);
|
||||
|
||||
uint256 length = tokenIds.length;
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
// Skip over the token if the corresponding value is 0.
|
||||
if (tokenValues[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Encode data for `balanceOf(ownerAddress, tokenIds[i])
|
||||
bytes memory balanceOfData = abi.encodeWithSelector(
|
||||
IERC1155(address(0)).balanceOf.selector,
|
||||
@@ -113,10 +119,14 @@ contract LibAssetData {
|
||||
|
||||
// Scale total balance down by corresponding value in assetData
|
||||
uint256 scaledBalance = totalBalance / tokenValues[i];
|
||||
if (scaledBalance == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (scaledBalance < balance || balance == 0) {
|
||||
balance = scaledBalance;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
|
||||
// Encode data for `staticCallProxy.transferFrom(assetData,...)`
|
||||
bytes memory transferFromData = abi.encodeWithSelector(
|
||||
@@ -132,17 +142,36 @@ contract LibAssetData {
|
||||
|
||||
// Success means that the staticcall can be made an unlimited amount of times
|
||||
balance = success ? _MAX_UINT256 : 0;
|
||||
|
||||
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
|
||||
// Get address of ERC20 token and bridge contract
|
||||
(, address tokenAddress, address bridgeAddress,) = decodeERC20BridgeAssetData(assetData);
|
||||
if (tokenAddress == _getDaiAddress() && bridgeAddress == _CHAI_BRIDGE_ADDRESS) {
|
||||
uint256 chaiBalance = _erc20BalanceOf(_getChaiAddress(), ownerAddress);
|
||||
// Calculate Dai balance
|
||||
balance = _convertChaiToDaiAmount(chaiBalance);
|
||||
}
|
||||
// Balance will be 0 if bridge is not supported
|
||||
|
||||
} else if (assetProxyId == IAssetData(address(0)).MultiAsset.selector) {
|
||||
// Get array of values and array of assetDatas
|
||||
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
||||
|
||||
uint256 length = nestedAssetData.length;
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
// Skip over the asset if the corresponding amount is 0.
|
||||
if (assetAmounts[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Query balance of individual assetData
|
||||
uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]);
|
||||
|
||||
// Scale total balance down by corresponding value in assetData
|
||||
uint256 scaledBalance = totalBalance / assetAmounts[i];
|
||||
if (scaledBalance == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (scaledBalance < balance || balance == 0) {
|
||||
balance = scaledBalance;
|
||||
}
|
||||
@@ -160,7 +189,6 @@ contract LibAssetData {
|
||||
/// corresponding to the same-indexed element in the assetData input.
|
||||
function getBatchBalances(address ownerAddress, bytes[] memory assetData)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory balances)
|
||||
{
|
||||
uint256 length = assetData.length;
|
||||
@@ -181,7 +209,6 @@ contract LibAssetData {
|
||||
/// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
|
||||
function getAssetProxyAllowance(address ownerAddress, bytes memory assetData)
|
||||
public
|
||||
view
|
||||
returns (uint256 allowance)
|
||||
{
|
||||
// Get id of AssetProxy contract
|
||||
@@ -193,11 +220,19 @@ contract LibAssetData {
|
||||
|
||||
uint256 length = nestedAssetData.length;
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
// Skip over the asset if the corresponding amount is 0.
|
||||
if (amounts[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Query allowance of individual assetData
|
||||
uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]);
|
||||
|
||||
// Scale total allowance down by corresponding value in assetData
|
||||
uint256 scaledAllowance = totalAllowance / amounts[i];
|
||||
if (scaledAllowance == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (scaledAllowance < allowance || allowance == 0) {
|
||||
allowance = scaledAllowance;
|
||||
}
|
||||
@@ -219,6 +254,7 @@ contract LibAssetData {
|
||||
// Query allowance
|
||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData);
|
||||
allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
||||
|
||||
} else if (assetProxyId == IAssetData(address(0)).ERC721Token.selector) {
|
||||
// Get ERC721 token address and id
|
||||
(, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
|
||||
@@ -244,6 +280,7 @@ contract LibAssetData {
|
||||
// Allowance is 2^256 - 1 if `isApprovedForAll` returned true
|
||||
allowance = _MAX_UINT256;
|
||||
}
|
||||
|
||||
} else if (assetProxyId == IAssetData(address(0)).ERC1155Assets.selector) {
|
||||
// Get ERC1155 token address
|
||||
(, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
|
||||
@@ -258,9 +295,26 @@ contract LibAssetData {
|
||||
// Query allowance
|
||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
|
||||
allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
|
||||
|
||||
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
|
||||
// The StaticCallProxy does not require any approvals
|
||||
allowance = _MAX_UINT256;
|
||||
|
||||
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
|
||||
// Get address of ERC20 token and bridge contract
|
||||
(, address tokenAddress, address bridgeAddress,) = decodeERC20BridgeAssetData(assetData);
|
||||
if (tokenAddress == _getDaiAddress() && bridgeAddress == _CHAI_BRIDGE_ADDRESS) {
|
||||
bytes memory allowanceData = abi.encodeWithSelector(
|
||||
IERC20Token(address(0)).allowance.selector,
|
||||
ownerAddress,
|
||||
_CHAI_BRIDGE_ADDRESS
|
||||
);
|
||||
(bool success, bytes memory returnData) = _getChaiAddress().staticcall(allowanceData);
|
||||
uint256 chaiAllowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
||||
// Dai allowance is unlimited if Chai allowance is unlimited
|
||||
allowance = chaiAllowance == _MAX_UINT256 ? _MAX_UINT256 : _convertChaiToDaiAmount(chaiAllowance);
|
||||
}
|
||||
// Allowance will be 0 if bridge is not supported
|
||||
}
|
||||
|
||||
// Allowance will be 0 if the assetProxyId is unknown
|
||||
@@ -274,7 +328,6 @@ contract LibAssetData {
|
||||
/// element corresponding to the same-indexed element in the assetData input.
|
||||
function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory allowances)
|
||||
{
|
||||
uint256 length = assetData.length;
|
||||
@@ -292,7 +345,6 @@ contract LibAssetData {
|
||||
/// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
|
||||
function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData)
|
||||
public
|
||||
view
|
||||
returns (uint256 balance, uint256 allowance)
|
||||
{
|
||||
balance = getBalance(ownerAddress, assetData);
|
||||
@@ -308,7 +360,6 @@ contract LibAssetData {
|
||||
/// corresponding to the same-indexed element in the assetData input.
|
||||
function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
|
||||
public
|
||||
view
|
||||
returns (uint256[] memory balances, uint256[] memory allowances)
|
||||
{
|
||||
balances = getBatchBalances(ownerAddress, assetData);
|
||||
@@ -589,6 +640,35 @@ contract LibAssetData {
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Decode ERC20Bridge asset data from the format described in the AssetProxy contract specification.
|
||||
/// @param assetData AssetProxy-compliant asset data describing an ERC20Bridge asset
|
||||
/// @return The ERC20BridgeProxy identifier, the address of the ERC20 token to transfer, the address
|
||||
/// of the bridge contract, and extra data to be passed to the bridge contract.
|
||||
function decodeERC20BridgeAssetData(bytes memory assetData)
|
||||
public
|
||||
pure
|
||||
returns (
|
||||
bytes4 assetProxyId,
|
||||
address tokenAddress,
|
||||
address bridgeAddress,
|
||||
bytes memory bridgeData
|
||||
)
|
||||
{
|
||||
assetProxyId = assetData.readBytes4(0);
|
||||
|
||||
require(
|
||||
assetProxyId == IAssetData(address(0)).ERC20Bridge.selector,
|
||||
"WRONG_PROXY_ID"
|
||||
);
|
||||
|
||||
(tokenAddress, bridgeAddress, bridgeData) = abi.decode(
|
||||
assetData.slice(4, assetData.length),
|
||||
(address, address, bytes)
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Reverts if assetData is not of a valid format for its given proxy id.
|
||||
/// @param assetData AssetProxy compliant asset data.
|
||||
function revertIfInvalidAssetData(bytes memory assetData)
|
||||
public
|
||||
pure
|
||||
@@ -605,8 +685,50 @@ contract LibAssetData {
|
||||
decodeMultiAssetData(assetData);
|
||||
} else if (assetProxyId == IAssetData(address(0)).StaticCall.selector) {
|
||||
decodeStaticCallAssetData(assetData);
|
||||
} else if (assetProxyId == IAssetData(address(0)).ERC20Bridge.selector) {
|
||||
decodeERC20BridgeAssetData(assetData);
|
||||
} else {
|
||||
revert("WRONG_PROXY_ID");
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Queries balance of an ERC20 token. Returns 0 if call was unsuccessful.
|
||||
/// @param tokenAddress Address of ERC20 token.
|
||||
/// @param ownerAddress Address of owner of ERC20 token.
|
||||
/// @return balance ERC20 token balance of owner.
|
||||
function _erc20BalanceOf(
|
||||
address tokenAddress,
|
||||
address ownerAddress
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (uint256 balance)
|
||||
{
|
||||
// Encode data for `balanceOf(ownerAddress)`
|
||||
bytes memory balanceOfData = abi.encodeWithSelector(
|
||||
IERC20Token(address(0)).balanceOf.selector,
|
||||
ownerAddress
|
||||
);
|
||||
|
||||
// Query balance
|
||||
(bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
|
||||
balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
|
||||
return balance;
|
||||
}
|
||||
|
||||
/// @dev Converts an amount of Chai into its equivalent Dai amount.
|
||||
/// Also accumulates Dai from DSR if called after the last time it was collected.
|
||||
/// @param chaiAmount Amount of Chai to converts.
|
||||
function _convertChaiToDaiAmount(uint256 chaiAmount)
|
||||
internal
|
||||
returns (uint256 daiAmount)
|
||||
{
|
||||
PotLike pot = IChai(_getChaiAddress()).pot();
|
||||
// Accumulate savings if called after last time savings were collected
|
||||
uint256 chiMultiplier = (now > pot.rho())
|
||||
? pot.drip()
|
||||
: pot.chi();
|
||||
daiAmount = LibMath.getPartialAmountFloor(chiMultiplier, 10**27, chaiAmount);
|
||||
return daiAmount;
|
||||
}
|
||||
}
|
||||
|
@@ -41,6 +41,10 @@ contract OrderTransferSimulationUtils is
|
||||
TransfersSuccessful // All transfers in the order were successful
|
||||
}
|
||||
|
||||
// NOTE(jalextowle): This is a random address that we use to avoid issues that addresses like `address(1)`
|
||||
// may cause later.
|
||||
address constant internal UNUSED_ADDRESS = address(0x377f698C4c287018D09b516F415317aEC5919332);
|
||||
|
||||
// keccak256(abi.encodeWithSignature("Error(string)", "TRANSFERS_SUCCESSFUL"));
|
||||
bytes32 constant internal _TRANSFERS_SUCCESSFUL_RESULT_HASH = 0xf43f26ea5a94b478394a975e856464913dc1a8a1ca70939d974aa7c238aa0ce0;
|
||||
|
||||
@@ -82,13 +86,13 @@ contract OrderTransferSimulationUtils is
|
||||
// Transfer `makerAsset` from maker to taker
|
||||
assetData[0] = order.makerAssetData;
|
||||
fromAddresses[0] = order.makerAddress;
|
||||
toAddresses[0] = takerAddress;
|
||||
toAddresses[0] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress;
|
||||
amounts[0] = fillResults.makerAssetFilledAmount;
|
||||
|
||||
// Transfer `makerFeeAsset` from maker to feeRecipient
|
||||
assetData[1] = order.makerFeeAssetData;
|
||||
fromAddresses[1] = order.makerAddress;
|
||||
toAddresses[1] = order.feeRecipientAddress;
|
||||
toAddresses[1] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
|
||||
amounts[1] = fillResults.makerFeePaid;
|
||||
|
||||
return _simulateTransferFromCalls(
|
||||
@@ -134,19 +138,19 @@ contract OrderTransferSimulationUtils is
|
||||
// Transfer `makerAsset` from maker to taker
|
||||
assetData[1] = order.makerAssetData;
|
||||
fromAddresses[1] = order.makerAddress;
|
||||
toAddresses[1] = takerAddress;
|
||||
toAddresses[1] = takerAddress == address(0) ? UNUSED_ADDRESS : takerAddress;
|
||||
amounts[1] = fillResults.makerAssetFilledAmount;
|
||||
|
||||
// Transfer `takerFeeAsset` from taker to feeRecipient
|
||||
assetData[2] = order.takerFeeAssetData;
|
||||
fromAddresses[2] = takerAddress;
|
||||
toAddresses[2] = order.feeRecipientAddress;
|
||||
toAddresses[2] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
|
||||
amounts[2] = fillResults.takerFeePaid;
|
||||
|
||||
// Transfer `makerFeeAsset` from maker to feeRecipient
|
||||
assetData[3] = order.makerFeeAssetData;
|
||||
fromAddresses[3] = order.makerAddress;
|
||||
toAddresses[3] = order.feeRecipientAddress;
|
||||
toAddresses[3] = order.feeRecipientAddress == address(0) ? UNUSED_ADDRESS : order.feeRecipientAddress;
|
||||
amounts[3] = fillResults.makerFeePaid;
|
||||
|
||||
return _simulateTransferFromCalls(
|
||||
|
@@ -35,9 +35,15 @@ contract OrderValidationUtils is
|
||||
using LibBytes for bytes;
|
||||
using LibSafeMath for uint256;
|
||||
|
||||
constructor (address _exchange)
|
||||
constructor (
|
||||
address _exchange,
|
||||
address _chaiBridge
|
||||
)
|
||||
public
|
||||
LibAssetData(_exchange)
|
||||
LibAssetData(
|
||||
_exchange,
|
||||
_chaiBridge
|
||||
)
|
||||
{}
|
||||
|
||||
/// @dev Fetches all order-relevant information needed to validate if the supplied order is fillable.
|
||||
@@ -127,6 +133,18 @@ contract OrderValidationUtils is
|
||||
fillableTakerAssetAmount
|
||||
) == OrderTransferResults.TransfersSuccessful ? fillableTakerAssetAmount : 0;
|
||||
|
||||
if (!_isAssetDataValid(order.takerAssetData)) {
|
||||
fillableTakerAssetAmount = 0;
|
||||
}
|
||||
|
||||
if (order.takerFee != 0 && !_isAssetDataValid(order.takerFeeAssetData)) {
|
||||
fillableTakerAssetAmount = 0;
|
||||
}
|
||||
|
||||
if (orderInfo.orderStatus != LibOrder.OrderStatus.FILLABLE) {
|
||||
fillableTakerAssetAmount = 0;
|
||||
}
|
||||
|
||||
return (orderInfo, fillableTakerAssetAmount, isValidSignature);
|
||||
}
|
||||
|
||||
@@ -173,11 +191,69 @@ contract OrderValidationUtils is
|
||||
/// the individual asset amounts located within the `assetData`.
|
||||
function getTransferableAssetAmount(address ownerAddress, bytes memory assetData)
|
||||
public
|
||||
view
|
||||
returns (uint256 transferableAssetAmount)
|
||||
{
|
||||
(uint256 balance, uint256 allowance) = getBalanceAndAssetProxyAllowance(ownerAddress, assetData);
|
||||
transferableAssetAmount = LibSafeMath.min256(balance, allowance);
|
||||
return transferableAssetAmount;
|
||||
}
|
||||
|
||||
/// @dev This function handles the edge cases around taker validation. This function
|
||||
/// currently attempts to find duplicate ERC721 token's in the taker
|
||||
/// multiAssetData.
|
||||
/// @param assetData The asset data that should be validated.
|
||||
/// @return Whether or not the order should be considered valid.
|
||||
function _isAssetDataValid(bytes memory assetData)
|
||||
internal
|
||||
pure
|
||||
returns (bool)
|
||||
{
|
||||
// Asset data must be composed of an asset proxy Id and a bytes segment with
|
||||
// a length divisible by 32.
|
||||
if (assetData.length % 32 != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only process the taker asset data if it is multiAssetData.
|
||||
bytes4 assetProxyId = assetData.readBytes4(0);
|
||||
if (assetProxyId != IAssetData(address(0)).MultiAsset.selector) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get array of values and array of assetDatas
|
||||
(, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
|
||||
|
||||
uint256 length = nestedAssetData.length;
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
// TODO(jalextowle): Implement similar validation for non-fungible ERC1155 asset data.
|
||||
bytes4 nestedAssetProxyId = nestedAssetData[i].readBytes4(0);
|
||||
if (nestedAssetProxyId == IAssetData(address(0)).ERC721Token.selector) {
|
||||
if (_isAssetDataDuplicated(nestedAssetData, i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Determines whether or not asset data is duplicated later in the nested asset data.
|
||||
/// @param nestedAssetData The asset data to scan for duplication.
|
||||
/// @param startIdx The index where the scan should begin.
|
||||
/// @return A boolean reflecting whether or not the starting asset data was duplicated.
|
||||
function _isAssetDataDuplicated(
|
||||
bytes[] memory nestedAssetData,
|
||||
uint256 startIdx
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (bool)
|
||||
{
|
||||
uint256 length = nestedAssetData.length;
|
||||
for (uint256 i = startIdx + 1; i < length; i++) {
|
||||
if (nestedAssetData[startIdx].equals(nestedAssetData[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-dev-utils",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.5",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -41,10 +41,10 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.3",
|
||||
"@0x/assert": "^3.0.3",
|
||||
"@0x/contracts-gen": "^2.0.3",
|
||||
"@0x/sol-compiler": "^4.0.3",
|
||||
"@0x/abi-gen": "^5.1.1",
|
||||
"@0x/assert": "^3.0.4",
|
||||
"@0x/contracts-gen": "^2.0.5",
|
||||
"@0x/sol-compiler": "^4.0.5",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@types/node": "*",
|
||||
@@ -59,7 +59,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.3"
|
||||
"@0x/base-contract": "^6.1.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
evmVersion: 'istanbul',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "2.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "2.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1578272714,
|
||||
"version": "2.0.3",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.0.5 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.4 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.0.3 - _January 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
|
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibAddress.sol";
|
||||
|
@@ -1,4 +1,23 @@
|
||||
/*
|
||||
|
||||
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/LibSafeMath.sol";
|
||||
import "./ERC1155.sol";
|
||||
|
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
contract MixinNonFungibleToken {
|
||||
@@ -64,7 +65,7 @@ contract MixinNonFungibleToken {
|
||||
// A base type has the NF bit but does has an index.
|
||||
return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK != 0);
|
||||
}
|
||||
|
||||
|
||||
/// @dev returns owner of a non-fungible token
|
||||
function ownerOf(uint256 id) public view returns (address) {
|
||||
return nfOwners[id];
|
||||
|
@@ -17,13 +17,14 @@
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
/// @title ERC-1155 Multi Token Standard
|
||||
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
|
||||
/// Note: The ERC-165 identifier for this interface is 0xd9b67a26.
|
||||
interface IERC1155 {
|
||||
|
||||
|
||||
/// @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred,
|
||||
/// including zero value transfers as well as minting or burning.
|
||||
/// Operator will always be msg.sender.
|
||||
|
@@ -1,4 +1,23 @@
|
||||
/*
|
||||
|
||||
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 "./IERC1155.sol";
|
||||
|
||||
|
@@ -17,10 +17,11 @@
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
interface IERC1155Receiver {
|
||||
|
||||
|
||||
/// @notice Handle the receipt of a single ERC1155 token type
|
||||
/// @dev The smart contract calls this function on the recipient
|
||||
/// after a `safeTransferFrom`. This function MAY throw to revert and reject the
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc1155",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.5",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,11 +52,11 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.3",
|
||||
"@0x/contracts-gen": "^2.0.3",
|
||||
"@0x/contracts-utils": "^4.0.3",
|
||||
"@0x/dev-utils": "^3.1.0",
|
||||
"@0x/sol-compiler": "^4.0.3",
|
||||
"@0x/abi-gen": "^5.1.1",
|
||||
"@0x/contracts-gen": "^2.0.5",
|
||||
"@0x/contracts-utils": "^4.2.0",
|
||||
"@0x/dev-utils": "^3.1.2",
|
||||
"@0x/sol-compiler": "^4.0.5",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
@@ -80,10 +80,10 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.3",
|
||||
"@0x/contracts-test-utils": "^5.1.0",
|
||||
"@0x/utils": "^5.1.2",
|
||||
"@0x/web3-wrapper": "^7.0.3",
|
||||
"@0x/base-contract": "^6.1.1",
|
||||
"@0x/contracts-test-utils": "^5.1.2",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { LogWithDecodedArgs, Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import { LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { ERC1155MintableContract, ERC1155TransferSingleEventArgs } from './wrappers';
|
||||
@@ -8,7 +8,7 @@ export class Erc1155Wrapper {
|
||||
private readonly _erc1155Contract: ERC1155MintableContract;
|
||||
private readonly _contractOwner: string;
|
||||
|
||||
constructor(contractInstance: ERC1155MintableContract, provider: Provider, contractOwner: string) {
|
||||
constructor(contractInstance: ERC1155MintableContract, contractOwner: string) {
|
||||
this._erc1155Contract = contractInstance;
|
||||
this._contractOwner = contractOwner;
|
||||
}
|
||||
|
@@ -5,21 +5,18 @@ export {
|
||||
IERC1155ReceiverContract,
|
||||
DummyERC1155ReceiverBatchTokenReceivedEventArgs,
|
||||
ERC1155TransferSingleEventArgs,
|
||||
ERC1155TransferBatchEventArgs,
|
||||
ERC1155Events,
|
||||
} from './wrappers';
|
||||
export { artifacts } from './artifacts';
|
||||
export { Erc1155Wrapper } from './erc1155_wrapper';
|
||||
export {
|
||||
Provider,
|
||||
TransactionReceiptWithDecodedLogs,
|
||||
JSONRPCRequestPayload,
|
||||
JSONRPCResponsePayload,
|
||||
JSONRPCResponseError,
|
||||
JSONRPCErrorCallback,
|
||||
TransactionReceiptStatus,
|
||||
ContractArtifact,
|
||||
ContractChains,
|
||||
CompilerOpts,
|
||||
StandardContractOutput,
|
||||
ContractArtifact,
|
||||
CompilerSettings,
|
||||
ContractChainData,
|
||||
ContractAbi,
|
||||
|
@@ -67,7 +67,7 @@ describe('ERC1155Token', () => {
|
||||
);
|
||||
receiver = erc1155Receiver.address;
|
||||
// create wrapper & mint erc1155 tokens
|
||||
erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, provider, owner);
|
||||
erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, owner);
|
||||
fungibleToken = await erc1155Wrapper.mintFungibleTokensAsync([spender], spenderInitialFungibleBalance);
|
||||
let nonFungibleTokens: BigNumber[];
|
||||
[, nonFungibleTokens] = await erc1155Wrapper.mintNonFungibleTokensAsync([spender]);
|
||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
evmVersion: 'istanbul',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
|
@@ -1,4 +1,28 @@
|
||||
[
|
||||
{
|
||||
"version": "1.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Make source IDs static on all networks, not inherited from `DeploymentConstants`.",
|
||||
"pr": 2459
|
||||
}
|
||||
],
|
||||
"timestamp": 1580811564
|
||||
},
|
||||
{
|
||||
"version": "1.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add batch functions to query quotes",
|
||||
"pr": 2427
|
||||
},
|
||||
{
|
||||
"note": "Early exit if a DEX sample fails",
|
||||
"pr": 2427
|
||||
}
|
||||
],
|
||||
"timestamp": 1579682890
|
||||
},
|
||||
{
|
||||
"version": "1.0.3",
|
||||
"changes": [
|
||||
|
@@ -5,6 +5,15 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v1.2.0 - _February 4, 2020_
|
||||
|
||||
* Make source IDs static on all networks, not inherited from `DeploymentConstants`. (#2459)
|
||||
|
||||
## v1.1.0 - _January 22, 2020_
|
||||
|
||||
* Add batch functions to query quotes (#2427)
|
||||
* Early exit if a DEX sample fails (#2427)
|
||||
|
||||
## v1.0.3 - _January 6, 2020_
|
||||
|
||||
* Add gas limits to external quote calls. (#2405)
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
|
@@ -37,9 +37,76 @@ contract ERC20BridgeSampler is
|
||||
DeploymentConstants
|
||||
{
|
||||
bytes4 constant internal ERC20_PROXY_ID = 0xf47261b0; // bytes4(keccak256("ERC20Token(address)"));
|
||||
uint256 constant internal KYBER_SAMPLE_CALL_GAS = 600e3;
|
||||
uint256 constant internal KYBER_SAMPLE_CALL_GAS = 1500e3;
|
||||
uint256 constant internal UNISWAP_SAMPLE_CALL_GAS = 150e3;
|
||||
uint256 constant internal ETH2DAI_SAMPLE_CALL_GAS = 250e3;
|
||||
uint256 constant internal ETH2DAI_SAMPLE_CALL_GAS = 1000e3;
|
||||
address constant private UNISWAP_SOURCE = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95;
|
||||
address constant private ETH2DAI_SOURCE = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e;
|
||||
address constant private KYBER_SOURCE = 0x818E6FECD516Ecc3849DAf6845e3EC868087B755;
|
||||
|
||||
/// @dev Query batches of native orders and sample sell quotes on multiple DEXes at once.
|
||||
/// @param orders Batches of Native orders to query.
|
||||
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param takerTokenAmounts Batches of Taker token sell amount for each sample.
|
||||
/// @return ordersAndSamples How much taker asset can be filled
|
||||
/// by each order in `orders`. Maker amounts bought for each source at
|
||||
/// each taker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryBatchOrdersAndSampleSells(
|
||||
LibOrder.Order[][] memory orders,
|
||||
bytes[][] memory orderSignatures,
|
||||
address[] memory sources,
|
||||
uint256[][] memory takerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (
|
||||
OrdersAndSample[] memory ordersAndSamples
|
||||
)
|
||||
{
|
||||
ordersAndSamples = new OrdersAndSample[](orders.length);
|
||||
for (uint256 i = 0; i != orders.length; i++) {
|
||||
(
|
||||
uint256[] memory orderFillableAssetAmounts,
|
||||
uint256[][] memory tokenAmountsBySource
|
||||
) = queryOrdersAndSampleSells(orders[i], orderSignatures[i], sources, takerTokenAmounts[i]);
|
||||
ordersAndSamples[i].orderFillableAssetAmounts = orderFillableAssetAmounts;
|
||||
ordersAndSamples[i].tokenAmountsBySource = tokenAmountsBySource;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Query batches of native orders and sample buy quotes on multiple DEXes at once.
|
||||
/// @param orders Batches of Native orders to query.
|
||||
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param makerTokenAmounts Batches of Maker token sell amount for each sample.
|
||||
/// @return ordersAndSamples How much taker asset can be filled
|
||||
/// by each order in `orders`. Taker amounts sold for each source at
|
||||
/// each maker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryBatchOrdersAndSampleBuys(
|
||||
LibOrder.Order[][] memory orders,
|
||||
bytes[][] memory orderSignatures,
|
||||
address[] memory sources,
|
||||
uint256[][] memory makerTokenAmounts
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (
|
||||
OrdersAndSample[] memory ordersAndSamples
|
||||
)
|
||||
{
|
||||
ordersAndSamples = new OrdersAndSample[](orders.length);
|
||||
for (uint256 i = 0; i != orders.length; i++) {
|
||||
(
|
||||
uint256[] memory orderFillableAssetAmounts,
|
||||
uint256[][] memory tokenAmountsBySource
|
||||
) = queryOrdersAndSampleBuys(orders[i], orderSignatures[i], sources, makerTokenAmounts[i]);
|
||||
ordersAndSamples[i].orderFillableAssetAmounts = orderFillableAssetAmounts;
|
||||
ordersAndSamples[i].tokenAmountsBySource = tokenAmountsBySource;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Query native orders and sample sell quotes on multiple DEXes at once.
|
||||
/// @param orders Native orders to query.
|
||||
@@ -281,6 +348,8 @@ contract ERC20BridgeSampler is
|
||||
uint256 rate = 0;
|
||||
if (didSucceed) {
|
||||
rate = abi.decode(resultData, (uint256));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] =
|
||||
rate *
|
||||
@@ -321,6 +390,8 @@ contract ERC20BridgeSampler is
|
||||
uint256 buyAmount = 0;
|
||||
if (didSucceed) {
|
||||
buyAmount = abi.decode(resultData, (uint256));
|
||||
} else{
|
||||
break;
|
||||
}
|
||||
makerTokenAmounts[i] = buyAmount;
|
||||
}
|
||||
@@ -356,6 +427,8 @@ contract ERC20BridgeSampler is
|
||||
uint256 sellAmount = 0;
|
||||
if (didSucceed) {
|
||||
sellAmount = abi.decode(resultData, (uint256));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
takerTokenAmounts[i] = sellAmount;
|
||||
}
|
||||
@@ -384,26 +457,28 @@ contract ERC20BridgeSampler is
|
||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
bool didSucceed = true;
|
||||
if (makerToken == _getWethAddress()) {
|
||||
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
||||
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthInputPrice.selector,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
} else if (takerToken == _getWethAddress()) {
|
||||
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
||||
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenInputPrice.selector,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
} else {
|
||||
uint256 ethBought = _callUniswapExchangePriceFunction(
|
||||
uint256 ethBought;
|
||||
(ethBought, didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthInputPrice.selector,
|
||||
takerTokenAmounts[i]
|
||||
);
|
||||
if (ethBought != 0) {
|
||||
makerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
||||
(makerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenInputPrice.selector,
|
||||
ethBought
|
||||
@@ -412,6 +487,9 @@ contract ERC20BridgeSampler is
|
||||
makerTokenAmounts[i] = 0;
|
||||
}
|
||||
}
|
||||
if (!didSucceed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,26 +516,28 @@ contract ERC20BridgeSampler is
|
||||
IUniswapExchangeQuotes makerTokenExchange = makerToken == _getWethAddress() ?
|
||||
IUniswapExchangeQuotes(0) : _getUniswapExchange(makerToken);
|
||||
for (uint256 i = 0; i < numSamples; i++) {
|
||||
bool didSucceed = true;
|
||||
if (makerToken == _getWethAddress()) {
|
||||
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
||||
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthOutputPrice.selector,
|
||||
makerTokenAmounts[i]
|
||||
);
|
||||
} else if (takerToken == _getWethAddress()) {
|
||||
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
||||
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenOutputPrice.selector,
|
||||
makerTokenAmounts[i]
|
||||
);
|
||||
} else {
|
||||
uint256 ethSold = _callUniswapExchangePriceFunction(
|
||||
uint256 ethSold;
|
||||
(ethSold, didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(makerTokenExchange),
|
||||
makerTokenExchange.getEthToTokenOutputPrice.selector,
|
||||
makerTokenAmounts[i]
|
||||
);
|
||||
if (ethSold != 0) {
|
||||
takerTokenAmounts[i] = _callUniswapExchangePriceFunction(
|
||||
(takerTokenAmounts[i], didSucceed) = _callUniswapExchangePriceFunction(
|
||||
address(takerTokenExchange),
|
||||
takerTokenExchange.getTokenToEthOutputPrice.selector,
|
||||
ethSold
|
||||
@@ -466,6 +546,9 @@ contract ERC20BridgeSampler is
|
||||
takerTokenAmounts[i] = 0;
|
||||
}
|
||||
}
|
||||
if (!didSucceed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,12 +576,13 @@ contract ERC20BridgeSampler is
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256 outputAmount)
|
||||
returns (uint256 outputAmount, bool didSucceed)
|
||||
{
|
||||
if (uniswapExchangeAddress == address(0)) {
|
||||
return 0;
|
||||
return (outputAmount, didSucceed);
|
||||
}
|
||||
(bool didSucceed, bytes memory resultData) =
|
||||
bytes memory resultData;
|
||||
(didSucceed, resultData) =
|
||||
uniswapExchangeAddress.staticcall.gas(UNISWAP_SAMPLE_CALL_GAS)(
|
||||
abi.encodeWithSelector(
|
||||
functionSelector,
|
||||
@@ -525,13 +609,13 @@ contract ERC20BridgeSampler is
|
||||
view
|
||||
returns (uint256[] memory makerTokenAmounts)
|
||||
{
|
||||
if (source == _getEth2DaiAddress()) {
|
||||
if (source == ETH2DAI_SOURCE) {
|
||||
return sampleSellsFromEth2Dai(takerToken, makerToken, takerTokenAmounts);
|
||||
}
|
||||
if (source == _getUniswapExchangeFactoryAddress()) {
|
||||
if (source == UNISWAP_SOURCE) {
|
||||
return sampleSellsFromUniswap(takerToken, makerToken, takerTokenAmounts);
|
||||
}
|
||||
if (source == _getKyberNetworkProxyAddress()) {
|
||||
if (source == KYBER_SOURCE) {
|
||||
return sampleSellsFromKyberNetwork(takerToken, makerToken, takerTokenAmounts);
|
||||
}
|
||||
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
|
||||
@@ -553,10 +637,10 @@ contract ERC20BridgeSampler is
|
||||
view
|
||||
returns (uint256[] memory takerTokenAmounts)
|
||||
{
|
||||
if (source == _getEth2DaiAddress()) {
|
||||
if (source == ETH2DAI_SOURCE) {
|
||||
return sampleBuysFromEth2Dai(takerToken, makerToken, makerTokenAmounts);
|
||||
}
|
||||
if (source == _getUniswapExchangeFactoryAddress()) {
|
||||
if (source == UNISWAP_SOURCE) {
|
||||
return sampleBuysFromUniswap(takerToken, makerToken, makerTokenAmounts);
|
||||
}
|
||||
revert("ERC20BridgeSampler/UNSUPPORTED_SOURCE");
|
||||
|
@@ -23,6 +23,52 @@ import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
|
||||
|
||||
|
||||
interface IERC20BridgeSampler {
|
||||
struct OrdersAndSample {
|
||||
uint256[] orderFillableAssetAmounts;
|
||||
uint256[][] tokenAmountsBySource;
|
||||
}
|
||||
|
||||
/// @dev Query batches of native orders and sample sell quotes on multiple DEXes at once.
|
||||
/// @param orders Batches of Native orders to query.
|
||||
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param takerTokenAmounts Batches of Taker token sell amount for each sample.
|
||||
/// @return ordersAndSamples How much taker asset can be filled
|
||||
/// by each order in `orders`. Maker amounts bought for each source at
|
||||
/// each taker token amount. First indexed by source index, then sample
|
||||
/// index.
|
||||
function queryBatchOrdersAndSampleSells(
|
||||
LibOrder.Order[][] calldata orders,
|
||||
bytes[][] calldata orderSignatures,
|
||||
address[] calldata sources,
|
||||
uint256[][] calldata takerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
OrdersAndSample[] memory ordersAndSamples
|
||||
);
|
||||
|
||||
/// @dev Query batches of native orders and sample buy quotes on multiple DEXes at once.
|
||||
/// @param orders Batches of Native orders to query.
|
||||
/// @param orderSignatures Batches of Signatures for each respective order in `orders`.
|
||||
/// @param sources Address of each DEX. Passing in an unsupported DEX will throw.
|
||||
/// @param makerTokenAmounts Batches of Maker token sell amount for each sample.
|
||||
/// @return ordersAndSamples How much taker asset can be filled
|
||||
/// by each order in `orders`. Taker amounts sold for each source at
|
||||
/// each maker token amount. First indexed by source index, then sample
|
||||
/// index
|
||||
function queryBatchOrdersAndSampleBuys(
|
||||
LibOrder.Order[][] calldata orders,
|
||||
bytes[][] calldata orderSignatures,
|
||||
address[] calldata sources,
|
||||
uint256[][] calldata makerTokenAmounts
|
||||
)
|
||||
external
|
||||
view
|
||||
returns (
|
||||
OrdersAndSample[] memory ordersAndSamples
|
||||
);
|
||||
|
||||
/// @dev Query native orders and sample sell quotes on multiple DEXes at once.
|
||||
/// @param orders Native orders to query.
|
||||
|
@@ -338,7 +338,11 @@ contract TestERC20BridgeSampler is
|
||||
bytes32 orderHash = keccak256(abi.encode(order.salt));
|
||||
// Everything else is derived from the hash.
|
||||
orderInfo.orderHash = orderHash;
|
||||
orderInfo.orderStatus = LibOrder.OrderStatus(uint256(orderHash) % MAX_ORDER_STATUS);
|
||||
if (uint256(orderHash) % 100 > 90) {
|
||||
orderInfo.orderStatus = LibOrder.OrderStatus.FULLY_FILLED;
|
||||
} else {
|
||||
orderInfo.orderStatus = LibOrder.OrderStatus.FILLABLE;
|
||||
}
|
||||
orderInfo.orderTakerAssetFilledAmount = uint256(orderHash) % order.takerAssetAmount;
|
||||
fillableTakerAssetAmount =
|
||||
order.takerAssetAmount - orderInfo.orderTakerAssetFilledAmount;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20-bridge-sampler",
|
||||
"version": "1.0.3",
|
||||
"version": "1.2.0",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -50,18 +50,18 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.3",
|
||||
"@0x/contracts-asset-proxy": "^3.1.0",
|
||||
"@0x/contracts-erc20": "^3.0.3",
|
||||
"@0x/contracts-exchange": "^3.0.3",
|
||||
"@0x/contracts-exchange-libs": "^4.0.3",
|
||||
"@0x/contracts-gen": "^2.0.3",
|
||||
"@0x/contracts-test-utils": "^5.1.0",
|
||||
"@0x/contracts-utils": "^4.0.3",
|
||||
"@0x/dev-utils": "^3.1.0",
|
||||
"@0x/sol-compiler": "^4.0.3",
|
||||
"@0x/abi-gen": "^5.1.1",
|
||||
"@0x/contracts-asset-proxy": "^3.1.2",
|
||||
"@0x/contracts-erc20": "^3.0.5",
|
||||
"@0x/contracts-exchange": "^3.1.1",
|
||||
"@0x/contracts-exchange-libs": "^4.1.1",
|
||||
"@0x/contracts-gen": "^2.0.5",
|
||||
"@0x/contracts-test-utils": "^5.1.2",
|
||||
"@0x/contracts-utils": "^4.2.0",
|
||||
"@0x/dev-utils": "^3.1.2",
|
||||
"@0x/sol-compiler": "^4.0.5",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.3",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -79,10 +79,10 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.3",
|
||||
"@0x/base-contract": "^6.1.1",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.1.2",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"ethereum-types": "^3.0.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -15,7 +15,6 @@ import { TestERC20BridgeSamplerContract } from './wrappers';
|
||||
|
||||
blockchainTests('erc20-bridge-sampler', env => {
|
||||
let testContract: TestERC20BridgeSamplerContract;
|
||||
let allSources: { [name: string]: string };
|
||||
const RATE_DENOMINATOR = constants.ONE_ETHER;
|
||||
const MIN_RATE = new BigNumber('0.01');
|
||||
const MAX_RATE = new BigNumber('100');
|
||||
@@ -30,6 +29,11 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const INVALID_ASSET_DATA = hexUtils.random(37);
|
||||
const SELL_SOURCES = ['Eth2Dai', 'Kyber', 'Uniswap'];
|
||||
const BUY_SOURCES = ['Eth2Dai', 'Uniswap'];
|
||||
const SOURCE_IDS: { [source: string]: string } = {
|
||||
Uniswap: '0xc0a47dfe034b400b47bdad5fecda2621de6c4d95',
|
||||
Eth2Dai: '0x39755357759ce0d7f32dc8dc45414cca409ae24e',
|
||||
Kyber: '0x818e6fecd516ecc3849daf6845e3ec868087b755',
|
||||
};
|
||||
const EMPTY_ORDERS_ERROR = 'ERC20BridgeSampler/EMPTY_ORDERS';
|
||||
const UNSUPPORTED_ASSET_PROXY_ERROR = 'ERC20BridgeSampler/UNSUPPORTED_ASSET_PROXY';
|
||||
const INVALID_ASSET_DATA_ERROR = 'ERC20BridgeSampler/INVALID_ASSET_DATA';
|
||||
@@ -45,14 +49,6 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
env.txDefaults,
|
||||
{},
|
||||
);
|
||||
allSources = _.zipObject(
|
||||
['Uniswap', 'Eth2Dai', 'Kyber'],
|
||||
[
|
||||
await testContract.uniswap().callAsync(),
|
||||
await testContract.eth2Dai().callAsync(),
|
||||
await testContract.kyber().callAsync(),
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
function getPackedHash(...args: string[]): string {
|
||||
@@ -195,7 +191,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
|
||||
function getDeterministicFillableTakerAssetAmount(order: Order): BigNumber {
|
||||
const hash = getPackedHash(hexUtils.toHex(order.salt, 32));
|
||||
const orderStatus = new BigNumber(hash).mod(255).toNumber();
|
||||
const orderStatus = new BigNumber(hash).mod(100).toNumber() > 90 ? 5 : 3;
|
||||
const isValidSignature = !!new BigNumber(hash).mod(2).toNumber();
|
||||
if (orderStatus !== 3 || !isValidSignature) {
|
||||
return constants.ZERO_AMOUNT;
|
||||
@@ -208,7 +204,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
return order.makerAssetAmount
|
||||
.times(takerAmount)
|
||||
.div(order.takerAssetAmount)
|
||||
.integerValue(BigNumber.ROUND_DOWN);
|
||||
.integerValue(BigNumber.ROUND_UP);
|
||||
}
|
||||
|
||||
function getERC20AssetData(tokenAddress: string): string {
|
||||
@@ -255,7 +251,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
describe('getOrderFillableTakerAssetAmounts()', () => {
|
||||
it('returns the expected amount for each order', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
||||
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||
const expected = orders.map(getDeterministicFillableTakerAssetAmount);
|
||||
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq(expected);
|
||||
@@ -269,7 +265,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('returns zero for an order with zero maker asset amount', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
|
||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
||||
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
@@ -277,7 +273,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('returns zero for an order with zero taker asset amount', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
|
||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
||||
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||
const actual = await testContract.getOrderFillableTakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
@@ -293,7 +289,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
describe('getOrderFillableMakerAssetAmounts()', () => {
|
||||
it('returns the expected amount for each order', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
||||
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||
const expected = orders.map(getDeterministicFillableMakerAssetAmount);
|
||||
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq(expected);
|
||||
@@ -307,7 +303,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('returns zero for an order with zero maker asset amount', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
orders[0].makerAssetAmount = constants.ZERO_AMOUNT;
|
||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
||||
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
@@ -315,7 +311,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('returns zero for an order with zero taker asset amount', async () => {
|
||||
const orders = createOrders(MAKER_TOKEN, TAKER_TOKEN, 1);
|
||||
orders[0].takerAssetAmount = constants.ZERO_AMOUNT;
|
||||
const signatures: string[] = _.times(orders.length, hexUtils.random);
|
||||
const signatures: string[] = _.times(orders.length, i => hexUtils.random());
|
||||
const actual = await testContract.getOrderFillableMakerAssetAmounts(orders, signatures).callAsync();
|
||||
expect(actual).to.deep.eq([constants.ZERO_AMOUNT]);
|
||||
});
|
||||
@@ -330,7 +326,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
|
||||
describe('queryOrdersAndSampleSells()', () => {
|
||||
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||
const SIGNATURES: string[] = _.times(ORDERS.length, hexUtils.random);
|
||||
const SIGNATURES: string[] = _.times(ORDERS.length, i => hexUtils.random());
|
||||
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
@@ -340,7 +336,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const takerTokenAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableTakerAssetAmount);
|
||||
const [orderInfos] = await testContract
|
||||
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => allSources[n]), takerTokenAmounts)
|
||||
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => SOURCE_IDS[n]), takerTokenAmounts)
|
||||
.callAsync();
|
||||
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
|
||||
});
|
||||
@@ -349,14 +345,14 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
|
||||
const [, quotes] = await testContract
|
||||
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => allSources[n]), sampleAmounts)
|
||||
.queryOrdersAndSampleSells(ORDERS, SIGNATURES, SELL_SOURCES.map(n => SOURCE_IDS[n]), sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws if no orders are passed in', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleSells([], [], SELL_SOURCES.map(n => allSources[n]), getSampleAmounts(TAKER_TOKEN))
|
||||
.queryOrdersAndSampleSells([], [], SELL_SOURCES.map(n => SOURCE_IDS[n]), getSampleAmounts(TAKER_TOKEN))
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
|
||||
});
|
||||
@@ -366,7 +362,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
.queryOrdersAndSampleSells(
|
||||
ORDERS,
|
||||
SIGNATURES,
|
||||
[...SELL_SOURCES.map(n => allSources[n]), randomAddress()],
|
||||
[...SELL_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -381,7 +377,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => allSources[n]),
|
||||
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -396,7 +392,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => allSources[n]),
|
||||
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -411,7 +407,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
makerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => allSources[n]),
|
||||
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -426,7 +422,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
takerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
SELL_SOURCES.map(n => allSources[n]),
|
||||
SELL_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -436,7 +432,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
|
||||
describe('queryOrdersAndSampleBuys()', () => {
|
||||
const ORDERS = createOrders(MAKER_TOKEN, TAKER_TOKEN);
|
||||
const SIGNATURES: string[] = _.times(ORDERS.length, hexUtils.random);
|
||||
const SIGNATURES: string[] = _.times(ORDERS.length, i => hexUtils.random());
|
||||
|
||||
before(async () => {
|
||||
await testContract.createTokenExchanges([MAKER_TOKEN, TAKER_TOKEN]).awaitTransactionSuccessAsync();
|
||||
@@ -446,7 +442,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const takerTokenAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedFillableAmounts = ORDERS.map(getDeterministicFillableMakerAssetAmount);
|
||||
const [orderInfos] = await testContract
|
||||
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => allSources[n]), takerTokenAmounts)
|
||||
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => SOURCE_IDS[n]), takerTokenAmounts)
|
||||
.callAsync();
|
||||
expect(orderInfos).to.deep.eq(expectedFillableAmounts);
|
||||
});
|
||||
@@ -455,14 +451,14 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
|
||||
const [, quotes] = await testContract
|
||||
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => allSources[n]), sampleAmounts)
|
||||
.queryOrdersAndSampleBuys(ORDERS, SIGNATURES, BUY_SOURCES.map(n => SOURCE_IDS[n]), sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
|
||||
it('throws if no orders are passed in', async () => {
|
||||
const tx = testContract
|
||||
.queryOrdersAndSampleBuys([], [], BUY_SOURCES.map(n => allSources[n]), getSampleAmounts(MAKER_TOKEN))
|
||||
.queryOrdersAndSampleBuys([], [], BUY_SOURCES.map(n => SOURCE_IDS[n]), getSampleAmounts(MAKER_TOKEN))
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(EMPTY_ORDERS_ERROR);
|
||||
});
|
||||
@@ -472,7 +468,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
.queryOrdersAndSampleBuys(
|
||||
ORDERS,
|
||||
SIGNATURES,
|
||||
[...BUY_SOURCES.map(n => allSources[n]), randomAddress()],
|
||||
[...BUY_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -485,7 +481,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
.queryOrdersAndSampleBuys(
|
||||
ORDERS,
|
||||
SIGNATURES,
|
||||
sources.map(n => allSources[n]),
|
||||
sources.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -500,7 +496,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
makerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => allSources[n]),
|
||||
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -515,7 +511,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
takerAssetData: INVALID_ASSET_PROXY_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => allSources[n]),
|
||||
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -530,7 +526,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
makerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => allSources[n]),
|
||||
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -545,7 +541,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
takerAssetData: INVALID_ASSET_DATA,
|
||||
})),
|
||||
SIGNATURES,
|
||||
BUY_SOURCES.map(n => allSources[n]),
|
||||
BUY_SOURCES.map(n => SOURCE_IDS[n]),
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
)
|
||||
.callAsync();
|
||||
@@ -561,7 +557,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('returns empty quotes with no sample amounts', async () => {
|
||||
const emptyQuotes = _.times(SELL_SOURCES.length, () => []);
|
||||
const quotes = await testContract
|
||||
.sampleSells(SELL_SOURCES.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, [])
|
||||
.sampleSells(SELL_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, [])
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(emptyQuotes);
|
||||
});
|
||||
@@ -570,7 +566,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sampleAmounts = getSampleAmounts(TAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, SELL_SOURCES, sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleSells(SELL_SOURCES.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.sampleSells(SELL_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@@ -580,7 +576,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sources = _.sampleSize(SELL_SOURCES, 1);
|
||||
const expectedQuotes = getDeterministicSellQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleSells(sources.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.sampleSells(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@@ -588,7 +584,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with an unsupported source', async () => {
|
||||
const tx = testContract
|
||||
.sampleSells(
|
||||
[...SELL_SOURCES.map(n => allSources[n]), randomAddress()],
|
||||
[...SELL_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||
TAKER_TOKEN,
|
||||
MAKER_TOKEN,
|
||||
getSampleAmounts(TAKER_TOKEN),
|
||||
@@ -606,7 +602,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('returns empty quotes with no sample amounts', async () => {
|
||||
const emptyQuotes = _.times(BUY_SOURCES.length, () => []);
|
||||
const quotes = await testContract
|
||||
.sampleBuys(BUY_SOURCES.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, [])
|
||||
.sampleBuys(BUY_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, [])
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(emptyQuotes);
|
||||
});
|
||||
@@ -615,7 +611,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sampleAmounts = getSampleAmounts(MAKER_TOKEN);
|
||||
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, BUY_SOURCES, sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleBuys(BUY_SOURCES.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.sampleBuys(BUY_SOURCES.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@@ -625,7 +621,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
const sources = _.sampleSize(BUY_SOURCES, 1);
|
||||
const expectedQuotes = getDeterministicBuyQuotes(TAKER_TOKEN, MAKER_TOKEN, sources, sampleAmounts);
|
||||
const quotes = await testContract
|
||||
.sampleBuys(sources.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.sampleBuys(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, sampleAmounts)
|
||||
.callAsync();
|
||||
expect(quotes).to.deep.eq(expectedQuotes);
|
||||
});
|
||||
@@ -633,7 +629,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws with an unsupported source', async () => {
|
||||
const tx = testContract
|
||||
.sampleBuys(
|
||||
[...BUY_SOURCES.map(n => allSources[n]), randomAddress()],
|
||||
[...BUY_SOURCES.map(n => SOURCE_IDS[n]), randomAddress()],
|
||||
TAKER_TOKEN,
|
||||
MAKER_TOKEN,
|
||||
getSampleAmounts(MAKER_TOKEN),
|
||||
@@ -645,7 +641,7 @@ blockchainTests('erc20-bridge-sampler', env => {
|
||||
it('throws if kyber is passed in as a source', async () => {
|
||||
const sources = [...BUY_SOURCES, 'Kyber'];
|
||||
const tx = testContract
|
||||
.sampleBuys(sources.map(n => allSources[n]), TAKER_TOKEN, MAKER_TOKEN, getSampleAmounts(MAKER_TOKEN))
|
||||
.sampleBuys(sources.map(n => SOURCE_IDS[n]), TAKER_TOKEN, MAKER_TOKEN, getSampleAmounts(MAKER_TOKEN))
|
||||
.callAsync();
|
||||
return expect(tx).to.revertWith(UNSUPPORTED_SOURCE_ERROR);
|
||||
});
|
||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
evmVersion: 'istanbul',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "3.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "3.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1578272714,
|
||||
"version": "3.0.3",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.5 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.4 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.3 - _January 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
|
@@ -14,7 +14,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// solhint-disable
|
||||
pragma solidity ^0.4.18;
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract WETH9 {
|
||||
@@ -30,27 +30,27 @@ contract WETH9 {
|
||||
mapping (address => uint) public balanceOf;
|
||||
mapping (address => mapping (address => uint)) public allowance;
|
||||
|
||||
function() public payable {
|
||||
function() external payable {
|
||||
deposit();
|
||||
}
|
||||
function deposit() public payable {
|
||||
balanceOf[msg.sender] += msg.value;
|
||||
Deposit(msg.sender, msg.value);
|
||||
emit Deposit(msg.sender, msg.value);
|
||||
}
|
||||
function withdraw(uint wad) public {
|
||||
require(balanceOf[msg.sender] >= wad);
|
||||
balanceOf[msg.sender] -= wad;
|
||||
msg.sender.transfer(wad);
|
||||
Withdrawal(msg.sender, wad);
|
||||
emit Withdrawal(msg.sender, wad);
|
||||
}
|
||||
|
||||
function totalSupply() public view returns (uint) {
|
||||
return this.balance;
|
||||
return address(this).balance;
|
||||
}
|
||||
|
||||
function approve(address guy, uint wad) public returns (bool) {
|
||||
allowance[msg.sender][guy] = wad;
|
||||
Approval(msg.sender, guy, wad);
|
||||
emit Approval(msg.sender, guy, wad);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ contract WETH9 {
|
||||
balanceOf[src] -= wad;
|
||||
balanceOf[dst] += wad;
|
||||
|
||||
Transfer(src, dst, wad);
|
||||
emit Transfer(src, dst, wad);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc20",
|
||||
"version": "3.0.3",
|
||||
"version": "3.0.5",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -51,18 +51,18 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.3",
|
||||
"@0x/contracts-gen": "^2.0.3",
|
||||
"@0x/contracts-test-utils": "^5.1.0",
|
||||
"@0x/contracts-utils": "^4.0.3",
|
||||
"@0x/dev-utils": "^3.1.0",
|
||||
"@0x/sol-compiler": "^4.0.3",
|
||||
"@0x/abi-gen": "^5.1.1",
|
||||
"@0x/contracts-gen": "^2.0.5",
|
||||
"@0x/contracts-test-utils": "^5.1.2",
|
||||
"@0x/contracts-utils": "^4.2.0",
|
||||
"@0x/dev-utils": "^3.1.2",
|
||||
"@0x/sol-compiler": "^4.0.5",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.1.2",
|
||||
"@0x/web3-wrapper": "^7.0.3",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -82,7 +82,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.3"
|
||||
"@0x/base-contract": "^6.1.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "3.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "3.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1578272714,
|
||||
"version": "3.0.3",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.0.5 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.4 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.0.3 - _January 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-erc721",
|
||||
"version": "3.0.3",
|
||||
"version": "3.0.5",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,18 +52,18 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.3",
|
||||
"@0x/contracts-gen": "^2.0.3",
|
||||
"@0x/contracts-test-utils": "^5.1.0",
|
||||
"@0x/contracts-utils": "^4.0.3",
|
||||
"@0x/dev-utils": "^3.1.0",
|
||||
"@0x/sol-compiler": "^4.0.3",
|
||||
"@0x/abi-gen": "^5.1.1",
|
||||
"@0x/contracts-gen": "^2.0.5",
|
||||
"@0x/contracts-test-utils": "^5.1.2",
|
||||
"@0x/contracts-utils": "^4.2.0",
|
||||
"@0x/dev-utils": "^3.1.2",
|
||||
"@0x/sol-compiler": "^4.0.5",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.1.2",
|
||||
"@0x/web3-wrapper": "^7.0.3",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -84,7 +84,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.3"
|
||||
"@0x/base-contract": "^6.1.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
evmVersion: 'istanbul',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "4.0.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "4.0.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1578272714,
|
||||
"version": "4.0.3",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.0.5 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.4 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.0.3 - _January 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
|
@@ -21,6 +21,7 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
import "./MixinForwarderCore.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "./MixinReceiver.sol";
|
||||
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
@@ -28,16 +29,19 @@ import "./libs/LibConstants.sol";
|
||||
// MixinForwarderCore.
|
||||
contract Forwarder is
|
||||
LibConstants,
|
||||
MixinForwarderCore
|
||||
MixinForwarderCore,
|
||||
MixinReceiver
|
||||
{
|
||||
constructor (
|
||||
address _exchange,
|
||||
address _exchangeV2,
|
||||
address _weth
|
||||
)
|
||||
public
|
||||
Ownable()
|
||||
LibConstants(
|
||||
_exchange,
|
||||
_exchangeV2,
|
||||
_weth
|
||||
)
|
||||
MixinForwarderCore()
|
||||
|
@@ -22,9 +22,9 @@ import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "./libs/LibAssetDataTransfer.sol";
|
||||
import "./libs/LibForwarderRichErrors.sol";
|
||||
import "./interfaces/IAssets.sol";
|
||||
|
||||
@@ -35,6 +35,7 @@ contract MixinAssets is
|
||||
IAssets
|
||||
{
|
||||
using LibBytes for bytes;
|
||||
using LibAssetDataTransfer for bytes;
|
||||
|
||||
/// @dev Withdraws assets from this contract. It may be used by the owner to withdraw assets
|
||||
/// that were accidentally sent to this contract.
|
||||
@@ -47,7 +48,7 @@ contract MixinAssets is
|
||||
external
|
||||
onlyOwner
|
||||
{
|
||||
_transferAssetToSender(assetData, amount);
|
||||
assetData.transferOut(amount);
|
||||
}
|
||||
|
||||
/// @dev Approves the respective proxy for a given asset to transfer tokens on the Forwarder contract's behalf.
|
||||
@@ -72,69 +73,4 @@ contract MixinAssets is
|
||||
LibERC20Token.approve(token, proxyAddress, MAX_UINT);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Transfers given amount of asset to sender.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to transfer to sender.
|
||||
function _transferAssetToSender(
|
||||
bytes memory assetData,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes4 proxyId = assetData.readBytes4(0);
|
||||
|
||||
if (
|
||||
proxyId == IAssetData(address(0)).ERC20Token.selector ||
|
||||
proxyId == IAssetData(address(0)).ERC20Bridge.selector
|
||||
) {
|
||||
_transferERC20Token(assetData, amount);
|
||||
} else if (proxyId == IAssetData(address(0)).ERC721Token.selector) {
|
||||
_transferERC721Token(assetData, amount);
|
||||
} else {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedAssetProxyError(
|
||||
proxyId
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC20 or ERC20Bridge assetData and transfers given amount to sender.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to transfer to sender.
|
||||
function _transferERC20Token(
|
||||
bytes memory assetData,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
address token = assetData.readAddress(16);
|
||||
// Transfer tokens.
|
||||
LibERC20Token.transfer(token, msg.sender, amount);
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC721 assetData and transfers given amount to sender.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to transfer to sender.
|
||||
function _transferERC721Token(
|
||||
bytes memory assetData,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
if (amount != 1) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.Erc721AmountMustEqualOneError(
|
||||
amount
|
||||
));
|
||||
}
|
||||
// Decode asset data.
|
||||
address token = assetData.readAddress(16);
|
||||
uint256 tokenId = assetData.readUint256(36);
|
||||
|
||||
// Perform transfer.
|
||||
IERC721Token(token).transferFrom(
|
||||
address(this),
|
||||
msg.sender,
|
||||
tokenId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -30,6 +30,7 @@ import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
|
||||
import "./libs/LibConstants.sol";
|
||||
import "./libs/LibForwarderRichErrors.sol";
|
||||
import "./interfaces/IExchangeV2.sol";
|
||||
import "./MixinAssets.sol";
|
||||
|
||||
|
||||
@@ -54,23 +55,19 @@ contract MixinExchangeWrapper is
|
||||
internal
|
||||
returns (LibFillResults.FillResults memory fillResults)
|
||||
{
|
||||
// ABI encode calldata for `fillOrder`
|
||||
bytes memory fillOrderCalldata = abi.encodeWithSelector(
|
||||
IExchange(address(0)).fillOrder.selector,
|
||||
if (_isV2Order(order)) {
|
||||
return _fillV2OrderNoThrow(
|
||||
order,
|
||||
takerAssetFillAmount,
|
||||
signature
|
||||
);
|
||||
}
|
||||
|
||||
return _fillV3OrderNoThrow(
|
||||
order,
|
||||
takerAssetFillAmount,
|
||||
signature
|
||||
);
|
||||
|
||||
address exchange = address(EXCHANGE);
|
||||
(bool didSucceed, bytes memory returnData) = exchange.call(fillOrderCalldata);
|
||||
if (didSucceed) {
|
||||
assert(returnData.length == 160);
|
||||
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
|
||||
}
|
||||
|
||||
// fillResults values will be 0 by default if call was unsuccessful
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
/// @dev Executes a single call of fillOrder according to the wethSellAmount and
|
||||
@@ -162,8 +159,7 @@ contract MixinExchangeWrapper is
|
||||
uint256 protocolFee = tx.gasprice.safeMul(EXCHANGE.protocolFeeMultiplier());
|
||||
bytes4 erc20BridgeProxyId = IAssetData(address(0)).ERC20Bridge.selector;
|
||||
|
||||
uint256 ordersLength = orders.length;
|
||||
for (uint256 i = 0; i != ordersLength; i++) {
|
||||
for (uint256 i = 0; i != orders.length; i++) {
|
||||
// Preemptively skip to avoid division by zero in _marketSellSingleOrder
|
||||
if (orders[i].makerAssetAmount == 0 || orders[i].takerAssetAmount == 0) {
|
||||
continue;
|
||||
@@ -172,7 +168,7 @@ contract MixinExchangeWrapper is
|
||||
// The remaining amount of WETH to sell
|
||||
uint256 remainingTakerAssetFillAmount = wethSellAmount
|
||||
.safeSub(totalWethSpentAmount)
|
||||
.safeSub(protocolFee);
|
||||
.safeSub(_isV2Order(orders[i]) ? 0 : protocolFee);
|
||||
|
||||
// If the maker asset is ERC20Bridge, take a snapshot of the Forwarder contract's balance.
|
||||
bytes4 makerAssetProxyId = orders[i].makerAssetData.readBytes4(0);
|
||||
@@ -201,7 +197,7 @@ contract MixinExchangeWrapper is
|
||||
);
|
||||
}
|
||||
|
||||
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount);
|
||||
orders[i].makerAssetData.transferOut(makerAssetAcquiredAmount);
|
||||
|
||||
totalWethSpentAmount = totalWethSpentAmount
|
||||
.safeAdd(wethSpentAmount);
|
||||
@@ -349,7 +345,7 @@ contract MixinExchangeWrapper is
|
||||
);
|
||||
}
|
||||
|
||||
_transferAssetToSender(orders[i].makerAssetData, makerAssetAcquiredAmount);
|
||||
orders[i].makerAssetData.transferOut(makerAssetAcquiredAmount);
|
||||
|
||||
totalWethSpentAmount = totalWethSpentAmount
|
||||
.safeAdd(wethSpentAmount);
|
||||
@@ -370,6 +366,91 @@ contract MixinExchangeWrapper is
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Fills the input ExchangeV2 order. The `makerFeeAssetData` must be
|
||||
// equal to EXCHANGE_V2_ORDER_ID (0x770501f8).
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return Amounts filled and fees paid by maker and taker.
|
||||
function _fillV2OrderNoThrow(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
returns (LibFillResults.FillResults memory fillResults)
|
||||
{
|
||||
// Strip v3 specific fields from order
|
||||
IExchangeV2.Order memory v2Order = IExchangeV2.Order({
|
||||
makerAddress: order.makerAddress,
|
||||
takerAddress: order.takerAddress,
|
||||
feeRecipientAddress: order.feeRecipientAddress,
|
||||
senderAddress: order.senderAddress,
|
||||
makerAssetAmount: order.makerAssetAmount,
|
||||
takerAssetAmount: order.takerAssetAmount,
|
||||
// NOTE: We assume fees are 0 for all v2 orders. Orders with non-zero fees will fail to be filled.
|
||||
makerFee: 0,
|
||||
takerFee: 0,
|
||||
expirationTimeSeconds: order.expirationTimeSeconds,
|
||||
salt: order.salt,
|
||||
makerAssetData: order.makerAssetData,
|
||||
takerAssetData: order.takerAssetData
|
||||
});
|
||||
|
||||
// ABI encode calldata for `fillOrder`
|
||||
bytes memory fillOrderCalldata = abi.encodeWithSelector(
|
||||
IExchangeV2(address(0)).fillOrder.selector,
|
||||
v2Order,
|
||||
takerAssetFillAmount,
|
||||
signature
|
||||
);
|
||||
|
||||
address exchange = address(EXCHANGE_V2);
|
||||
(bool didSucceed, bytes memory returnData) = exchange.call(fillOrderCalldata);
|
||||
if (didSucceed) {
|
||||
assert(returnData.length == 128);
|
||||
// NOTE: makerFeePaid, takerFeePaid, and protocolFeePaid will always be 0 for v2 orders
|
||||
(fillResults.makerAssetFilledAmount, fillResults.takerAssetFilledAmount) = abi.decode(returnData, (uint256, uint256));
|
||||
}
|
||||
|
||||
// fillResults values will be 0 by default if call was unsuccessful
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
/// @dev Fills the input ExchangeV3 order.
|
||||
/// Returns false if the transaction would otherwise revert.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return Amounts filled and fees paid by maker and taker.
|
||||
function _fillV3OrderNoThrow(
|
||||
LibOrder.Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
internal
|
||||
returns (LibFillResults.FillResults memory fillResults)
|
||||
{
|
||||
// ABI encode calldata for `fillOrder`
|
||||
bytes memory fillOrderCalldata = abi.encodeWithSelector(
|
||||
IExchange(address(0)).fillOrder.selector,
|
||||
order,
|
||||
takerAssetFillAmount,
|
||||
signature
|
||||
);
|
||||
|
||||
address exchange = address(EXCHANGE);
|
||||
(bool didSucceed, bytes memory returnData) = exchange.call(fillOrderCalldata);
|
||||
if (didSucceed) {
|
||||
assert(returnData.length == 160);
|
||||
fillResults = abi.decode(returnData, (LibFillResults.FillResults));
|
||||
}
|
||||
|
||||
// fillResults values will be 0 by default if call was unsuccessful
|
||||
return fillResults;
|
||||
}
|
||||
|
||||
/// @dev Checks whether one asset is effectively equal to another asset.
|
||||
/// This is the case if they have the same ERC20Proxy/ERC20BridgeProxy asset data, or if
|
||||
/// one is the ERC20Bridge equivalent of the other.
|
||||
@@ -398,7 +479,18 @@ contract MixinExchangeWrapper is
|
||||
address token2 = assetData2.readAddress(16);
|
||||
return (token1 == token2);
|
||||
} else {
|
||||
return false;
|
||||
return assetData1.equals(assetData2);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Checks whether an order is a v2 order.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @return True if the order's `makerFeeAssetData` is set to the v2 order id.
|
||||
function _isV2Order(LibOrder.Order memory order)
|
||||
internal
|
||||
pure
|
||||
returns (bool)
|
||||
{
|
||||
return order.makerFeeAssetData.length > 3 && order.makerFeeAssetData.readBytes4(0) == EXCHANGE_V2_ORDER_ID;
|
||||
}
|
||||
}
|
||||
|
@@ -85,7 +85,6 @@ contract MixinForwarderCore is
|
||||
ethFeeAmounts,
|
||||
feeRecipients
|
||||
);
|
||||
|
||||
// Spends up to wethRemaining to fill orders, transfers purchased assets to msg.sender,
|
||||
// and pays WETH order fees.
|
||||
(
|
||||
|
76
contracts/exchange-forwarder/contracts/src/MixinReceiver.sol
Normal file
76
contracts/exchange-forwarder/contracts/src/MixinReceiver.sol
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
|
||||
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 MixinReceiver {
|
||||
|
||||
bytes4 constant public ERC1155_RECEIVED = 0xf23a6e61;
|
||||
bytes4 constant public ERC1155_BATCH_RECEIVED = 0xbc197c81;
|
||||
|
||||
/// @notice Handle the receipt of a single ERC1155 token type
|
||||
/// @dev The smart contract calls this function on the recipient
|
||||
/// after a `safeTransferFrom`. This function MAY throw to revert and reject the
|
||||
/// transfer. Return of other than the magic value MUST result in the
|
||||
///transaction being reverted
|
||||
/// Note: the contract address is always the message sender
|
||||
/// @param operator The address which called `safeTransferFrom` function
|
||||
/// @param from The address which previously owned the token
|
||||
/// @param id An array containing the ids of the token being transferred
|
||||
/// @param value An array containing the amount of tokens being transferred
|
||||
/// @param data Additional data with no specified format
|
||||
/// @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
|
||||
function onERC1155Received(
|
||||
address operator,
|
||||
address from,
|
||||
uint256 id,
|
||||
uint256 value,
|
||||
bytes calldata data
|
||||
)
|
||||
external
|
||||
returns (bytes4)
|
||||
{
|
||||
return ERC1155_RECEIVED;
|
||||
}
|
||||
|
||||
/// @notice Handle the receipt of multiple ERC1155 token types
|
||||
/// @dev The smart contract calls this function on the recipient
|
||||
/// after a `safeTransferFrom`. This function MAY throw to revert and reject the
|
||||
/// transfer. Return of other than the magic value MUST result in the
|
||||
/// transaction being reverted
|
||||
/// Note: the contract address is always the message sender
|
||||
/// @param operator The address which called `safeTransferFrom` function
|
||||
/// @param from The address which previously owned the token
|
||||
/// @param ids An array containing ids of each token being transferred
|
||||
/// @param values An array containing amounts of each token being transferred
|
||||
/// @param data Additional data with no specified format
|
||||
/// @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
|
||||
function onERC1155BatchReceived(
|
||||
address operator,
|
||||
address from,
|
||||
uint256[] calldata ids,
|
||||
uint256[] calldata values,
|
||||
bytes calldata data
|
||||
)
|
||||
external
|
||||
returns (bytes4)
|
||||
{
|
||||
return ERC1155_BATCH_RECEIVED;
|
||||
}
|
||||
}
|
@@ -109,7 +109,6 @@ contract MixinWeth is
|
||||
if (wethRemaining > 0) {
|
||||
// Convert remaining WETH to ETH
|
||||
ETHER_TOKEN.withdraw(wethRemaining);
|
||||
|
||||
// Transfer remaining ETH to sender
|
||||
msg.sender.transfer(wethRemaining);
|
||||
}
|
||||
|
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
|
||||
contract IExchangeV2 {
|
||||
|
||||
// solhint-disable max-line-length
|
||||
struct Order {
|
||||
address makerAddress; // Address that created the order.
|
||||
address takerAddress; // Address that is allowed to fill the order. If set to 0, any address is allowed to fill the order.
|
||||
address feeRecipientAddress; // Address that will recieve fees when order is filled.
|
||||
address senderAddress; // Address that is allowed to call Exchange contract methods that affect this order. If set to 0, any address is allowed to call these methods.
|
||||
uint256 makerAssetAmount; // Amount of makerAsset being offered by maker. Must be greater than 0.
|
||||
uint256 takerAssetAmount; // Amount of takerAsset being bid on by maker. Must be greater than 0.
|
||||
uint256 makerFee; // Amount of ZRX paid to feeRecipient by maker when order is filled. If set to 0, no transfer of ZRX from maker to feeRecipient will be attempted.
|
||||
uint256 takerFee; // Amount of ZRX paid to feeRecipient by taker when order is filled. If set to 0, no transfer of ZRX from taker to feeRecipient will be attempted.
|
||||
uint256 expirationTimeSeconds; // Timestamp in seconds at which order expires.
|
||||
uint256 salt; // Arbitrary number to facilitate uniqueness of the order's hash.
|
||||
bytes makerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring makerAsset. The last byte references the id of this proxy.
|
||||
bytes takerAssetData; // Encoded data that can be decoded by a specified proxy contract when transferring takerAsset. The last byte references the id of this proxy.
|
||||
}
|
||||
// solhint-enable max-line-length
|
||||
|
||||
struct FillResults {
|
||||
uint256 makerAssetFilledAmount; // Total amount of makerAsset(s) filled.
|
||||
uint256 takerAssetFilledAmount; // Total amount of takerAsset(s) filled.
|
||||
uint256 makerFeePaid; // Total amount of ZRX paid by maker(s) to feeRecipient(s).
|
||||
uint256 takerFeePaid; // Total amount of ZRX paid by taker to feeRecipients(s).
|
||||
}
|
||||
|
||||
struct OrderInfo {
|
||||
uint8 orderStatus; // Status that describes order's validity and fillability.
|
||||
bytes32 orderHash; // EIP712 typed data hash of the order (see LibOrder.getTypedDataHash).
|
||||
uint256 orderTakerAssetFilledAmount; // Amount of order that has already been filled.
|
||||
}
|
||||
|
||||
/// @dev Fills the input order.
|
||||
/// @param order Order struct containing order specifications.
|
||||
/// @param takerAssetFillAmount Desired amount of takerAsset to sell.
|
||||
/// @param signature Proof that order has been created by maker.
|
||||
/// @return Amounts filled and fees paid by maker and taker.
|
||||
function fillOrder(
|
||||
Order memory order,
|
||||
uint256 takerAssetFillAmount,
|
||||
bytes memory signature
|
||||
)
|
||||
public
|
||||
returns (FillResults memory fillResults);
|
||||
|
||||
/// @dev Gets information about an order: status, hash, and amount filled.
|
||||
/// @param order Order to gather information on.
|
||||
/// @return OrderInfo Information about the order and its state.
|
||||
/// See LibOrder.OrderInfo for a complete description.
|
||||
function getOrderInfo(Order memory order)
|
||||
public
|
||||
returns (OrderInfo memory orderInfo);
|
||||
}
|
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
|
||||
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/LibRichErrors.sol";
|
||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
|
||||
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
|
||||
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
|
||||
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
|
||||
import "./LibForwarderRichErrors.sol";
|
||||
|
||||
|
||||
library LibAssetDataTransfer {
|
||||
|
||||
using LibBytes for bytes;
|
||||
using LibSafeMath for uint256;
|
||||
using LibAssetDataTransfer for bytes;
|
||||
|
||||
/// @dev Transfers given amount of asset to sender.
|
||||
/// @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 to sender.
|
||||
function transferFrom(
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
if (amount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
bytes4 proxyId = assetData.readBytes4(0);
|
||||
|
||||
if (
|
||||
proxyId == IAssetData(address(0)).ERC20Token.selector ||
|
||||
proxyId == IAssetData(address(0)).ERC20Bridge.selector
|
||||
) {
|
||||
assetData.transferERC20Token(
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
} else if (proxyId == IAssetData(address(0)).ERC721Token.selector) {
|
||||
assetData.transferERC721Token(
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
} else if (proxyId == IAssetData(address(0)).ERC1155Assets.selector) {
|
||||
assetData.transferERC1155Assets(
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
} else if (proxyId == IAssetData(address(0)).MultiAsset.selector) {
|
||||
assetData.transferMultiAsset(
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
} else if (proxyId != IAssetData(address(0)).StaticCall.selector) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.UnsupportedAssetProxyError(
|
||||
proxyId
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
///@dev Transfer asset from sender to this contract.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to transfer to sender.
|
||||
function transferIn(
|
||||
bytes memory assetData,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
assetData.transferFrom(
|
||||
msg.sender,
|
||||
address(this),
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
///@dev Transfer asset from this contract to sender.
|
||||
/// @param assetData Byte array encoded for the respective asset proxy.
|
||||
/// @param amount Amount of asset to transfer to sender.
|
||||
function transferOut(
|
||||
bytes memory assetData,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
assetData.transferFrom(
|
||||
address(this),
|
||||
msg.sender,
|
||||
amount
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC20 or ERC20Bridge assetData and transfers given amount to sender.
|
||||
/// @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 to sender.
|
||||
function transferERC20Token(
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
address token = assetData.readAddress(16);
|
||||
// Transfer tokens.
|
||||
if (from == address(this)) {
|
||||
LibERC20Token.transfer(
|
||||
token,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
} else {
|
||||
LibERC20Token.transferFrom(
|
||||
token,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC721 assetData and transfers given amount to sender.
|
||||
/// @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 to sender.
|
||||
function transferERC721Token(
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
if (amount != 1) {
|
||||
LibRichErrors.rrevert(LibForwarderRichErrors.Erc721AmountMustEqualOneError(
|
||||
amount
|
||||
));
|
||||
}
|
||||
// Decode asset data.
|
||||
address token = assetData.readAddress(16);
|
||||
uint256 tokenId = assetData.readUint256(36);
|
||||
|
||||
// Perform transfer.
|
||||
IERC721Token(token).transferFrom(
|
||||
from,
|
||||
to,
|
||||
tokenId
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Decodes ERC1155 assetData and transfers given amounts to sender.
|
||||
/// @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 to sender.
|
||||
function transferERC1155Assets(
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// Decode assetData
|
||||
// solhint-disable
|
||||
(
|
||||
address token,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory values,
|
||||
bytes memory data
|
||||
) = abi.decode(
|
||||
assetData.slice(4, assetData.length),
|
||||
(address, uint256[], uint256[], bytes)
|
||||
);
|
||||
// solhint-enable
|
||||
|
||||
// Scale up values by `amount`
|
||||
uint256 length = values.length;
|
||||
uint256[] memory scaledValues = new uint256[](length);
|
||||
for (uint256 i = 0; i != length; i++) {
|
||||
scaledValues[i] = values[i].safeMul(amount);
|
||||
}
|
||||
|
||||
// Execute `safeBatchTransferFrom` call
|
||||
// Either succeeds or throws
|
||||
IERC1155(token).safeBatchTransferFrom(
|
||||
from,
|
||||
to,
|
||||
ids,
|
||||
scaledValues,
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Decodes MultiAsset assetData and recursively transfers assets to sender.
|
||||
/// @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 to sender.
|
||||
function transferMultiAsset(
|
||||
bytes memory assetData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
// solhint-disable indent
|
||||
(uint256[] memory nestedAmounts, bytes[] memory nestedAssetData) = abi.decode(
|
||||
assetData.slice(4, assetData.length),
|
||||
(uint256[], bytes[])
|
||||
);
|
||||
// solhint-enable indent
|
||||
|
||||
uint256 numNestedAssets = nestedAssetData.length;
|
||||
for (uint256 i = 0; i != numNestedAssets; i++) {
|
||||
transferFrom(
|
||||
nestedAssetData[i],
|
||||
from,
|
||||
to,
|
||||
amount.safeMul(nestedAmounts[i])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@@ -18,29 +18,49 @@
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
|
||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
|
||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
|
||||
import "../interfaces/IExchangeV2.sol";
|
||||
|
||||
|
||||
contract LibConstants {
|
||||
|
||||
using LibBytes for bytes;
|
||||
uint256 constant internal MAX_UINT = uint256(-1);
|
||||
|
||||
uint256 constant internal MAX_UINT = 2**256 - 1;
|
||||
// The v2 order id is the first 4 bytes of the ExchangeV2 order schema hash.
|
||||
// bytes4(keccak256(abi.encodePacked(
|
||||
// "Order(",
|
||||
// "address makerAddress,",
|
||||
// "address takerAddress,",
|
||||
// "address feeRecipientAddress,",
|
||||
// "address senderAddress,",
|
||||
// "uint256 makerAssetAmount,",
|
||||
// "uint256 takerAssetAmount,",
|
||||
// "uint256 makerFee,",
|
||||
// "uint256 takerFee,",
|
||||
// "uint256 expirationTimeSeconds,",
|
||||
// "uint256 salt,",
|
||||
// "bytes makerAssetData,",
|
||||
// "bytes takerAssetData",
|
||||
// ")"
|
||||
// )));
|
||||
bytes4 constant public EXCHANGE_V2_ORDER_ID = 0x770501f8;
|
||||
|
||||
// solhint-disable var-name-mixedcase
|
||||
IExchange internal EXCHANGE;
|
||||
IExchangeV2 internal EXCHANGE_V2;
|
||||
IEtherToken internal ETHER_TOKEN;
|
||||
// solhint-enable var-name-mixedcase
|
||||
|
||||
constructor (
|
||||
address _exchange,
|
||||
address _exchangeV2,
|
||||
address _weth
|
||||
)
|
||||
public
|
||||
{
|
||||
EXCHANGE = IExchange(_exchange);
|
||||
EXCHANGE_V2 = IExchangeV2(_exchangeV2);
|
||||
ETHER_TOKEN = IEtherToken(_weth);
|
||||
}
|
||||
}
|
||||
|
@@ -21,16 +21,22 @@ pragma experimental ABIEncoderV2;
|
||||
|
||||
import "../src/MixinExchangeWrapper.sol";
|
||||
import "../src/libs/LibConstants.sol";
|
||||
import "../src/libs/LibAssetDataTransfer.sol";
|
||||
import "../src/MixinReceiver.sol";
|
||||
|
||||
|
||||
contract TestForwarder is
|
||||
LibConstants,
|
||||
MixinExchangeWrapper
|
||||
MixinExchangeWrapper,
|
||||
MixinReceiver
|
||||
{
|
||||
using LibAssetDataTransfer for bytes;
|
||||
|
||||
// solhint-disable no-empty-blocks
|
||||
constructor ()
|
||||
public
|
||||
LibConstants(
|
||||
address(0),
|
||||
address(0),
|
||||
address(0)
|
||||
)
|
||||
@@ -49,15 +55,12 @@ contract TestForwarder is
|
||||
);
|
||||
}
|
||||
|
||||
function transferAssetToSender(
|
||||
function transferOut(
|
||||
bytes memory assetData,
|
||||
uint256 amount
|
||||
)
|
||||
public
|
||||
{
|
||||
_transferAssetToSender(
|
||||
assetData,
|
||||
amount
|
||||
);
|
||||
assetData.transferOut(amount);
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-forwarder",
|
||||
"version": "4.0.3",
|
||||
"version": "4.0.5",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -38,8 +38,8 @@
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
|
||||
},
|
||||
"config": {
|
||||
"publicInterfaceContracts": "Forwarder",
|
||||
"abis": "./test/generated-artifacts/@(Forwarder|IAssets|IForwarder|IForwarderCore|LibConstants|LibForwarderRichErrors|MixinAssets|MixinExchangeWrapper|MixinForwarderCore|MixinWeth|TestForwarder).json",
|
||||
"publicInterfaceContracts": "Forwarder,IExchangeV2",
|
||||
"abis": "./test/generated-artifacts/@(Forwarder|IAssets|IExchangeV2|IForwarder|IForwarderCore|LibAssetDataTransfer|LibConstants|LibForwarderRichErrors|MixinAssets|MixinExchangeWrapper|MixinForwarderCore|MixinReceiver|MixinWeth|TestForwarder).json",
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
|
||||
},
|
||||
"repository": {
|
||||
@@ -52,24 +52,25 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.3",
|
||||
"@0x/contracts-asset-proxy": "^3.1.0",
|
||||
"@0x/contracts-dev-utils": "^1.0.3",
|
||||
"@0x/contracts-erc20": "^3.0.3",
|
||||
"@0x/contracts-erc721": "^3.0.3",
|
||||
"@0x/contracts-exchange": "^3.0.3",
|
||||
"@0x/contracts-exchange-libs": "^4.0.3",
|
||||
"@0x/contracts-gen": "^2.0.3",
|
||||
"@0x/contracts-test-utils": "^5.1.0",
|
||||
"@0x/contracts-utils": "^4.0.3",
|
||||
"@0x/dev-utils": "^3.1.0",
|
||||
"@0x/order-utils": "^10.1.0",
|
||||
"@0x/sol-compiler": "^4.0.3",
|
||||
"@0x/abi-gen": "^5.1.1",
|
||||
"@0x/contracts-asset-proxy": "^3.1.2",
|
||||
"@0x/contracts-dev-utils": "^1.0.5",
|
||||
"@0x/contracts-erc1155": "^2.0.5",
|
||||
"@0x/contracts-erc20": "^3.0.5",
|
||||
"@0x/contracts-erc721": "^3.0.5",
|
||||
"@0x/contracts-exchange": "^3.1.1",
|
||||
"@0x/contracts-exchange-libs": "^4.1.1",
|
||||
"@0x/contracts-gen": "^2.0.5",
|
||||
"@0x/contracts-test-utils": "^5.1.2",
|
||||
"@0x/contracts-utils": "^4.2.0",
|
||||
"@0x/dev-utils": "^3.1.2",
|
||||
"@0x/order-utils": "^10.1.2",
|
||||
"@0x/sol-compiler": "^4.0.5",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/utils": "^5.1.2",
|
||||
"@0x/web3-wrapper": "^7.0.3",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -89,7 +90,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.3",
|
||||
"@0x/base-contract": "^6.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"ethereum-types": "^3.0.0"
|
||||
},
|
||||
|
@@ -6,4 +6,5 @@
|
||||
import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as Forwarder from '../generated-artifacts/Forwarder.json';
|
||||
export const artifacts = { Forwarder: Forwarder as ContractArtifact };
|
||||
import * as IExchangeV2 from '../generated-artifacts/IExchangeV2.json';
|
||||
export const artifacts = { Forwarder: Forwarder as ContractArtifact, IExchangeV2: IExchangeV2 as ContractArtifact };
|
||||
|
@@ -1,5 +1,5 @@
|
||||
export { artifacts } from './artifacts';
|
||||
export { ForwarderContract } from './wrappers';
|
||||
export { ForwarderContract, IExchangeV2Contract } from './wrappers';
|
||||
export { ExchangeForwarderRevertErrors } from '@0x/utils';
|
||||
export {
|
||||
ContractArtifact,
|
||||
|
@@ -4,3 +4,4 @@
|
||||
* -----------------------------------------------------------------------------
|
||||
*/
|
||||
export * from '../generated-wrappers/forwarder';
|
||||
export * from '../generated-wrappers/i_exchange_v2';
|
||||
|
@@ -7,13 +7,16 @@ import { ContractArtifact } from 'ethereum-types';
|
||||
|
||||
import * as Forwarder from '../test/generated-artifacts/Forwarder.json';
|
||||
import * as IAssets from '../test/generated-artifacts/IAssets.json';
|
||||
import * as IExchangeV2 from '../test/generated-artifacts/IExchangeV2.json';
|
||||
import * as IForwarder from '../test/generated-artifacts/IForwarder.json';
|
||||
import * as IForwarderCore from '../test/generated-artifacts/IForwarderCore.json';
|
||||
import * as LibAssetDataTransfer from '../test/generated-artifacts/LibAssetDataTransfer.json';
|
||||
import * as LibConstants from '../test/generated-artifacts/LibConstants.json';
|
||||
import * as LibForwarderRichErrors from '../test/generated-artifacts/LibForwarderRichErrors.json';
|
||||
import * as MixinAssets from '../test/generated-artifacts/MixinAssets.json';
|
||||
import * as MixinExchangeWrapper from '../test/generated-artifacts/MixinExchangeWrapper.json';
|
||||
import * as MixinForwarderCore from '../test/generated-artifacts/MixinForwarderCore.json';
|
||||
import * as MixinReceiver from '../test/generated-artifacts/MixinReceiver.json';
|
||||
import * as MixinWeth from '../test/generated-artifacts/MixinWeth.json';
|
||||
import * as TestForwarder from '../test/generated-artifacts/TestForwarder.json';
|
||||
export const artifacts = {
|
||||
@@ -21,10 +24,13 @@ export const artifacts = {
|
||||
MixinAssets: MixinAssets as ContractArtifact,
|
||||
MixinExchangeWrapper: MixinExchangeWrapper as ContractArtifact,
|
||||
MixinForwarderCore: MixinForwarderCore as ContractArtifact,
|
||||
MixinReceiver: MixinReceiver as ContractArtifact,
|
||||
MixinWeth: MixinWeth as ContractArtifact,
|
||||
IAssets: IAssets as ContractArtifact,
|
||||
IExchangeV2: IExchangeV2 as ContractArtifact,
|
||||
IForwarder: IForwarder as ContractArtifact,
|
||||
IForwarderCore: IForwarderCore as ContractArtifact,
|
||||
LibAssetDataTransfer: LibAssetDataTransfer as ContractArtifact,
|
||||
LibConstants: LibConstants as ContractArtifact,
|
||||
LibForwarderRichErrors: LibForwarderRichErrors as ContractArtifact,
|
||||
TestForwarder: TestForwarder as ContractArtifact,
|
||||
|
@@ -1,4 +1,11 @@
|
||||
import { IAssetDataContract } from '@0x/contracts-asset-proxy';
|
||||
import {
|
||||
artifacts as ERC1155Artifacts,
|
||||
ERC1155Events,
|
||||
ERC1155MintableContract,
|
||||
ERC1155TransferBatchEventArgs,
|
||||
Erc1155Wrapper,
|
||||
} from '@0x/contracts-erc1155';
|
||||
import {
|
||||
artifacts as ERC20Artifacts,
|
||||
DummyERC20TokenContract,
|
||||
@@ -20,11 +27,13 @@ import {
|
||||
verifyEventsFromLogs,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { BigNumber, ExchangeForwarderRevertErrors, hexUtils } from '@0x/utils';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { TestForwarderContract } from './wrappers';
|
||||
|
||||
blockchainTests('Supported asset type unit tests', env => {
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
blockchainTests.resets('Supported asset type unit tests', env => {
|
||||
let forwarder: TestForwarderContract;
|
||||
let assetDataEncoder: IAssetDataContract;
|
||||
let bridgeAddress: string;
|
||||
@@ -33,11 +42,15 @@ blockchainTests('Supported asset type unit tests', env => {
|
||||
|
||||
let erc20Token: DummyERC20TokenContract;
|
||||
let erc721Token: DummyERC721TokenContract;
|
||||
let erc1155Token: ERC1155MintableContract;
|
||||
let erc1155Wrapper: Erc1155Wrapper;
|
||||
let nftId: BigNumber;
|
||||
|
||||
let erc20AssetData: string;
|
||||
let erc721AssetData: string;
|
||||
let erc20BridgeAssetData: string;
|
||||
let staticCallAssetData: string;
|
||||
let multiAssetData: string;
|
||||
|
||||
before(async () => {
|
||||
[receiver] = await env.getAccountAddressesAsync();
|
||||
@@ -47,7 +60,7 @@ blockchainTests('Supported asset type unit tests', env => {
|
||||
artifacts.TestForwarder,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
{ ...artifacts, ...ERC20Artifacts, ...ERC721Artifacts },
|
||||
{ ...artifacts, ...ERC20Artifacts, ...ERC721Artifacts, ...ERC1155Artifacts },
|
||||
);
|
||||
|
||||
erc20Token = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
@@ -70,14 +83,30 @@ blockchainTests('Supported asset type unit tests', env => {
|
||||
constants.DUMMY_TOKEN_NAME,
|
||||
constants.DUMMY_TOKEN_SYMBOL,
|
||||
);
|
||||
nftId = getRandomInteger(constants.ZERO_AMOUNT, constants.MAX_UINT256);
|
||||
nftId = getRandomInteger(0, constants.MAX_UINT256);
|
||||
erc721AssetData = assetDataEncoder.ERC721Token(erc721Token.address, nftId).getABIEncodedTransactionData();
|
||||
|
||||
erc1155Token = await ERC1155MintableContract.deployFrom0xArtifactAsync(
|
||||
ERC1155Artifacts.ERC1155Mintable,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
ERC1155Artifacts,
|
||||
);
|
||||
erc1155Wrapper = new Erc1155Wrapper(erc1155Token, receiver);
|
||||
|
||||
bridgeAddress = randomAddress();
|
||||
bridgeData = hexUtils.random();
|
||||
erc20BridgeAssetData = assetDataEncoder
|
||||
.ERC20Bridge(erc20Token.address, bridgeAddress, bridgeData)
|
||||
.getABIEncodedTransactionData();
|
||||
|
||||
staticCallAssetData = assetDataEncoder
|
||||
.StaticCall(randomAddress(), hexUtils.random(), constants.KECCAK256_NULL)
|
||||
.getABIEncodedTransactionData();
|
||||
|
||||
multiAssetData = assetDataEncoder
|
||||
.MultiAsset([new BigNumber(1)], [erc20AssetData])
|
||||
.getABIEncodedTransactionData();
|
||||
});
|
||||
|
||||
describe('_areUnderlyingAssetsEqual', () => {
|
||||
@@ -115,13 +144,64 @@ blockchainTests('Supported asset type unit tests', env => {
|
||||
.callAsync();
|
||||
expect(result).to.be.false();
|
||||
});
|
||||
it('returns false if assetData1 == assetData2 are ERC721', async () => {
|
||||
it('returns true if assetData1 == assetData2 are ERC721', async () => {
|
||||
const result = await forwarder.areUnderlyingAssetsEqual(erc721AssetData, erc721AssetData).callAsync();
|
||||
expect(result).to.be.true();
|
||||
});
|
||||
it('returns false if assetData1 != assetData2 are ERC721', async () => {
|
||||
const differentErc721AssetData = assetDataEncoder
|
||||
.ERC721Token(randomAddress(), getRandomInteger(0, constants.MAX_UINT256))
|
||||
.getABIEncodedTransactionData();
|
||||
const result = await forwarder
|
||||
.areUnderlyingAssetsEqual(erc721AssetData, differentErc721AssetData)
|
||||
.callAsync();
|
||||
expect(result).to.be.false();
|
||||
});
|
||||
it('returns true if assetData1 == assetData2 are StaticCall', async () => {
|
||||
const result = await forwarder
|
||||
.areUnderlyingAssetsEqual(staticCallAssetData, staticCallAssetData)
|
||||
.callAsync();
|
||||
expect(result).to.be.true();
|
||||
});
|
||||
it('returns false if assetData1 != assetData2 are StaticCall', async () => {
|
||||
const differentStaticCallAssetData = assetDataEncoder
|
||||
.StaticCall(randomAddress(), hexUtils.random(), constants.KECCAK256_NULL)
|
||||
.getABIEncodedTransactionData();
|
||||
const result = await forwarder
|
||||
.areUnderlyingAssetsEqual(staticCallAssetData, differentStaticCallAssetData)
|
||||
.callAsync();
|
||||
expect(result).to.be.false();
|
||||
});
|
||||
it('returns false if assetData1 is ERC20 and assetData2 is MultiAsset', async () => {
|
||||
const result = await forwarder.areUnderlyingAssetsEqual(erc20AssetData, multiAssetData).callAsync();
|
||||
expect(result).to.be.false();
|
||||
});
|
||||
it('returns true if assetData1 == assetData2 are MultiAsset (single nested asset)', async () => {
|
||||
const result = await forwarder.areUnderlyingAssetsEqual(multiAssetData, multiAssetData).callAsync();
|
||||
expect(result).to.be.true();
|
||||
});
|
||||
it('returns true if assetData1 == assetData2 are MultiAsset (multiple nested assets)', async () => {
|
||||
const assetData = assetDataEncoder
|
||||
.MultiAsset(
|
||||
[getRandomInteger(0, constants.MAX_UINT256), new BigNumber(1)],
|
||||
[erc20AssetData, erc721AssetData],
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
const result = await forwarder.areUnderlyingAssetsEqual(assetData, assetData).callAsync();
|
||||
expect(result).to.be.true();
|
||||
});
|
||||
it('returns false if assetData1 != assetData2 are MultiAsset', async () => {
|
||||
const differentMultiAssetData = assetDataEncoder
|
||||
.MultiAsset([getRandomInteger(0, constants.MAX_UINT256)], [erc721AssetData])
|
||||
.getABIEncodedTransactionData();
|
||||
const result = await forwarder
|
||||
.areUnderlyingAssetsEqual(multiAssetData, differentMultiAssetData)
|
||||
.callAsync();
|
||||
expect(result).to.be.false();
|
||||
});
|
||||
});
|
||||
|
||||
describe('_transferAssetToSender', () => {
|
||||
describe('transferOut', () => {
|
||||
const TRANSFER_AMOUNT = new BigNumber(1);
|
||||
before(async () => {
|
||||
await erc20Token
|
||||
@@ -132,7 +212,7 @@ blockchainTests('Supported asset type unit tests', env => {
|
||||
|
||||
it('transfers an ERC20 token given ERC20 assetData', async () => {
|
||||
const txReceipt = await forwarder
|
||||
.transferAssetToSender(erc20AssetData, TRANSFER_AMOUNT)
|
||||
.transferOut(erc20AssetData, TRANSFER_AMOUNT)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
verifyEventsFromLogs<ERC20TokenTransferEventArgs>(
|
||||
txReceipt.logs,
|
||||
@@ -142,7 +222,7 @@ blockchainTests('Supported asset type unit tests', env => {
|
||||
});
|
||||
it('transfers an ERC721 token given ERC721 assetData and amount == 1', async () => {
|
||||
const txReceipt = await forwarder
|
||||
.transferAssetToSender(erc721AssetData, TRANSFER_AMOUNT)
|
||||
.transferOut(erc721AssetData, TRANSFER_AMOUNT)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
verifyEventsFromLogs<ERC721TokenTransferEventArgs>(
|
||||
txReceipt.logs,
|
||||
@@ -153,14 +233,120 @@ blockchainTests('Supported asset type unit tests', env => {
|
||||
it('reverts if attempting to transfer an ERC721 token with amount != 1', async () => {
|
||||
const invalidAmount = new BigNumber(2);
|
||||
const tx = forwarder
|
||||
.transferAssetToSender(erc721AssetData, invalidAmount)
|
||||
.transferOut(erc721AssetData, invalidAmount)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
const expectedError = new ExchangeForwarderRevertErrors.Erc721AmountMustEqualOneError(invalidAmount);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
it('transfers a single ERC1155 token', async () => {
|
||||
const values = [new BigNumber(1)];
|
||||
const amount = new BigNumber(1);
|
||||
const ids = [await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], values)];
|
||||
const assetData = assetDataEncoder
|
||||
.ERC1155Assets(erc1155Token.address, ids, values, constants.NULL_BYTES)
|
||||
.getABIEncodedTransactionData();
|
||||
const txReceipt = await forwarder
|
||||
.transferOut(assetData, amount)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
verifyEventsFromLogs<ERC1155TransferBatchEventArgs>(
|
||||
txReceipt.logs,
|
||||
[{ operator: forwarder.address, from: forwarder.address, to: receiver, ids, values }],
|
||||
ERC1155Events.TransferBatch,
|
||||
);
|
||||
});
|
||||
it('transfers multiple ids of an ERC1155 token', async () => {
|
||||
const amount = new BigNumber(1);
|
||||
const ids = [
|
||||
await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [amount]),
|
||||
await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [amount]),
|
||||
];
|
||||
const values = [amount, amount];
|
||||
const assetData = assetDataEncoder
|
||||
.ERC1155Assets(erc1155Token.address, ids, values, constants.NULL_BYTES)
|
||||
.getABIEncodedTransactionData();
|
||||
const txReceipt = await forwarder.transferOut(assetData, amount).awaitTransactionSuccessAsync();
|
||||
verifyEventsFromLogs<ERC1155TransferBatchEventArgs>(
|
||||
txReceipt.logs,
|
||||
[{ operator: forwarder.address, from: forwarder.address, to: receiver, ids, values }],
|
||||
ERC1155Events.TransferBatch,
|
||||
);
|
||||
});
|
||||
it('scales up values when transfering ERC1155 tokens', async () => {
|
||||
const amount = new BigNumber(2);
|
||||
const values = [new BigNumber(1), new BigNumber(2)];
|
||||
const scaledValues = values.map(value => value.times(amount));
|
||||
const ids = [
|
||||
await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [scaledValues[0]]),
|
||||
await erc1155Wrapper.mintFungibleTokensAsync([forwarder.address], [scaledValues[1]]),
|
||||
];
|
||||
const assetData = assetDataEncoder
|
||||
.ERC1155Assets(erc1155Token.address, ids, values, constants.NULL_BYTES)
|
||||
.getABIEncodedTransactionData();
|
||||
const txReceipt = await forwarder.transferOut(assetData, amount).awaitTransactionSuccessAsync();
|
||||
verifyEventsFromLogs<ERC1155TransferBatchEventArgs>(
|
||||
txReceipt.logs,
|
||||
[{ operator: forwarder.address, from: forwarder.address, to: receiver, ids, values: scaledValues }],
|
||||
ERC1155Events.TransferBatch,
|
||||
);
|
||||
});
|
||||
it('transfers a single ERC20 token wrapped as MultiAsset', async () => {
|
||||
const nestedAmount = new BigNumber(1337);
|
||||
const erc20MultiAssetData = assetDataEncoder
|
||||
.MultiAsset([nestedAmount], [erc20AssetData])
|
||||
.getABIEncodedTransactionData();
|
||||
const multiAssetAmount = new BigNumber(2);
|
||||
const txReceipt = await forwarder
|
||||
.transferOut(erc20MultiAssetData, multiAssetAmount)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
verifyEventsFromLogs<ERC20TokenTransferEventArgs>(
|
||||
txReceipt.logs,
|
||||
[{ _from: forwarder.address, _to: receiver, _value: multiAssetAmount.times(nestedAmount) }],
|
||||
ERC20TokenEvents.Transfer,
|
||||
);
|
||||
});
|
||||
it('transfers ERC20, ERC721, and StaticCall assets wrapped as MultiAsset', async () => {
|
||||
const nestedAmounts = [new BigNumber(1337), TRANSFER_AMOUNT, TRANSFER_AMOUNT];
|
||||
const assortedMultiAssetData = assetDataEncoder
|
||||
.MultiAsset(nestedAmounts, [erc20AssetData, erc721AssetData, staticCallAssetData])
|
||||
.getABIEncodedTransactionData();
|
||||
const txReceipt = await forwarder
|
||||
.transferOut(assortedMultiAssetData, TRANSFER_AMOUNT)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
expect(txReceipt.logs.length).to.equal(2);
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
const erc20TransferEvent = (txReceipt.logs[0] as LogWithDecodedArgs<ERC20TokenTransferEventArgs>).args;
|
||||
const erc721TransferEvent = (txReceipt.logs[1] as LogWithDecodedArgs<ERC721TokenTransferEventArgs>).args;
|
||||
// tslint:enable:no-unnecessary-type-assertion
|
||||
expect(erc20TransferEvent).to.deep.equal({
|
||||
_from: forwarder.address,
|
||||
_to: receiver,
|
||||
_value: nestedAmounts[0],
|
||||
});
|
||||
expect(erc721TransferEvent).to.deep.equal({ _from: forwarder.address, _to: receiver, _tokenId: nftId });
|
||||
});
|
||||
it('performs nested MultiAsset transfers', async () => {
|
||||
const nestedAmounts = [TRANSFER_AMOUNT, TRANSFER_AMOUNT, TRANSFER_AMOUNT];
|
||||
const assortedMultiAssetData = assetDataEncoder
|
||||
.MultiAsset(nestedAmounts, [multiAssetData, erc721AssetData, staticCallAssetData])
|
||||
.getABIEncodedTransactionData();
|
||||
const txReceipt = await forwarder
|
||||
.transferOut(assortedMultiAssetData, TRANSFER_AMOUNT)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
expect(txReceipt.logs.length).to.equal(2);
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
const erc20TransferEvent = (txReceipt.logs[0] as LogWithDecodedArgs<ERC20TokenTransferEventArgs>).args;
|
||||
const erc721TransferEvent = (txReceipt.logs[1] as LogWithDecodedArgs<ERC721TokenTransferEventArgs>).args;
|
||||
// tslint:enable:no-unnecessary-type-assertion
|
||||
expect(erc20TransferEvent).to.deep.equal({
|
||||
_from: forwarder.address,
|
||||
_to: receiver,
|
||||
_value: TRANSFER_AMOUNT,
|
||||
});
|
||||
expect(erc721TransferEvent).to.deep.equal({ _from: forwarder.address, _to: receiver, _tokenId: nftId });
|
||||
});
|
||||
it('transfers an ERC20 token given ERC20Bridge assetData', async () => {
|
||||
const txReceipt = await forwarder
|
||||
.transferAssetToSender(erc20BridgeAssetData, TRANSFER_AMOUNT)
|
||||
.transferOut(erc20BridgeAssetData, TRANSFER_AMOUNT)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
verifyEventsFromLogs<ERC20TokenTransferEventArgs>(
|
||||
txReceipt.logs,
|
||||
@@ -168,10 +354,16 @@ blockchainTests('Supported asset type unit tests', env => {
|
||||
ERC20TokenEvents.Transfer,
|
||||
);
|
||||
});
|
||||
it('noops (emits no events) for StaticCall assetData', async () => {
|
||||
const txReceipt = await forwarder
|
||||
.transferOut(staticCallAssetData, TRANSFER_AMOUNT)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
expect(txReceipt.logs.length).to.equal(0);
|
||||
});
|
||||
it('reverts if assetData is unsupported', async () => {
|
||||
const randomBytes = hexUtils.random();
|
||||
const tx = forwarder
|
||||
.transferAssetToSender(randomBytes, TRANSFER_AMOUNT)
|
||||
.transferOut(randomBytes, TRANSFER_AMOUNT)
|
||||
.awaitTransactionSuccessAsync({ from: receiver });
|
||||
const expectedError = new ExchangeForwarderRevertErrors.UnsupportedAssetProxyError(
|
||||
hexUtils.slice(randomBytes, 0, 4),
|
||||
|
@@ -5,12 +5,15 @@
|
||||
*/
|
||||
export * from '../test/generated-wrappers/forwarder';
|
||||
export * from '../test/generated-wrappers/i_assets';
|
||||
export * from '../test/generated-wrappers/i_exchange_v2';
|
||||
export * from '../test/generated-wrappers/i_forwarder';
|
||||
export * from '../test/generated-wrappers/i_forwarder_core';
|
||||
export * from '../test/generated-wrappers/lib_asset_data_transfer';
|
||||
export * from '../test/generated-wrappers/lib_constants';
|
||||
export * from '../test/generated-wrappers/lib_forwarder_rich_errors';
|
||||
export * from '../test/generated-wrappers/mixin_assets';
|
||||
export * from '../test/generated-wrappers/mixin_exchange_wrapper';
|
||||
export * from '../test/generated-wrappers/mixin_forwarder_core';
|
||||
export * from '../test/generated-wrappers/mixin_receiver';
|
||||
export * from '../test/generated-wrappers/mixin_weth';
|
||||
export * from '../test/generated-wrappers/test_forwarder';
|
||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
evmVersion: 'istanbul',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
|
@@ -4,15 +4,19 @@
|
||||
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
|
||||
"files": [
|
||||
"generated-artifacts/Forwarder.json",
|
||||
"generated-artifacts/IExchangeV2.json",
|
||||
"test/generated-artifacts/Forwarder.json",
|
||||
"test/generated-artifacts/IAssets.json",
|
||||
"test/generated-artifacts/IExchangeV2.json",
|
||||
"test/generated-artifacts/IForwarder.json",
|
||||
"test/generated-artifacts/IForwarderCore.json",
|
||||
"test/generated-artifacts/LibAssetDataTransfer.json",
|
||||
"test/generated-artifacts/LibConstants.json",
|
||||
"test/generated-artifacts/LibForwarderRichErrors.json",
|
||||
"test/generated-artifacts/MixinAssets.json",
|
||||
"test/generated-artifacts/MixinExchangeWrapper.json",
|
||||
"test/generated-artifacts/MixinForwarderCore.json",
|
||||
"test/generated-artifacts/MixinReceiver.json",
|
||||
"test/generated-artifacts/MixinWeth.json",
|
||||
"test/generated-artifacts/TestForwarder.json"
|
||||
],
|
||||
|
@@ -1,4 +1,23 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "4.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Reference functions for `matchOrders` and `matchOrdersWithMaximalFill`.",
|
||||
"pr": 2437
|
||||
}
|
||||
],
|
||||
"timestamp": 1579682890
|
||||
},
|
||||
{
|
||||
"timestamp": 1578272714,
|
||||
"version": "4.0.3",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v4.1.1 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v4.1.0 - _January 22, 2020_
|
||||
|
||||
* Reference functions for `matchOrders` and `matchOrdersWithMaximalFill`. (#2437)
|
||||
|
||||
## v4.0.3 - _January 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange-libs",
|
||||
"version": "4.0.3",
|
||||
"version": "4.1.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,15 +52,14 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/libs/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.3",
|
||||
"@0x/contracts-gen": "^2.0.3",
|
||||
"@0x/contracts-test-utils": "^5.1.0",
|
||||
"@0x/dev-utils": "^3.1.0",
|
||||
"@0x/sol-compiler": "^4.0.3",
|
||||
"@0x/subproviders": "^6.0.3",
|
||||
"@0x/abi-gen": "^5.1.1",
|
||||
"@0x/contracts-gen": "^2.0.5",
|
||||
"@0x/dev-utils": "^3.1.2",
|
||||
"@0x/sol-compiler": "^4.0.5",
|
||||
"@0x/subproviders": "^6.0.5",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/web3-wrapper": "^7.0.3",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -81,12 +80,13 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.3",
|
||||
"@0x/contracts-utils": "^4.0.3",
|
||||
"@0x/order-utils": "^10.1.0",
|
||||
"@0x/base-contract": "^6.1.1",
|
||||
"@0x/contracts-test-utils": "^5.1.2",
|
||||
"@0x/contracts-utils": "^4.2.0",
|
||||
"@0x/order-utils": "^10.1.2",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/utils": "^5.1.2",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"ethereum-types": "^3.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { orderHashUtils } from '@0x/contracts-test-utils';
|
||||
import { ReferenceFunctions } from '@0x/contracts-utils';
|
||||
import { FillResults, Order } from '@0x/types';
|
||||
import { BigNumber, LibMathRevertErrors } from '@0x/utils';
|
||||
import { FillResults, MatchedFillResults, Order } from '@0x/types';
|
||||
import { BigNumber, ExchangeRevertErrors, LibMathRevertErrors } from '@0x/utils';
|
||||
|
||||
const { safeAdd, safeSub, safeMul, safeDiv } = ReferenceFunctions;
|
||||
|
||||
@@ -114,6 +115,119 @@ export function calculateFillResults(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates amounts filled and fees paid by maker and taker.
|
||||
*/
|
||||
export function calculateMatchResults(
|
||||
leftOrder: Order,
|
||||
rightOrder: Order,
|
||||
protocolFeeMultiplier: BigNumber,
|
||||
gasPrice: BigNumber,
|
||||
withMaximalFill: boolean = false,
|
||||
): MatchedFillResults {
|
||||
// Initialize empty fill results.
|
||||
const leftFillResults: FillResults = {
|
||||
makerAssetFilledAmount: new BigNumber(0),
|
||||
takerAssetFilledAmount: new BigNumber(0),
|
||||
makerFeePaid: new BigNumber(0),
|
||||
takerFeePaid: new BigNumber(0),
|
||||
protocolFeePaid: new BigNumber(0),
|
||||
};
|
||||
const rightFillResults: FillResults = {
|
||||
makerAssetFilledAmount: new BigNumber(0),
|
||||
takerAssetFilledAmount: new BigNumber(0),
|
||||
makerFeePaid: new BigNumber(0),
|
||||
takerFeePaid: new BigNumber(0),
|
||||
protocolFeePaid: new BigNumber(0),
|
||||
};
|
||||
let profitInLeftMakerAsset = new BigNumber(0);
|
||||
let profitInRightMakerAsset = new BigNumber(0);
|
||||
|
||||
// Assert matchable
|
||||
if (
|
||||
leftOrder.makerAssetAmount
|
||||
.times(rightOrder.makerAssetAmount)
|
||||
.lt(leftOrder.takerAssetAmount.times(rightOrder.takerAssetAmount))
|
||||
) {
|
||||
throw new ExchangeRevertErrors.NegativeSpreadError(
|
||||
orderHashUtils.getOrderHashHex(leftOrder),
|
||||
orderHashUtils.getOrderHashHex(rightOrder),
|
||||
);
|
||||
}
|
||||
|
||||
// Asset Transfer Amounts
|
||||
if (leftOrder.takerAssetAmount.gt(rightOrder.makerAssetAmount)) {
|
||||
leftFillResults.makerAssetFilledAmount = safeGetPartialAmountFloor(
|
||||
leftOrder.makerAssetAmount,
|
||||
leftOrder.takerAssetAmount,
|
||||
rightOrder.makerAssetAmount,
|
||||
);
|
||||
leftFillResults.takerAssetFilledAmount = rightOrder.makerAssetAmount;
|
||||
rightFillResults.makerAssetFilledAmount = rightOrder.makerAssetAmount;
|
||||
rightFillResults.takerAssetFilledAmount = rightOrder.takerAssetAmount;
|
||||
} else if (withMaximalFill && leftOrder.makerAssetAmount.lt(rightOrder.takerAssetAmount)) {
|
||||
leftFillResults.makerAssetFilledAmount = leftOrder.makerAssetAmount;
|
||||
leftFillResults.takerAssetFilledAmount = leftOrder.takerAssetAmount;
|
||||
rightFillResults.makerAssetFilledAmount = safeGetPartialAmountFloor(
|
||||
rightOrder.makerAssetAmount,
|
||||
rightOrder.takerAssetAmount,
|
||||
leftOrder.makerAssetAmount,
|
||||
);
|
||||
rightFillResults.takerAssetFilledAmount = leftOrder.makerAssetAmount;
|
||||
} else if (!withMaximalFill && leftOrder.takerAssetAmount.lt(rightOrder.makerAssetAmount)) {
|
||||
leftFillResults.makerAssetFilledAmount = leftOrder.makerAssetAmount;
|
||||
leftFillResults.takerAssetFilledAmount = leftOrder.takerAssetAmount;
|
||||
rightFillResults.makerAssetFilledAmount = leftOrder.takerAssetAmount;
|
||||
rightFillResults.takerAssetFilledAmount = safeGetPartialAmountCeil(
|
||||
rightOrder.takerAssetAmount,
|
||||
rightOrder.makerAssetAmount,
|
||||
leftOrder.takerAssetAmount,
|
||||
);
|
||||
} else {
|
||||
leftFillResults.makerAssetFilledAmount = leftOrder.makerAssetAmount;
|
||||
leftFillResults.takerAssetFilledAmount = leftOrder.takerAssetAmount;
|
||||
rightFillResults.makerAssetFilledAmount = rightOrder.makerAssetAmount;
|
||||
rightFillResults.takerAssetFilledAmount = rightOrder.takerAssetAmount;
|
||||
}
|
||||
|
||||
// Profit
|
||||
profitInLeftMakerAsset = leftFillResults.makerAssetFilledAmount.minus(rightFillResults.makerAssetFilledAmount);
|
||||
profitInRightMakerAsset = rightFillResults.makerAssetFilledAmount.minus(leftFillResults.makerAssetFilledAmount);
|
||||
|
||||
// Fees
|
||||
leftFillResults.makerFeePaid = safeGetPartialAmountFloor(
|
||||
leftFillResults.makerAssetFilledAmount,
|
||||
leftOrder.makerAssetAmount,
|
||||
leftOrder.makerFee,
|
||||
);
|
||||
leftFillResults.takerFeePaid = safeGetPartialAmountFloor(
|
||||
leftFillResults.takerAssetFilledAmount,
|
||||
leftOrder.takerAssetAmount,
|
||||
leftOrder.takerFee,
|
||||
);
|
||||
rightFillResults.makerFeePaid = safeGetPartialAmountFloor(
|
||||
rightFillResults.makerAssetFilledAmount,
|
||||
rightOrder.makerAssetAmount,
|
||||
rightOrder.makerFee,
|
||||
);
|
||||
rightFillResults.takerFeePaid = safeGetPartialAmountFloor(
|
||||
rightFillResults.takerAssetFilledAmount,
|
||||
rightOrder.takerAssetAmount,
|
||||
rightOrder.takerFee,
|
||||
);
|
||||
|
||||
// Protocol Fee
|
||||
leftFillResults.protocolFeePaid = safeMul(protocolFeeMultiplier, gasPrice);
|
||||
rightFillResults.protocolFeePaid = safeMul(protocolFeeMultiplier, gasPrice);
|
||||
|
||||
return {
|
||||
left: leftFillResults,
|
||||
right: rightFillResults,
|
||||
profitInLeftMakerAsset,
|
||||
profitInRightMakerAsset,
|
||||
};
|
||||
}
|
||||
|
||||
export const LibFractions = {
|
||||
add: (n1: BigNumber, d1: BigNumber, n2: BigNumber, d2: BigNumber): [BigNumber, BigNumber] => {
|
||||
if (n1.isZero()) {
|
||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
evmVersion: 'istanbul',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
|
@@ -1,4 +1,23 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "3.1.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "3.1.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Uses updated event decoding to properly decodes arrays and objects.",
|
||||
"pr": 2443
|
||||
}
|
||||
],
|
||||
"timestamp": 1579682890
|
||||
},
|
||||
{
|
||||
"timestamp": 1578272714,
|
||||
"version": "3.0.3",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v3.1.1 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v3.1.0 - _January 22, 2020_
|
||||
|
||||
* Uses updated event decoding to properly decodes arrays and objects. (#2443)
|
||||
|
||||
## v3.0.3 - _January 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-exchange",
|
||||
"version": "3.0.3",
|
||||
"version": "3.1.1",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,21 +52,21 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.3",
|
||||
"@0x/contracts-asset-proxy": "^3.1.0",
|
||||
"@0x/contracts-exchange-libs": "^4.0.3",
|
||||
"@0x/contracts-gen": "^2.0.3",
|
||||
"@0x/contracts-multisig": "^4.0.3",
|
||||
"@0x/contracts-staking": "^2.0.3",
|
||||
"@0x/contracts-test-utils": "^5.1.0",
|
||||
"@0x/contracts-utils": "^4.0.3",
|
||||
"@0x/dev-utils": "^3.1.0",
|
||||
"@0x/sol-compiler": "^4.0.3",
|
||||
"@0x/abi-gen": "^5.1.1",
|
||||
"@0x/contracts-asset-proxy": "^3.1.2",
|
||||
"@0x/contracts-exchange-libs": "^4.1.1",
|
||||
"@0x/contracts-gen": "^2.0.5",
|
||||
"@0x/contracts-multisig": "^4.0.5",
|
||||
"@0x/contracts-staking": "^2.0.5",
|
||||
"@0x/contracts-test-utils": "^5.1.2",
|
||||
"@0x/contracts-utils": "^4.2.0",
|
||||
"@0x/dev-utils": "^3.1.2",
|
||||
"@0x/sol-compiler": "^4.0.5",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"@0x/web3-wrapper": "^7.0.3",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -88,13 +88,13 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.3",
|
||||
"@0x/contracts-dev-utils": "^1.0.3",
|
||||
"@0x/contracts-erc1155": "^2.0.3",
|
||||
"@0x/contracts-erc20": "^3.0.3",
|
||||
"@0x/contracts-erc721": "^3.0.3",
|
||||
"@0x/order-utils": "^10.1.0",
|
||||
"@0x/utils": "^5.1.2",
|
||||
"@0x/base-contract": "^6.1.1",
|
||||
"@0x/contracts-dev-utils": "^1.0.5",
|
||||
"@0x/contracts-erc1155": "^2.0.5",
|
||||
"@0x/contracts-erc20": "^3.0.5",
|
||||
"@0x/contracts-erc721": "^3.0.5",
|
||||
"@0x/order-utils": "^10.1.2",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@@ -121,22 +121,21 @@ blockchainTests('Exchange wrapper functions unit tests.', env => {
|
||||
}
|
||||
}
|
||||
|
||||
function assertSameOrderFromEvent(actual: any[], expected: Order): void {
|
||||
expect(actual.length === 14);
|
||||
expect(actual[0].toLowerCase()).to.be.eq(expected.makerAddress);
|
||||
expect(actual[1].toLowerCase()).to.be.eq(expected.takerAddress);
|
||||
expect(actual[2].toLowerCase()).to.be.eq(expected.feeRecipientAddress);
|
||||
expect(actual[3].toLowerCase()).to.be.eq(expected.senderAddress);
|
||||
expect(actual[4]).to.be.bignumber.eq(expected.makerAssetAmount);
|
||||
expect(actual[5]).to.be.bignumber.eq(expected.takerAssetAmount);
|
||||
expect(actual[6]).to.be.bignumber.eq(expected.makerFee);
|
||||
expect(actual[7]).to.be.bignumber.eq(expected.takerFee);
|
||||
expect(actual[8]).to.be.bignumber.eq(expected.expirationTimeSeconds);
|
||||
expect(actual[9]).to.be.bignumber.eq(expected.salt);
|
||||
expect(actual[10]).to.be.eq(expected.makerAssetData);
|
||||
expect(actual[11]).to.be.eq(expected.takerAssetData);
|
||||
expect(actual[12]).to.be.eq(expected.makerFeeAssetData);
|
||||
expect(actual[13]).to.be.eq(expected.takerFeeAssetData);
|
||||
function assertSameOrderFromEvent(actual: any, expected: Order): void {
|
||||
expect(actual.makerAddress).to.be.eq(expected.makerAddress);
|
||||
expect(actual.takerAddress).to.be.eq(expected.takerAddress);
|
||||
expect(actual.feeRecipientAddress).to.be.eq(expected.feeRecipientAddress);
|
||||
expect(actual.senderAddress).to.be.eq(expected.senderAddress);
|
||||
expect(actual.makerAssetAmount).to.bignumber.eq(expected.makerAssetAmount);
|
||||
expect(actual.takerAssetAmount).to.bignumber.eq(expected.takerAssetAmount);
|
||||
expect(actual.makerFee).to.bignumber.eq(expected.makerFee);
|
||||
expect(actual.takerFee).to.bignumber.eq(expected.takerFee);
|
||||
expect(actual.expirationTimeSeconds).to.bignumber.eq(expected.expirationTimeSeconds);
|
||||
expect(actual.salt).to.bignumber.eq(expected.salt);
|
||||
expect(actual.makerAssetData).to.eq(expected.makerAssetData);
|
||||
expect(actual.takerAssetData).to.eq(expected.takerAssetData);
|
||||
expect(actual.makerFeeAssetData).to.eq(expected.makerFeeAssetData);
|
||||
expect(actual.takerFeeAssetData).to.eq(expected.takerFeeAssetData);
|
||||
}
|
||||
|
||||
describe('fillOrKillOrder', () => {
|
||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
evmVersion: 'istanbul',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
|
@@ -1,4 +1,22 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "5.1.4",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579682890,
|
||||
"version": "5.1.3",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1578272714,
|
||||
"version": "5.1.2",
|
||||
|
@@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v5.1.4 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.1.3 - _January 22, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v5.1.2 - _January 6, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0x/contracts-extensions",
|
||||
"version": "5.1.2",
|
||||
"version": "5.1.4",
|
||||
"engines": {
|
||||
"node": ">=6.12"
|
||||
},
|
||||
@@ -52,24 +52,24 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
|
||||
"devDependencies": {
|
||||
"@0x/abi-gen": "^5.0.3",
|
||||
"@0x/contracts-asset-proxy": "^3.1.0",
|
||||
"@0x/contracts-dev-utils": "^1.0.3",
|
||||
"@0x/contracts-erc20": "^3.0.3",
|
||||
"@0x/contracts-erc721": "^3.0.3",
|
||||
"@0x/contracts-exchange": "^3.0.3",
|
||||
"@0x/contracts-exchange-libs": "^4.0.3",
|
||||
"@0x/contracts-gen": "^2.0.3",
|
||||
"@0x/contracts-test-utils": "^5.1.0",
|
||||
"@0x/contracts-utils": "^4.0.3",
|
||||
"@0x/dev-utils": "^3.1.0",
|
||||
"@0x/order-utils": "^10.1.0",
|
||||
"@0x/sol-compiler": "^4.0.3",
|
||||
"@0x/abi-gen": "^5.1.1",
|
||||
"@0x/contracts-asset-proxy": "^3.1.2",
|
||||
"@0x/contracts-dev-utils": "^1.0.5",
|
||||
"@0x/contracts-erc20": "^3.0.5",
|
||||
"@0x/contracts-erc721": "^3.0.5",
|
||||
"@0x/contracts-exchange": "^3.1.1",
|
||||
"@0x/contracts-exchange-libs": "^4.1.1",
|
||||
"@0x/contracts-gen": "^2.0.5",
|
||||
"@0x/contracts-test-utils": "^5.1.2",
|
||||
"@0x/contracts-utils": "^4.2.0",
|
||||
"@0x/dev-utils": "^3.1.2",
|
||||
"@0x/order-utils": "^10.1.2",
|
||||
"@0x/sol-compiler": "^4.0.5",
|
||||
"@0x/ts-doc-gen": "^0.0.22",
|
||||
"@0x/tslint-config": "^4.0.0",
|
||||
"@0x/types": "^3.1.1",
|
||||
"@0x/utils": "^5.1.2",
|
||||
"@0x/web3-wrapper": "^7.0.3",
|
||||
"@0x/utils": "^5.2.0",
|
||||
"@0x/web3-wrapper": "^7.0.4",
|
||||
"@types/lodash": "4.14.104",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "*",
|
||||
@@ -91,7 +91,7 @@
|
||||
"typescript": "3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0x/base-contract": "^6.0.3",
|
||||
"@0x/base-contract": "^6.1.1",
|
||||
"@0x/typescript-typings": "^5.0.1",
|
||||
"ethereum-types": "^3.0.0"
|
||||
},
|
||||
|
@@ -84,7 +84,7 @@ module.exports = {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
evmVersion: 'constantinople',
|
||||
evmVersion: 'istanbul',
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 1000000,
|
||||
|
@@ -1,4 +1,40 @@
|
||||
[
|
||||
{
|
||||
"timestamp": 1580811564,
|
||||
"version": "2.2.2",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1579744659,
|
||||
"version": "2.2.1",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Dependencies updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add mainnet contract wrapper `callAsync()` revert behavior tests.",
|
||||
"pr": 2433
|
||||
},
|
||||
{
|
||||
"note": "Fuzz tests for `matchOrders` and `matchOrdersWithMaximalFill`.",
|
||||
"pr": 2437
|
||||
},
|
||||
{
|
||||
"note": "Add various negative assertions for fuzz tests",
|
||||
"pr": 2431
|
||||
}
|
||||
],
|
||||
"timestamp": 1579682890
|
||||
},
|
||||
{
|
||||
"version": "2.1.0",
|
||||
"changes": [
|
||||
@@ -9,6 +45,10 @@
|
||||
{
|
||||
"note": "Add aggregator mainnet tests.",
|
||||
"pr": 2407
|
||||
},
|
||||
{
|
||||
"note": "Add fuzz tests for Exchange signature validation.",
|
||||
"pr": 2425
|
||||
}
|
||||
],
|
||||
"timestamp": 1578272714
|
||||
|
@@ -5,10 +5,25 @@ Edit the package's CHANGELOG.json file only.
|
||||
|
||||
CHANGELOG
|
||||
|
||||
## v2.2.2 - _February 4, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.2.1 - _January 23, 2020_
|
||||
|
||||
* Dependencies updated
|
||||
|
||||
## v2.2.0 - _January 22, 2020_
|
||||
|
||||
* Add mainnet contract wrapper `callAsync()` revert behavior tests. (#2433)
|
||||
* Fuzz tests for `matchOrders` and `matchOrdersWithMaximalFill`. (#2437)
|
||||
* Add various negative assertions for fuzz tests (#2431)
|
||||
|
||||
## v2.1.0 - _January 6, 2020_
|
||||
|
||||
* Integration tests for DydxBridge with (i) Exchange v3 and (ii) Mainnet dYdX SoloMargin contract. (#2401)
|
||||
* Add aggregator mainnet tests. (#2407)
|
||||
* Add fuzz tests for Exchange signature validation. (#2425)
|
||||
|
||||
## v2.0.2 - _December 17, 2019_
|
||||
|
||||
|
@@ -4,7 +4,7 @@
|
||||
"useDockerisedSolc": false,
|
||||
"isOfflineMode": false,
|
||||
"compilerSettings": {
|
||||
"evmVersion": "constantinople",
|
||||
"evmVersion": "istanbul",
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
|
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
|
||||
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 no-empty-blocks
|
||||
contract TestContractWrapper {
|
||||
|
||||
uint256 constant public VALID_RETURN_VALUE = 0xf984f922a56ea9a20a32a32f0f60f2d216ff0c0a0d16c986a97a7f1897a6613b;
|
||||
|
||||
function throwStringRevert() external returns (uint256) {
|
||||
revert("ERROR");
|
||||
}
|
||||
|
||||
function throwEmptyRevert() external returns (uint256) {
|
||||
revert();
|
||||
}
|
||||
|
||||
function throwInvalidOpcode() external returns (uint256) {
|
||||
assembly {
|
||||
invalid()
|
||||
}
|
||||
}
|
||||
|
||||
function returnForcedEmpty() external returns (uint256) {
|
||||
assembly {
|
||||
return(0x60, 0)
|
||||
}
|
||||
}
|
||||
|
||||
function returnTruncated() external returns (uint256) {
|
||||
uint256 v = VALID_RETURN_VALUE;
|
||||
assembly {
|
||||
mstore(0x0, v)
|
||||
return(0x0, 16)
|
||||
}
|
||||
}
|
||||
|
||||
function returnEmpty() external { }
|
||||
|
||||
function returnValid() external returns (uint256) {
|
||||
return VALID_RETURN_VALUE;
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.5;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
import "@0x/contracts-utils/contracts/src/LibEIP1271.sol";
|
||||
|
||||
|
||||
contract TestSignatureValidationWallet is
|
||||
LibEIP1271
|
||||
{
|
||||
bytes4 private constant LEGACY_WALLET_MAGIC_VALUE = 0xb0671381;
|
||||
|
||||
// Callback used by `EIP1271Wallet` and `Validator` signature types.
|
||||
function isValidSignature(
|
||||
bytes memory,
|
||||
bytes memory
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return EIP1271_MAGIC_VALUE;
|
||||
}
|
||||
|
||||
// Callback used by `Wallet` signature type.
|
||||
function isValidSignature(
|
||||
bytes32,
|
||||
bytes memory
|
||||
)
|
||||
public
|
||||
pure
|
||||
returns (bytes4 magicValue)
|
||||
{
|
||||
return LEGACY_WALLET_MAGIC_VALUE;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user