Compare commits

..

4 Commits

206 changed files with 3506 additions and 2965 deletions

View File

@@ -1,137 +1,108 @@
name: Continuous Integration
on:
push:
branches:
- main
- development
pull_request:
push:
branches:
- main
- development
pull_request:
jobs:
build:
name: Build and test
runs-on: ubuntu-latest
build:
name: Build and test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: "16"
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build solution
run: yarn build
- name: Lint typescript
run: yarn lint:ts
- name: Lint solidity
run: yarn lint:contracts
- name: Run prettier
run: yarn prettier:ci
- name: Check dependent packages have consistent versions
run: yarn deps_versions:ci
- name: Check diff in docs
run: yarn diff_md_docs:ci
- name: Check for broken links in markdown files
run: yarn test:links
- name: Test doc generation
run: yarn test:generate_docs:ci
- name: Test @0x/contracts-*
run: |
yarn wsrun \
-p @0x/contracts-multisig \
-p @0x/contracts-utils \
-p @0x/contracts-exchange-libs \
-p @0x/contracts-erc20 \
-p @0x/contracts-erc721 \
-p @0x/contracts-erc1155 \
-p @0x/contracts-asset-proxy \
-p @0x/contracts-broker \
-p @0x/contracts-zero-ex \
-m --serial -c test:ci
- name: Test local @0x/contracts-*
run: |
yarn wsrun \
-p @0x/contracts-test-utils \
-p @0x/contract-addresses \
-p @0x/contract-artifacts \
-p @0x/contract-wrappers-test \
-p @0x/order-utils \
-m --serial -c test:ci
- name: Add foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
- name: Run Forge build
working-directory: contracts/zero-ex
run: |
forge --version
forge build --sizes
- name: Run Forge tests
working-directory: contracts/zero-ex
env:
ARBITRUM_RPC_URL: ${{ secrets.ARBITRUM_RPC_URL }}
AVALANCHE_RPC_URL: ${{ secrets.AVALANCHE_RPC_URL }}
BSC_RPC_URL: ${{ secrets.BSC_RPC_URL }}
FANTOM_RPC_URL: ${{ secrets.FANTOM_RPC_URL }}
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
OPTIMISM_RPC_URL: ${{ secrets.OPTIMISM_RPC_URL }}
POLYGON_RPC_URL: ${{ secrets.POLYGON_RPC_URL }}
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
ARBITRUM_RPC_URL: ${{ secrets.ARBITRUM_RPC_URL }}
AVALANCHE_RPC_URL: ${{ secrets.AVALANCHE_RPC_URL }}
BSC_RPC_URL: ${{ secrets.BSC_RPC_URL }}
FANTOM_RPC_URL: ${{ secrets.FANTOM_RPC_URL }}
MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
OPTIMISM_RPC_URL: ${{ secrets.OPTIMISM_RPC_URL }}
POLYGON_RPC_URL: ${{ secrets.POLYGON_RPC_URL }}
run: |
forge test -vvv --gas-report
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '16'
- name: Run Forge coverage
working-directory: contracts/zero-ex
run: |
forge coverage --report lcov
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build solution
run: yarn build
- name: Lint typescript
run: yarn lint:ts
- name: Lint solidity
run: yarn lint:contracts
- name: Run prettier
run: yarn prettier:ci
- name: Check dependent packages have consistent versions
run: yarn deps_versions:ci
- name: Check diff in docs
run: yarn diff_md_docs:ci
- name: Check for broken links in markdown files
run: yarn test:links
- name: Test doc generation
run: yarn test:generate_docs:ci
- name: Test @0x/contracts-*
run: |
yarn wsrun \
-p @0x/contracts-multisig \
-p @0x/contracts-utils \
-p @0x/contracts-exchange-libs \
-p @0x/contracts-erc721 \
-p @0x/contracts-erc1155 \
-p @0x/contracts-asset-proxy \
-p @0x/contracts-broker \
-p @0x/contracts-zero-ex \
-m --serial -c test:ci
- name: Test local @0x/contracts-*
run: |
yarn wsrun \
-p @0x/contracts-test-utils \
-p @0x/contract-addresses \
-p @0x/contract-artifacts \
-p @0x/contract-wrappers-test \
-p @0x/order-utils \
-m --serial -c test:ci
- name: Add foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
- name: Run Forge build for erc20
working-directory: contracts/erc20
run: |
forge --version
forge build --sizes
- name: Run Forge tests for erc20
working-directory: contracts/erc20
run: |
forge test -vvv --gas-report
- name: Run Forge coverage for erc20
working-directory: contracts/erc20
run: |
forge coverage --report summary --report lcov
- name: Upload the coverage report to Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
base-path: ./contracts/erc20/
path-to-lcov: ./contracts/erc20/lcov.info
- name: Run Forge build for zero-ex
working-directory: contracts/zero-ex
run: |
forge --version
forge build --sizes
- name: Run Forge tests for zero-ex
working-directory: contracts/zero-ex
run: |
forge test -vvv --gas-report
- name: Run Forge coverage for zero-ex
working-directory: contracts/zero-ex
run: |
forge coverage --report summary --report lcov
- name: Upload the coverage report to Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
base-path: ./contracts/zero-ex/
path-to-lcov: ./contracts/zero-ex/lcov.info
- name: Check coverage threshold
uses: VeryGoodOpenSource/very_good_coverage@v2
with:
path: ./contracts/zero-ex/lcov.info
min_coverage: 6.98
exclude: '**/tests'
- name: Upload the coverage report to Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
base-path: ./contracts/zero-ex/
path-to-lcov: ./contracts/zero-ex/lcov.info

3
.gitmodules vendored
View File

@@ -1,6 +1,3 @@
[submodule "contracts/zero-ex/contracts/deps/forge-std"]
path = contracts/zero-ex/contracts/deps/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "contracts/erc20/lib/forge-std"]
path = contracts/erc20/lib/forge-std
url = https://github.com/foundry-rs/forge-std

View File

@@ -1,4 +1,4 @@
contracts/erc20/src/ZRXToken.sol
contracts/erc20/contracts/src/ZRXToken.sol
node_modules/
lib
deps

25
contracts/erc20/.eslintrc Normal file
View File

@@ -0,0 +1,25 @@
{
"env": {
"es2021": true,
"node": true
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
"overrides": [],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json",
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"ignorePatterns": [
"lib/**/*",
"contracts/**/*",
"generated-wrappers/**/*",
"generated-artifacts/**/*",
"test/generated-wrappers/**/*",
"test/generated-artifacts/**/*"
],
"rules": {}
}

View File

@@ -1,21 +1,4 @@
[
{
"timestamp": 1677693479,
"version": "4.0.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "4.0.0",
"changes": [
{
"note": "Migrated package to foundry"
}
]
},
{
"timestamp": 1675210931,
"version": "3.3.57",

View File

@@ -5,14 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.0.1 - _March 1, 2023_
* Dependencies updated
## v4.0.0 - _Invalid date_
* Migrated package to foundry
## v3.3.57 - _February 1, 2023_
* Dependencies updated

View File

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

View File

@@ -0,0 +1,93 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "./interfaces/IERC20Token.sol";
contract ERC20Token is IERC20Token {
mapping(address => uint256) internal balances;
mapping(address => mapping(address => uint256)) internal allowed;
uint256 internal _totalSupply;
/// @dev send `value` token to `to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return True if transfer was successful
function transfer(address _to, uint256 _value) external returns (bool) {
require(balances[msg.sender] >= _value, "ERC20_INSUFFICIENT_BALANCE");
require(balances[_to] + _value >= balances[_to], "UINT256_OVERFLOW");
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
/// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return True if transfer was successful
function transferFrom(address _from, address _to, uint256 _value) external returns (bool) {
require(balances[_from] >= _value, "ERC20_INSUFFICIENT_BALANCE");
require(allowed[_from][msg.sender] >= _value, "ERC20_INSUFFICIENT_ALLOWANCE");
require(balances[_to] + _value >= balances[_to], "UINT256_OVERFLOW");
balances[_to] += _value;
balances[_from] -= _value;
allowed[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
}
/// @dev `msg.sender` approves `_spender` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of wei to be approved for transfer
/// @return Always true if the call has enough gas to complete execution
function approve(address _spender, uint256 _value) external returns (bool) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/// @dev Query total supply of token
/// @return Total supply of token
function totalSupply() external view returns (uint256) {
return _totalSupply;
}
/// @dev Query the balance of owner
/// @param _owner The address from which the balance will be retrieved
/// @return Balance of owner
function balanceOf(address _owner) external view returns (uint256) {
return balances[_owner];
}
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens allowed to spent
function allowance(address _owner, address _spender) external view returns (uint256) {
return allowed[_owner][_spender];
}
}

View File

@@ -0,0 +1,136 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "../src/interfaces/IERC20Token.sol";
library LibERC20Token {
bytes private constant DECIMALS_CALL_DATA = hex"313ce567";
/// @dev Calls `IERC20Token(token).approve()`.
/// Reverts if `false` is returned or if the return
/// data length is nonzero and not 32 bytes.
/// @param token The address of the token contract.
/// @param spender The address that receives an allowance.
/// @param allowance The allowance to set.
function approve(address token, address spender, uint256 allowance) internal {
bytes memory callData = abi.encodeWithSelector(IERC20Token(0).approve.selector, spender, allowance);
_callWithOptionalBooleanResult(token, callData);
}
/// @dev Calls `IERC20Token(token).approve()` and sets the allowance to the
/// maximum if the current approval is not already >= an amount.
/// Reverts if `false` is returned or if the return
/// data length is nonzero and not 32 bytes.
/// @param token The address of the token contract.
/// @param spender The address that receives an allowance.
/// @param amount The minimum allowance needed.
function approveIfBelow(address token, address spender, uint256 amount) internal {
if (IERC20Token(token).allowance(address(this), spender) < amount) {
approve(token, spender, uint256(-1));
}
}
/// @dev Calls `IERC20Token(token).transfer()`.
/// Reverts if `false` is returned or if the return
/// data length is nonzero and not 32 bytes.
/// @param token The address of the token contract.
/// @param to The address that receives the tokens
/// @param amount Number of tokens to transfer.
function transfer(address token, address to, uint256 amount) internal {
bytes memory callData = abi.encodeWithSelector(IERC20Token(0).transfer.selector, to, amount);
_callWithOptionalBooleanResult(token, callData);
}
/// @dev Calls `IERC20Token(token).transferFrom()`.
/// Reverts if `false` is returned or if the return
/// data length is nonzero and not 32 bytes.
/// @param token The address of the token contract.
/// @param from The owner of the tokens.
/// @param to The address that receives the tokens
/// @param amount Number of tokens to transfer.
function transferFrom(address token, address from, address to, uint256 amount) internal {
bytes memory callData = abi.encodeWithSelector(IERC20Token(0).transferFrom.selector, from, to, amount);
_callWithOptionalBooleanResult(token, callData);
}
/// @dev Retrieves the number of decimals for a token.
/// Returns `18` if the call reverts.
/// @param token The address of the token contract.
/// @return tokenDecimals The number of decimals places for the token.
function decimals(address token) internal view returns (uint8 tokenDecimals) {
tokenDecimals = 18;
(bool didSucceed, bytes memory resultData) = token.staticcall(DECIMALS_CALL_DATA);
if (didSucceed && resultData.length == 32) {
tokenDecimals = uint8(LibBytes.readUint256(resultData, 0));
}
}
/// @dev Retrieves the allowance for a token, owner, and spender.
/// Returns `0` if the call reverts.
/// @param token The address of the token contract.
/// @param owner The owner of the tokens.
/// @param spender The address the spender.
/// @return allowance The allowance for a token, owner, and spender.
function allowance(address token, address owner, address spender) internal view returns (uint256 allowance_) {
(bool didSucceed, bytes memory resultData) = token.staticcall(
abi.encodeWithSelector(IERC20Token(0).allowance.selector, owner, spender)
);
if (didSucceed && resultData.length == 32) {
allowance_ = LibBytes.readUint256(resultData, 0);
}
}
/// @dev Retrieves the balance for a token owner.
/// Returns `0` if the call reverts.
/// @param token The address of the token contract.
/// @param owner The owner of the tokens.
/// @return balance The token balance of an owner.
function balanceOf(address token, address owner) internal view returns (uint256 balance) {
(bool didSucceed, bytes memory resultData) = token.staticcall(
abi.encodeWithSelector(IERC20Token(0).balanceOf.selector, owner)
);
if (didSucceed && resultData.length == 32) {
balance = LibBytes.readUint256(resultData, 0);
}
}
/// @dev Executes a call on address `target` with calldata `callData`
/// and asserts that either nothing was returned or a single boolean
/// was returned equal to `true`.
/// @param target The call target.
/// @param callData The abi-encoded call data.
function _callWithOptionalBooleanResult(address target, bytes memory callData) private {
(bool didSucceed, bytes memory resultData) = target.call(callData);
if (didSucceed) {
if (resultData.length == 0) {
return;
}
if (resultData.length == 32) {
uint256 result = LibBytes.readUint256(resultData, 0);
if (result == 1) {
return;
}
}
}
LibRichErrors.rrevert(resultData);
}
}

View File

@@ -0,0 +1,46 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "./UnlimitedAllowanceERC20Token.sol";
contract MintableERC20Token is UnlimitedAllowanceERC20Token {
using LibSafeMath for uint256;
/// @dev Mints new tokens
/// @param _to Address of the beneficiary that will own the minted token
/// @param _value Amount of tokens to mint
function _mint(address _to, uint256 _value) internal {
balances[_to] = _value.safeAdd(balances[_to]);
_totalSupply = _totalSupply.safeAdd(_value);
emit Transfer(address(0), _to, _value);
}
/// @dev Mints new tokens
/// @param _owner Owner of tokens that will be burned
/// @param _value Amount of tokens to burn
function _burn(address _owner, uint256 _value) internal {
balances[_owner] = balances[_owner].safeSub(_value);
_totalSupply = _totalSupply.safeSub(_value);
emit Transfer(_owner, address(0), _value);
}
}

View File

@@ -0,0 +1,48 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "./ERC20Token.sol";
contract UnlimitedAllowanceERC20Token is ERC20Token {
uint256 internal constant MAX_UINT = 2 ** 256 - 1;
/// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.
// See https://github.com/ethereum/EIPs/issues/717
/// @param _from Address to transfer from.
/// @param _to Address to transfer to.
/// @param _value Amount to transfer.
/// @return Success of transfer.
function transferFrom(address _from, address _to, uint256 _value) external returns (bool) {
uint256 allowance = allowed[_from][msg.sender];
require(balances[_from] >= _value, "ERC20_INSUFFICIENT_BALANCE");
require(allowance >= _value, "ERC20_INSUFFICIENT_ALLOWANCE");
require(balances[_to] + _value >= balances[_to], "UINT256_OVERFLOW");
balances[_to] += _value;
balances[_from] -= _value;
if (allowance < MAX_UINT) {
allowed[_from][msg.sender] -= _value;
}
emit Transfer(_from, _to, _value);
return true;
}
}

View File

@@ -0,0 +1,57 @@
/*
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 IERC20Token {
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
/// @dev send `value` token to `to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return True if transfer was successful
function transfer(address _to, uint256 _value) external returns (bool);
/// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return True if transfer was successful
function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
/// @dev `msg.sender` approves `_spender` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of wei to be approved for transfer
/// @return Always true if the call has enough gas to complete execution
function approve(address _spender, uint256 _value) external returns (bool);
/// @dev Query total supply of token
/// @return Total supply of token
function totalSupply() external view returns (uint256);
/// @param _owner The address from which the balance will be retrieved
/// @return Balance of owner
function balanceOf(address _owner) external view returns (uint256);
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens allowed to spent
function allowance(address _owner, address _spender) external view returns (uint256);
}

View File

@@ -0,0 +1,27 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "./IERC20Token.sol";
contract IEtherToken is IERC20Token {
function deposit() public payable;
function withdraw(uint256 amount) public;
}

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2023 ZeroEx Intl.
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -17,9 +17,9 @@
*/
pragma solidity >=0.6.5 <0.9;
pragma solidity ^0.6.5;
interface IERC20Token {
interface IERC20TokenV06 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);

View File

@@ -19,9 +19,9 @@
pragma solidity ^0.6.5;
import "./IERC20Token.sol";
import "./IERC20TokenV06.sol";
interface IEtherToken is IERC20Token {
interface IEtherTokenV06 is IERC20TokenV06 {
/// @dev Wrap ether.
function deposit() external payable;

View File

@@ -21,50 +21,50 @@ pragma solidity ^0.6.5;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
import "../IERC20Token.sol";
import "./IERC20TokenV06.sol";
library LibERC20TokenV06 {
bytes private constant DECIMALS_CALL_DATA = hex"313ce567";
/// @dev Calls `IERC20Token(token).approve()`.
/// @dev Calls `IERC20TokenV06(token).approve()`.
/// Reverts if the return data is invalid or the call reverts.
/// @param token The address of the token contract.
/// @param spender The address that receives an allowance.
/// @param allowance The allowance to set.
function compatApprove(IERC20Token token, address spender, uint256 allowance) internal {
function compatApprove(IERC20TokenV06 token, address spender, uint256 allowance) internal {
bytes memory callData = abi.encodeWithSelector(token.approve.selector, spender, allowance);
_callWithOptionalBooleanResult(address(token), callData);
}
/// @dev Calls `IERC20Token(token).approve()` and sets the allowance to the
/// @dev Calls `IERC20TokenV06(token).approve()` and sets the allowance to the
/// maximum if the current approval is not already >= an amount.
/// Reverts if the return data is invalid or the call reverts.
/// @param token The address of the token contract.
/// @param spender The address that receives an allowance.
/// @param amount The minimum allowance needed.
function approveIfBelow(IERC20Token token, address spender, uint256 amount) internal {
function approveIfBelow(IERC20TokenV06 token, address spender, uint256 amount) internal {
if (token.allowance(address(this), spender) < amount) {
compatApprove(token, spender, uint256(-1));
}
}
/// @dev Calls `IERC20Token(token).transfer()`.
/// @dev Calls `IERC20TokenV06(token).transfer()`.
/// Reverts if the return data is invalid or the call reverts.
/// @param token The address of the token contract.
/// @param to The address that receives the tokens
/// @param amount Number of tokens to transfer.
function compatTransfer(IERC20Token token, address to, uint256 amount) internal {
function compatTransfer(IERC20TokenV06 token, address to, uint256 amount) internal {
bytes memory callData = abi.encodeWithSelector(token.transfer.selector, to, amount);
_callWithOptionalBooleanResult(address(token), callData);
}
/// @dev Calls `IERC20Token(token).transferFrom()`.
/// @dev Calls `IERC20TokenV06(token).transferFrom()`.
/// Reverts if the return data is invalid or the call reverts.
/// @param token The address of the token contract.
/// @param from The owner of the tokens.
/// @param to The address that receives the tokens
/// @param amount Number of tokens to transfer.
function compatTransferFrom(IERC20Token token, address from, address to, uint256 amount) internal {
function compatTransferFrom(IERC20TokenV06 token, address from, address to, uint256 amount) internal {
bytes memory callData = abi.encodeWithSelector(token.transferFrom.selector, from, to, amount);
_callWithOptionalBooleanResult(address(token), callData);
}
@@ -73,7 +73,7 @@ library LibERC20TokenV06 {
/// Returns `18` if the call reverts.
/// @param token The address of the token contract.
/// @return tokenDecimals The number of decimals places for the token.
function compatDecimals(IERC20Token token) internal view returns (uint8 tokenDecimals) {
function compatDecimals(IERC20TokenV06 token) internal view returns (uint8 tokenDecimals) {
tokenDecimals = 18;
(bool didSucceed, bytes memory resultData) = address(token).staticcall(DECIMALS_CALL_DATA);
if (didSucceed && resultData.length >= 32) {
@@ -88,7 +88,7 @@ library LibERC20TokenV06 {
/// @param spender The address the spender.
/// @return allowance_ The allowance for a token, owner, and spender.
function compatAllowance(
IERC20Token token,
IERC20TokenV06 token,
address owner,
address spender
) internal view returns (uint256 allowance_) {
@@ -105,7 +105,7 @@ library LibERC20TokenV06 {
/// @param token The address of the token contract.
/// @param owner The owner of the tokens.
/// @return balance The token balance of an owner.
function compatBalanceOf(IERC20Token token, address owner) internal view returns (uint256 balance) {
function compatBalanceOf(IERC20TokenV06 token, address owner) internal view returns (uint256 balance) {
(bool didSucceed, bytes memory resultData) = address(token).staticcall(
abi.encodeWithSelector(token.balanceOf.selector, owner)
);

View File

@@ -0,0 +1,63 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.0;
interface IERC20TokenV08 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
/// @dev send `value` token to `to` from `msg.sender`
/// @param to The address of the recipient
/// @param value The amount of token to be transferred
/// @return True if transfer was successful
function transfer(address to, uint256 value) external returns (bool);
/// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
/// @param from The address of the sender
/// @param to The address of the recipient
/// @param value The amount of token to be transferred
/// @return True if transfer was successful
function transferFrom(address from, address to, uint256 value) external returns (bool);
/// @dev `msg.sender` approves `spender` to spend `value` tokens
/// @param spender The address of the account able to transfer the tokens
/// @param value The amount of wei to be approved for transfer
/// @return Always true if the call has enough gas to complete execution
function approve(address spender, uint256 value) external returns (bool);
/// @dev Query total supply of token
/// @return Total supply of token
function totalSupply() external view returns (uint256);
/// @dev Get the balance of `owner`.
/// @param owner The address from which the balance will be retrieved
/// @return Balance of owner
function balanceOf(address owner) external view returns (uint256);
/// @dev Get the allowance for `spender` to spend from `owner`.
/// @param owner The address of the account owning tokens
/// @param spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens allowed to spent
function allowance(address owner, address spender) external view returns (uint256);
/// @dev Get the number of decimals this token has.
function decimals() external view returns (uint8);
}

View File

@@ -0,0 +1,30 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2020 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.8.0;
import "./IERC20TokenV08.sol";
interface IEtherTokenV08 is IERC20TokenV08 {
/// @dev Wrap ether.
function deposit() external payable;
/// @dev Unwrap ether.
function withdraw(uint256 amount) external;
}

View File

@@ -21,50 +21,50 @@ pragma solidity ^0.8.0;
import "@0x/contracts-utils/contracts/src/v08/errors/LibRichErrorsV08.sol";
import "@0x/contracts-utils/contracts/src/v08/LibBytesV08.sol";
import "../IERC20Token.sol";
import "./IERC20TokenV08.sol";
library LibERC20TokenV08 {
bytes private constant DECIMALS_CALL_DATA = hex"313ce567";
/// @dev Calls `IERC20Token(token).approve()`.
/// @dev Calls `IERC20TokenV08(token).approve()`.
/// Reverts if the return data is invalid or the call reverts.
/// @param token The address of the token contract.
/// @param spender The address that receives an allowance.
/// @param allowance The allowance to set.
function compatApprove(IERC20Token token, address spender, uint256 allowance) internal {
function compatApprove(IERC20TokenV08 token, address spender, uint256 allowance) internal {
bytes memory callData = abi.encodeCall(token.approve, (spender, allowance));
_callWithOptionalBooleanResult(address(token), callData);
}
/// @dev Calls `IERC20Token(token).approve()` and sets the allowance to the
/// @dev Calls `IERC20TokenV08(token).approve()` and sets the allowance to the
/// maximum if the current approval is not already >= an amount.
/// Reverts if the return data is invalid or the call reverts.
/// @param token The address of the token contract.
/// @param spender The address that receives an allowance.
/// @param amount The minimum allowance needed.
function approveIfBelow(IERC20Token token, address spender, uint256 amount) internal {
function approveIfBelow(IERC20TokenV08 token, address spender, uint256 amount) internal {
if (token.allowance(address(this), spender) < amount) {
compatApprove(token, spender, type(uint256).max);
}
}
/// @dev Calls `IERC20Token(token).transfer()`.
/// @dev Calls `IERC20TokenV08(token).transfer()`.
/// Reverts if the return data is invalid or the call reverts.
/// @param token The address of the token contract.
/// @param to The address that receives the tokens
/// @param amount Number of tokens to transfer.
function compatTransfer(IERC20Token token, address to, uint256 amount) internal {
function compatTransfer(IERC20TokenV08 token, address to, uint256 amount) internal {
bytes memory callData = abi.encodeCall(token.transfer, (to, amount));
_callWithOptionalBooleanResult(address(token), callData);
}
/// @dev Calls `IERC20Token(token).transferFrom()`.
/// @dev Calls `IERC20TokenV08(token).transferFrom()`.
/// Reverts if the return data is invalid or the call reverts.
/// @param token The address of the token contract.
/// @param from The owner of the tokens.
/// @param to The address that receives the tokens
/// @param amount Number of tokens to transfer.
function compatTransferFrom(IERC20Token token, address from, address to, uint256 amount) internal {
function compatTransferFrom(IERC20TokenV08 token, address from, address to, uint256 amount) internal {
bytes memory callData = abi.encodeCall(token.transferFrom, (from, to, amount));
_callWithOptionalBooleanResult(address(token), callData);
}
@@ -73,7 +73,7 @@ library LibERC20TokenV08 {
/// Returns `18` if the call reverts.
/// @param token The address of the token contract.
/// @return tokenDecimals The number of decimals places for the token.
function compatDecimals(IERC20Token token) internal view returns (uint8 tokenDecimals) {
function compatDecimals(IERC20TokenV08 token) internal view returns (uint8 tokenDecimals) {
tokenDecimals = 18;
(bool didSucceed, bytes memory resultData) = address(token).staticcall(DECIMALS_CALL_DATA);
if (didSucceed && resultData.length >= 32) {
@@ -88,7 +88,7 @@ library LibERC20TokenV08 {
/// @param spender The address the spender.
/// @return allowance_ The allowance for a token, owner, and spender.
function compatAllowance(
IERC20Token token,
IERC20TokenV08 token,
address owner,
address spender
) internal view returns (uint256 allowance_) {
@@ -105,7 +105,7 @@ library LibERC20TokenV08 {
/// @param token The address of the token contract.
/// @param owner The owner of the tokens.
/// @return balance The token balance of an owner.
function compatBalanceOf(IERC20Token token, address owner) internal view returns (uint256 balance) {
function compatBalanceOf(IERC20TokenV08 token, address owner) internal view returns (uint256 balance) {
(bool didSucceed, bytes memory resultData) = address(token).staticcall(
abi.encodeCall(token.balanceOf, (owner))
);

View File

@@ -0,0 +1,61 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.5;
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "../src/MintableERC20Token.sol";
contract DummyERC20Token is Ownable, MintableERC20Token {
using LibSafeMath for uint256;
string public name;
string public symbol;
uint256 public decimals;
uint256 public constant MAX_MINT_AMOUNT = 10000000000000000000000;
constructor(string memory _name, string memory _symbol, uint256 _decimals, uint256 _totalSupply) public {
name = _name;
symbol = _symbol;
decimals = _decimals;
_totalSupply = _totalSupply;
balances[msg.sender] = _totalSupply;
}
/// @dev Sets the balance of target address
/// @param _target Address or which balance will be updated
/// @param _value New balance of target address
function setBalance(address _target, uint256 _value) external onlyOwner {
uint256 currBalance = balances[_target];
if (_value < currBalance) {
_totalSupply = _totalSupply.safeSub(currBalance.safeSub(_value));
} else {
_totalSupply = _totalSupply.safeAdd(_value.safeSub(currBalance));
}
balances[_target] = _value;
}
/// @dev Mints new tokens for sender
/// @param _value Amount of tokens to mint
function mint(uint256 _value) external {
require(_value <= MAX_MINT_AMOUNT, "VALUE_TOO_LARGE");
_mint(msg.sender, _value);
}
}

View File

@@ -0,0 +1,46 @@
/*
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;
import "./DummyERC20Token.sol";
contract DummyMultipleReturnERC20Token is DummyERC20Token {
constructor(
string memory _name,
string memory _symbol,
uint256 _decimals,
uint256 _totalSupply
) public DummyERC20Token(_name, _symbol, _decimals, _totalSupply) {}
/// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
function transferFrom(address _from, address _to, uint256 _value) external returns (bool) {
emit Transfer(_from, _to, _value);
// HACK: This contract will not compile if we remove `returns (bool)`, so we manually return 64 bytes
// (equiavalent to true, true)
assembly {
mstore(0, 1)
mstore(32, 1)
return(0, 64)
}
}
}

View File

@@ -0,0 +1,69 @@
/*
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;
import "./DummyERC20Token.sol";
contract DummyNoReturnERC20Token is DummyERC20Token {
constructor(
string memory _name,
string memory _symbol,
uint256 _decimals,
uint256 _totalSupply
) public DummyERC20Token(_name, _symbol, _decimals, _totalSupply) {}
/// @dev send `value` token to `to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
function transfer(address _to, uint256 _value) external returns (bool) {
require(balances[msg.sender] >= _value, "ERC20_INSUFFICIENT_BALANCE");
require(balances[_to] + _value >= balances[_to], "UINT256_OVERFLOW");
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
// HACK: This contract will not compile if we remove `returns (bool)`, so we manually return no data
assembly {
return(0, 0)
}
}
/// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
function transferFrom(address _from, address _to, uint256 _value) external returns (bool) {
require(balances[_from] >= _value, "ERC20_INSUFFICIENT_BALANCE");
require(allowed[_from][msg.sender] >= _value, "ERC20_INSUFFICIENT_ALLOWANCE");
require(balances[_to] + _value >= balances[_to], "UINT256_OVERFLOW");
balances[_to] += _value;
balances[_from] -= _value;
allowed[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
// HACK: This contract will not compile if we remove `returns (bool)`, so we manually return no data
assembly {
return(0, 0)
}
}
}

View File

@@ -0,0 +1,73 @@
/*
Copyright 2019 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.5.9;
import "../src/LibERC20Token.sol";
import "./TestLibERC20TokenTarget.sol";
contract TestLibERC20Token {
TestLibERC20TokenTarget public target;
constructor() public {
target = new TestLibERC20TokenTarget();
}
function testApprove(
bool shouldRevert,
bytes calldata revertData,
bytes calldata returnData,
address spender,
uint256 allowance
) external {
target.setBehavior(shouldRevert, revertData, returnData);
LibERC20Token.approve(address(target), spender, allowance);
}
function testTransfer(
bool shouldRevert,
bytes calldata revertData,
bytes calldata returnData,
address to,
uint256 amount
) external {
target.setBehavior(shouldRevert, revertData, returnData);
LibERC20Token.transfer(address(target), to, amount);
}
function testTransferFrom(
bool shouldRevert,
bytes calldata revertData,
bytes calldata returnData,
address from,
address to,
uint256 amount
) external {
target.setBehavior(shouldRevert, revertData, returnData);
LibERC20Token.transferFrom(address(target), from, to, amount);
}
function testDecimals(
bool shouldRevert,
bytes calldata revertData,
bytes calldata returnData
) external returns (uint8) {
target.setBehavior(shouldRevert, revertData, returnData);
return LibERC20Token.decimals(address(target));
}
}

View File

@@ -0,0 +1,69 @@
/*
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 TestLibERC20TokenTarget {
event ApproveCalled(address spender, uint256 allowance);
event TransferCalled(address to, uint256 amount);
event TransferFromCalled(address from, address to, uint256 amount);
bool private _shouldRevert;
bytes private _revertData;
bytes private _returnData;
function setBehavior(bool shouldRevert, bytes calldata revertData, bytes calldata returnData) external {
_shouldRevert = shouldRevert;
_revertData = revertData;
_returnData = returnData;
}
function approve(address spender, uint256 allowance) external returns (bool) {
emit ApproveCalled(spender, allowance);
_execute();
}
function transfer(address to, uint256 amount) external returns (bool) {
emit TransferCalled(to, amount);
_execute();
}
function transferFrom(address from, address to, uint256 amount) external returns (bool) {
emit TransferFromCalled(from, to, amount);
_execute();
}
function decimals() external view returns (uint8) {
_execute();
}
function _execute() private view {
if (_shouldRevert) {
bytes memory revertData = _revertData;
assembly {
revert(add(revertData, 0x20), mload(revertData))
}
}
bytes memory returnData = _returnData;
assembly {
return(add(returnData, 0x20), mload(returnData))
}
}
}

View File

@@ -0,0 +1,38 @@
/*
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;
import "./DummyERC20Token.sol";
contract UntransferrableDummyERC20Token is DummyERC20Token {
constructor(
string memory _name,
string memory _symbol,
uint256 _decimals,
uint256 _totalSupply
) public DummyERC20Token(_name, _symbol, _decimals, _totalSupply) {}
/// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
function transferFrom(address _from, address _to, uint256 _value) external returns (bool) {
require(false, "TRANSFER_DISABLED");
}
}

View File

@@ -1,18 +0,0 @@
[profile.default]
src = 'src'
out = 'out'
libs = [
'lib',
'node_modules',
]
remappings = [
'@0x/contracts-utils/=../utils/'
]
allow_paths = [
'../utils/'
]
fs_permissions = [{ access = "read", path = "./out/ZRXToken.sol" }]
optimizer_runs = 1_000_000
# See more config options https://github.com/foundry-rs/foundry/tree/master/config

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-erc20",
"version": "4.0.1",
"version": "3.3.57",
"engines": {
"node": ">=6.12"
},
@@ -10,10 +10,31 @@
"test": "test"
},
"scripts": {
"test:ci": "forge test",
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
"compile": "sol-compiler",
"watch": "sol-compiler -w",
"clean": "shx rm -rf lib test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --debug --abis ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
"lint": "eslint src test",
"fix": "eslint --fix src test",
"test:ci": "yarn test",
"contracts:gen": "contracts-gen generate",
"contracts:copy": "contracts-gen copy",
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
"docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
},
"config": {
"publicInterfaceContracts": "DummyERC20Token,ERC20Token,WETH9,ZRXToken,DummyNoReturnERC20Token,DummyMultipleReturnERC20Token",
"abis": "./test/generated-artifacts/@(DummyERC20Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|ERC20Token|IERC20Token|IERC20TokenV06|IERC20TokenV08|IEtherToken|IEtherTokenV06|IEtherTokenV08|LibERC20Token|LibERC20TokenV06|LibERC20TokenV08|MintableERC20Token|TestLibERC20Token|TestLibERC20TokenTarget|UnlimitedAllowanceERC20Token|UntransferrableDummyERC20Token|WETH9|WETH9V06|ZRXToken).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/protocol.git"
@@ -22,11 +43,42 @@
"bugs": {
"url": "https://github.com/0xProject/protocol/issues"
},
"homepage": "https://github.com/0xProject/protocol",
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
"devDependencies": {
"@0x/contracts-utils": "^4.8.39",
"@0x/abi-gen": "^5.8.1",
"@0x/contracts-gen": "^2.0.48",
"@0x/contracts-test-utils": "^5.4.47",
"@0x/contracts-utils": "^4.8.38",
"@0x/dev-utils": "^5.0.0",
"@0x/sol-compiler": "^4.8.2",
"@0x/ts-doc-gen": "^0.0.28",
"typedoc": "~0.16.11"
"@0x/types": "^3.3.6",
"@0x/typescript-typings": "^5.3.1",
"@0x/utils": "^7.0.0",
"@0x/web3-wrapper": "^8.0.0",
"@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7",
"@types/node": "12.12.54",
"@typescript-eslint/eslint-plugin": "^5.38.0",
"@typescript-eslint/parser": "^5.38.0",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^3.0.0",
"dirty-chai": "^2.0.1",
"eslint": "^8.23.1",
"eslint-config-prettier": "^8.5.0",
"ethereum-types": "^3.7.1",
"lodash": "^4.17.11",
"make-promises-safe": "^1.1.0",
"mocha": "^6.2.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"typedoc": "~0.16.11",
"typescript": "4.6.3"
},
"dependencies": {
"@0x/base-contract": "^7.0.0",
"ethers": "~4.0.4"
},
"publishConfig": {
"access": "public"

View File

@@ -0,0 +1,21 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
import { ContractArtifact } from 'ethereum-types';
import * as DummyERC20Token from '../generated-artifacts/DummyERC20Token.json';
import * as DummyMultipleReturnERC20Token from '../generated-artifacts/DummyMultipleReturnERC20Token.json';
import * as DummyNoReturnERC20Token from '../generated-artifacts/DummyNoReturnERC20Token.json';
import * as ERC20Token from '../generated-artifacts/ERC20Token.json';
import * as WETH9 from '../generated-artifacts/WETH9.json';
import * as ZRXToken from '../generated-artifacts/ZRXToken.json';
export const artifacts = {
DummyERC20Token: DummyERC20Token as ContractArtifact,
ERC20Token: ERC20Token as ContractArtifact,
WETH9: WETH9 as ContractArtifact,
ZRXToken: ZRXToken as any as ContractArtifact,
DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact,
DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
};

View File

@@ -0,0 +1,47 @@
export {
DummyERC20TokenContract,
DummyMultipleReturnERC20TokenContract,
DummyNoReturnERC20TokenContract,
WETH9Contract,
WETH9Events,
WETH9DepositEventArgs,
WETH9TransferEventArgs,
WETH9WithdrawalEventArgs,
ZRXTokenContract,
DummyERC20TokenTransferEventArgs,
ERC20TokenEventArgs,
ERC20TokenEvents,
ERC20TokenTransferEventArgs,
ERC20TokenApprovalEventArgs,
ERC20TokenContract,
} from './wrappers';
export { artifacts } from './artifacts';
export {
ContractArtifact,
ContractChains,
CompilerOpts,
StandardContractOutput,
CompilerSettings,
ContractChainData,
ContractAbi,
DevdocOutput,
EvmOutput,
CompilerSettingsMetadata,
OptimizerSettings,
OutputField,
ParamDescription,
EvmBytecodeOutput,
EvmBytecodeOutputLinkReferences,
AbiDefinition,
FunctionAbi,
EventAbi,
RevertErrorAbi,
EventParameter,
DataItem,
MethodAbi,
ConstructorAbi,
FallbackAbi,
ConstructorStateMutability,
TupleDataItem,
StateMutability,
} from 'ethereum-types';

View File

@@ -0,0 +1,11 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../generated-wrappers/dummy_erc20_token';
export * from '../generated-wrappers/dummy_multiple_return_erc20_token';
export * from '../generated-wrappers/dummy_no_return_erc20_token';
export * from '../generated-wrappers/erc20_token';
export * from '../generated-wrappers/weth9';
export * from '../generated-wrappers/zrx_token';

View File

@@ -1,76 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2023 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.6.5;
pragma experimental ABIEncoderV2;
import "forge-std/Test.sol";
import "../src/v06/WETH9V06.sol";
contract WETH9V06Test is Test {
address payable internal owner = payable(vm.addr(1));
address payable internal user = payable(vm.addr(2));
WETH9V06 internal etherToken;
function setUp() public {
vm.deal(owner, 1e20);
vm.deal(user, 1e20);
etherToken = new WETH9V06();
}
function testShouldRevertIfCallerAttemptsToDepositMoreThanTheirBalance() public {
vm.prank(user);
vm.expectRevert();
etherToken.deposit{value: 1e20 + 1}();
}
function testShouldConvertDepositedETHToWrappedETH() public {
vm.prank(user);
etherToken.deposit{value: 1e20}();
vm.stopPrank();
assertEq(etherToken.balanceOf(user), 1e20);
assertEq(address(etherToken).balance, 1e20);
}
function testShouldRevertIfCallerAttemptsToWithdrawMoreThanTheirBalance() public {
vm.prank(user);
etherToken.deposit{value: 1e20}();
vm.expectRevert();
etherToken.withdraw(1e20 + 1);
}
function testShouldConvertWithdrawWrappedETHToETH() public {
vm.prank(user);
etherToken.deposit{value: 1e20}();
vm.prank(user);
etherToken.withdraw(100);
vm.stopPrank();
assertEq(etherToken.balanceOf(user), 1e20 - 100);
assertEq(address(etherToken).balance, 1e20 - 100);
assertEq(user.balance, 100);
}
function testShouldConvertSentETHToWrappedETH() public {
vm.prank(user);
address(etherToken).call{value: 1e20}(new bytes(0));
vm.stopPrank();
assertEq(etherToken.balanceOf(user), 1e20);
assertEq(address(etherToken).balance, 1e20);
}
}

View File

@@ -1,117 +0,0 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2023 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.8.17;
import "forge-std/Test.sol";
import "../src/IERC20Token.sol";
contract ZRXTokenTest is Test {
address payable internal owner = payable(vm.addr(1));
address payable internal user = payable(vm.addr(2));
address payable internal anotherUser = payable(vm.addr(3));
uint256 internal totalSupply = 1_000_000_000 * 1e18;
IERC20Token zrxToken;
function setUp() public {
vm.deal(owner, 1e20);
vm.deal(user, 1e20);
vm.prank(owner);
bytes memory _bytecode = vm.getCode("./out/ZRXToken.sol/ZRXToken.json");
address _address;
assembly {
_address := create(0, add(_bytecode, 0x20), mload(_bytecode))
}
vm.stopPrank();
zrxToken = IERC20Token(address(_address));
}
function testShouldHave18Decimals() public {
assertEq(zrxToken.decimals(), 18);
}
function testShouldHaveTotalSupplyOf1Billion() public {
assertEq(zrxToken.totalSupply(), totalSupply);
}
function testShouldInitializeOwnerBalanceToTotalSupply() public {
assertEq(zrxToken.balanceOf(owner), totalSupply);
}
function testShouldTransferBalanceCorrectly() public {
vm.prank(owner);
zrxToken.transfer(user, 100);
assertEq(zrxToken.balanceOf(user), 100);
assertEq(zrxToken.balanceOf(owner), totalSupply - 100);
}
function testShouldReturnTrueOnAZeroValueTransfer() public {
vm.prank(owner);
bool success = zrxToken.transfer(user, 0);
assertTrue(success);
}
function testShouldReturnTrueOnAZeroValueTransferByUserWithZeroBalance() public {
vm.prank(anotherUser);
bool success = zrxToken.transfer(user, 0);
assertTrue(success);
}
function testShouldReturnFalseIfSenderHasInsufficientBalance() public {
vm.prank(owner);
zrxToken.approve(user, totalSupply + 1);
vm.stopPrank();
bool success = zrxToken.transferFrom(owner, user, totalSupply + 1);
assertEq(success, false);
}
function testShouldReturnFalseIfRecipientHasInsufficientAllowance() public {
vm.prank(owner);
zrxToken.approve(user, totalSupply - 1);
vm.stopPrank();
bool success = zrxToken.transferFrom(owner, user, totalSupply);
assertEq(success, false);
}
function testShouldReturnTrueOnAZeroValueApprovedTransfer() public {
vm.prank(user);
bool success = zrxToken.transferFrom(owner, user, 0);
assertEq(success, true);
}
function testShouldNotModifySenderAllowanceIfSetToUINT256Max() public {
vm.prank(owner);
zrxToken.approve(user, type(uint256).max);
vm.stopPrank();
zrxToken.transferFrom(owner, user, 100);
assertEq(zrxToken.allowance(owner, user), type(uint256).max);
}
function testShouldTransferCorrectlyWhenSufficientAllowance() public {
vm.prank(owner);
zrxToken.approve(user, 1000 * 1e18);
vm.stopPrank();
vm.prank(user);
zrxToken.transferFrom(owner, user, 100 * 1e18);
assertEq(zrxToken.allowance(owner, user), 900 * 1e18);
assertEq(zrxToken.balanceOf(user), 100 * 1e18);
assertEq(zrxToken.balanceOf(owner), totalSupply - 100 * 1e18);
}
}

View File

@@ -0,0 +1,51 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
import { ContractArtifact } from 'ethereum-types';
import * as DummyERC20Token from '../test/generated-artifacts/DummyERC20Token.json';
import * as DummyMultipleReturnERC20Token from '../test/generated-artifacts/DummyMultipleReturnERC20Token.json';
import * as DummyNoReturnERC20Token from '../test/generated-artifacts/DummyNoReturnERC20Token.json';
import * as ERC20Token from '../test/generated-artifacts/ERC20Token.json';
import * as IERC20Token from '../test/generated-artifacts/IERC20Token.json';
import * as IERC20TokenV06 from '../test/generated-artifacts/IERC20TokenV06.json';
import * as IERC20TokenV08 from '../test/generated-artifacts/IERC20TokenV08.json';
import * as IEtherToken from '../test/generated-artifacts/IEtherToken.json';
import * as IEtherTokenV06 from '../test/generated-artifacts/IEtherTokenV06.json';
import * as IEtherTokenV08 from '../test/generated-artifacts/IEtherTokenV08.json';
import * as LibERC20Token from '../test/generated-artifacts/LibERC20Token.json';
import * as LibERC20TokenV06 from '../test/generated-artifacts/LibERC20TokenV06.json';
import * as LibERC20TokenV08 from '../test/generated-artifacts/LibERC20TokenV08.json';
import * as MintableERC20Token from '../test/generated-artifacts/MintableERC20Token.json';
import * as TestLibERC20Token from '../test/generated-artifacts/TestLibERC20Token.json';
import * as TestLibERC20TokenTarget from '../test/generated-artifacts/TestLibERC20TokenTarget.json';
import * as UnlimitedAllowanceERC20Token from '../test/generated-artifacts/UnlimitedAllowanceERC20Token.json';
import * as UntransferrableDummyERC20Token from '../test/generated-artifacts/UntransferrableDummyERC20Token.json';
import * as WETH9 from '../test/generated-artifacts/WETH9.json';
import * as WETH9V06 from '../test/generated-artifacts/WETH9V06.json';
import * as ZRXToken from '../test/generated-artifacts/ZRXToken.json';
export const artifacts = {
ERC20Token: ERC20Token as ContractArtifact,
LibERC20Token: LibERC20Token as ContractArtifact,
MintableERC20Token: MintableERC20Token as ContractArtifact,
UnlimitedAllowanceERC20Token: UnlimitedAllowanceERC20Token as ContractArtifact,
WETH9: WETH9 as ContractArtifact,
ZRXToken: ZRXToken as any as ContractArtifact,
IERC20Token: IERC20Token as ContractArtifact,
IEtherToken: IEtherToken as ContractArtifact,
IERC20TokenV06: IERC20TokenV06 as ContractArtifact,
IEtherTokenV06: IEtherTokenV06 as ContractArtifact,
LibERC20TokenV06: LibERC20TokenV06 as ContractArtifact,
WETH9V06: WETH9V06 as ContractArtifact,
IERC20TokenV08: IERC20TokenV08 as ContractArtifact,
IEtherTokenV08: IEtherTokenV08 as ContractArtifact,
LibERC20TokenV08: LibERC20TokenV08 as ContractArtifact,
DummyERC20Token: DummyERC20Token as ContractArtifact,
DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact,
TestLibERC20Token: TestLibERC20Token as ContractArtifact,
TestLibERC20TokenTarget: TestLibERC20TokenTarget as ContractArtifact,
UntransferrableDummyERC20Token: UntransferrableDummyERC20Token as ContractArtifact,
};

View File

@@ -0,0 +1,335 @@
import {
blockchainTests,
constants,
expect,
getRandomInteger,
randomAddress,
verifyEventsFromLogs,
} from '@0x/contracts-test-utils';
import { hexUtils, RawRevertError, StringRevertError } from '@0x/utils';
import { TestLibERC20TokenContract, TestLibERC20TokenTargetEvents } from './wrappers';
import { artifacts } from './artifacts';
blockchainTests('LibERC20Token', env => {
let testContract: TestLibERC20TokenContract;
const REVERT_STRING = 'WHOOPSIE';
const ENCODED_REVERT = new StringRevertError(REVERT_STRING).encode();
const ENCODED_TRUE = hexUtils.leftPad(1);
const ENCODED_FALSE = hexUtils.leftPad(0);
const ENCODED_TWO = hexUtils.leftPad(2);
const ENCODED_SHORT_TRUE = hexUtils.leftPad(2, 31);
const ENCODED_LONG_TRUE = hexUtils.leftPad(2, 33);
before(async () => {
testContract = await TestLibERC20TokenContract.deployFrom0xArtifactAsync(
artifacts.TestLibERC20Token,
env.provider,
env.txDefaults,
artifacts,
);
});
describe('approve()', () => {
it('calls the target with the correct arguments', async () => {
const spender = randomAddress();
const allowance = getRandomInteger(0, 100e18);
const { logs } = await testContract
.testApprove(false, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
.awaitTransactionSuccessAsync();
expect(logs).to.be.length(1);
verifyEventsFromLogs(logs, [{ spender, allowance }], TestLibERC20TokenTargetEvents.ApproveCalled);
});
it('succeeds if the target returns true', async () => {
const spender = randomAddress();
const allowance = getRandomInteger(0, 100e18);
await testContract
.testApprove(false, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
.awaitTransactionSuccessAsync();
});
it('succeeds if the target returns nothing', async () => {
const spender = randomAddress();
const allowance = getRandomInteger(0, 100e18);
await testContract
.testApprove(false, ENCODED_REVERT, constants.NULL_BYTES, spender, allowance)
.awaitTransactionSuccessAsync();
});
it('fails if the target returns false', async () => {
const spender = randomAddress();
const allowance = getRandomInteger(0, 100e18);
const tx = testContract
.testApprove(false, ENCODED_REVERT, ENCODED_FALSE, spender, allowance)
.awaitTransactionSuccessAsync();
const expectedError = new RawRevertError(ENCODED_FALSE);
return expect(tx).to.revertWith(expectedError);
});
it('fails if the target returns nonzero and not true', async () => {
const spender = randomAddress();
const allowance = getRandomInteger(0, 100e18);
const tx = testContract
.testApprove(false, ENCODED_REVERT, ENCODED_TWO, spender, allowance)
.awaitTransactionSuccessAsync();
const expectedError = new RawRevertError(ENCODED_TWO);
return expect(tx).to.revertWith(expectedError);
});
it('fails if the target returns less than 32 bytes', async () => {
const spender = randomAddress();
const allowance = getRandomInteger(0, 100e18);
const tx = testContract
.testApprove(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, spender, allowance)
.awaitTransactionSuccessAsync();
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
return expect(tx).to.revertWith(expectedError);
});
it('fails if the target returns greater than 32 bytes', async () => {
const spender = randomAddress();
const allowance = getRandomInteger(0, 100e18);
const tx = testContract
.testApprove(false, ENCODED_REVERT, ENCODED_LONG_TRUE, spender, allowance)
.awaitTransactionSuccessAsync();
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
return expect(tx).to.revertWith(expectedError);
});
it('fails if the target reverts', async () => {
const spender = randomAddress();
const allowance = getRandomInteger(0, 100e18);
const tx = testContract
.testApprove(true, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
.awaitTransactionSuccessAsync();
return expect(tx).to.revertWith(REVERT_STRING);
});
it('fails if the target reverts with no data', async () => {
const spender = randomAddress();
const allowance = getRandomInteger(0, 100e18);
const tx = testContract
.testApprove(true, constants.NULL_BYTES, ENCODED_TRUE, spender, allowance)
.awaitTransactionSuccessAsync();
return expect(tx).to.be.rejectedWith('revert');
});
});
describe('transfer()', () => {
it('calls the target with the correct arguments', async () => {
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const { logs } = await testContract
.testTransfer(false, ENCODED_REVERT, ENCODED_TRUE, to, amount)
.awaitTransactionSuccessAsync();
expect(logs).to.be.length(1);
verifyEventsFromLogs(logs, [{ to, amount }], TestLibERC20TokenTargetEvents.TransferCalled);
});
it('succeeds if the target returns true', async () => {
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
await testContract
.testTransfer(false, ENCODED_REVERT, ENCODED_TRUE, to, amount)
.awaitTransactionSuccessAsync();
});
it('succeeds if the target returns nothing', async () => {
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
await testContract
.testTransfer(false, ENCODED_REVERT, constants.NULL_BYTES, to, amount)
.awaitTransactionSuccessAsync();
});
it('fails if the target returns false', async () => {
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const tx = testContract
.testTransfer(false, ENCODED_REVERT, ENCODED_FALSE, to, amount)
.awaitTransactionSuccessAsync();
const expectedError = new RawRevertError(ENCODED_FALSE);
return expect(tx).to.revertWith(expectedError);
});
it('fails if the target returns nonzero and not true', async () => {
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const tx = testContract
.testTransfer(false, ENCODED_REVERT, ENCODED_TWO, to, amount)
.awaitTransactionSuccessAsync();
const expectedError = new RawRevertError(ENCODED_TWO);
return expect(tx).to.revertWith(expectedError);
});
it('fails if the target returns less than 32 bytes', async () => {
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const tx = testContract
.testTransfer(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, to, amount)
.awaitTransactionSuccessAsync();
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
return expect(tx).to.revertWith(expectedError);
});
it('fails if the target returns greater than 32 bytes', async () => {
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const tx = testContract
.testTransfer(false, ENCODED_REVERT, ENCODED_LONG_TRUE, to, amount)
.awaitTransactionSuccessAsync();
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
return expect(tx).to.revertWith(expectedError);
});
it('fails if the target reverts', async () => {
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const tx = testContract
.testTransfer(true, ENCODED_REVERT, ENCODED_TRUE, to, amount)
.awaitTransactionSuccessAsync();
return expect(tx).to.revertWith(REVERT_STRING);
});
it('fails if the target reverts with no data', async () => {
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const tx = testContract
.testTransfer(true, constants.NULL_BYTES, ENCODED_TRUE, to, amount)
.awaitTransactionSuccessAsync();
return expect(tx).to.be.rejectedWith('revert');
});
});
describe('transferFrom()', () => {
it('calls the target with the correct arguments', async () => {
const owner = randomAddress();
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const { logs } = await testContract
.testTransferFrom(false, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
.awaitTransactionSuccessAsync();
expect(logs).to.be.length(1);
verifyEventsFromLogs(logs, [{ from: owner, to, amount }], TestLibERC20TokenTargetEvents.TransferFromCalled);
});
it('succeeds if the target returns true', async () => {
const owner = randomAddress();
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
await testContract
.testTransferFrom(false, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
.awaitTransactionSuccessAsync();
});
it('succeeds if the target returns nothing', async () => {
const owner = randomAddress();
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
await testContract
.testTransferFrom(false, ENCODED_REVERT, constants.NULL_BYTES, owner, to, amount)
.awaitTransactionSuccessAsync();
});
it('fails if the target returns false', async () => {
const owner = randomAddress();
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const tx = testContract
.testTransferFrom(false, ENCODED_REVERT, ENCODED_FALSE, owner, to, amount)
.awaitTransactionSuccessAsync();
const expectedError = new RawRevertError(ENCODED_FALSE);
return expect(tx).to.revertWith(expectedError);
});
it('fails if the target returns nonzero and not true', async () => {
const owner = randomAddress();
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const tx = testContract
.testTransferFrom(false, ENCODED_REVERT, ENCODED_TWO, owner, to, amount)
.awaitTransactionSuccessAsync();
const expectedError = new RawRevertError(ENCODED_TWO);
return expect(tx).to.revertWith(expectedError);
});
it('fails if the target returns less than 32 bytes', async () => {
const owner = randomAddress();
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const tx = testContract
.testTransferFrom(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, owner, to, amount)
.awaitTransactionSuccessAsync();
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
return expect(tx).to.revertWith(expectedError);
});
it('fails if the target returns greater than 32 bytes', async () => {
const owner = randomAddress();
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const tx = testContract
.testTransferFrom(false, ENCODED_REVERT, ENCODED_LONG_TRUE, owner, to, amount)
.awaitTransactionSuccessAsync();
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
return expect(tx).to.revertWith(expectedError);
});
it('fails if the target reverts', async () => {
const owner = randomAddress();
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const tx = testContract
.testTransferFrom(true, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
.awaitTransactionSuccessAsync();
return expect(tx).to.revertWith(REVERT_STRING);
});
it('fails if the target reverts with no data', async () => {
const owner = randomAddress();
const to = randomAddress();
const amount = getRandomInteger(0, 100e18);
const tx = testContract
.testTransferFrom(true, constants.NULL_BYTES, ENCODED_TRUE, owner, to, amount)
.awaitTransactionSuccessAsync();
return expect(tx).to.be.rejectedWith('revert');
});
});
describe('decimals()', () => {
const DEFAULT_DECIMALS = 18;
const ENCODED_ZERO = hexUtils.leftPad(0);
const ENCODED_SHORT_ZERO = hexUtils.leftPad(0, 31);
const ENCODED_LONG_ZERO = hexUtils.leftPad(0, 33);
const randomDecimals = () => Math.floor(Math.random() * 256) + 1;
it('returns the number of decimals defined by the token', async () => {
const decimals = randomDecimals();
const encodedDecimals = hexUtils.leftPad(decimals);
const result = await testContract.testDecimals(false, ENCODED_REVERT, encodedDecimals).callAsync();
return expect(result).to.bignumber.eq(decimals);
});
it('returns 0 if the token returns 0', async () => {
const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_ZERO).callAsync();
return expect(result).to.bignumber.eq(0);
});
it('returns 18 if the token returns less than 32 bytes', async () => {
const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_SHORT_ZERO).callAsync();
return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
});
it('returns 18 if the token returns greater than 32 bytes', async () => {
const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_LONG_ZERO).callAsync();
return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
});
it('returns 18 if the token reverts', async () => {
const result = await testContract.testDecimals(true, ENCODED_REVERT, ENCODED_ZERO).callAsync();
return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
});
});
});

View File

@@ -0,0 +1,187 @@
import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import { DummyERC20TokenContract } from './wrappers';
import { artifacts } from './artifacts';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('UnlimitedAllowanceToken', () => {
let owner: string;
let spender: string;
const MAX_MINT_VALUE = new BigNumber(10000000000000000000000);
let token: DummyERC20TokenContract;
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
owner = accounts[0];
spender = accounts[1];
token = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
artifacts.DummyERC20Token,
provider,
txDefaults,
artifacts,
constants.DUMMY_TOKEN_NAME,
constants.DUMMY_TOKEN_SYMBOL,
constants.DUMMY_TOKEN_DECIMALS,
constants.DUMMY_TOKEN_TOTAL_SUPPLY,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await token.mint(MAX_MINT_VALUE).sendTransactionAsync({ from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('transfer', () => {
it('should revert if owner has insufficient balance', async () => {
const ownerBalance = await token.balanceOf(owner).callAsync();
const amountToTransfer = ownerBalance.plus(1);
return expect(token.transfer(spender, amountToTransfer).callAsync({ from: owner })).to.revertWith(
RevertReason.Erc20InsufficientBalance,
);
});
it('should transfer balance from sender to receiver', async () => {
const receiver = spender;
const initOwnerBalance = await token.balanceOf(owner).callAsync();
const amountToTransfer = new BigNumber(1);
await web3Wrapper.awaitTransactionSuccessAsync(
await token.transfer(receiver, amountToTransfer).sendTransactionAsync({ from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const finalOwnerBalance = await token.balanceOf(owner).callAsync();
const finalReceiverBalance = await token.balanceOf(receiver).callAsync();
const expectedFinalOwnerBalance = initOwnerBalance.minus(amountToTransfer);
const expectedFinalReceiverBalance = amountToTransfer;
expect(finalOwnerBalance).to.be.bignumber.equal(expectedFinalOwnerBalance);
expect(finalReceiverBalance).to.be.bignumber.equal(expectedFinalReceiverBalance);
});
it('should return true on a 0 value transfer', async () => {
const didReturnTrue = await token.transfer(spender, new BigNumber(0)).callAsync({
from: owner,
});
expect(didReturnTrue).to.be.true();
});
});
describe('transferFrom', () => {
it('should revert if owner has insufficient balance', async () => {
const ownerBalance = await token.balanceOf(owner).callAsync();
const amountToTransfer = ownerBalance.plus(1);
await web3Wrapper.awaitTransactionSuccessAsync(
await token.approve(spender, amountToTransfer).sendTransactionAsync({ from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
return expect(
token.transferFrom(owner, spender, amountToTransfer).callAsync({
from: spender,
}),
).to.revertWith(RevertReason.Erc20InsufficientBalance);
});
it('should revert if spender has insufficient allowance', async () => {
const ownerBalance = await token.balanceOf(owner).callAsync();
const amountToTransfer = ownerBalance;
const spenderAllowance = await token.allowance(owner, spender).callAsync();
const isSpenderAllowanceInsufficient = spenderAllowance.comparedTo(amountToTransfer) < 0;
expect(isSpenderAllowanceInsufficient).to.be.true();
return expect(
token.transferFrom(owner, spender, amountToTransfer).callAsync({
from: spender,
}),
).to.revertWith(RevertReason.Erc20InsufficientAllowance);
});
it('should return true on a 0 value transfer', async () => {
const amountToTransfer = new BigNumber(0);
const didReturnTrue = await token.transferFrom(owner, spender, amountToTransfer).callAsync({
from: spender,
});
expect(didReturnTrue).to.be.true();
});
it('should not modify spender allowance if spender allowance is 2^256 - 1', async () => {
const initOwnerBalance = await token.balanceOf(owner).callAsync();
const amountToTransfer = initOwnerBalance;
const initSpenderAllowance = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
await web3Wrapper.awaitTransactionSuccessAsync(
await token.approve(spender, initSpenderAllowance).sendTransactionAsync({ from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await token.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
from: spender,
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const newSpenderAllowance = await token.allowance(owner, spender).callAsync();
expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance);
});
it('should transfer the correct balances if spender has sufficient allowance', async () => {
const initOwnerBalance = await token.balanceOf(owner).callAsync();
const amountToTransfer = initOwnerBalance;
const initSpenderAllowance = initOwnerBalance;
await web3Wrapper.awaitTransactionSuccessAsync(
await token.approve(spender, initSpenderAllowance).sendTransactionAsync({ from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await token.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
from: spender,
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const newOwnerBalance = await token.balanceOf(owner).callAsync();
const newSpenderBalance = await token.balanceOf(spender).callAsync();
expect(newOwnerBalance).to.be.bignumber.equal(0);
expect(newSpenderBalance).to.be.bignumber.equal(initOwnerBalance);
});
it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => {
const initOwnerBalance = await token.balanceOf(owner).callAsync();
const amountToTransfer = initOwnerBalance;
const initSpenderAllowance = initOwnerBalance;
await web3Wrapper.awaitTransactionSuccessAsync(
await token.approve(spender, initSpenderAllowance).sendTransactionAsync({ from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await token.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
from: spender,
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const newSpenderAllowance = await token.allowance(owner, spender).callAsync();
expect(newSpenderAllowance).to.be.bignumber.equal(0);
});
});
});

View File

@@ -0,0 +1,149 @@
import {
chaiSetup,
constants,
expectInsufficientFundsAsync,
expectTransactionFailedWithoutReasonAsync,
provider,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as chai from 'chai';
import { WETH9Contract } from './wrappers';
import { artifacts } from './artifacts';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('EtherToken', () => {
let account: string;
const gasPrice = new BigNumber(constants.DEFAULT_GAS_PRICE);
let etherToken: WETH9Contract;
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
account = accounts[0];
etherToken = await WETH9Contract.deployFrom0xArtifactAsync(
artifacts.WETH9,
provider,
{
...txDefaults,
gasPrice,
},
artifacts,
);
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('deposit', () => {
it('should revert if caller attempts to deposit more Ether than caller balance', async () => {
const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
const ethToDeposit = initEthBalance.plus(1);
return expectInsufficientFundsAsync(etherToken.deposit().sendTransactionAsync({ value: ethToDeposit }));
});
it('should convert deposited Ether to wrapped Ether tokens', async () => {
const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
const initEthTokenBalance = await etherToken.balanceOf(account).callAsync();
const ethToDeposit = new BigNumber(Web3Wrapper.toWei(new BigNumber(1)));
const txHash = await etherToken.deposit().sendTransactionAsync({ value: ethToDeposit });
const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
txHash,
constants.AWAIT_TRANSACTION_MINED_MS,
);
const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
const finalEthTokenBalance = await etherToken.balanceOf(account).callAsync();
expect(finalEthBalance).to.be.bignumber.equal(initEthBalance.minus(ethToDeposit.plus(ethSpentOnGas)));
expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.plus(ethToDeposit));
});
});
describe('withdraw', () => {
it('should revert if caller attempts to withdraw greater than caller balance', async () => {
const initEthTokenBalance = await etherToken.balanceOf(account).callAsync();
const ethTokensToWithdraw = initEthTokenBalance.plus(1);
return expectTransactionFailedWithoutReasonAsync(
etherToken.withdraw(ethTokensToWithdraw).sendTransactionAsync(),
);
});
it('should convert ether tokens to ether with sufficient balance', async () => {
const ethToDeposit = new BigNumber(Web3Wrapper.toWei(new BigNumber(1)));
await web3Wrapper.awaitTransactionSuccessAsync(
await etherToken.deposit().sendTransactionAsync({ value: ethToDeposit }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const initEthTokenBalance = await etherToken.balanceOf(account).callAsync();
const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
const ethTokensToWithdraw = initEthTokenBalance;
expect(ethTokensToWithdraw).to.not.be.bignumber.equal(0);
const txHash = await etherToken.withdraw(ethTokensToWithdraw).sendTransactionAsync({
gas: constants.MAX_ETHERTOKEN_WITHDRAW_GAS,
});
const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
txHash,
constants.AWAIT_TRANSACTION_MINED_MS,
);
const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
const finalEthTokenBalance = await etherToken.balanceOf(account).callAsync();
expect(finalEthBalance).to.be.bignumber.equal(
initEthBalance.plus(ethTokensToWithdraw.minus(ethSpentOnGas)),
);
expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.minus(ethTokensToWithdraw));
});
});
describe('fallback', () => {
it('should convert sent ether to ether tokens', async () => {
const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
const initEthTokenBalance = await etherToken.balanceOf(account).callAsync();
const ethToDeposit = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18);
const txHash = await web3Wrapper.sendTransactionAsync({
from: account,
to: etherToken.address,
value: ethToDeposit,
gasPrice,
});
const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
txHash,
constants.AWAIT_TRANSACTION_MINED_MS,
);
const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
const finalEthTokenBalance = await etherToken.balanceOf(account).callAsync();
expect(finalEthBalance).to.be.bignumber.equal(initEthBalance.minus(ethToDeposit.plus(ethSpentOnGas)));
expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.plus(ethToDeposit));
});
});
});

View File

@@ -0,0 +1,26 @@
/*
* -----------------------------------------------------------------------------
* Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* -----------------------------------------------------------------------------
*/
export * from '../test/generated-wrappers/dummy_erc20_token';
export * from '../test/generated-wrappers/dummy_multiple_return_erc20_token';
export * from '../test/generated-wrappers/dummy_no_return_erc20_token';
export * from '../test/generated-wrappers/erc20_token';
export * from '../test/generated-wrappers/i_erc20_token';
export * from '../test/generated-wrappers/i_erc20_token_v06';
export * from '../test/generated-wrappers/i_erc20_token_v08';
export * from '../test/generated-wrappers/i_ether_token';
export * from '../test/generated-wrappers/i_ether_token_v06';
export * from '../test/generated-wrappers/i_ether_token_v08';
export * from '../test/generated-wrappers/lib_erc20_token';
export * from '../test/generated-wrappers/lib_erc20_token_v06';
export * from '../test/generated-wrappers/lib_erc20_token_v08';
export * from '../test/generated-wrappers/mintable_erc20_token';
export * from '../test/generated-wrappers/test_lib_erc20_token';
export * from '../test/generated-wrappers/test_lib_erc20_token_target';
export * from '../test/generated-wrappers/unlimited_allowance_erc20_token';
export * from '../test/generated-wrappers/untransferrable_dummy_erc20_token';
export * from '../test/generated-wrappers/weth9';
export * from '../test/generated-wrappers/weth9v06';
export * from '../test/generated-wrappers/zrx_token';

View File

@@ -0,0 +1,210 @@
import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as chai from 'chai';
import { ZRXTokenContract } from './wrappers';
import { artifacts } from './artifacts';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('ZRXToken', () => {
let owner: string;
let spender: string;
let MAX_UINT: BigNumber;
let zrxToken: ZRXTokenContract;
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
owner = accounts[0];
spender = accounts[1];
zrxToken = await ZRXTokenContract.deployFrom0xArtifactAsync(
artifacts.ZRXToken,
provider,
txDefaults,
artifacts,
);
MAX_UINT = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('constants', () => {
it('should have 18 decimals', async () => {
const decimals = new BigNumber(await zrxToken.decimals().callAsync());
const expectedDecimals = 18;
expect(decimals).to.be.bignumber.equal(expectedDecimals);
});
it('should have a total supply of 1 billion tokens', async () => {
const totalSupply = new BigNumber(await zrxToken.totalSupply().callAsync());
const expectedTotalSupply = 1000000000;
expect(Web3Wrapper.toUnitAmount(totalSupply, 18)).to.be.bignumber.equal(expectedTotalSupply);
});
it('should be named 0x Protocol Token', async () => {
const name = await zrxToken.name().callAsync();
const expectedName = '0x Protocol Token';
expect(name).to.be.equal(expectedName);
});
it('should have the symbol ZRX', async () => {
const symbol = await zrxToken.symbol().callAsync();
const expectedSymbol = 'ZRX';
expect(symbol).to.be.equal(expectedSymbol);
});
});
describe('constructor', () => {
it('should initialize owner balance to totalSupply', async () => {
const ownerBalance = await zrxToken.balanceOf(owner).callAsync();
const totalSupply = new BigNumber(await zrxToken.totalSupply().callAsync());
expect(totalSupply).to.be.bignumber.equal(ownerBalance);
});
});
describe('transfer', () => {
it('should transfer balance from sender to receiver', async () => {
const receiver = spender;
const initOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
const amountToTransfer = new BigNumber(1);
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.transfer(receiver, amountToTransfer).sendTransactionAsync({ from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const finalOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
const finalReceiverBalance = await zrxToken.balanceOf(receiver).callAsync();
const expectedFinalOwnerBalance = initOwnerBalance.minus(amountToTransfer);
const expectedFinalReceiverBalance = amountToTransfer;
expect(finalOwnerBalance).to.be.bignumber.equal(expectedFinalOwnerBalance);
expect(finalReceiverBalance).to.be.bignumber.equal(expectedFinalReceiverBalance);
});
it('should return true on a 0 value transfer', async () => {
const didReturnTrue = await zrxToken.transfer(spender, new BigNumber(0)).callAsync({
from: owner,
});
expect(didReturnTrue).to.be.true();
});
});
describe('transferFrom', () => {
it('should return false if owner has insufficient balance', async () => {
const ownerBalance = await zrxToken.balanceOf(owner).callAsync();
const amountToTransfer = ownerBalance.plus(1);
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.approve(spender, amountToTransfer).sendTransactionAsync({
from: owner,
gas: constants.MAX_TOKEN_APPROVE_GAS,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const didReturnTrue = await zrxToken.transferFrom(owner, spender, amountToTransfer).callAsync({
from: spender,
});
expect(didReturnTrue).to.be.false();
});
it('should return false if spender has insufficient allowance', async () => {
const ownerBalance = await zrxToken.balanceOf(owner).callAsync();
const amountToTransfer = ownerBalance;
const spenderAllowance = await zrxToken.allowance(owner, spender).callAsync();
const isSpenderAllowanceInsufficient = spenderAllowance.comparedTo(amountToTransfer) < 0;
expect(isSpenderAllowanceInsufficient).to.be.true();
const didReturnTrue = await zrxToken.transferFrom(owner, spender, amountToTransfer).callAsync({
from: spender,
});
expect(didReturnTrue).to.be.false();
});
it('should return true on a 0 value transfer', async () => {
const amountToTransfer = new BigNumber(0);
const didReturnTrue = await zrxToken.transferFrom(owner, spender, amountToTransfer).callAsync({
from: spender,
});
expect(didReturnTrue).to.be.true();
});
it('should not modify spender allowance if spender allowance is 2^256 - 1', async () => {
const initOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
const amountToTransfer = initOwnerBalance;
const initSpenderAllowance = MAX_UINT;
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.approve(spender, initSpenderAllowance).sendTransactionAsync({
from: owner,
gas: constants.MAX_TOKEN_APPROVE_GAS,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
from: spender,
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const newSpenderAllowance = await zrxToken.allowance(owner, spender).callAsync();
expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance);
});
it('should transfer the correct balances if spender has sufficient allowance', async () => {
const initOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
const initSpenderBalance = await zrxToken.balanceOf(spender).callAsync();
const amountToTransfer = initOwnerBalance;
const initSpenderAllowance = initOwnerBalance;
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.approve(spender, initSpenderAllowance).sendTransactionAsync(),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
from: spender,
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const newOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
const newSpenderBalance = await zrxToken.balanceOf(spender).callAsync();
expect(newOwnerBalance).to.be.bignumber.equal(0);
expect(newSpenderBalance).to.be.bignumber.equal(initSpenderBalance.plus(initOwnerBalance));
});
it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => {
const initOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
const amountToTransfer = initOwnerBalance;
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.approve(spender, amountToTransfer).sendTransactionAsync(),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
from: spender,
gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const newSpenderAllowance = await zrxToken.allowance(owner, spender).callAsync();
expect(newSpenderAllowance).to.be.bignumber.equal(0);
});
});
});

View File

@@ -0,0 +1,35 @@
{
"extends": "../../tsconfig",
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"generated-artifacts/DummyERC20Token.json",
"generated-artifacts/DummyMultipleReturnERC20Token.json",
"generated-artifacts/DummyNoReturnERC20Token.json",
"generated-artifacts/ERC20Token.json",
"generated-artifacts/WETH9.json",
"generated-artifacts/ZRXToken.json",
"test/generated-artifacts/DummyERC20Token.json",
"test/generated-artifacts/DummyMultipleReturnERC20Token.json",
"test/generated-artifacts/DummyNoReturnERC20Token.json",
"test/generated-artifacts/ERC20Token.json",
"test/generated-artifacts/IERC20Token.json",
"test/generated-artifacts/IERC20TokenV06.json",
"test/generated-artifacts/IERC20TokenV08.json",
"test/generated-artifacts/IEtherToken.json",
"test/generated-artifacts/IEtherTokenV06.json",
"test/generated-artifacts/IEtherTokenV08.json",
"test/generated-artifacts/LibERC20Token.json",
"test/generated-artifacts/LibERC20TokenV06.json",
"test/generated-artifacts/LibERC20TokenV08.json",
"test/generated-artifacts/MintableERC20Token.json",
"test/generated-artifacts/TestLibERC20Token.json",
"test/generated-artifacts/TestLibERC20TokenTarget.json",
"test/generated-artifacts/UnlimitedAllowanceERC20Token.json",
"test/generated-artifacts/UntransferrableDummyERC20Token.json",
"test/generated-artifacts/WETH9.json",
"test/generated-artifacts/WETH9V06.json",
"test/generated-artifacts/ZRXToken.json"
],
"exclude": ["./deploy/solc/solc_bin"]
}

View File

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

View File

@@ -1,13 +1,4 @@
[
{
"timestamp": 1677693479,
"version": "5.4.48",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1675210931,
"version": "5.4.47",

View File

@@ -5,10 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v5.4.48 - _March 1, 2023_
* Dependencies updated
## v5.4.47 - _February 1, 2023_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-test-utils",
"version": "5.4.48",
"version": "5.4.47",
"engines": {
"node": ">=6.12"
},
@@ -41,7 +41,7 @@
"dependencies": {
"@0x/assert": "^3.0.35",
"@0x/base-contract": "^7.0.0",
"@0x/contract-addresses": "^8.1.0",
"@0x/contract-addresses": "^8.0.3",
"@0x/dev-utils": "^5.0.0",
"@0x/json-schemas": "^6.4.4",
"@0x/order-utils": "^10.4.28",

View File

@@ -1,13 +1,4 @@
[
{
"timestamp": 1677693479,
"version": "1.4.41",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1675210931,
"version": "1.4.40",

View File

@@ -5,10 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v1.4.41 - _March 1, 2023_
* Dependencies updated
## v1.4.40 - _February 1, 2023_
* Dependencies updated

View File

@@ -20,19 +20,19 @@
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "./IStaking.sol";
contract DefaultPoolOperator {
// Immutables
IStaking public immutable stakingProxy;
IERC20Token public immutable weth;
IERC20TokenV06 public immutable weth;
bytes32 public immutable poolId;
/// @dev Initializes this contract and creates a staking pool.
/// @param stakingProxy_ The 0x staking proxy contract.
/// @param weth_ The WETH token contract.
constructor(IStaking stakingProxy_, IERC20Token weth_) public {
constructor(IStaking stakingProxy_, IERC20TokenV06 weth_) public {
stakingProxy = stakingProxy_;
weth = weth_;
// operator share = 100%

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-treasury",
"version": "1.4.41",
"version": "1.4.40",
"engines": {
"node": ">=6.12"
},
@@ -46,12 +46,12 @@
"homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury",
"devDependencies": {
"@0x/abi-gen": "^5.8.1",
"@0x/contract-addresses": "^8.1.0",
"@0x/contract-addresses": "^8.0.3",
"@0x/contracts-asset-proxy": "^3.7.19",
"@0x/contracts-erc20": "3.3.57",
"@0x/contracts-erc20": "^3.3.57",
"@0x/contracts-gen": "^2.0.48",
"@0x/contracts-staking": "^2.0.45",
"@0x/contracts-test-utils": "^5.4.48",
"@0x/contracts-test-utils": "^5.4.47",
"@0x/sol-compiler": "^4.8.2",
"@0x/ts-doc-gen": "^0.0.28",
"@types/isomorphic-fetch": "^0.0.35",
@@ -73,7 +73,7 @@
},
"dependencies": {
"@0x/base-contract": "^7.0.0",
"@0x/protocol-utils": "^11.18.0",
"@0x/protocol-utils": "^11.17.6",
"@0x/subproviders": "^7.0.0",
"@0x/types": "^3.3.6",
"@0x/typescript-typings": "^5.3.1",

View File

@@ -1,13 +1,4 @@
[
{
"timestamp": 1677693479,
"version": "4.8.39",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1675210931,
"version": "4.8.38",

View File

@@ -5,10 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v4.8.39 - _March 1, 2023_
* Dependencies updated
## v4.8.38 - _February 1, 2023_
* Dependencies updated

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-utils",
"version": "4.8.39",
"version": "4.8.38",
"engines": {
"node": ">=6.12"
},
@@ -46,7 +46,7 @@
"devDependencies": {
"@0x/abi-gen": "^5.8.1",
"@0x/contracts-gen": "^2.0.48",
"@0x/contracts-test-utils": "^5.4.48",
"@0x/contracts-test-utils": "^5.4.47",
"@0x/dev-utils": "^5.0.0",
"@0x/order-utils": "^10.4.28",
"@0x/sol-compiler": "^4.8.2",

View File

@@ -1,16 +1,4 @@
[
{
"version": "0.39.0",
"changes": [
{
"note": "Add KyberElastic mixin for Ethereum, Polygon, Arbitrum, Avalanche"
},
{
"note": "Skip chain id validation in AbstractBridgeAdapter on testnets"
}
],
"timestamp": 1677693479
},
{
"timestamp": 1675210931,
"version": "0.38.6",

View File

@@ -5,11 +5,6 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v0.39.0 - _March 1, 2023_
* Add KyberElastic mixin for Ethereum, Polygon, Arbitrum, Avalanche
* Skip chain id validation in AbstractBridgeAdapter on testnets
## v0.38.6 - _February 1, 2023_
* Dependencies updated

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/AuthorizableV06.sol";
import "../vendor/v3/IStaking.sol";
@@ -33,14 +33,14 @@ contract FeeCollector is AuthorizableV06 {
/// @param weth The WETH contract.
/// @param staking The staking contract.
/// @param poolId The pool ID this contract is collecting fees for.
function initialize(IEtherToken weth, IStaking staking, bytes32 poolId) external onlyAuthorized {
function initialize(IEtherTokenV06 weth, IStaking staking, bytes32 poolId) external onlyAuthorized {
weth.approve(address(staking), type(uint256).max);
staking.joinStakingPoolAsMaker(poolId);
}
/// @dev Convert all held ether to WETH. Only an authority can call this.
/// @param weth The WETH contract.
function convertToWeth(IEtherToken weth) external onlyAuthorized {
function convertToWeth(IEtherTokenV06 weth) external onlyAuthorized {
if (address(this).balance > 0) {
weth.deposit{value: address(this).balance}();
}

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "../vendor/v3/IStaking.sol";
import "./FeeCollector.sol";
import "./LibFeeCollector.sol";
@@ -25,11 +25,11 @@ contract FeeCollectorController {
/// @dev Hash of the fee collector init code.
bytes32 public immutable FEE_COLLECTOR_INIT_CODE_HASH;
/// @dev The WETH contract.
IEtherToken private immutable WETH;
IEtherTokenV06 private immutable WETH;
/// @dev The staking contract.
IStaking private immutable STAKING;
constructor(IEtherToken weth, IStaking staking) public {
constructor(IEtherTokenV06 weth, IStaking staking) public {
FEE_COLLECTOR_INIT_CODE_HASH = keccak256(type(FeeCollector).creationCode);
WETH = weth;
STAKING = staking;

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../vendor/ILiquidityProvider.sol";
interface ILiquidityProviderSandbox {
@@ -29,8 +29,8 @@ interface ILiquidityProviderSandbox {
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
function executeSellTokenForToken(
ILiquidityProvider provider,
IERC20Token inputToken,
IERC20Token outputToken,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
@@ -45,7 +45,7 @@ interface ILiquidityProviderSandbox {
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
function executeSellEthForToken(
ILiquidityProvider provider,
IERC20Token outputToken,
IERC20TokenV06 outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
@@ -60,7 +60,7 @@ interface ILiquidityProviderSandbox {
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
function executeSellTokenForEth(
ILiquidityProvider provider,
IERC20Token inputToken,
IERC20TokenV06 inputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData

View File

@@ -17,7 +17,7 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/errors/LibOwnableRichErrorsV06.sol";
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../vendor/ILiquidityProvider.sol";
import "../vendor/v3/IERC20Bridge.sol";
import "./ILiquidityProviderSandbox.sol";
@@ -52,8 +52,8 @@ contract LiquidityProviderSandbox is ILiquidityProviderSandbox {
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
function executeSellTokenForToken(
ILiquidityProvider provider,
IERC20Token inputToken,
IERC20Token outputToken,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
@@ -70,7 +70,7 @@ contract LiquidityProviderSandbox is ILiquidityProviderSandbox {
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
function executeSellEthForToken(
ILiquidityProvider provider,
IERC20Token outputToken,
IERC20TokenV06 outputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData
@@ -87,7 +87,7 @@ contract LiquidityProviderSandbox is ILiquidityProviderSandbox {
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
function executeSellTokenForEth(
ILiquidityProvider provider,
IERC20Token inputToken,
IERC20TokenV06 inputToken,
address recipient,
uint256 minBuyAmount,
bytes calldata auxiliaryData

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../migrations/LibMigrate.sol";
import "../fixins/FixinCommon.sol";
import "./interfaces/IFeature.sol";
@@ -41,7 +41,7 @@ contract FundRecoveryFeature is IFeature, IFundRecoveryFeature, FixinCommon {
/// @param amountOut Amount of tokens to withdraw.
/// @param recipientWallet Recipient wallet address.
function transferTrappedTokensTo(
IERC20Token erc20,
IERC20TokenV06 erc20,
uint256 amountOut,
address payable recipientWallet
) external override onlyOwner {

View File

@@ -15,9 +15,10 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../errors/LibLiquidityProviderRichErrors.sol";
import "../external/ILiquidityProviderSandbox.sol";
import "../external/LiquidityProviderSandbox.sol";
@@ -66,8 +67,8 @@ contract LiquidityProviderFeature is IFeature, ILiquidityProviderFeature, FixinC
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellToLiquidityProvider(
IERC20Token inputToken,
IERC20Token outputToken,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
ILiquidityProvider provider,
address recipient,
uint256 sellAmount,
@@ -91,7 +92,7 @@ contract LiquidityProviderFeature is IFeature, ILiquidityProviderFeature, FixinC
if (LibERC20Transformer.isTokenETH(inputToken)) {
uint256 balanceBefore = outputToken.balanceOf(recipient);
sandbox.executeSellEthForToken(provider, outputToken, recipient, minBuyAmount, auxiliaryData);
boughtAmount = IERC20Token(outputToken).balanceOf(recipient).safeSub(balanceBefore);
boughtAmount = IERC20TokenV06(outputToken).balanceOf(recipient).safeSub(balanceBefore);
} else if (LibERC20Transformer.isTokenETH(outputToken)) {
uint256 balanceBefore = recipient.balance;
sandbox.executeSellTokenForEth(provider, inputToken, recipient, minBuyAmount, auxiliaryData);

View File

@@ -15,6 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
@@ -27,6 +28,7 @@ import "../migrations/LibMigrate.sol";
import "../storage/LibMetaTransactionsStorage.sol";
import "./interfaces/IFeature.sol";
import "./interfaces/IMetaTransactionsFeature.sol";
import "./interfaces/IMultiplexFeature.sol";
import "./interfaces/INativeOrdersFeature.sol";
import "./interfaces/ITransformERC20Feature.sol";
import "./libs/LibSignature.sol";
@@ -63,8 +65,8 @@ contract MetaTransactionsFeature is
/// @dev Arguments for a `TransformERC20.transformERC20()` call.
struct ExternalTransformERC20Args {
IERC20Token inputToken;
IERC20Token outputToken;
IERC20TokenV06 inputToken;
IERC20TokenV06 outputToken;
uint256 inputTokenAmount;
uint256 minOutputTokenAmount;
ITransformERC20Feature.Transformation[] transformations;
@@ -91,6 +93,9 @@ contract MetaTransactionsFeature is
")"
);
/// @dev The WETH token contract.
IEtherTokenV06 private immutable WETH;
/// @dev Refunds up to `msg.value` leftover ETH at the end of the call.
modifier refundsAttachedEth() {
_;
@@ -108,7 +113,12 @@ contract MetaTransactionsFeature is
require(initialBalance <= address(this).balance, "MetaTransactionsFeature/ETH_LEAK");
}
constructor(address zeroExAddress) public FixinCommon() FixinEIP712(zeroExAddress) {}
constructor(
address zeroExAddress,
IEtherTokenV06 weth
) public FixinCommon() FixinEIP712(zeroExAddress) {
WETH = weth;
}
/// @dev Initialize and register this feature.
/// Should be delegatecalled by `Migrate.migrate()`.
@@ -245,6 +255,14 @@ contract MetaTransactionsFeature is
returnResult = _executeFillLimitOrderCall(state);
} else if (state.selector == INativeOrdersFeature.fillRfqOrder.selector) {
returnResult = _executeFillRfqOrderCall(state);
} else if (state.selector == IMultiplexFeature.multiplexBatchSellTokenForToken.selector) {
returnResult = _executeMultiplexBatchSellTokenForTokenCall(state);
} else if (state.selector == IMultiplexFeature.multiplexBatchSellTokenForEth.selector) {
returnResult = _executeMultiplexBatchSellTokenForEthCall(state);
} else if (state.selector == IMultiplexFeature.multiplexMultiHopSellTokenForToken.selector) {
returnResult = _executeMultiplexMultiHopSellTokenForTokenCall(state);
} else if (state.selector == IMultiplexFeature.multiplexMultiHopSellTokenForEth.selector) {
returnResult = _executeMultiplexMultiHopSellTokenForEthCall(state);
} else {
LibMetaTransactionsRichErrors.MetaTransactionUnsupportedFunctionError(state.hash, state.selector).rrevert();
}
@@ -426,7 +444,7 @@ contract MetaTransactionsFeature is
/// @dev Execute a `INativeOrdersFeature.fillRfqOrder()` meta-transaction call
/// by decoding the call args and translating the call to the internal
/// `INativeOrdersFeature._fillRfqOrder()` variant, where we can overrideunimpleme
/// `INativeOrdersFeature._fillRfqOrder()` variant, where we can override
/// the taker address.
function _executeFillRfqOrderCall(ExecuteState memory state) private returns (bytes memory returnResult) {
LibNativeOrder.RfqOrder memory order;
@@ -455,6 +473,162 @@ contract MetaTransactionsFeature is
);
}
/// @dev Execute a `IMultiplexFeature.multiplexBatchSellTokenForToken()` meta-transaction
/// call by decoding the call args and translating the call to the internal
/// `IMultiplexFeature._multiplexBatchSell()` variant, where we can override the
/// msgSender address.
function _executeMultiplexBatchSellTokenForTokenCall(ExecuteState memory state) private returns (bytes memory returnResult) {
IERC20TokenV06 inputToken;
IERC20TokenV06 outputToken;
IMultiplexFeature.BatchSellSubcall[] memory calls;
uint256 sellAmount;
uint256 minBuyAmount;
bytes memory args = _extractArgumentsFromCallData(state.mtx.callData);
(inputToken, outputToken, calls, sellAmount, minBuyAmount) = abi.decode(
args,
(IERC20TokenV06, IERC20TokenV06, IMultiplexFeature.BatchSellSubcall[], uint256, uint256)
);
return
_callSelf(
state.hash,
abi.encodeWithSelector(
IMultiplexFeature._multiplexBatchSell.selector,
IMultiplexFeature.BatchSellParams({
inputToken: inputToken,
outputToken: outputToken,
sellAmount: sellAmount,
calls: calls,
useSelfBalance: false,
recipient: state.mtx.signer,
msgSender: state.mtx.signer
}),
minBuyAmount
),
state.mtx.value
);
}
/// @dev Execute a `IMultiplexFeature.multiplexBatchSellTokenForEth()` meta-transaction
/// call by decoding the call args and translating the call to the internal
/// `IMultiplexFeature._multiplexBatchSellTokenForEth()` variant, where we can override the
/// msgSender address.
function _executeMultiplexBatchSellTokenForEthCall(ExecuteState memory state) private returns (bytes memory returnResult) {
IERC20TokenV06 inputToken;
IMultiplexFeature.BatchSellSubcall[] memory calls;
uint256 sellAmount;
uint256 minBuyAmount;
bytes memory args = _extractArgumentsFromCallData(state.mtx.callData);
(inputToken, calls, sellAmount, minBuyAmount) = abi.decode(
args,
(IERC20TokenV06, IMultiplexFeature.BatchSellSubcall[], uint256, uint256)
);
returnResult = _callSelf(
state.hash,
abi.encodeWithSelector(
IMultiplexFeature._multiplexBatchSell.selector,
IMultiplexFeature.BatchSellParams({
inputToken: inputToken,
outputToken: IERC20TokenV06(WETH),
sellAmount: sellAmount,
calls: calls,
useSelfBalance: false,
recipient: address(this),
msgSender: state.mtx.signer
}),
minBuyAmount
),
state.mtx.value
);
// Unwrap and transfer WETH
uint256 boughtAmount = abi.decode(returnResult, (uint256));
WETH.withdraw(boughtAmount);
_transferEth(state.mtx.signer, boughtAmount);
}
/// @dev Execute a `IMultiplexFeature.multiplexMultiHopSellTokenForToken()` meta-transaction
/// call by decoding the call args and translating the call to the internal
/// `IMultiplexFeature._multiplexMultiHopSell()` variant, where we can override the
/// msgSender address.
function _executeMultiplexMultiHopSellTokenForTokenCall(ExecuteState memory state) private returns (bytes memory returnResult) {
address[] memory tokens;
IMultiplexFeature.MultiHopSellSubcall[] memory calls;
uint256 sellAmount;
uint256 minBuyAmount;
bytes memory args = _extractArgumentsFromCallData(state.mtx.callData);
(tokens, calls, sellAmount, minBuyAmount) = abi.decode(
args,
(address[], IMultiplexFeature.MultiHopSellSubcall[], uint256, uint256)
);
return
_callSelf(
state.hash,
abi.encodeWithSelector(
IMultiplexFeature._multiplexMultiHopSell.selector,
IMultiplexFeature.MultiHopSellParams({
tokens: tokens,
sellAmount: sellAmount,
calls: calls,
useSelfBalance: false,
recipient: state.mtx.signer,
msgSender: state.mtx.signer
}),
minBuyAmount
),
state.mtx.value
);
}
/// @dev Execute a `IMultiplexFeature.multiplexMultiHopSellTokenForEth()` meta-transaction
/// call by decoding the call args and translating the call to the internal
/// `IMultiplexFeature._multiplexMultiHopSellTokenForEth()` variant, where we can override the
/// msgSender address.
function _executeMultiplexMultiHopSellTokenForEthCall(ExecuteState memory state) private returns (bytes memory returnResult) {
address[] memory tokens;
IMultiplexFeature.MultiHopSellSubcall[] memory calls;
uint256 sellAmount;
uint256 minBuyAmount;
bytes memory args = _extractArgumentsFromCallData(state.mtx.callData);
(tokens, calls, sellAmount, minBuyAmount) = abi.decode(
args,
(address[], IMultiplexFeature.MultiHopSellSubcall[], uint256, uint256)
);
require(
tokens[tokens.length - 1] == address(WETH),
"MetaTransactionsFeature::multiplexMultiHopSellTokenForEth/NOT_WETH"
);
returnResult = _callSelf(
state.hash,
abi.encodeWithSelector(
IMultiplexFeature._multiplexMultiHopSell.selector,
IMultiplexFeature.MultiHopSellParams({
tokens: tokens,
sellAmount: sellAmount,
calls: calls,
useSelfBalance: false,
recipient: address(this),
msgSender: state.mtx.signer
}),
minBuyAmount
),
state.mtx.value
);
// Unwrap and transfer WETH
uint256 boughtAmount = abi.decode(returnResult, (uint256));
WETH.withdraw(boughtAmount);
_transferEth(state.mtx.signer, boughtAmount);
}
/// @dev Make an arbitrary internal, meta-transaction call.
/// Warning: Do not let unadulterated `callData` into this function.
function _callSelf(bytes32 hash, bytes memory callData, uint256 value) private returns (bytes memory returnResult) {

View File

@@ -29,7 +29,7 @@ contract NativeOrdersFeature is IFeature, NativeOrdersSettlement {
constructor(
address zeroExAddress,
IEtherToken weth,
IEtherTokenV06 weth,
IStaking staking,
FeeCollectorController feeCollectorController,
uint32 protocolFeeMultiplier

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
import "../errors/LibNativeOrdersRichErrors.sol";
@@ -42,9 +42,9 @@ contract OtcOrdersFeature is IFeature, IOtcOrdersFeature, FixinCommon, FixinEIP7
/// @dev ETH pseudo-token address.
address private constant ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev The WETH token contract.
IEtherToken private immutable WETH;
IEtherTokenV06 private immutable WETH;
constructor(address zeroExAddress, IEtherToken weth) public FixinEIP712(zeroExAddress) {
constructor(address zeroExAddress, IEtherTokenV06 weth) public FixinEIP712(zeroExAddress) {
WETH = weth;
}

View File

@@ -15,8 +15,8 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "../migrations/LibMigrate.sol";
import "../fixins/FixinCommon.sol";
import "./interfaces/IFeature.sol";
@@ -29,7 +29,7 @@ contract PancakeSwapFeature is IFeature, IPancakeSwapFeature, FixinCommon {
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 2);
/// @dev WBNB contract.
IEtherToken private immutable WBNB;
IEtherTokenV06 private immutable WBNB;
// 0xFF + address of the PancakeSwap factory contract.
uint256 private constant FF_PANCAKESWAP_FACTORY =
@@ -112,7 +112,7 @@ contract PancakeSwapFeature is IFeature, IPancakeSwapFeature, FixinCommon {
/// @dev Construct this contract.
/// @param wbnb The WBNB contract.
constructor(IEtherToken wbnb) public {
constructor(IEtherTokenV06 wbnb) public {
WBNB = wbnb;
}
@@ -131,7 +131,7 @@ contract PancakeSwapFeature is IFeature, IPancakeSwapFeature, FixinCommon {
/// @param fork The protocol fork to use.
/// @return buyAmount Amount of `tokens[-1]` bought.
function sellToPancakeSwap(
IERC20Token[] calldata tokens,
IERC20TokenV06[] calldata tokens,
uint256 sellAmount,
uint256 minBuyAmount,
ProtocolFork fork
@@ -139,7 +139,7 @@ contract PancakeSwapFeature is IFeature, IPancakeSwapFeature, FixinCommon {
require(tokens.length > 1, "PancakeSwapFeature/InvalidTokensLength");
{
// Load immutables onto the stack.
IEtherToken wbnb = WBNB;
IEtherTokenV06 wbnb = WBNB;
// Store some vars in memory to get around stack limits.
assembly {

View File

@@ -15,8 +15,8 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
@@ -124,8 +124,8 @@ contract TransformERC20Feature is IFeature, ITransformERC20Feature, FixinCommon,
/// in sequence.
/// @return outputTokenAmount The amount of `outputToken` received by the sender.
function transformERC20(
IERC20Token inputToken,
IERC20Token outputToken,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 minOutputTokenAmount,
Transformation[] memory transformations
@@ -301,7 +301,7 @@ contract TransformERC20Feature is IFeature, ITransformERC20Feature, FixinCommon,
}
function _executeOutputTokenTransfer(
IERC20Token outputToken,
IERC20TokenV06 outputToken,
IFlashWallet wallet,
address payable recipient
) private returns (uint256 transferAmount) {
@@ -311,7 +311,7 @@ contract TransformERC20Feature is IFeature, ITransformERC20Feature, FixinCommon,
} else {
bytes memory resultData = wallet.executeCall(
payable(address(outputToken)),
abi.encodeWithSelector(IERC20Token.transfer.selector, recipient, transferAmount),
abi.encodeWithSelector(IERC20TokenV06.transfer.selector, recipient, transferAmount),
0
);
if (resultData.length == 0) {

View File

@@ -15,8 +15,8 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "../migrations/LibMigrate.sol";
import "../fixins/FixinCommon.sol";
import "./interfaces/IFeature.sol";
@@ -29,7 +29,7 @@ contract UniswapFeature is IFeature, IUniswapFeature, FixinCommon {
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 2);
/// @dev WETH contract.
IEtherToken private immutable WETH;
IEtherTokenV06 private immutable WETH;
// 0xFF + address of the UniswapV2Factory contract.
uint256 private constant FF_UNISWAP_FACTORY = 0xFF5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f0000000000000000000000;
@@ -75,7 +75,7 @@ contract UniswapFeature is IFeature, IUniswapFeature, FixinCommon {
/// @dev Construct this contract.
/// @param weth The WETH contract.
constructor(IEtherToken weth) public {
constructor(IEtherTokenV06 weth) public {
WETH = weth;
}
@@ -94,7 +94,7 @@ contract UniswapFeature is IFeature, IUniswapFeature, FixinCommon {
/// @param isSushi Use sushiswap if true.
/// @return buyAmount Amount of `tokens[-1]` bought.
function sellToUniswap(
IERC20Token[] calldata tokens,
IERC20TokenV06[] calldata tokens,
uint256 sellAmount,
uint256 minBuyAmount,
bool isSushi
@@ -102,7 +102,7 @@ contract UniswapFeature is IFeature, IUniswapFeature, FixinCommon {
require(tokens.length > 1, "UniswapFeature/InvalidTokensLength");
{
// Load immutables onto the stack.
IEtherToken weth = WETH;
IEtherTokenV06 weth = WETH;
// Store some vars in memory to get around stack limits.
assembly {

View File

@@ -15,8 +15,8 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "../vendor/IUniswapV3Pool.sol";
import "../migrations/LibMigrate.sol";
import "../fixins/FixinCommon.sol";
@@ -31,7 +31,7 @@ contract UniswapV3Feature is IFeature, IUniswapV3Feature, FixinCommon, FixinToke
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 1, 0);
/// @dev WETH contract.
IEtherToken private immutable WETH;
IEtherTokenV06 private immutable WETH;
/// @dev UniswapV3 Factory contract address prepended with '0xff' and left-aligned.
bytes32 private immutable UNI_FF_FACTORY_ADDRESS;
/// @dev UniswapV3 pool init code hash.
@@ -57,7 +57,7 @@ contract UniswapV3Feature is IFeature, IUniswapV3Feature, FixinCommon, FixinToke
/// @param weth The WETH contract.
/// @param uniFactory The UniswapV3 factory contract.
/// @param poolInitCodeHash The UniswapV3 pool init code hash.
constructor(IEtherToken weth, address uniFactory, bytes32 poolInitCodeHash) public {
constructor(IEtherTokenV06 weth, address uniFactory, bytes32 poolInitCodeHash) public {
WETH = weth;
UNI_FF_FACTORY_ADDRESS = bytes32((uint256(0xff) << 248) | (uint256(uniFactory) << 88));
UNI_POOL_INIT_CODE_HASH = poolInitCodeHash;
@@ -70,6 +70,7 @@ contract UniswapV3Feature is IFeature, IUniswapV3Feature, FixinCommon, FixinToke
_registerFeatureFunction(this.sellEthForTokenToUniswapV3.selector);
_registerFeatureFunction(this.sellTokenForEthToUniswapV3.selector);
_registerFeatureFunction(this.sellTokenForTokenToUniswapV3.selector);
_registerFeatureFunction(this._sellTokenForTokenToUniswapV3.selector);
_registerFeatureFunction(this._sellHeldTokenForTokenToUniswapV3.selector);
_registerFeatureFunction(this.uniswapV3SwapCallback.selector);
return LibMigrate.MIGRATE_SUCCESS;
@@ -139,6 +140,23 @@ contract UniswapV3Feature is IFeature, IUniswapV3Feature, FixinCommon, FixinToke
buyAmount = _swap(encodedPath, sellAmount, minBuyAmount, msg.sender, _normalizeRecipient(recipient));
}
/// @dev Sell a token for another token directly against uniswap v3. Internal variant.
/// @param encodedPath Uniswap-encoded path.
/// @param sellAmount amount of the first token in the path to sell.
/// @param minBuyAmount Minimum amount of the last token in the path to buy.
/// @param recipient The recipient of the bought tokens. Can be zero for payer.
/// @param payer The address to pull the sold tokens from.
/// @return buyAmount Amount of the last token in the path bought.
function _sellTokenForTokenToUniswapV3(
bytes memory encodedPath,
uint256 sellAmount,
uint256 minBuyAmount,
address recipient,
address payer
) public override onlySelf returns (uint256 buyAmount) {
buyAmount = _swap(encodedPath, sellAmount, minBuyAmount, payer, _normalizeRecipient(recipient, payer));
}
/// @dev Sell a token for another token directly against uniswap v3.
/// Private variant, uses tokens held by `address(this)`.
/// @param encodedPath Uniswap-encoded path.
@@ -163,8 +181,8 @@ contract UniswapV3Feature is IFeature, IUniswapV3Feature, FixinCommon, FixinToke
/// @param data Arbitrary data forwarded from swap() caller. An ABI-encoded
/// struct of: inputToken, outputToken, fee, payer
function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external override {
IERC20Token token0;
IERC20Token token1;
IERC20TokenV06 token0;
IERC20TokenV06 token1;
address payer;
{
uint24 fee;
@@ -212,7 +230,7 @@ contract UniswapV3Feature is IFeature, IUniswapV3Feature, FixinCommon, FixinToke
bool zeroForOne;
IUniswapV3Pool pool;
{
(IERC20Token inputToken, uint24 fee, IERC20Token outputToken) = _decodeFirstPoolInfoFromPath(
(IERC20TokenV06 inputToken, uint24 fee, IERC20TokenV06 outputToken) = _decodeFirstPoolInfoFromPath(
encodedPath
);
pool = _toPool(inputToken, fee, outputToken);
@@ -248,7 +266,7 @@ contract UniswapV3Feature is IFeature, IUniswapV3Feature, FixinCommon, FixinToke
// Pay tokens from `payer` to `to`, using `transferFrom()` if
// `payer` != this contract.
function _pay(IERC20Token token, address payer, address to, uint256 amount) private {
function _pay(IERC20TokenV06 token, address payer, address to, uint256 amount) private {
if (payer != address(this)) {
_transferERC20TokensFrom(token, payer, to, amount);
} else {
@@ -259,8 +277,8 @@ contract UniswapV3Feature is IFeature, IUniswapV3Feature, FixinCommon, FixinToke
// Update `swapCallbackData` in place with new values.
function _updateSwapCallbackData(
bytes memory swapCallbackData,
IERC20Token inputToken,
IERC20Token outputToken,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint24 fee,
address payer
) private pure {
@@ -275,9 +293,9 @@ contract UniswapV3Feature is IFeature, IUniswapV3Feature, FixinCommon, FixinToke
// Compute the pool address given two tokens and a fee.
function _toPool(
IERC20Token inputToken,
IERC20TokenV06 inputToken,
uint24 fee,
IERC20Token outputToken
IERC20TokenV06 outputToken
) private view returns (IUniswapV3Pool pool) {
// address(keccak256(abi.encodePacked(
// hex"ff",
@@ -287,7 +305,7 @@ contract UniswapV3Feature is IFeature, IUniswapV3Feature, FixinCommon, FixinToke
// )))
bytes32 ffFactoryAddress = UNI_FF_FACTORY_ADDRESS;
bytes32 poolInitCodeHash = UNI_POOL_INIT_CODE_HASH;
(IERC20Token token0, IERC20Token token1) = inputToken < outputToken
(IERC20TokenV06 token0, IERC20TokenV06 token1) = inputToken < outputToken
? (inputToken, outputToken)
: (outputToken, inputToken);
assembly {
@@ -314,7 +332,7 @@ contract UniswapV3Feature is IFeature, IUniswapV3Feature, FixinCommon, FixinToke
// Return the first input token, output token, and fee of an encoded uniswap path.
function _decodeFirstPoolInfoFromPath(
bytes memory encodedPath
) private pure returns (IERC20Token inputToken, uint24 fee, IERC20Token outputToken) {
) private pure returns (IERC20TokenV06 inputToken, uint24 fee, IERC20TokenV06 outputToken) {
require(encodedPath.length >= SINGLE_HOP_PATH_SIZE, "UniswapV3Feature/BAD_PATH_ENCODING");
assembly {
let p := add(encodedPath, 32)
@@ -337,8 +355,13 @@ contract UniswapV3Feature is IFeature, IUniswapV3Feature, FixinCommon, FixinToke
}
}
// Convert null address values to fallback.
function _normalizeRecipient(address recipient, address alternative) private pure returns (address payable normalizedRecipient) {
return recipient == address(0) ? payable(alternative) : payable(recipient);
}
// Convert null address values to msg.sender.
function _normalizeRecipient(address recipient) private view returns (address payable normalizedRecipient) {
return recipient == address(0) ? msg.sender : payable(recipient);
return _normalizeRecipient(recipient, msg.sender);
}
}

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../libs/LibNFTOrder.sol";
import "../libs/LibSignature.sol";
import "../../vendor/IERC1155Token.sol";
@@ -39,7 +39,7 @@ interface IERC1155OrdersFeature {
address maker,
address taker,
uint256 nonce,
IERC20Token erc20Token,
IERC20TokenV06 erc20Token,
uint256 erc20FillAmount,
IERC1155Token erc1155Token,
uint256 erc1155TokenId,
@@ -60,7 +60,7 @@ interface IERC1155OrdersFeature {
address taker,
uint256 expiry,
uint256 nonce,
IERC20Token erc20Token,
IERC20TokenV06 erc20Token,
uint256 erc20TokenAmount,
LibNFTOrder.Fee[] fees,
IERC1155Token erc1155Token,

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../libs/LibNFTOrder.sol";
import "../libs/LibSignature.sol";
import "../../vendor/IERC721Token.sol";
@@ -40,7 +40,7 @@ interface IERC721OrdersFeature {
address maker,
address taker,
uint256 nonce,
IERC20Token erc20Token,
IERC20TokenV06 erc20Token,
uint256 erc20TokenAmount,
IERC721Token erc721Token,
uint256 erc721TokenId,
@@ -60,7 +60,7 @@ interface IERC721OrdersFeature {
address taker,
uint256 expiry,
uint256 nonce,
IERC20Token erc20Token,
IERC20TokenV06 erc20Token,
uint256 erc20TokenAmount,
LibNFTOrder.Fee[] fees,
IERC721Token erc721Token,

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
/// @dev Exchange Proxy Recovery Functions
interface IFundRecoveryFeature {
@@ -24,5 +24,5 @@ interface IFundRecoveryFeature {
/// @param erc20 ERC20 Token Address.
/// @param amountOut Amount of tokens to withdraw.
/// @param recipientWallet Recipient wallet address.
function transferTrappedTokensTo(IERC20Token erc20, uint256 amountOut, address payable recipientWallet) external;
function transferTrappedTokensTo(IERC20TokenV06 erc20, uint256 amountOut, address payable recipientWallet) external;
}

View File

@@ -15,15 +15,15 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../../vendor/ILiquidityProvider.sol";
/// @dev Feature to swap directly with an on-chain liquidity provider.
interface ILiquidityProviderFeature {
/// @dev Event for data pipeline.
event LiquidityProviderSwap(
IERC20Token inputToken,
IERC20Token outputToken,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 outputTokenAmount,
ILiquidityProvider provider,
@@ -44,8 +44,8 @@ interface ILiquidityProviderFeature {
/// @param auxiliaryData Auxiliary data supplied to the `provider` contract.
/// @return boughtAmount The amount of `outputToken` bought.
function sellToLiquidityProvider(
IERC20Token inputToken,
IERC20Token outputToken,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
ILiquidityProvider provider,
address recipient,
uint256 sellAmount,

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../libs/LibSignature.sol";
/// @dev Meta-transactions feature.
@@ -39,7 +39,7 @@ interface IMetaTransactionsFeature {
// Amount of ETH to attach to the call.
uint256 value;
// ERC20 fee `signer` pays `sender`.
IERC20Token feeToken;
IERC20TokenV06 feeToken;
// ERC20 fee amount.
uint256 feeAmount;
}

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
interface IMultiplexFeature {
// Identifies the type of subcall.
@@ -34,9 +34,9 @@ interface IMultiplexFeature {
// Parameters for a batch sell.
struct BatchSellParams {
// The token being sold.
IERC20Token inputToken;
IERC20TokenV06 inputToken;
// The token being bought.
IERC20Token outputToken;
IERC20TokenV06 outputToken;
// The amount of `inputToken` to sell.
uint256 sellAmount;
// The nested calls to perform.
@@ -46,6 +46,8 @@ interface IMultiplexFeature {
bool useSelfBalance;
// The recipient of the bought output tokens.
address recipient;
// The sender of the transaction.
address msgSender;
}
// Represents a constituent call of a batch sell.
@@ -75,6 +77,8 @@ interface IMultiplexFeature {
bool useSelfBalance;
// The recipient of the bought output tokens.
address recipient;
// The sender of the transaction.
address msgSender;
}
// Represents a constituent call of a multi-hop sell.
@@ -116,7 +120,7 @@ interface IMultiplexFeature {
/// must be bought for this function to not revert.
/// @return boughtAmount The amount of `outputToken` bought.
function multiplexBatchSellEthForToken(
IERC20Token outputToken,
IERC20TokenV06 outputToken,
BatchSellSubcall[] calldata calls,
uint256 minBuyAmount
) external payable returns (uint256 boughtAmount);
@@ -130,7 +134,7 @@ interface IMultiplexFeature {
/// must be bought for this function to not revert.
/// @return boughtAmount The amount of ETH bought.
function multiplexBatchSellTokenForEth(
IERC20Token inputToken,
IERC20TokenV06 inputToken,
BatchSellSubcall[] calldata calls,
uint256 sellAmount,
uint256 minBuyAmount
@@ -146,13 +150,24 @@ interface IMultiplexFeature {
/// that must be bought for this function to not revert.
/// @return boughtAmount The amount of `outputToken` bought.
function multiplexBatchSellTokenForToken(
IERC20Token inputToken,
IERC20Token outputToken,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
BatchSellSubcall[] calldata calls,
uint256 sellAmount,
uint256 minBuyAmount
) external returns (uint256 boughtAmount);
/// @dev Executes a multiplex BatchSell using the given
/// parameters. Internal only.
/// @param params The parameters for the BatchSell.
/// @param minBuyAmount The minimum amount of `params.outputToken`
/// that must be bought for this function to not revert.
/// @return boughtAmount The amount of `params.outputToken` bought.
function _multiplexBatchSell(
BatchSellParams memory params,
uint256 minBuyAmount
) external returns (uint256 boughtAmount);
/// @dev Sells attached ETH via the given sequence of tokens
/// and calls. `tokens[0]` must be WETH.
/// The last token in `tokens` is the output token that
@@ -204,4 +219,15 @@ interface IMultiplexFeature {
uint256 sellAmount,
uint256 minBuyAmount
) external returns (uint256 boughtAmount);
/// @dev Executes a multiplex MultiHopSell using the given
/// parameters. Internal only.
/// @param params The parameters for the MultiHopSell.
/// @param minBuyAmount The minimum amount of the output token
/// that must be bought for this function to not revert.
/// @return boughtAmount The amount of the output token bought.
function _multiplexMultiHopSell(
MultiHopSellParams memory params,
uint256 minBuyAmount
) external returns (uint256 boughtAmount);
}

View File

@@ -15,6 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../libs/LibSignature.sol";
import "../libs/LibNativeOrder.sol";

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../libs/LibSignature.sol";
import "../libs/LibNativeOrder.sol";
import "./INativeOrdersEvents.sol";
@@ -150,7 +150,7 @@ interface INativeOrdersFeature is INativeOrdersEvents {
/// @param makerToken The maker token.
/// @param takerToken The taker token.
/// @param minValidSalt The new minimum valid salt.
function cancelPairLimitOrders(IERC20Token makerToken, IERC20Token takerToken, uint256 minValidSalt) external;
function cancelPairLimitOrders(IERC20TokenV06 makerToken, IERC20TokenV06 takerToken, uint256 minValidSalt) external;
/// @dev Cancel all limit orders for a given maker and pair with a salt less
/// than the value provided. The caller must be a signer registered to the maker.
@@ -162,8 +162,8 @@ interface INativeOrdersFeature is INativeOrdersEvents {
/// @param minValidSalt The new minimum valid salt.
function cancelPairLimitOrdersWithSigner(
address maker,
IERC20Token makerToken,
IERC20Token takerToken,
IERC20TokenV06 makerToken,
IERC20TokenV06 takerToken,
uint256 minValidSalt
) external;
@@ -175,8 +175,8 @@ interface INativeOrdersFeature is INativeOrdersEvents {
/// @param takerTokens The taker tokens.
/// @param minValidSalts The new minimum valid salts.
function batchCancelPairLimitOrders(
IERC20Token[] calldata makerTokens,
IERC20Token[] calldata takerTokens,
IERC20TokenV06[] calldata makerTokens,
IERC20TokenV06[] calldata takerTokens,
uint256[] calldata minValidSalts
) external;
@@ -190,8 +190,8 @@ interface INativeOrdersFeature is INativeOrdersEvents {
/// @param minValidSalts The new minimum valid salts.
function batchCancelPairLimitOrdersWithSigner(
address maker,
IERC20Token[] memory makerTokens,
IERC20Token[] memory takerTokens,
IERC20TokenV06[] memory makerTokens,
IERC20TokenV06[] memory takerTokens,
uint256[] memory minValidSalts
) external;
@@ -202,7 +202,7 @@ interface INativeOrdersFeature is INativeOrdersEvents {
/// @param makerToken The maker token.
/// @param takerToken The taker token.
/// @param minValidSalt The new minimum valid salt.
function cancelPairRfqOrders(IERC20Token makerToken, IERC20Token takerToken, uint256 minValidSalt) external;
function cancelPairRfqOrders(IERC20TokenV06 makerToken, IERC20TokenV06 takerToken, uint256 minValidSalt) external;
/// @dev Cancel all RFQ orders for a given maker and pair with a salt less
/// than the value provided. The caller must be a signer registered to the maker.
@@ -214,8 +214,8 @@ interface INativeOrdersFeature is INativeOrdersEvents {
/// @param minValidSalt The new minimum valid salt.
function cancelPairRfqOrdersWithSigner(
address maker,
IERC20Token makerToken,
IERC20Token takerToken,
IERC20TokenV06 makerToken,
IERC20TokenV06 takerToken,
uint256 minValidSalt
) external;
@@ -227,8 +227,8 @@ interface INativeOrdersFeature is INativeOrdersEvents {
/// @param takerTokens The taker tokens.
/// @param minValidSalts The new minimum valid salts.
function batchCancelPairRfqOrders(
IERC20Token[] calldata makerTokens,
IERC20Token[] calldata takerTokens,
IERC20TokenV06[] calldata makerTokens,
IERC20TokenV06[] calldata takerTokens,
uint256[] calldata minValidSalts
) external;
@@ -242,8 +242,8 @@ interface INativeOrdersFeature is INativeOrdersEvents {
/// @param minValidSalts The new minimum valid salts.
function batchCancelPairRfqOrdersWithSigner(
address maker,
IERC20Token[] memory makerTokens,
IERC20Token[] memory takerTokens,
IERC20TokenV06[] memory makerTokens,
IERC20TokenV06[] memory takerTokens,
uint256[] memory minValidSalts
) external;

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
/// @dev VIP PancakeSwap (and forks) fill functions.
interface IPancakeSwapFeature {
@@ -37,7 +37,7 @@ interface IPancakeSwapFeature {
/// @param fork The protocol fork to use.
/// @return buyAmount Amount of `tokens[-1]` bought.
function sellToPancakeSwap(
IERC20Token[] calldata tokens,
IERC20TokenV06[] calldata tokens,
uint256 sellAmount,
uint256 minBuyAmount,
ProtocolFork fork

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
/// @dev Feature that allows spending token allowances.
interface ITokenSpenderFeature {
@@ -25,14 +25,14 @@ interface ITokenSpenderFeature {
/// @param owner The owner of the tokens.
/// @param to The recipient of the tokens.
/// @param amount The amount of `token` to transfer.
function _spendERC20Tokens(IERC20Token token, address owner, address to, uint256 amount) external;
function _spendERC20Tokens(IERC20TokenV06 token, address owner, address to, uint256 amount) external;
/// @dev Gets the maximum amount of an ERC20 token `token` that can be
/// pulled from `owner`.
/// @param token The token to spend.
/// @param owner The owner of the tokens.
/// @return amount The amount of tokens that can be pulled.
function getSpendableERC20BalanceOf(IERC20Token token, address owner) external view returns (uint256 amount);
function getSpendableERC20BalanceOf(IERC20TokenV06 token, address owner) external view returns (uint256 amount);
/// @dev Get the address of the allowance target.
/// @return target The target of token allowances.

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../../transformers/IERC20Transformer.sol";
import "../../external/IFlashWallet.sol";
@@ -37,10 +37,10 @@ interface ITransformERC20Feature {
address payable taker;
// The token being provided by the taker.
// If `0xeee...`, ETH is implied and should be provided with the call.`
IERC20Token inputToken;
IERC20TokenV06 inputToken;
// The token to be acquired by the taker.
// `0xeee...` implies ETH.
IERC20Token outputToken;
IERC20TokenV06 outputToken;
// The amount of `inputToken` to take from the taker.
// If set to `uint256(-1)`, the entire spendable balance of the taker
// will be solt.
@@ -112,8 +112,8 @@ interface ITransformERC20Feature {
/// in sequence.
/// @return outputTokenAmount The amount of `outputToken` received by the sender.
function transformERC20(
IERC20Token inputToken,
IERC20Token outputToken,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 minOutputTokenAmount,
Transformation[] calldata transformations

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
/// @dev VIP uniswap fill functions.
interface IUniswapFeature {
@@ -26,7 +26,7 @@ interface IUniswapFeature {
/// @param isSushi Use sushiswap if true.
/// @return buyAmount Amount of `tokens[-1]` bought.
function sellToUniswap(
IERC20Token[] calldata tokens,
IERC20TokenV06[] calldata tokens,
uint256 sellAmount,
uint256 minBuyAmount,
bool isSushi

View File

@@ -15,6 +15,8 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
/// @dev VIP uniswap v3 fill functions.
interface IUniswapV3Feature {
/// @dev Sell attached ETH directly against uniswap v3.
@@ -54,6 +56,21 @@ interface IUniswapV3Feature {
address recipient
) external returns (uint256 buyAmount);
/// @dev Sell a token for another token directly against uniswap v3. Internal variant.
/// @param encodedPath Uniswap-encoded path.
/// @param sellAmount amount of the first token in the path to sell.
/// @param minBuyAmount Minimum amount of the last token in the path to buy.
/// @param recipient The recipient of the bought tokens. Can be zero for payer.
/// @param payer The address to pull the sold tokens from.
/// @return buyAmount Amount of the last token in the path bought.
function _sellTokenForTokenToUniswapV3(
bytes memory encodedPath,
uint256 sellAmount,
uint256 minBuyAmount,
address recipient,
address payer
) external returns (uint256 buyAmount);
/// @dev Sell a token for another token directly against uniswap v3.
/// Private variant, uses tokens held by `address(this)`.
/// @param encodedPath Uniswap-encoded path.

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../../vendor/IERC1155Token.sol";
import "../../vendor/IERC721Token.sol";
import "../../vendor/IPropertyValidator.sol";
@@ -53,7 +53,7 @@ library LibNFTOrder {
address taker;
uint256 expiry;
uint256 nonce;
IERC20Token erc20Token;
IERC20TokenV06 erc20Token;
uint256 erc20TokenAmount;
Fee[] fees;
address nft;
@@ -68,7 +68,7 @@ library LibNFTOrder {
address taker;
uint256 expiry;
uint256 nonce;
IERC20Token erc20Token;
IERC20TokenV06 erc20Token;
uint256 erc20TokenAmount;
Fee[] fees;
IERC721Token erc721Token;
@@ -84,7 +84,7 @@ library LibNFTOrder {
address taker;
uint256 expiry;
uint256 nonce;
IERC20Token erc20Token;
IERC20TokenV06 erc20Token;
uint256 erc20TokenAmount;
Fee[] fees;
IERC1155Token erc1155Token;

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../../errors/LibNativeOrdersRichErrors.sol";
@@ -35,8 +35,8 @@ library LibNativeOrder {
/// @dev A standard OTC or OO limit order.
struct LimitOrder {
IERC20Token makerToken;
IERC20Token takerToken;
IERC20TokenV06 makerToken;
IERC20TokenV06 takerToken;
uint128 makerAmount;
uint128 takerAmount;
uint128 takerTokenFeeAmount;
@@ -51,8 +51,8 @@ library LibNativeOrder {
/// @dev An RFQ limit order.
struct RfqOrder {
IERC20Token makerToken;
IERC20Token takerToken;
IERC20TokenV06 makerToken;
IERC20TokenV06 takerToken;
uint128 makerAmount;
uint128 takerAmount;
address maker;
@@ -65,8 +65,8 @@ library LibNativeOrder {
/// @dev An OTC limit order.
struct OtcOrder {
IERC20Token makerToken;
IERC20Token takerToken;
IERC20TokenV06 makerToken;
IERC20TokenV06 takerToken;
uint128 makerAmount;
uint128 takerAmount;
address maker;

View File

@@ -15,8 +15,8 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../../external/ILiquidityProviderSandbox.sol";
import "../../fixins/FixinCommon.sol";
@@ -54,11 +54,11 @@ contract MultiplexFeature is
uint256 private constant LOWER_255_BITS = HIGH_BIT - 1;
/// @dev The WETH token contract.
IEtherToken private immutable WETH;
IEtherTokenV06 private immutable WETH;
constructor(
address zeroExAddress,
IEtherToken weth,
IEtherTokenV06 weth,
ILiquidityProviderSandbox sandbox,
address uniswapFactory,
address sushiswapFactory,
@@ -80,9 +80,11 @@ contract MultiplexFeature is
_registerFeatureFunction(this.multiplexBatchSellEthForToken.selector);
_registerFeatureFunction(this.multiplexBatchSellTokenForEth.selector);
_registerFeatureFunction(this.multiplexBatchSellTokenForToken.selector);
_registerFeatureFunction(this._multiplexBatchSell.selector);
_registerFeatureFunction(this.multiplexMultiHopSellEthForToken.selector);
_registerFeatureFunction(this.multiplexMultiHopSellTokenForEth.selector);
_registerFeatureFunction(this.multiplexMultiHopSellTokenForToken.selector);
_registerFeatureFunction(this._multiplexMultiHopSell.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
@@ -94,7 +96,7 @@ contract MultiplexFeature is
/// must be bought for this function to not revert.
/// @return boughtAmount The amount of `outputToken` bought.
function multiplexBatchSellEthForToken(
IERC20Token outputToken,
IERC20TokenV06 outputToken,
BatchSellSubcall[] memory calls,
uint256 minBuyAmount
) public payable override returns (uint256 boughtAmount) {
@@ -103,14 +105,15 @@ contract MultiplexFeature is
// WETH is now held by this contract,
// so `useSelfBalance` is true.
return
_multiplexBatchSell(
_multiplexBatchSellPrivate(
BatchSellParams({
inputToken: WETH,
outputToken: outputToken,
sellAmount: msg.value,
calls: calls,
useSelfBalance: true,
recipient: msg.sender
recipient: msg.sender,
msgSender: msg.sender
}),
minBuyAmount
);
@@ -125,7 +128,7 @@ contract MultiplexFeature is
/// must be bought for this function to not revert.
/// @return boughtAmount The amount of ETH bought.
function multiplexBatchSellTokenForEth(
IERC20Token inputToken,
IERC20TokenV06 inputToken,
BatchSellSubcall[] memory calls,
uint256 sellAmount,
uint256 minBuyAmount
@@ -133,14 +136,15 @@ contract MultiplexFeature is
// The outputToken is implicitly WETH. The `recipient`
// of the WETH is set to this contract, since we
// must unwrap the WETH and transfer the resulting ETH.
boughtAmount = _multiplexBatchSell(
boughtAmount = _multiplexBatchSellPrivate(
BatchSellParams({
inputToken: inputToken,
outputToken: WETH,
sellAmount: sellAmount,
calls: calls,
useSelfBalance: false,
recipient: address(this)
recipient: address(this),
msgSender: msg.sender
}),
minBuyAmount
);
@@ -160,33 +164,48 @@ contract MultiplexFeature is
/// that must be bought for this function to not revert.
/// @return boughtAmount The amount of `outputToken` bought.
function multiplexBatchSellTokenForToken(
IERC20Token inputToken,
IERC20Token outputToken,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
BatchSellSubcall[] memory calls,
uint256 sellAmount,
uint256 minBuyAmount
) public override returns (uint256 boughtAmount) {
return
_multiplexBatchSell(
_multiplexBatchSellPrivate(
BatchSellParams({
inputToken: inputToken,
outputToken: outputToken,
sellAmount: sellAmount,
calls: calls,
useSelfBalance: false,
recipient: msg.sender
recipient: msg.sender,
msgSender: msg.sender
}),
minBuyAmount
);
}
/// @dev Executes a batch sell and checks that at least
/// `minBuyAmount` of `outputToken` was bought. Internal
/// variant.
/// @param params Batch sell parameters.
/// @param minBuyAmount The minimum amount of `outputToken` that
/// must be bought for this function to not revert.
/// @return boughtAmount The amount of `outputToken` bought.
function _multiplexBatchSell(
BatchSellParams memory params,
uint256 minBuyAmount
) public override onlySelf returns (uint256 boughtAmount) {
return _multiplexBatchSellPrivate(params, minBuyAmount);
}
/// @dev Executes a batch sell and checks that at least
/// `minBuyAmount` of `outputToken` was bought.
/// @param params Batch sell parameters.
/// @param minBuyAmount The minimum amount of `outputToken` that
/// must be bought for this function to not revert.
/// @return boughtAmount The amount of `outputToken` bought.
function _multiplexBatchSell(
function _multiplexBatchSellPrivate(
BatchSellParams memory params,
uint256 minBuyAmount
) private returns (uint256 boughtAmount) {
@@ -226,13 +245,14 @@ contract MultiplexFeature is
// WETH is now held by this contract,
// so `useSelfBalance` is true.
return
_multiplexMultiHopSell(
_multiplexMultiHopSellPrivate(
MultiHopSellParams({
tokens: tokens,
sellAmount: msg.value,
calls: calls,
useSelfBalance: true,
recipient: msg.sender
recipient: msg.sender,
msgSender: msg.sender
}),
minBuyAmount
);
@@ -262,13 +282,14 @@ contract MultiplexFeature is
);
// The `recipient of the WETH is set to this contract, since
// we must unwrap the WETH and transfer the resulting ETH.
boughtAmount = _multiplexMultiHopSell(
boughtAmount = _multiplexMultiHopSellPrivate(
MultiHopSellParams({
tokens: tokens,
sellAmount: sellAmount,
calls: calls,
useSelfBalance: false,
recipient: address(this)
recipient: address(this),
msgSender: msg.sender
}),
minBuyAmount
);
@@ -297,25 +318,38 @@ contract MultiplexFeature is
uint256 minBuyAmount
) public override returns (uint256 boughtAmount) {
return
_multiplexMultiHopSell(
_multiplexMultiHopSellPrivate(
MultiHopSellParams({
tokens: tokens,
sellAmount: sellAmount,
calls: calls,
useSelfBalance: false,
recipient: msg.sender
recipient: msg.sender,
msgSender: msg.sender
}),
minBuyAmount
);
}
/// @dev Executes a multi-hop sell. Internal variant.
/// @param params Multi-hop sell parameters.
/// @param minBuyAmount The minimum amount of output tokens that
/// must be bought for this function to not revert.
/// @return boughtAmount The amount of output tokens bought.
function _multiplexMultiHopSell(
MultiHopSellParams memory params,
uint256 minBuyAmount
) public override onlySelf returns (uint256 boughtAmount) {
return _multiplexMultiHopSellPrivate(params, minBuyAmount);
}
/// @dev Executes a multi-hop sell and checks that at least
/// `minBuyAmount` of output tokens were bought.
/// @param params Multi-hop sell parameters.
/// @param minBuyAmount The minimum amount of output tokens that
/// must be bought for this function to not revert.
/// @return boughtAmount The amount of output tokens bought.
function _multiplexMultiHopSell(
function _multiplexMultiHopSellPrivate(
MultiHopSellParams memory params,
uint256 minBuyAmount
) private returns (uint256 boughtAmount) {
@@ -327,7 +361,7 @@ contract MultiplexFeature is
"MultiplexFeature::_multiplexMultiHopSell/MISMATCHED_ARRAY_LENGTHS"
);
// The output token is the last token in the path.
IERC20Token outputToken = IERC20Token(params.tokens[params.tokens.length - 1]);
IERC20TokenV06 outputToken = IERC20TokenV06(params.tokens[params.tokens.length - 1]);
// Cache the recipient's balance of the output token.
uint256 balanceBefore = outputToken.balanceOf(params.recipient);
// Execute the multi-hop sell.
@@ -387,19 +421,19 @@ contract MultiplexFeature is
// amount of the multi-hop fill.
state.outputTokenAmount = params.sellAmount;
// The first call may expect the input tokens to be held by
// `msg.sender`, `address(this)`, or some other address.
// `msgSender`, `address(this)`, or some other address.
// Compute the expected address and transfer the input tokens
// there if necessary.
state.from = _computeHopTarget(params, 0);
// If the input tokens are currently held by `msg.sender` but
// If the input tokens are currently held by `msgSender` but
// the first hop expects them elsewhere, perform a `transferFrom`.
if (!params.useSelfBalance && state.from != msg.sender) {
_transferERC20TokensFrom(IERC20Token(params.tokens[0]), msg.sender, state.from, params.sellAmount);
if (!params.useSelfBalance && state.from != params.msgSender) {
_transferERC20TokensFrom(IERC20TokenV06(params.tokens[0]), params.msgSender, state.from, params.sellAmount);
}
// If the input tokens are currently held by `address(this)` but
// the first hop expects them elsewhere, perform a `transfer`.
if (params.useSelfBalance && state.from != address(this)) {
_transferERC20Tokens(IERC20Token(params.tokens[0]), state.from, params.sellAmount);
_transferERC20Tokens(IERC20TokenV06(params.tokens[0]), state.from, params.sellAmount);
}
// Iterate through the calls and execute each one.
for (state.hopIndex = 0; state.hopIndex != params.calls.length; state.hopIndex++) {
@@ -411,7 +445,7 @@ contract MultiplexFeature is
if (subcall.id == MultiplexSubcall.UniswapV2) {
_multiHopSellUniswapV2(state, params, subcall.data);
} else if (subcall.id == MultiplexSubcall.UniswapV3) {
_multiHopSellUniswapV3(state, subcall.data);
_multiHopSellUniswapV3(state, params, subcall.data);
} else if (subcall.id == MultiplexSubcall.LiquidityProvider) {
_multiHopSellLiquidityProvider(state, params, subcall.data);
} else if (subcall.id == MultiplexSubcall.BatchSell) {
@@ -443,6 +477,8 @@ contract MultiplexFeature is
// Likewise, the recipient of the multi-hop sell is
// equal to the recipient of its containing batch sell.
multiHopParams.recipient = params.recipient;
// The msgSender is the same too.
multiHopParams.msgSender = params.msgSender;
// Execute the nested multi-hop sell.
uint256 outputTokenAmount = _executeMultiHopSell(multiHopParams).outputTokenAmount;
// Increment the sold and bought amounts.
@@ -461,15 +497,15 @@ contract MultiplexFeature is
// The input and output tokens of the batch
// sell are the current and next tokens in
// `params.tokens`, respectively.
batchSellParams.inputToken = IERC20Token(params.tokens[state.hopIndex]);
batchSellParams.outputToken = IERC20Token(params.tokens[state.hopIndex + 1]);
batchSellParams.inputToken = IERC20TokenV06(params.tokens[state.hopIndex]);
batchSellParams.outputToken = IERC20TokenV06(params.tokens[state.hopIndex + 1]);
// The `sellAmount` for the batch sell is the
// `outputTokenAmount` from the previous hop.
batchSellParams.sellAmount = state.outputTokenAmount;
// If the nested batch sell is the first hop
// and `useSelfBalance` for the containing multi-
// hop sell is false, the nested batch sell should
// pull tokens from `msg.sender` (so `batchSellParams.useSelfBalance`
// pull tokens from `msgSender` (so `batchSellParams.useSelfBalance`
// should be false). Otherwise `batchSellParams.useSelfBalance`
// should be true.
batchSellParams.useSelfBalance = state.hopIndex > 0 || params.useSelfBalance;
@@ -477,6 +513,8 @@ contract MultiplexFeature is
// that should receive the output tokens of the
// batch sell.
batchSellParams.recipient = state.to;
// msgSender shound be the same too.
batchSellParams.msgSender = params.msgSender;
// Execute the nested batch sell.
state.outputTokenAmount = _executeBatchSell(batchSellParams).boughtAmount;
}
@@ -509,25 +547,25 @@ contract MultiplexFeature is
// UniswapV3 uses a callback to pull in the tokens being
// sold to it. The callback implemented in `UniswapV3Feature`
// can either:
// - call `transferFrom` to move tokens from `msg.sender` to the
// - call `transferFrom` to move tokens from `msgSender` to the
// UniswapV3 pool, or
// - call `transfer` to move tokens from `address(this)` to the
// UniswapV3 pool.
// A nested batch sell is similar, in that it can either:
// - use tokens from `msg.sender`, or
// - use tokens from `msgSender`, or
// - use tokens held by `address(this)`.
// Suppose UniswapV3/BatchSell is the first call in the multi-hop
// path. The input tokens are either held by `msg.sender`,
// path. The input tokens are either held by `msgSender`,
// or in the case of `multiplexMultiHopSellEthForToken` WETH is
// held by `address(this)`. The target is set accordingly.
// If this is _not_ the first call in the multi-hop path, we
// are dealing with an "intermediate" token in the multi-hop path,
// which `msg.sender` may not have an allowance set for. Thus
// which `msgSender` may not have an allowance set for. Thus
// target must be set to `address(this)` for `i > 0`.
if (i == 0 && !params.useSelfBalance) {
target = msg.sender;
target = params.msgSender;
} else {
target = address(this);
}

View File

@@ -15,8 +15,8 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../../external/ILiquidityProviderSandbox.sol";
import "../../fixins/FixinCommon.sol";
@@ -25,7 +25,7 @@ import "../../vendor/ILiquidityProvider.sol";
import "../interfaces/IMultiplexFeature.sol";
abstract contract MultiplexLiquidityProvider is FixinCommon, FixinTokenSpender {
using LibERC20TokenV06 for IERC20Token;
using LibERC20TokenV06 for IERC20TokenV06;
using LibSafeMathV06 for uint256;
// Same event fired by LiquidityProviderFeature
@@ -66,8 +66,8 @@ abstract contract MultiplexLiquidityProvider is FixinCommon, FixinTokenSpender {
// held by `address(this)`.
_transferERC20Tokens(params.inputToken, provider, sellAmount);
} else {
// Otherwise, transfer the input tokens from `msg.sender`.
_transferERC20TokensFrom(params.inputToken, msg.sender, provider, sellAmount);
// Otherwise, transfer the input tokens from `msgSender`.
_transferERC20TokensFrom(params.inputToken, params.msgSender, provider, sellAmount);
}
// Cache the recipient's balance of the output token.
uint256 balanceBefore = params.outputToken.balanceOf(params.recipient);
@@ -125,8 +125,8 @@ abstract contract MultiplexLiquidityProvider is FixinCommon, FixinTokenSpender {
IMultiplexFeature.MultiHopSellParams memory params,
bytes memory wrappedCallData
) internal {
IERC20Token inputToken = IERC20Token(params.tokens[state.hopIndex]);
IERC20Token outputToken = IERC20Token(params.tokens[state.hopIndex + 1]);
IERC20TokenV06 inputToken = IERC20TokenV06(params.tokens[state.hopIndex]);
IERC20TokenV06 outputToken = IERC20TokenV06(params.tokens[state.hopIndex + 1]);
// Decode the provider address and auxiliary data.
(address provider, bytes memory auxiliaryData) = abi.decode(wrappedCallData, (address, bytes));
// Cache the recipient's balance of the output token.

View File

@@ -55,7 +55,7 @@ abstract contract MultiplexOtc is FixinEIP712 {
order,
signature,
sellAmount.safeDowncastToUint128(),
msg.sender,
params.msgSender,
params.useSelfBalance,
params.recipient
)

View File

@@ -54,7 +54,7 @@ abstract contract MultiplexRfq is FixinEIP712 {
order,
signature,
sellAmount.safeDowncastToUint128(),
msg.sender,
params.msgSender,
params.useSelfBalance,
params.recipient
)

View File

@@ -30,8 +30,8 @@ abstract contract MultiplexTransformERC20 {
) internal {
ITransformERC20Feature.TransformERC20Args memory args;
// We want the TransformedERC20 event to have
// `msg.sender` as the taker.
args.taker = msg.sender;
// `msgSender` as the taker.
args.taker = payable(params.msgSender);
args.inputToken = params.inputToken;
args.outputToken = params.outputToken;
args.inputTokenAmount = sellAmount;

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../../fixins/FixinCommon.sol";
import "../../fixins/FixinTokenSpender.sol";
@@ -75,9 +75,9 @@ abstract contract MultiplexUniswapV2 is FixinCommon, FixinTokenSpender {
// so we transfer the tokens in now (either from `msg.sender`
// or using the Exchange Proxy's balance).
if (params.useSelfBalance) {
_transferERC20Tokens(IERC20Token(tokens[0]), firstPairAddress, sellAmount);
_transferERC20Tokens(IERC20TokenV06(tokens[0]), firstPairAddress, sellAmount);
} else {
_transferERC20TokensFrom(IERC20Token(tokens[0]), msg.sender, firstPairAddress, sellAmount);
_transferERC20TokensFrom(IERC20TokenV06(tokens[0]), params.msgSender, firstPairAddress, sellAmount);
}
// Execute the Uniswap/Sushiswap trade.
return _sellToUniswapV2(tokens, sellAmount, isSushi, firstPairAddress, params.recipient);

View File

@@ -15,6 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../../fixins/FixinTokenSpender.sol";
import "../interfaces/IMultiplexFeature.sol";
@@ -45,16 +46,16 @@ abstract contract MultiplexUniswapV3 is FixinTokenSpender {
)
);
} else {
// Otherwise, we self-delegatecall the normal variant
// `sellTokenForTokenToUniswapV3`, which pulls the input token
// from `msg.sender`.
// Otherwise, we self-delegatecall `_sellTokenForTokenToUniswapV3`,
// which pulls the input token from a specified `payer`.
(success, resultData) = address(this).delegatecall(
abi.encodeWithSelector(
IUniswapV3Feature.sellTokenForTokenToUniswapV3.selector,
IUniswapV3Feature._sellTokenForTokenToUniswapV3.selector,
wrappedCallData,
sellAmount,
0,
params.recipient
params.recipient,
params.msgSender
)
);
}
@@ -69,6 +70,7 @@ abstract contract MultiplexUniswapV3 is FixinTokenSpender {
function _multiHopSellUniswapV3(
IMultiplexFeature.MultiHopSellState memory state,
IMultiplexFeature.MultiHopSellParams memory params,
bytes memory wrappedCallData
) internal {
bool success;
@@ -87,16 +89,16 @@ abstract contract MultiplexUniswapV3 is FixinTokenSpender {
)
);
} else {
// Otherwise, we self-delegatecall the normal variant
// `sellTokenForTokenToUniswapV3`, which pulls the input token
// from `msg.sender`.
// Otherwise, we self-delegatecall `_sellTokenForTokenToUniswapV3`,
// which pulls the input token from `msgSender`.
(success, resultData) = address(this).delegatecall(
abi.encodeWithSelector(
IUniswapV3Feature.sellTokenForTokenToUniswapV3.selector,
IUniswapV3Feature._sellTokenForTokenToUniswapV3.selector,
wrappedCallData,
state.outputTokenAmount,
0,
state.to
state.to,
params.msgSender
)
);
}

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "../../errors/LibNativeOrdersRichErrors.sol";
import "../../storage/LibNativeOrdersStorage.sol";
@@ -80,7 +80,7 @@ abstract contract NativeOrdersCancellation is INativeOrdersEvents, NativeOrdersI
/// @param makerToken The maker token.
/// @param takerToken The taker token.
/// @param minValidSalt The new minimum valid salt.
function cancelPairLimitOrders(IERC20Token makerToken, IERC20Token takerToken, uint256 minValidSalt) public {
function cancelPairLimitOrders(IERC20TokenV06 makerToken, IERC20TokenV06 takerToken, uint256 minValidSalt) public {
_cancelPairLimitOrders(msg.sender, makerToken, takerToken, minValidSalt);
}
@@ -94,8 +94,8 @@ abstract contract NativeOrdersCancellation is INativeOrdersEvents, NativeOrdersI
/// @param minValidSalt The new minimum valid salt.
function cancelPairLimitOrdersWithSigner(
address maker,
IERC20Token makerToken,
IERC20Token takerToken,
IERC20TokenV06 makerToken,
IERC20TokenV06 takerToken,
uint256 minValidSalt
) public {
// verify that the signer is authorized for the maker
@@ -114,8 +114,8 @@ abstract contract NativeOrdersCancellation is INativeOrdersEvents, NativeOrdersI
/// @param takerTokens The taker tokens.
/// @param minValidSalts The new minimum valid salts.
function batchCancelPairLimitOrders(
IERC20Token[] memory makerTokens,
IERC20Token[] memory takerTokens,
IERC20TokenV06[] memory makerTokens,
IERC20TokenV06[] memory takerTokens,
uint256[] memory minValidSalts
) public {
require(
@@ -138,8 +138,8 @@ abstract contract NativeOrdersCancellation is INativeOrdersEvents, NativeOrdersI
/// @param minValidSalts The new minimum valid salts.
function batchCancelPairLimitOrdersWithSigner(
address maker,
IERC20Token[] memory makerTokens,
IERC20Token[] memory takerTokens,
IERC20TokenV06[] memory makerTokens,
IERC20TokenV06[] memory takerTokens,
uint256[] memory minValidSalts
) public {
require(
@@ -163,7 +163,7 @@ abstract contract NativeOrdersCancellation is INativeOrdersEvents, NativeOrdersI
/// @param makerToken The maker token.
/// @param takerToken The taker token.
/// @param minValidSalt The new minimum valid salt.
function cancelPairRfqOrders(IERC20Token makerToken, IERC20Token takerToken, uint256 minValidSalt) public {
function cancelPairRfqOrders(IERC20TokenV06 makerToken, IERC20TokenV06 takerToken, uint256 minValidSalt) public {
_cancelPairRfqOrders(msg.sender, makerToken, takerToken, minValidSalt);
}
@@ -177,8 +177,8 @@ abstract contract NativeOrdersCancellation is INativeOrdersEvents, NativeOrdersI
/// @param minValidSalt The new minimum valid salt.
function cancelPairRfqOrdersWithSigner(
address maker,
IERC20Token makerToken,
IERC20Token takerToken,
IERC20TokenV06 makerToken,
IERC20TokenV06 takerToken,
uint256 minValidSalt
) public {
if (!isValidOrderSigner(maker, msg.sender)) {
@@ -196,8 +196,8 @@ abstract contract NativeOrdersCancellation is INativeOrdersEvents, NativeOrdersI
/// @param takerTokens The taker tokens.
/// @param minValidSalts The new minimum valid salts.
function batchCancelPairRfqOrders(
IERC20Token[] memory makerTokens,
IERC20Token[] memory takerTokens,
IERC20TokenV06[] memory makerTokens,
IERC20TokenV06[] memory takerTokens,
uint256[] memory minValidSalts
) public {
require(
@@ -220,8 +220,8 @@ abstract contract NativeOrdersCancellation is INativeOrdersEvents, NativeOrdersI
/// @param minValidSalts The new minimum valid salts.
function batchCancelPairRfqOrdersWithSigner(
address maker,
IERC20Token[] memory makerTokens,
IERC20Token[] memory takerTokens,
IERC20TokenV06[] memory makerTokens,
IERC20TokenV06[] memory takerTokens,
uint256[] memory minValidSalts
) public {
require(
@@ -258,8 +258,8 @@ abstract contract NativeOrdersCancellation is INativeOrdersEvents, NativeOrdersI
/// @param minValidSalt The new minimum valid salt.
function _cancelPairRfqOrders(
address maker,
IERC20Token makerToken,
IERC20Token takerToken,
IERC20TokenV06 makerToken,
IERC20TokenV06 takerToken,
uint256 minValidSalt
) private {
LibNativeOrdersStorage.Storage storage stor = LibNativeOrdersStorage.getStorage();
@@ -288,8 +288,8 @@ abstract contract NativeOrdersCancellation is INativeOrdersEvents, NativeOrdersI
/// @param minValidSalt The new minimum valid salt.
function _cancelPairLimitOrders(
address maker,
IERC20Token makerToken,
IERC20Token takerToken,
IERC20TokenV06 makerToken,
IERC20TokenV06 takerToken,
uint256 minValidSalt
) private {
LibNativeOrdersStorage.Storage storage stor = LibNativeOrdersStorage.getStorage();

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
import "../../fixins/FixinEIP712.sol";
@@ -32,7 +32,7 @@ abstract contract NativeOrdersInfo is FixinEIP712, FixinTokenSpender {
// @dev Params for `_getActualFillableTakerTokenAmount()`.
struct GetActualFillableTakerTokenAmountParams {
address maker;
IERC20Token makerToken;
IERC20TokenV06 makerToken;
uint128 orderMakerAmount;
uint128 orderTakerAmount;
LibNativeOrder.OrderInfo orderInfo;

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../../fixins/FixinProtocolFees.sol";
@@ -28,7 +28,7 @@ abstract contract NativeOrdersProtocolFees is FixinProtocolFees {
using LibRichErrorsV06 for bytes;
constructor(
IEtherToken weth,
IEtherTokenV06 weth,
IStaking staking,
FeeCollectorController feeCollectorController,
uint32 protocolFeeMultiplier

View File

@@ -15,8 +15,8 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
@@ -51,9 +51,9 @@ abstract contract NativeOrdersSettlement is
// Recipient of the maker tokens.
address recipient;
// Maker token.
IERC20Token makerToken;
IERC20TokenV06 makerToken;
// Taker token.
IERC20Token takerToken;
IERC20TokenV06 takerToken;
// Maker token amount.
uint128 makerAmount;
// Taker token amount.
@@ -105,7 +105,7 @@ abstract contract NativeOrdersSettlement is
constructor(
address zeroExAddress,
IEtherToken weth,
IEtherTokenV06 weth,
IStaking staking,
FeeCollectorController feeCollectorController,
uint32 protocolFeeMultiplier
@@ -352,8 +352,8 @@ abstract contract NativeOrdersSettlement is
maker: params.order.maker,
payer: params.taker,
recipient: params.taker,
makerToken: IERC20Token(params.order.makerToken),
takerToken: IERC20Token(params.order.takerToken),
makerToken: IERC20TokenV06(params.order.makerToken),
takerToken: IERC20TokenV06(params.order.takerToken),
makerAmount: params.order.makerAmount,
takerAmount: params.order.takerAmount,
takerTokenFillAmount: params.takerTokenFillAmount,
@@ -441,8 +441,8 @@ abstract contract NativeOrdersSettlement is
maker: params.order.maker,
payer: params.useSelfBalance ? address(this) : params.taker,
recipient: params.recipient,
makerToken: IERC20Token(params.order.makerToken),
takerToken: IERC20Token(params.order.takerToken),
makerToken: IERC20TokenV06(params.order.makerToken),
takerToken: IERC20TokenV06(params.order.takerToken),
makerAmount: params.order.makerAmount,
takerAmount: params.order.takerAmount,
takerTokenFillAmount: params.takerTokenFillAmount,

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../../fixins/FixinERC1155Spender.sol";
import "../../migrations/LibMigrate.sol";
@@ -41,7 +41,7 @@ contract ERC1155OrdersFeature is IFeature, IERC1155OrdersFeature, FixinERC1155Sp
/// @dev The magic return value indicating the success of a `onERC1155Received`.
bytes4 private constant ERC1155_RECEIVED_MAGIC_BYTES = this.onERC1155Received.selector;
constructor(address zeroExAddress, IEtherToken weth) public NFTOrders(zeroExAddress, weth) {}
constructor(address zeroExAddress, IEtherTokenV06 weth) public NFTOrders(zeroExAddress, weth) {}
/// @dev Initialize and register this feature.
/// Should be delegatecalled by `Migrate.migrate()`.

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../../fixins/FixinERC721Spender.sol";
import "../../migrations/LibMigrate.sol";
@@ -40,7 +40,7 @@ contract ERC721OrdersFeature is IFeature, IERC721OrdersFeature, FixinERC721Spend
/// @dev The magic return value indicating the success of a `onERC721Received`.
bytes4 private constant ERC721_RECEIVED_MAGIC_BYTES = this.onERC721Received.selector;
constructor(address zeroExAddress, IEtherToken weth) public NFTOrders(zeroExAddress, weth) {}
constructor(address zeroExAddress, IEtherTokenV06 weth) public NFTOrders(zeroExAddress, weth) {}
/// @dev Initialize and register this feature.
/// Should be delegatecalled by `Migrate.migrate()`.

View File

@@ -15,7 +15,8 @@
pragma solidity ^0.6;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibMathV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../../errors/LibNFTOrdersRichErrors.sol";
@@ -35,14 +36,14 @@ abstract contract NFTOrders is FixinCommon, FixinEIP712, FixinTokenSpender {
/// @dev Native token pseudo-address.
address internal constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev The WETH token contract.
IEtherToken internal immutable WETH;
IEtherTokenV06 internal immutable WETH;
/// @dev The magic return value indicating the success of a `receiveZeroExFeeCallback`.
bytes4 private constant FEE_CALLBACK_MAGIC_BYTES = IFeeRecipient.receiveZeroExFeeCallback.selector;
/// @dev The magic return value indicating the success of a `zeroExTakerCallback`.
bytes4 private constant TAKER_CALLBACK_MAGIC_BYTES = ITakerCallback.zeroExTakerCallback.selector;
constructor(address zeroExAddress, IEtherToken weth) public FixinEIP712(zeroExAddress) {
constructor(address zeroExAddress, IEtherTokenV06 weth) public FixinEIP712(zeroExAddress) {
WETH = weth;
}

View File

@@ -15,7 +15,7 @@
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol";
import "../external/FeeCollector.sol";
import "../external/FeeCollectorController.sol";
import "../external/LibFeeCollector.sol";
@@ -30,12 +30,12 @@ abstract contract FixinProtocolFees {
/// @dev Hash of the fee collector init code.
bytes32 private immutable FEE_COLLECTOR_INIT_CODE_HASH;
/// @dev The WETH token contract.
IEtherToken private immutable WETH;
IEtherTokenV06 private immutable WETH;
/// @dev The staking contract.
IStaking private immutable STAKING;
constructor(
IEtherToken weth,
IEtherTokenV06 weth,
IStaking staking,
FeeCollectorController feeCollectorController,
uint32 protocolFeeMultiplier

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