ZeroEx: TransformERC20, TokenSpender (#2545)

* `@0x/contracts-utils`: Convert more 0.6 contracts

* `@0x/contracts-erc20`: Add solidity 0.6 contracts.

* `@0x/utils`: Add new `ZeroExRevertErrors` revert types

* `@0x/contracts-zero-ex`: Introduce the `TransformERC20` feature.

* `@0x/subproviders`: Update ganache-core.
`@0x/web3-wrapper`: Update ganache-core.

* `@0x/contracts-zero-ex`: Make `TokenSpender`'s puppet contract a distinct contract type and rename `getTokenSpenderPuppet()` to `getAllowanceTarget()`

* `@0x/zero-ex`: Rebase and use "slot" instead of "offset" language in storage buckets.

* `@0x/web3-wrapper`: Add `getAccountNonceAsync()` to `Web3Wrapper`

* `@0x/contracts-zero-ex`: Revamp TransformERC20.

* `@0x/contracts-zero-ex`: Remove `payable` from `IERC20Transformer.transform()` and disable hex capitalization linter rule because of prettier conflicts.

* `@0x/contracts-zero-ex`: Use `immutable` owner in `Puppet` instead of `Ownable`.

* `@x/utils`: Address review feedback.

* `@0x/contracts-zero-ex`: Address review feedback.

* `@0x/contracts-utils`: Address review feedback.

* `@0x/contracts-zero-ex`: Return deployment nonce in `transform()`.

* `@0x/contracts-zero-ex`: Finish returning deployment nonce in `transform()`.

* `@0x/contracts-zero-ex`: Fix doc-gen bug.

* `@0x/contracts-zero-ex`: Address review comments.

* `@0x/utils`: Add `NegativeTransformERC20OutputERror`

* `@0x/contracts-zero-ex`: Revert if the taker's output amount decreases.

Co-authored-by: Lawrence Forman <me@merklejerk.com>
This commit is contained in:
Lawrence Forman 2020-05-20 22:47:21 -04:00 committed by GitHub
parent b23f1eb145
commit 2fce332ed7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
87 changed files with 5613 additions and 260 deletions

View File

@ -5,6 +5,10 @@
{ {
"note": "Add `LibERC20Token.approveIfBelow()`", "note": "Add `LibERC20Token.approveIfBelow()`",
"pr": 2512 "pr": 2512
},
{
"note": "Add solidity 0.6 contracts",
"pr": 2545
} }
] ]
}, },

View File

@ -0,0 +1,95 @@
/*
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.6.5;
interface IERC20TokenV06 {
// solhint-disable no-simple-event-func-name
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,32 @@
/*
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.6.5;
import "./IERC20TokenV06.sol";
interface IEtherTokenV06 is
IERC20TokenV06
{
/// @dev Wrap ether.
function deposit() external payable;
/// @dev Unwrap ether.
function withdraw(uint256 amount) external;
}

View File

@ -0,0 +1,212 @@
/*
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.6.5;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
import "./IERC20TokenV06.sol";
library LibERC20TokenV06 {
bytes constant private DECIMALS_CALL_DATA = hex"313ce567";
/// @dev Calls `IERC20TokenV06(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 compatApprove(
IERC20TokenV06 token,
address spender,
uint256 allowance
)
internal
{
bytes memory callData = abi.encodeWithSelector(
token.approve.selector,
spender,
allowance
);
_callWithOptionalBooleanResult(address(token), callData);
}
/// @dev Calls `IERC20TokenV06(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(
IERC20TokenV06 token,
address spender,
uint256 amount
)
internal
{
if (token.allowance(address(this), spender) < amount) {
compatApprove(token, spender, uint256(-1));
}
}
/// @dev Calls `IERC20TokenV06(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 compatTransfer(
IERC20TokenV06 token,
address to,
uint256 amount
)
internal
{
bytes memory callData = abi.encodeWithSelector(
token.transfer.selector,
to,
amount
);
_callWithOptionalBooleanResult(address(token), callData);
}
/// @dev Calls `IERC20TokenV06(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 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);
}
/// @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 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) {
tokenDecimals = uint8(LibBytesV06.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 compatAllowance(IERC20TokenV06 token, address owner, address spender)
internal
view
returns (uint256 allowance_)
{
(bool didSucceed, bytes memory resultData) = address(token).staticcall(
abi.encodeWithSelector(
token.allowance.selector,
owner,
spender
)
);
if (didSucceed && resultData.length == 32) {
allowance_ = LibBytesV06.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 compatBalanceOf(IERC20TokenV06 token, address owner)
internal
view
returns (uint256 balance)
{
(bool didSucceed, bytes memory resultData) = address(token).staticcall(
abi.encodeWithSelector(
token.balanceOf.selector,
owner
)
);
if (didSucceed && resultData.length == 32) {
balance = LibBytesV06.readUint256(resultData, 0);
}
}
/// @dev Check if the data returned by a non-static call to an ERC20 token
/// is a successful result. Supported functions are `transfer()`,
/// `transferFrom()`, and `approve()`.
/// @param resultData The raw data returned by a non-static call to the ERC20 token.
/// @return isSuccessful Whether the result data indicates success.
function isSuccessfulResult(bytes memory resultData)
internal
pure
returns (bool isSuccessful)
{
if (resultData.length == 0) {
return true;
}
if (resultData.length == 32) {
uint256 result = LibBytesV06.readUint256(resultData, 0);
if (result == 1) {
return true;
}
}
}
/// @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 && isSuccessfulResult(resultData)) {
return;
}
LibRichErrorsV06.rrevert(resultData);
}
}

View File

@ -38,7 +38,7 @@
}, },
"config": { "config": {
"publicInterfaceContracts": "DummyERC20Token,ERC20Token,WETH9,ZRXToken,DummyNoReturnERC20Token,DummyMultipleReturnERC20Token", "publicInterfaceContracts": "DummyERC20Token,ERC20Token,WETH9,ZRXToken,DummyNoReturnERC20Token,DummyMultipleReturnERC20Token",
"abis": "./test/generated-artifacts/@(DummyERC20Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|ERC20Token|IERC20Token|IEtherToken|LibERC20Token|MintableERC20Token|TestLibERC20Token|TestLibERC20TokenTarget|UnlimitedAllowanceERC20Token|UntransferrableDummyERC20Token|WETH9|ZRXToken).json", "abis": "./test/generated-artifacts/@(DummyERC20Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|ERC20Token|IERC20Token|IERC20TokenV06|IEtherToken|IEtherTokenV06|LibERC20Token|LibERC20TokenV06|MintableERC20Token|TestLibERC20Token|TestLibERC20TokenTarget|UnlimitedAllowanceERC20Token|UntransferrableDummyERC20Token|WETH9|ZRXToken).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
}, },
"repository": { "repository": {

View File

@ -10,8 +10,11 @@ import * as DummyMultipleReturnERC20Token from '../test/generated-artifacts/Dumm
import * as DummyNoReturnERC20Token from '../test/generated-artifacts/DummyNoReturnERC20Token.json'; import * as DummyNoReturnERC20Token from '../test/generated-artifacts/DummyNoReturnERC20Token.json';
import * as ERC20Token from '../test/generated-artifacts/ERC20Token.json'; import * as ERC20Token from '../test/generated-artifacts/ERC20Token.json';
import * as IERC20Token from '../test/generated-artifacts/IERC20Token.json'; import * as IERC20Token from '../test/generated-artifacts/IERC20Token.json';
import * as IERC20TokenV06 from '../test/generated-artifacts/IERC20TokenV06.json';
import * as IEtherToken from '../test/generated-artifacts/IEtherToken.json'; import * as IEtherToken from '../test/generated-artifacts/IEtherToken.json';
import * as IEtherTokenV06 from '../test/generated-artifacts/IEtherTokenV06.json';
import * as LibERC20Token from '../test/generated-artifacts/LibERC20Token.json'; import * as LibERC20Token from '../test/generated-artifacts/LibERC20Token.json';
import * as LibERC20TokenV06 from '../test/generated-artifacts/LibERC20TokenV06.json';
import * as MintableERC20Token from '../test/generated-artifacts/MintableERC20Token.json'; import * as MintableERC20Token from '../test/generated-artifacts/MintableERC20Token.json';
import * as TestLibERC20Token from '../test/generated-artifacts/TestLibERC20Token.json'; import * as TestLibERC20Token from '../test/generated-artifacts/TestLibERC20Token.json';
import * as TestLibERC20TokenTarget from '../test/generated-artifacts/TestLibERC20TokenTarget.json'; import * as TestLibERC20TokenTarget from '../test/generated-artifacts/TestLibERC20TokenTarget.json';
@ -28,6 +31,9 @@ export const artifacts = {
ZRXToken: (ZRXToken as any) as ContractArtifact, ZRXToken: (ZRXToken as any) as ContractArtifact,
IERC20Token: IERC20Token as ContractArtifact, IERC20Token: IERC20Token as ContractArtifact,
IEtherToken: IEtherToken as ContractArtifact, IEtherToken: IEtherToken as ContractArtifact,
IERC20TokenV06: IERC20TokenV06 as ContractArtifact,
IEtherTokenV06: IEtherTokenV06 as ContractArtifact,
LibERC20TokenV06: LibERC20TokenV06 as ContractArtifact,
DummyERC20Token: DummyERC20Token as ContractArtifact, DummyERC20Token: DummyERC20Token as ContractArtifact,
DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact, DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact, DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact,

View File

@ -8,8 +8,11 @@ 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/dummy_no_return_erc20_token';
export * from '../test/generated-wrappers/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';
export * from '../test/generated-wrappers/i_erc20_token_v06';
export * from '../test/generated-wrappers/i_ether_token'; export * from '../test/generated-wrappers/i_ether_token';
export * from '../test/generated-wrappers/i_ether_token_v06';
export * from '../test/generated-wrappers/lib_erc20_token'; export * from '../test/generated-wrappers/lib_erc20_token';
export * from '../test/generated-wrappers/lib_erc20_token_v06';
export * from '../test/generated-wrappers/mintable_erc20_token'; 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';
export * from '../test/generated-wrappers/test_lib_erc20_token_target'; export * from '../test/generated-wrappers/test_lib_erc20_token_target';

View File

@ -14,8 +14,11 @@
"test/generated-artifacts/DummyNoReturnERC20Token.json", "test/generated-artifacts/DummyNoReturnERC20Token.json",
"test/generated-artifacts/ERC20Token.json", "test/generated-artifacts/ERC20Token.json",
"test/generated-artifacts/IERC20Token.json", "test/generated-artifacts/IERC20Token.json",
"test/generated-artifacts/IERC20TokenV06.json",
"test/generated-artifacts/IEtherToken.json", "test/generated-artifacts/IEtherToken.json",
"test/generated-artifacts/IEtherTokenV06.json",
"test/generated-artifacts/LibERC20Token.json", "test/generated-artifacts/LibERC20Token.json",
"test/generated-artifacts/LibERC20TokenV06.json",
"test/generated-artifacts/MintableERC20Token.json", "test/generated-artifacts/MintableERC20Token.json",
"test/generated-artifacts/TestLibERC20Token.json", "test/generated-artifacts/TestLibERC20Token.json",
"test/generated-artifacts/TestLibERC20TokenTarget.json", "test/generated-artifacts/TestLibERC20TokenTarget.json",

View File

@ -13,6 +13,10 @@
{ {
"note": "Add solidity 0.6 contracts", "note": "Add solidity 0.6 contracts",
"pr": 2540 "pr": 2540
},
{
"note": "Add more solidity 0.6 contracts",
"pr": 2545
} }
] ]
}, },

View File

@ -0,0 +1,166 @@
/*
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.6.5;
import "./interfaces/IAuthorizableV06.sol";
import "./errors/LibRichErrorsV06.sol";
import "./errors/LibAuthorizableRichErrorsV06.sol";
import "./OwnableV06.sol";
// solhint-disable no-empty-blocks
contract AuthorizableV06 is
OwnableV06,
IAuthorizableV06
{
/// @dev Only authorized addresses can invoke functions with this modifier.
modifier onlyAuthorized {
_assertSenderIsAuthorized();
_;
}
/// @dev Whether an address is authorized to call privileged functions.
/// @param 0 Address to query.
/// @return 0 Whether the address is authorized.
mapping (address => bool) public override authorized;
/// @dev Whether an address is authorized to call privileged functions.
/// @param 0 Index of authorized address.
/// @return 0 Authorized address.
address[] public override authorities;
/// @dev Initializes the `owner` address.
constructor()
public
OwnableV06()
{}
/// @dev Authorizes an address.
/// @param target Address to authorize.
function addAuthorizedAddress(address target)
external
override
onlyOwner
{
_addAuthorizedAddress(target);
}
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
function removeAuthorizedAddress(address target)
external
override
onlyOwner
{
if (!authorized[target]) {
LibRichErrorsV06.rrevert(LibAuthorizableRichErrorsV06.TargetNotAuthorizedError(target));
}
for (uint256 i = 0; i < authorities.length; i++) {
if (authorities[i] == target) {
_removeAuthorizedAddressAtIndex(target, i);
break;
}
}
}
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
/// @param index Index of target in authorities array.
function removeAuthorizedAddressAtIndex(
address target,
uint256 index
)
external
override
onlyOwner
{
_removeAuthorizedAddressAtIndex(target, index);
}
/// @dev Gets all authorized addresses.
/// @return Array of authorized addresses.
function getAuthorizedAddresses()
external
override
view
returns (address[] memory)
{
return authorities;
}
/// @dev Reverts if msg.sender is not authorized.
function _assertSenderIsAuthorized()
internal
view
{
if (!authorized[msg.sender]) {
LibRichErrorsV06.rrevert(LibAuthorizableRichErrorsV06.SenderNotAuthorizedError(msg.sender));
}
}
/// @dev Authorizes an address.
/// @param target Address to authorize.
function _addAuthorizedAddress(address target)
internal
{
// Ensure that the target is not the zero address.
if (target == address(0)) {
LibRichErrorsV06.rrevert(LibAuthorizableRichErrorsV06.ZeroCantBeAuthorizedError());
}
// Ensure that the target is not already authorized.
if (authorized[target]) {
LibRichErrorsV06.rrevert(LibAuthorizableRichErrorsV06.TargetAlreadyAuthorizedError(target));
}
authorized[target] = true;
authorities.push(target);
emit AuthorizedAddressAdded(target, msg.sender);
}
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
/// @param index Index of target in authorities array.
function _removeAuthorizedAddressAtIndex(
address target,
uint256 index
)
internal
{
if (!authorized[target]) {
LibRichErrorsV06.rrevert(LibAuthorizableRichErrorsV06.TargetNotAuthorizedError(target));
}
if (index >= authorities.length) {
LibRichErrorsV06.rrevert(LibAuthorizableRichErrorsV06.IndexOutOfBoundsError(
index,
authorities.length
));
}
if (authorities[index] != target) {
LibRichErrorsV06.rrevert(LibAuthorizableRichErrorsV06.AuthorizedAddressMismatchError(
authorities[index],
target
));
}
delete authorized[target];
authorities[index] = authorities[authorities.length - 1];
authorities.pop();
emit AuthorizedAddressRemoved(target, msg.sender);
}
}

View File

@ -0,0 +1,228 @@
/*
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.6.5;
import "./LibSafeMathV06.sol";
import "./errors/LibRichErrorsV06.sol";
import "./errors/LibMathRichErrorsV06.sol";
library LibMathV06 {
using LibSafeMathV06 for uint256;
/// @dev Calculates partial value given a numerator and denominator rounded down.
/// Reverts if rounding error is >= 0.1%
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to calculate partial of.
/// @return partialAmount Partial value of target rounded down.
function safeGetPartialAmountFloor(
uint256 numerator,
uint256 denominator,
uint256 target
)
internal
pure
returns (uint256 partialAmount)
{
if (isRoundingErrorFloor(
numerator,
denominator,
target
)) {
LibRichErrorsV06.rrevert(LibMathRichErrorsV06.RoundingError(
numerator,
denominator,
target
));
}
partialAmount = numerator.safeMul(target).safeDiv(denominator);
return partialAmount;
}
/// @dev Calculates partial value given a numerator and denominator rounded down.
/// Reverts if rounding error is >= 0.1%
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to calculate partial of.
/// @return partialAmount Partial value of target rounded up.
function safeGetPartialAmountCeil(
uint256 numerator,
uint256 denominator,
uint256 target
)
internal
pure
returns (uint256 partialAmount)
{
if (isRoundingErrorCeil(
numerator,
denominator,
target
)) {
LibRichErrorsV06.rrevert(LibMathRichErrorsV06.RoundingError(
numerator,
denominator,
target
));
}
// safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
// ceil(a / b) = floor((a + b - 1) / b)
// To implement `ceil(a / b)` using safeDiv.
partialAmount = numerator.safeMul(target)
.safeAdd(denominator.safeSub(1))
.safeDiv(denominator);
return partialAmount;
}
/// @dev Calculates partial value given a numerator and denominator rounded down.
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to calculate partial of.
/// @return partialAmount Partial value of target rounded down.
function getPartialAmountFloor(
uint256 numerator,
uint256 denominator,
uint256 target
)
internal
pure
returns (uint256 partialAmount)
{
partialAmount = numerator.safeMul(target).safeDiv(denominator);
return partialAmount;
}
/// @dev Calculates partial value given a numerator and denominator rounded down.
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to calculate partial of.
/// @return partialAmount Partial value of target rounded up.
function getPartialAmountCeil(
uint256 numerator,
uint256 denominator,
uint256 target
)
internal
pure
returns (uint256 partialAmount)
{
// safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
// ceil(a / b) = floor((a + b - 1) / b)
// To implement `ceil(a / b)` using safeDiv.
partialAmount = numerator.safeMul(target)
.safeAdd(denominator.safeSub(1))
.safeDiv(denominator);
return partialAmount;
}
/// @dev Checks if rounding error >= 0.1% when rounding down.
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to multiply with numerator/denominator.
/// @return isError Rounding error is present.
function isRoundingErrorFloor(
uint256 numerator,
uint256 denominator,
uint256 target
)
internal
pure
returns (bool isError)
{
if (denominator == 0) {
LibRichErrorsV06.rrevert(LibMathRichErrorsV06.DivisionByZeroError());
}
// The absolute rounding error is the difference between the rounded
// value and the ideal value. The relative rounding error is the
// absolute rounding error divided by the absolute value of the
// ideal value. This is undefined when the ideal value is zero.
//
// The ideal value is `numerator * target / denominator`.
// Let's call `numerator * target % denominator` the remainder.
// The absolute error is `remainder / denominator`.
//
// When the ideal value is zero, we require the absolute error to
// be zero. Fortunately, this is always the case. The ideal value is
// zero iff `numerator == 0` and/or `target == 0`. In this case the
// remainder and absolute error are also zero.
if (target == 0 || numerator == 0) {
return false;
}
// Otherwise, we want the relative rounding error to be strictly
// less than 0.1%.
// The relative error is `remainder / (numerator * target)`.
// We want the relative error less than 1 / 1000:
// remainder / (numerator * denominator) < 1 / 1000
// or equivalently:
// 1000 * remainder < numerator * target
// so we have a rounding error iff:
// 1000 * remainder >= numerator * target
uint256 remainder = mulmod(
target,
numerator,
denominator
);
isError = remainder.safeMul(1000) >= numerator.safeMul(target);
return isError;
}
/// @dev Checks if rounding error >= 0.1% when rounding up.
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to multiply with numerator/denominator.
/// @return isError Rounding error is present.
function isRoundingErrorCeil(
uint256 numerator,
uint256 denominator,
uint256 target
)
internal
pure
returns (bool isError)
{
if (denominator == 0) {
LibRichErrorsV06.rrevert(LibMathRichErrorsV06.DivisionByZeroError());
}
// See the comments in `isRoundingError`.
if (target == 0 || numerator == 0) {
// When either is zero, the ideal value and rounded value are zero
// and there is no rounding error. (Although the relative error
// is undefined.)
return false;
}
// Compute remainder as before
uint256 remainder = mulmod(
target,
numerator,
denominator
);
remainder = denominator.safeSub(remainder) % denominator;
isError = remainder.safeMul(1000) >= numerator.safeMul(target);
return isError;
}
}

View File

@ -0,0 +1,108 @@
/*
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.6.5;
import "./errors/LibRichErrorsV06.sol";
import "./errors/LibSafeMathRichErrorsV06.sol";
library LibSafeMathV06 {
function safeMul(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
if (a == 0) {
return 0;
}
uint256 c = a * b;
if (c / a != b) {
LibRichErrorsV06.rrevert(LibSafeMathRichErrorsV06.Uint256BinOpError(
LibSafeMathRichErrorsV06.BinOpErrorCodes.MULTIPLICATION_OVERFLOW,
a,
b
));
}
return c;
}
function safeDiv(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
if (b == 0) {
LibRichErrorsV06.rrevert(LibSafeMathRichErrorsV06.Uint256BinOpError(
LibSafeMathRichErrorsV06.BinOpErrorCodes.DIVISION_BY_ZERO,
a,
b
));
}
uint256 c = a / b;
return c;
}
function safeSub(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
if (b > a) {
LibRichErrorsV06.rrevert(LibSafeMathRichErrorsV06.Uint256BinOpError(
LibSafeMathRichErrorsV06.BinOpErrorCodes.SUBTRACTION_UNDERFLOW,
a,
b
));
}
return a - b;
}
function safeAdd(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
uint256 c = a + b;
if (c < a) {
LibRichErrorsV06.rrevert(LibSafeMathRichErrorsV06.Uint256BinOpError(
LibSafeMathRichErrorsV06.BinOpErrorCodes.ADDITION_OVERFLOW,
a,
b
));
}
return c;
}
function max256(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
return a >= b ? a : b;
}
function min256(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
return a < b ? a : b;
}
}

View File

@ -0,0 +1,68 @@
/*
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.6.5;
import "./interfaces/IOwnableV06.sol";
import "./errors/LibRichErrorsV06.sol";
import "./errors/LibOwnableRichErrorsV06.sol";
contract OwnableV06 is
IOwnableV06
{
/// @dev The owner of this contract.
/// @return 0 The owner address.
address public override owner;
constructor() public {
owner = msg.sender;
}
modifier onlyOwner() {
_assertSenderIsOwner();
_;
}
/// @dev Change the owner of this contract.
/// @param newOwner New owner address.
function transferOwnership(address newOwner)
public
override
onlyOwner
{
if (newOwner == address(0)) {
LibRichErrorsV06.rrevert(LibOwnableRichErrorsV06.TransferOwnerToZeroError());
} else {
owner = newOwner;
emit OwnershipTransferred(msg.sender, newOwner);
}
}
function _assertSenderIsOwner()
internal
view
{
if (msg.sender != owner) {
LibRichErrorsV06.rrevert(LibOwnableRichErrorsV06.OnlyOwnerError(
msg.sender,
owner
));
}
}
}

View File

@ -0,0 +1,57 @@
/*
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.6.5;
import "./errors/LibReentrancyGuardRichErrorsV06.sol";
import "./errors/LibRichErrorsV06.sol";
contract ReentrancyGuardV06 {
// Locked state of mutex.
bool private _locked = false;
/// @dev Functions with this modifer cannot be reentered. The mutex will be locked
/// before function execution and unlocked after.
modifier nonReentrant() {
_lockMutexOrThrowIfAlreadyLocked();
_;
_unlockMutex();
}
function _lockMutexOrThrowIfAlreadyLocked()
internal
{
// Ensure mutex is unlocked.
if (_locked) {
LibRichErrorsV06.rrevert(
LibReentrancyGuardRichErrorsV06.IllegalReentrancyError()
);
}
// Lock mutex.
_locked = true;
}
function _unlockMutex()
internal
{
// Unlock mutex.
_locked = false;
}
}

View File

@ -0,0 +1,119 @@
/*
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.6.5;
library LibAuthorizableRichErrorsV06 {
// bytes4(keccak256("AuthorizedAddressMismatchError(address,address)"))
bytes4 internal constant AUTHORIZED_ADDRESS_MISMATCH_ERROR_SELECTOR =
0x140a84db;
// bytes4(keccak256("IndexOutOfBoundsError(uint256,uint256)"))
bytes4 internal constant INDEX_OUT_OF_BOUNDS_ERROR_SELECTOR =
0xe9f83771;
// bytes4(keccak256("SenderNotAuthorizedError(address)"))
bytes4 internal constant SENDER_NOT_AUTHORIZED_ERROR_SELECTOR =
0xb65a25b9;
// bytes4(keccak256("TargetAlreadyAuthorizedError(address)"))
bytes4 internal constant TARGET_ALREADY_AUTHORIZED_ERROR_SELECTOR =
0xde16f1a0;
// bytes4(keccak256("TargetNotAuthorizedError(address)"))
bytes4 internal constant TARGET_NOT_AUTHORIZED_ERROR_SELECTOR =
0xeb5108a2;
// bytes4(keccak256("ZeroCantBeAuthorizedError()"))
bytes internal constant ZERO_CANT_BE_AUTHORIZED_ERROR_BYTES =
hex"57654fe4";
// solhint-disable func-name-mixedcase
function AuthorizedAddressMismatchError(
address authorized,
address target
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
AUTHORIZED_ADDRESS_MISMATCH_ERROR_SELECTOR,
authorized,
target
);
}
function IndexOutOfBoundsError(
uint256 index,
uint256 length
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
INDEX_OUT_OF_BOUNDS_ERROR_SELECTOR,
index,
length
);
}
function SenderNotAuthorizedError(address sender)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
SENDER_NOT_AUTHORIZED_ERROR_SELECTOR,
sender
);
}
function TargetAlreadyAuthorizedError(address target)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
TARGET_ALREADY_AUTHORIZED_ERROR_SELECTOR,
target
);
}
function TargetNotAuthorizedError(address target)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
TARGET_NOT_AUTHORIZED_ERROR_SELECTOR,
target
);
}
function ZeroCantBeAuthorizedError()
internal
pure
returns (bytes memory)
{
return ZERO_CANT_BE_AUTHORIZED_ERROR_BYTES;
}
}

View File

@ -0,0 +1,57 @@
/*
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.6.5;
library LibMathRichErrorsV06 {
// bytes4(keccak256("DivisionByZeroError()"))
bytes internal constant DIVISION_BY_ZERO_ERROR =
hex"a791837c";
// bytes4(keccak256("RoundingError(uint256,uint256,uint256)"))
bytes4 internal constant ROUNDING_ERROR_SELECTOR =
0x339f3de2;
// solhint-disable func-name-mixedcase
function DivisionByZeroError()
internal
pure
returns (bytes memory)
{
return DIVISION_BY_ZERO_ERROR;
}
function RoundingError(
uint256 numerator,
uint256 denominator,
uint256 target
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
ROUNDING_ERROR_SELECTOR,
numerator,
denominator,
target
);
}
}

View File

@ -0,0 +1,54 @@
/*
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.6.5;
library LibOwnableRichErrorsV06 {
// bytes4(keccak256("OnlyOwnerError(address,address)"))
bytes4 internal constant ONLY_OWNER_ERROR_SELECTOR =
0x1de45ad1;
// bytes4(keccak256("TransferOwnerToZeroError()"))
bytes internal constant TRANSFER_OWNER_TO_ZERO_ERROR_BYTES =
hex"e69edc3e";
// solhint-disable func-name-mixedcase
function OnlyOwnerError(
address sender,
address owner
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
ONLY_OWNER_ERROR_SELECTOR,
sender,
owner
);
}
function TransferOwnerToZeroError()
internal
pure
returns (bytes memory)
{
return TRANSFER_OWNER_TO_ZERO_ERROR_BYTES;
}
}

View File

@ -0,0 +1,36 @@
/*
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.6.5;
library LibReentrancyGuardRichErrorsV06 {
// bytes4(keccak256("IllegalReentrancyError()"))
bytes internal constant ILLEGAL_REENTRANCY_ERROR_SELECTOR_BYTES =
hex"0c3b823f";
// solhint-disable func-name-mixedcase
function IllegalReentrancyError()
internal
pure
returns (bytes memory)
{
return ILLEGAL_REENTRANCY_ERROR_SELECTOR_BYTES;
}
}

View File

@ -0,0 +1,77 @@
/*
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.6.5;
library LibSafeMathRichErrorsV06 {
// bytes4(keccak256("Uint256BinOpError(uint8,uint256,uint256)"))
bytes4 internal constant UINT256_BINOP_ERROR_SELECTOR =
0xe946c1bb;
// bytes4(keccak256("Uint256DowncastError(uint8,uint256)"))
bytes4 internal constant UINT256_DOWNCAST_ERROR_SELECTOR =
0xc996af7b;
enum BinOpErrorCodes {
ADDITION_OVERFLOW,
MULTIPLICATION_OVERFLOW,
SUBTRACTION_UNDERFLOW,
DIVISION_BY_ZERO
}
enum DowncastErrorCodes {
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT32,
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT64,
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT96
}
// solhint-disable func-name-mixedcase
function Uint256BinOpError(
BinOpErrorCodes errorCode,
uint256 a,
uint256 b
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
UINT256_BINOP_ERROR_SELECTOR,
errorCode,
a,
b
);
}
function Uint256DowncastError(
DowncastErrorCodes errorCode,
uint256 a
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
UINT256_DOWNCAST_ERROR_SELECTOR,
errorCode,
a
);
}
}

View File

@ -0,0 +1,75 @@
/*
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.6.5;
import "./IOwnableV06.sol";
interface IAuthorizableV06 is
IOwnableV06
{
// Event logged when a new address is authorized.
event AuthorizedAddressAdded(
address indexed target,
address indexed caller
);
// Event logged when a currently authorized address is unauthorized.
event AuthorizedAddressRemoved(
address indexed target,
address indexed caller
);
/// @dev Authorizes an address.
/// @param target Address to authorize.
function addAuthorizedAddress(address target)
external;
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
function removeAuthorizedAddress(address target)
external;
/// @dev Removes authorizion of an address.
/// @param target Address to remove authorization from.
/// @param index Index of target in authorities array.
function removeAuthorizedAddressAtIndex(
address target,
uint256 index
)
external;
/// @dev Gets all authorized addresses.
/// @return authorizedAddresses Array of authorized addresses.
function getAuthorizedAddresses()
external
view
returns (address[] memory authorizedAddresses);
/// @dev Whether an adderss is authorized to call privileged functions.
/// @param addr Address to query.
/// @return isAuthorized Whether the address is authorized.
function authorized(address addr) external view returns (bool isAuthorized);
/// @dev All addresseses authorized to call privileged functions.
/// @param idx Index of authorized address.
/// @return addr Authorized address.
function authorities(uint256 idx) external view returns (address addr);
}

View File

@ -38,7 +38,7 @@
"config": { "config": {
"publicInterfaceContracts": "Authorizable,IAuthorizable,IOwnable,LibAddress,LibAddressArray,LibAddressArrayRichErrors,LibAuthorizableRichErrors,LibBytes,LibBytesRichErrors,LibEIP1271,LibEIP712,LibFractions,LibOwnableRichErrors,LibReentrancyGuardRichErrors,LibRichErrors,LibSafeMath,LibSafeMathRichErrors,Ownable,ReentrancyGuard,Refundable", "publicInterfaceContracts": "Authorizable,IAuthorizable,IOwnable,LibAddress,LibAddressArray,LibAddressArrayRichErrors,LibAuthorizableRichErrors,LibBytes,LibBytesRichErrors,LibEIP1271,LibEIP712,LibFractions,LibOwnableRichErrors,LibReentrancyGuardRichErrors,LibRichErrors,LibSafeMath,LibSafeMathRichErrors,Ownable,ReentrancyGuard,Refundable",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(Authorizable|D18|DeploymentConstants|IAuthorizable|IOwnable|IOwnableV06|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibBytes|LibBytesRichErrors|LibBytesRichErrorsV06|LibBytesV06|LibEIP1271|LibEIP712|LibFractions|LibOwnableRichErrors|LibReentrancyGuardRichErrors|LibRichErrors|LibRichErrorsV06|LibSafeMath|LibSafeMathRichErrors|Ownable|ReentrancyGuard|Refundable|TestAuthorizable|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibRichErrors|TestLibSafeMath|TestLogDecoding|TestLogDecodingDownstream|TestOwnable|TestReentrancyGuard|TestRefundable|TestRefundableReceiver).json" "abis": "./test/generated-artifacts/@(Authorizable|AuthorizableV06|D18|DeploymentConstants|IAuthorizable|IAuthorizableV06|IOwnable|IOwnableV06|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibAuthorizableRichErrorsV06|LibBytes|LibBytesRichErrors|LibBytesRichErrorsV06|LibBytesV06|LibEIP1271|LibEIP712|LibFractions|LibMathRichErrorsV06|LibMathV06|LibOwnableRichErrors|LibOwnableRichErrorsV06|LibReentrancyGuardRichErrors|LibReentrancyGuardRichErrorsV06|LibRichErrors|LibRichErrorsV06|LibSafeMath|LibSafeMathRichErrors|LibSafeMathRichErrorsV06|LibSafeMathV06|Ownable|OwnableV06|ReentrancyGuard|ReentrancyGuardV06|Refundable|TestAuthorizable|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibRichErrors|TestLibSafeMath|TestLogDecoding|TestLogDecodingDownstream|TestOwnable|TestReentrancyGuard|TestRefundable|TestRefundableReceiver).json"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -6,15 +6,18 @@
import { ContractArtifact } from 'ethereum-types'; import { ContractArtifact } from 'ethereum-types';
import * as Authorizable from '../test/generated-artifacts/Authorizable.json'; import * as Authorizable from '../test/generated-artifacts/Authorizable.json';
import * as AuthorizableV06 from '../test/generated-artifacts/AuthorizableV06.json';
import * as D18 from '../test/generated-artifacts/D18.json'; import * as D18 from '../test/generated-artifacts/D18.json';
import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json'; import * as DeploymentConstants from '../test/generated-artifacts/DeploymentConstants.json';
import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json'; import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json';
import * as IAuthorizableV06 from '../test/generated-artifacts/IAuthorizableV06.json';
import * as IOwnable from '../test/generated-artifacts/IOwnable.json'; import * as IOwnable from '../test/generated-artifacts/IOwnable.json';
import * as IOwnableV06 from '../test/generated-artifacts/IOwnableV06.json'; import * as IOwnableV06 from '../test/generated-artifacts/IOwnableV06.json';
import * as LibAddress from '../test/generated-artifacts/LibAddress.json'; import * as LibAddress from '../test/generated-artifacts/LibAddress.json';
import * as LibAddressArray from '../test/generated-artifacts/LibAddressArray.json'; import * as LibAddressArray from '../test/generated-artifacts/LibAddressArray.json';
import * as LibAddressArrayRichErrors from '../test/generated-artifacts/LibAddressArrayRichErrors.json'; import * as LibAddressArrayRichErrors from '../test/generated-artifacts/LibAddressArrayRichErrors.json';
import * as LibAuthorizableRichErrors from '../test/generated-artifacts/LibAuthorizableRichErrors.json'; import * as LibAuthorizableRichErrors from '../test/generated-artifacts/LibAuthorizableRichErrors.json';
import * as LibAuthorizableRichErrorsV06 from '../test/generated-artifacts/LibAuthorizableRichErrorsV06.json';
import * as LibBytes from '../test/generated-artifacts/LibBytes.json'; import * as LibBytes from '../test/generated-artifacts/LibBytes.json';
import * as LibBytesRichErrors from '../test/generated-artifacts/LibBytesRichErrors.json'; import * as LibBytesRichErrors from '../test/generated-artifacts/LibBytesRichErrors.json';
import * as LibBytesRichErrorsV06 from '../test/generated-artifacts/LibBytesRichErrorsV06.json'; import * as LibBytesRichErrorsV06 from '../test/generated-artifacts/LibBytesRichErrorsV06.json';
@ -22,14 +25,22 @@ import * as LibBytesV06 from '../test/generated-artifacts/LibBytesV06.json';
import * as LibEIP1271 from '../test/generated-artifacts/LibEIP1271.json'; import * as LibEIP1271 from '../test/generated-artifacts/LibEIP1271.json';
import * as LibEIP712 from '../test/generated-artifacts/LibEIP712.json'; import * as LibEIP712 from '../test/generated-artifacts/LibEIP712.json';
import * as LibFractions from '../test/generated-artifacts/LibFractions.json'; import * as LibFractions from '../test/generated-artifacts/LibFractions.json';
import * as LibMathRichErrorsV06 from '../test/generated-artifacts/LibMathRichErrorsV06.json';
import * as LibMathV06 from '../test/generated-artifacts/LibMathV06.json';
import * as LibOwnableRichErrors from '../test/generated-artifacts/LibOwnableRichErrors.json'; import * as LibOwnableRichErrors from '../test/generated-artifacts/LibOwnableRichErrors.json';
import * as LibOwnableRichErrorsV06 from '../test/generated-artifacts/LibOwnableRichErrorsV06.json';
import * as LibReentrancyGuardRichErrors from '../test/generated-artifacts/LibReentrancyGuardRichErrors.json'; import * as LibReentrancyGuardRichErrors from '../test/generated-artifacts/LibReentrancyGuardRichErrors.json';
import * as LibReentrancyGuardRichErrorsV06 from '../test/generated-artifacts/LibReentrancyGuardRichErrorsV06.json';
import * as LibRichErrors from '../test/generated-artifacts/LibRichErrors.json'; import * as LibRichErrors from '../test/generated-artifacts/LibRichErrors.json';
import * as LibRichErrorsV06 from '../test/generated-artifacts/LibRichErrorsV06.json'; import * as LibRichErrorsV06 from '../test/generated-artifacts/LibRichErrorsV06.json';
import * as LibSafeMath from '../test/generated-artifacts/LibSafeMath.json'; import * as LibSafeMath from '../test/generated-artifacts/LibSafeMath.json';
import * as LibSafeMathRichErrors from '../test/generated-artifacts/LibSafeMathRichErrors.json'; import * as LibSafeMathRichErrors from '../test/generated-artifacts/LibSafeMathRichErrors.json';
import * as LibSafeMathRichErrorsV06 from '../test/generated-artifacts/LibSafeMathRichErrorsV06.json';
import * as LibSafeMathV06 from '../test/generated-artifacts/LibSafeMathV06.json';
import * as Ownable from '../test/generated-artifacts/Ownable.json'; import * as Ownable from '../test/generated-artifacts/Ownable.json';
import * as OwnableV06 from '../test/generated-artifacts/OwnableV06.json';
import * as ReentrancyGuard from '../test/generated-artifacts/ReentrancyGuard.json'; import * as ReentrancyGuard from '../test/generated-artifacts/ReentrancyGuard.json';
import * as ReentrancyGuardV06 from '../test/generated-artifacts/ReentrancyGuardV06.json';
import * as Refundable from '../test/generated-artifacts/Refundable.json'; import * as Refundable from '../test/generated-artifacts/Refundable.json';
import * as TestAuthorizable from '../test/generated-artifacts/TestAuthorizable.json'; import * as TestAuthorizable from '../test/generated-artifacts/TestAuthorizable.json';
import * as TestLibAddress from '../test/generated-artifacts/TestLibAddress.json'; import * as TestLibAddress from '../test/generated-artifacts/TestLibAddress.json';
@ -67,9 +78,20 @@ export const artifacts = {
Refundable: Refundable as ContractArtifact, Refundable: Refundable as ContractArtifact,
IAuthorizable: IAuthorizable as ContractArtifact, IAuthorizable: IAuthorizable as ContractArtifact,
IOwnable: IOwnable as ContractArtifact, IOwnable: IOwnable as ContractArtifact,
AuthorizableV06: AuthorizableV06 as ContractArtifact,
LibBytesV06: LibBytesV06 as ContractArtifact, LibBytesV06: LibBytesV06 as ContractArtifact,
LibMathV06: LibMathV06 as ContractArtifact,
LibSafeMathV06: LibSafeMathV06 as ContractArtifact,
OwnableV06: OwnableV06 as ContractArtifact,
ReentrancyGuardV06: ReentrancyGuardV06 as ContractArtifact,
LibAuthorizableRichErrorsV06: LibAuthorizableRichErrorsV06 as ContractArtifact,
LibBytesRichErrorsV06: LibBytesRichErrorsV06 as ContractArtifact, LibBytesRichErrorsV06: LibBytesRichErrorsV06 as ContractArtifact,
LibMathRichErrorsV06: LibMathRichErrorsV06 as ContractArtifact,
LibOwnableRichErrorsV06: LibOwnableRichErrorsV06 as ContractArtifact,
LibReentrancyGuardRichErrorsV06: LibReentrancyGuardRichErrorsV06 as ContractArtifact,
LibRichErrorsV06: LibRichErrorsV06 as ContractArtifact, LibRichErrorsV06: LibRichErrorsV06 as ContractArtifact,
LibSafeMathRichErrorsV06: LibSafeMathRichErrorsV06 as ContractArtifact,
IAuthorizableV06: IAuthorizableV06 as ContractArtifact,
IOwnableV06: IOwnableV06 as ContractArtifact, IOwnableV06: IOwnableV06 as ContractArtifact,
TestAuthorizable: TestAuthorizable as ContractArtifact, TestAuthorizable: TestAuthorizable as ContractArtifact,
TestLibAddress: TestLibAddress as ContractArtifact, TestLibAddress: TestLibAddress as ContractArtifact,

View File

@ -4,15 +4,18 @@
* ----------------------------------------------------------------------------- * -----------------------------------------------------------------------------
*/ */
export * from '../test/generated-wrappers/authorizable'; export * from '../test/generated-wrappers/authorizable';
export * from '../test/generated-wrappers/authorizable_v06';
export * from '../test/generated-wrappers/d18'; export * from '../test/generated-wrappers/d18';
export * from '../test/generated-wrappers/deployment_constants'; export * from '../test/generated-wrappers/deployment_constants';
export * from '../test/generated-wrappers/i_authorizable'; export * from '../test/generated-wrappers/i_authorizable';
export * from '../test/generated-wrappers/i_authorizable_v06';
export * from '../test/generated-wrappers/i_ownable'; export * from '../test/generated-wrappers/i_ownable';
export * from '../test/generated-wrappers/i_ownable_v06'; export * from '../test/generated-wrappers/i_ownable_v06';
export * from '../test/generated-wrappers/lib_address'; export * from '../test/generated-wrappers/lib_address';
export * from '../test/generated-wrappers/lib_address_array'; export * from '../test/generated-wrappers/lib_address_array';
export * from '../test/generated-wrappers/lib_address_array_rich_errors'; export * from '../test/generated-wrappers/lib_address_array_rich_errors';
export * from '../test/generated-wrappers/lib_authorizable_rich_errors'; export * from '../test/generated-wrappers/lib_authorizable_rich_errors';
export * from '../test/generated-wrappers/lib_authorizable_rich_errors_v06';
export * from '../test/generated-wrappers/lib_bytes'; export * from '../test/generated-wrappers/lib_bytes';
export * from '../test/generated-wrappers/lib_bytes_rich_errors'; export * from '../test/generated-wrappers/lib_bytes_rich_errors';
export * from '../test/generated-wrappers/lib_bytes_rich_errors_v06'; export * from '../test/generated-wrappers/lib_bytes_rich_errors_v06';
@ -20,14 +23,22 @@ export * from '../test/generated-wrappers/lib_bytes_v06';
export * from '../test/generated-wrappers/lib_e_i_p1271'; export * from '../test/generated-wrappers/lib_e_i_p1271';
export * from '../test/generated-wrappers/lib_e_i_p712'; export * from '../test/generated-wrappers/lib_e_i_p712';
export * from '../test/generated-wrappers/lib_fractions'; export * from '../test/generated-wrappers/lib_fractions';
export * from '../test/generated-wrappers/lib_math_rich_errors_v06';
export * from '../test/generated-wrappers/lib_math_v06';
export * from '../test/generated-wrappers/lib_ownable_rich_errors'; export * from '../test/generated-wrappers/lib_ownable_rich_errors';
export * from '../test/generated-wrappers/lib_ownable_rich_errors_v06';
export * from '../test/generated-wrappers/lib_reentrancy_guard_rich_errors'; export * from '../test/generated-wrappers/lib_reentrancy_guard_rich_errors';
export * from '../test/generated-wrappers/lib_reentrancy_guard_rich_errors_v06';
export * from '../test/generated-wrappers/lib_rich_errors'; export * from '../test/generated-wrappers/lib_rich_errors';
export * from '../test/generated-wrappers/lib_rich_errors_v06'; export * from '../test/generated-wrappers/lib_rich_errors_v06';
export * from '../test/generated-wrappers/lib_safe_math'; export * from '../test/generated-wrappers/lib_safe_math';
export * from '../test/generated-wrappers/lib_safe_math_rich_errors'; export * from '../test/generated-wrappers/lib_safe_math_rich_errors';
export * from '../test/generated-wrappers/lib_safe_math_rich_errors_v06';
export * from '../test/generated-wrappers/lib_safe_math_v06';
export * from '../test/generated-wrappers/ownable'; export * from '../test/generated-wrappers/ownable';
export * from '../test/generated-wrappers/ownable_v06';
export * from '../test/generated-wrappers/reentrancy_guard'; export * from '../test/generated-wrappers/reentrancy_guard';
export * from '../test/generated-wrappers/reentrancy_guard_v06';
export * from '../test/generated-wrappers/refundable'; export * from '../test/generated-wrappers/refundable';
export * from '../test/generated-wrappers/test_authorizable'; export * from '../test/generated-wrappers/test_authorizable';
export * from '../test/generated-wrappers/test_lib_address'; export * from '../test/generated-wrappers/test_lib_address';

View File

@ -24,15 +24,18 @@
"generated-artifacts/ReentrancyGuard.json", "generated-artifacts/ReentrancyGuard.json",
"generated-artifacts/Refundable.json", "generated-artifacts/Refundable.json",
"test/generated-artifacts/Authorizable.json", "test/generated-artifacts/Authorizable.json",
"test/generated-artifacts/AuthorizableV06.json",
"test/generated-artifacts/D18.json", "test/generated-artifacts/D18.json",
"test/generated-artifacts/DeploymentConstants.json", "test/generated-artifacts/DeploymentConstants.json",
"test/generated-artifacts/IAuthorizable.json", "test/generated-artifacts/IAuthorizable.json",
"test/generated-artifacts/IAuthorizableV06.json",
"test/generated-artifacts/IOwnable.json", "test/generated-artifacts/IOwnable.json",
"test/generated-artifacts/IOwnableV06.json", "test/generated-artifacts/IOwnableV06.json",
"test/generated-artifacts/LibAddress.json", "test/generated-artifacts/LibAddress.json",
"test/generated-artifacts/LibAddressArray.json", "test/generated-artifacts/LibAddressArray.json",
"test/generated-artifacts/LibAddressArrayRichErrors.json", "test/generated-artifacts/LibAddressArrayRichErrors.json",
"test/generated-artifacts/LibAuthorizableRichErrors.json", "test/generated-artifacts/LibAuthorizableRichErrors.json",
"test/generated-artifacts/LibAuthorizableRichErrorsV06.json",
"test/generated-artifacts/LibBytes.json", "test/generated-artifacts/LibBytes.json",
"test/generated-artifacts/LibBytesRichErrors.json", "test/generated-artifacts/LibBytesRichErrors.json",
"test/generated-artifacts/LibBytesRichErrorsV06.json", "test/generated-artifacts/LibBytesRichErrorsV06.json",
@ -40,14 +43,22 @@
"test/generated-artifacts/LibEIP1271.json", "test/generated-artifacts/LibEIP1271.json",
"test/generated-artifacts/LibEIP712.json", "test/generated-artifacts/LibEIP712.json",
"test/generated-artifacts/LibFractions.json", "test/generated-artifacts/LibFractions.json",
"test/generated-artifacts/LibMathRichErrorsV06.json",
"test/generated-artifacts/LibMathV06.json",
"test/generated-artifacts/LibOwnableRichErrors.json", "test/generated-artifacts/LibOwnableRichErrors.json",
"test/generated-artifacts/LibOwnableRichErrorsV06.json",
"test/generated-artifacts/LibReentrancyGuardRichErrors.json", "test/generated-artifacts/LibReentrancyGuardRichErrors.json",
"test/generated-artifacts/LibReentrancyGuardRichErrorsV06.json",
"test/generated-artifacts/LibRichErrors.json", "test/generated-artifacts/LibRichErrors.json",
"test/generated-artifacts/LibRichErrorsV06.json", "test/generated-artifacts/LibRichErrorsV06.json",
"test/generated-artifacts/LibSafeMath.json", "test/generated-artifacts/LibSafeMath.json",
"test/generated-artifacts/LibSafeMathRichErrors.json", "test/generated-artifacts/LibSafeMathRichErrors.json",
"test/generated-artifacts/LibSafeMathRichErrorsV06.json",
"test/generated-artifacts/LibSafeMathV06.json",
"test/generated-artifacts/Ownable.json", "test/generated-artifacts/Ownable.json",
"test/generated-artifacts/OwnableV06.json",
"test/generated-artifacts/ReentrancyGuard.json", "test/generated-artifacts/ReentrancyGuard.json",
"test/generated-artifacts/ReentrancyGuardV06.json",
"test/generated-artifacts/Refundable.json", "test/generated-artifacts/Refundable.json",
"test/generated-artifacts/TestAuthorizable.json", "test/generated-artifacts/TestAuthorizable.json",
"test/generated-artifacts/TestLibAddress.json", "test/generated-artifacts/TestLibAddress.json",

View File

@ -5,6 +5,10 @@
{ {
"note": "Create this package", "note": "Create this package",
"pr": 2540 "pr": 2540
},
{
"note": "Introduce fill `TransformERC20` feature.",
"pr": 2545
} }
] ]
} }

View File

@ -33,4 +33,14 @@ library LibCommonRichErrors {
sender sender
); );
} }
function IllegalReentrancyError()
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("IllegalReentrancyError()"))
);
}
} }

View File

@ -0,0 +1,46 @@
/*
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.6.5;
library LibSpenderRichErrors {
// solhint-disable func-name-mixedcase
function SpenderERC20TransferFromFailedError(
address token,
address owner,
address to,
uint256 amount,
bytes memory errorData
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("SpenderERC20TransferFromFailedError(address,address,address,uint256,bytes)")),
token,
owner,
to,
amount,
errorData
);
}
}

View File

@ -0,0 +1,209 @@
/*
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.6.5;
library LibTransformERC20RichErrors {
// solhint-disable func-name-mixedcase,separate-by-one-line-in-contract
function InsufficientEthAttachedError(
uint256 ethAttached,
uint256 ethNeeded
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("InsufficientEthAttachedError(uint256,uint256)")),
ethAttached,
ethNeeded
);
}
function IncompleteTransformERC20Error(
address outputToken,
uint256 outputTokenAmount,
uint256 minOutputTokenAmount
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("IncompleteTransformERC20Error(address,uint256,uint256)")),
outputToken,
outputTokenAmount,
minOutputTokenAmount
);
}
function NegativeTransformERC20OutputError(
address outputToken,
uint256 outputTokenLostAmount
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("NegativeTransformERC20OutputError(address,uint256)")),
outputToken,
outputTokenLostAmount
);
}
function UnauthorizedTransformerError(
address transformer,
bytes memory rlpNonce
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("UnauthorizedTransformerError(address,bytes)")),
transformer,
rlpNonce
);
}
function InvalidRLPNonceError(
bytes memory rlpNonce
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("InvalidRLPNonceError(bytes)")),
rlpNonce
);
}
// FillQuoteTransformer errors /////////////////////////////////////////////
function IncompleteFillSellQuoteError(
address sellToken,
uint256 soldAmount,
uint256 sellAmount
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("IncompleteFillSellQuoteError(address,uint256,uint256)")),
sellToken,
soldAmount,
sellAmount
);
}
function IncompleteFillBuyQuoteError(
address buyToken,
uint256 boughtAmount,
uint256 buyAmount
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("IncompleteFillBuyQuoteError(address,uint256,uint256)")),
buyToken,
boughtAmount,
buyAmount
);
}
function InsufficientTakerTokenError(
uint256 tokenBalance,
uint256 tokensNeeded
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("InsufficientTakerTokenError(uint256,uint256)")),
tokenBalance,
tokensNeeded
);
}
function InsufficientProtocolFeeError(
uint256 ethBalance,
uint256 ethNeeded
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("InsufficientProtocolFeeError(uint256,uint256)")),
ethBalance,
ethNeeded
);
}
function InvalidERC20AssetDataError(
bytes memory assetData
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("InvalidERC20AssetDataError(bytes)")),
assetData
);
}
// WethTransformer errors ////////////////////////////////////////////////////
function WrongNumberOfTokensReceivedError(
uint256 actual,
uint256 expected
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("WrongNumberOfTokensReceivedError(uint256,uint256)")),
actual,
expected
);
}
function InvalidTokenReceivedError(
address token
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("InvalidTokenReceivedError(address)")),
token
);
}
}

View File

@ -0,0 +1,65 @@
/*
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.6.5;
library LibWalletRichErrors {
// solhint-disable func-name-mixedcase
function WalletExecuteCallFailedError(
address wallet,
address callTarget,
bytes memory callData,
uint256 callValue,
bytes memory errorData
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("WalletExecuteCallFailedError(address,address,bytes,uint256,bytes)")),
wallet,
callTarget,
callData,
callValue,
errorData
);
}
function WalletExecuteDelegateCallFailedError(
address wallet,
address callTarget,
bytes memory callData,
bytes memory errorData
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
bytes4(keccak256("WalletExecuteDelegateCallFailedError(address,address,bytes,bytes)")),
wallet,
callTarget,
callData,
errorData
);
}
}

View File

@ -0,0 +1,56 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/AuthorizableV06.sol";
import "../errors/LibSpenderRichErrors.sol";
import "./IAllowanceTarget.sol";
/// @dev The allowance target for the TokenSpender feature.
contract AllowanceTarget is
IAllowanceTarget,
AuthorizableV06
{
// solhint-disable no-unused-vars,indent,no-empty-blocks
using LibRichErrorsV06 for bytes;
/// @dev Execute an arbitrary call. Only an authority can call this.
/// @param target The call target.
/// @param callData The call data.
/// @return resultData The data returned by the call.
function executeCall(
address payable target,
bytes calldata callData
)
external
payable
override
onlyAuthorized
returns (bytes memory resultData)
{
bool success;
(success, resultData) = target.call(callData);
if (!success) {
resultData.rrevert();
}
}
}

View File

@ -0,0 +1,175 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/errors/LibOwnableRichErrorsV06.sol";
import "../errors/LibWalletRichErrors.sol";
import "./IFlashWallet.sol";
/// @dev A contract that can execute arbitrary calls from its owner.
contract FlashWallet is
IFlashWallet
{
// solhint-disable no-unused-vars,indent,no-empty-blocks
using LibRichErrorsV06 for bytes;
// solhint-disable
/// @dev Store the owner/deployer as an immutable to make this contract stateless.
address public override immutable owner;
// solhint-enable
constructor() public {
// The deployer is the owner.
owner = msg.sender;
}
/// @dev Allows only the (immutable) owner to call a function.
modifier onlyOwner() virtual {
if (msg.sender != owner) {
LibOwnableRichErrorsV06.OnlyOwnerError(
msg.sender,
owner
).rrevert();
}
_;
}
/// @dev Execute an arbitrary call. Only an authority can call this.
/// @param target The call target.
/// @param callData The call data.
/// @param value Ether to attach to the call.
/// @return resultData The data returned by the call.
function executeCall(
address payable target,
bytes calldata callData,
uint256 value
)
external
payable
override
onlyOwner
returns (bytes memory resultData)
{
bool success;
(success, resultData) = target.call{value: value}(callData);
if (!success) {
LibWalletRichErrors
.WalletExecuteCallFailedError(
address(this),
target,
callData,
value,
resultData
)
.rrevert();
}
}
/// @dev Execute an arbitrary delegatecall, in the context of this puppet.
/// Only an authority can call this.
/// @param target The call target.
/// @param callData The call data.
/// @return resultData The data returned by the call.
function executeDelegateCall(
address payable target,
bytes calldata callData
)
external
payable
override
onlyOwner
returns (bytes memory resultData)
{
bool success;
(success, resultData) = target.delegatecall(callData);
if (!success) {
LibWalletRichErrors
.WalletExecuteDelegateCallFailedError(
address(this),
target,
callData,
resultData
)
.rrevert();
}
}
// solhint-disable
/// @dev Allows this contract to receive ether.
receive() external override payable {}
// solhint-enable
/// @dev Signal support for receiving ERC1155 tokens.
/// @param interfaceID The interface ID, as per ERC-165 rules.
/// @return hasSupport `true` if this contract supports an ERC-165 interface.
function supportsInterface(bytes4 interfaceID)
external
pure
returns (bool hasSupport)
{
return interfaceID == this.supportsInterface.selector ||
interfaceID == this.onERC1155Received.selector ^ this.onERC1155BatchReceived.selector ||
interfaceID == this.tokenFallback.selector;
}
/// @dev Allow this contract to receive ERC1155 tokens.
/// @return success `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
function onERC1155Received(
address, // operator,
address, // from,
uint256, // id,
uint256, // value,
bytes calldata //data
)
external
pure
returns (bytes4 success)
{
return this.onERC1155Received.selector;
}
/// @dev Allow this contract to receive ERC1155 tokens.
/// @return success `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
function onERC1155BatchReceived(
address, // operator,
address, // from,
uint256[] calldata, // ids,
uint256[] calldata, // values,
bytes calldata // data
)
external
pure
returns (bytes4 success)
{
return this.onERC1155BatchReceived.selector;
}
/// @dev Allows this contract to receive ERC223 tokens.
function tokenFallback(
address, // from,
uint256, // value,
bytes calldata // value
)
external
pure
{}
}

View File

@ -0,0 +1,40 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/interfaces/IAuthorizableV06.sol";
/// @dev The allowance target for the TokenSpender feature.
interface IAllowanceTarget is
IAuthorizableV06
{
/// @dev Execute an arbitrary call. Only an authority can call this.
/// @param target The call target.
/// @param callData The call data.
/// @return resultData The data returned by the call.
function executeCall(
address payable target,
bytes calldata callData
)
external
payable
returns (bytes memory resultData);
}

View File

@ -0,0 +1,61 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/interfaces/IOwnableV06.sol";
/// @dev A contract that can execute arbitrary calls from its owner.
interface IFlashWallet {
/// @dev Execute an arbitrary call. Only an authority can call this.
/// @param target The call target.
/// @param callData The call data.
/// @param value Ether to attach to the call.
/// @return resultData The data returned by the call.
function executeCall(
address payable target,
bytes calldata callData,
uint256 value
)
external
payable
returns (bytes memory resultData);
/// @dev Execute an arbitrary delegatecall, in the context of this puppet.
/// Only an authority can call this.
/// @param target The call target.
/// @param callData The call data.
/// @return resultData The data returned by the call.
function executeDelegateCall(
address payable target,
bytes calldata callData
)
external
payable
returns (bytes memory resultData);
/// @dev Allows the puppet to receive ETH.
receive() external payable;
/// @dev Fetch the immutable owner/deployer of this contract.
/// @return owner_ The immutable owner/deployer/
function owner() external view returns (address owner_);
}

View File

@ -0,0 +1,55 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
/// @dev Feature that allows spending token allowances.
interface ITokenSpender {
/// @dev Transfers ERC20 tokens from `owner` to `to`.
/// Only callable from within.
/// @param token The token to spend.
/// @param owner The owner of the tokens.
/// @param to The recipient of the tokens.
/// @param amount The amount of `token` to transfer.
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(IERC20TokenV06 token, address owner)
external
view
returns (uint256 amount);
/// @dev Get the address of the allowance target.
/// @return target The target of token allowances.
function getAllowanceTarget() external view returns (address target);
}

View File

@ -0,0 +1,126 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../transformers/IERC20Transformer.sol";
import "../external/IFlashWallet.sol";
/// @dev Feature to composably transform between ERC20 tokens.
interface ITransformERC20 {
/// @dev Defines a transformation to run in `transformERC20()`.
struct Transformation {
// The transformation handler.
// Can receive the entire balance of `tokens`.
IERC20Transformer transformer;
// Arbitrary data to pass to the transformer.
bytes data;
}
/// @dev Raised upon a successful `transformERC20`.
/// @param taker The taker (caller) address.
/// @param inputToken The token being provided by the taker.
/// If `0xeee...`, ETH is implied and should be provided with the call.`
/// @param outputToken The token to be acquired by the taker.
/// `0xeee...` implies ETH.
/// @param inputTokenAmount The amount of `inputToken` to take from the taker.
/// @param outputTokenAmount The amount of `outputToken` received by the taker.
event TransformedERC20(
address indexed taker,
address inputToken,
address outputToken,
uint256 inputTokenAmount,
uint256 outputTokenAmount
);
/// @dev Deploy a new flash wallet instance and replace the current one with it.
/// Useful if we somehow break the current wallet instance.
/// Anyone can call this.
/// @return wallet The new wallet instance.
function createTransformWallet()
external
returns (IFlashWallet wallet);
/// @dev Executes a series of transformations to convert an ERC20 `inputToken`
/// to an ERC20 `outputToken`.
/// @param inputToken The token being provided by the sender.
/// If `0xeee...`, ETH is implied and should be provided with the call.`
/// @param outputToken The token to be acquired by the sender.
/// `0xeee...` implies ETH.
/// @param inputTokenAmount The amount of `inputToken` to take from the sender.
/// @param minOutputTokenAmount The minimum amount of `outputToken` the sender
/// must receive for the entire transformation to succeed.
/// @param transformations The transformations to execute on the token balance(s)
/// in sequence.
/// @return outputTokenAmount The amount of `outputToken` received by the sender.
function transformERC20(
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 minOutputTokenAmount,
Transformation[] calldata transformations
)
external
payable
returns (uint256 outputTokenAmount);
/// @dev Internal version of `transformERC20()`. Only callable from within.
/// @param callDataHash Hash of the ingress calldata.
/// @param taker The taker address.
/// @param inputToken The token being provided by the taker.
/// If `0xeee...`, ETH is implied and should be provided with the call.`
/// @param outputToken The token to be acquired by the taker.
/// `0xeee...` implies ETH.
/// @param inputTokenAmount The amount of `inputToken` to take from the taker.
/// @param minOutputTokenAmount The minimum amount of `outputToken` the taker
/// must receive for the entire transformation to succeed.
/// @param transformations The transformations to execute on the token balance(s)
/// in sequence.
/// @return outputTokenAmount The amount of `outputToken` received by the taker.
function _transformERC20(
bytes32 callDataHash,
address payable taker,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 minOutputTokenAmount,
Transformation[] calldata transformations
)
external
payable
returns (uint256 outputTokenAmount);
/// @dev Return the current wallet instance that will serve as the execution
/// context for transformations.
/// @return wallet The wallet instance.
function getTransformWallet()
external
view
returns (IFlashWallet wallet);
/// @dev Return the allowed deployer for transformers.
/// @return deployer The transform deployer address.
function getTransformerDeployer()
external
view
returns (address deployer);
}

View File

@ -37,14 +37,11 @@ contract Ownable is
FixinCommon FixinCommon
{ {
// solhint-disable const-name-snakecase
/// @dev Name of this feature.
string constant public override FEATURE_NAME = "Ownable";
/// @dev Version of this feature.
uint256 constant public override FEATURE_VERSION = (1 << 64) | (0 << 32) | (0);
// solhint-enable const-name-snakecase
// solhint-disable // solhint-disable
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "Ownable";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
/// @dev The deployed address of this contract. /// @dev The deployed address of this contract.
address immutable private _implementation; address immutable private _implementation;
// solhint-enable // solhint-enable

View File

@ -35,17 +35,13 @@ contract SimpleFunctionRegistry is
ISimpleFunctionRegistry, ISimpleFunctionRegistry,
FixinCommon FixinCommon
{ {
// solhint-disable const-name-snakecase
/// @dev Name of this feature.
string constant public override FEATURE_NAME = "SimpleFunctionRegistry";
/// @dev Version of this feature.
uint256 constant public override FEATURE_VERSION = (1 << 64) | (0 << 32) | (0);
// solhint-enable const-name-snakecase
// solhint-disable // solhint-disable
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "SimpleFunctionRegistry";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
/// @dev The deployed address of this contract. /// @dev The deployed address of this contract.
address immutable private _implementation; address private immutable _implementation;
// solhint-enable // solhint-enable
using LibRichErrorsV06 for bytes; using LibRichErrorsV06 for bytes;
@ -55,16 +51,15 @@ contract SimpleFunctionRegistry is
} }
/// @dev Initializes this feature. /// @dev Initializes this feature.
/// @param impl The actual address of this feature contract.
/// @return success Magic bytes if successful. /// @return success Magic bytes if successful.
function bootstrap(address impl) external returns (bytes4 success) { function bootstrap() external returns (bytes4 success) {
// Register the registration functions (inception vibes). // Register the registration functions (inception vibes).
_extend(this.extend.selector, impl); _extend(this.extend.selector, _implementation);
// Register the rollback function. // Register the rollback function.
_extend(this.rollback.selector, impl); _extend(this.rollback.selector, _implementation);
// Register getters. // Register getters.
_extend(this.getRollbackLength.selector, impl); _extend(this.getRollbackLength.selector, _implementation);
_extend(this.getRollbackEntryAtIndex.selector, impl); _extend(this.getRollbackEntryAtIndex.selector, _implementation);
return LibBootstrap.BOOTSTRAP_SUCCESS; return LibBootstrap.BOOTSTRAP_SUCCESS;
} }

View File

@ -0,0 +1,143 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
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 "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
import "../errors/LibSpenderRichErrors.sol";
import "../fixins/FixinCommon.sol";
import "../migrations/LibMigrate.sol";
import "../external/IAllowanceTarget.sol";
import "../storage/LibTokenSpenderStorage.sol";
import "./ITokenSpender.sol";
import "./IFeature.sol";
import "./ISimpleFunctionRegistry.sol";
/// @dev Feature that allows spending token allowances.
contract TokenSpender is
IFeature,
ITokenSpender,
FixinCommon
{
// solhint-disable
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "TokenSpender";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
/// @dev The implementation address of this feature.
address private immutable _implementation;
// solhint-enable
using LibRichErrorsV06 for bytes;
constructor() public {
_implementation = address(this);
}
/// @dev Initialize and register this feature. Should be delegatecalled
/// into during a `Migrate.migrate()`.
/// @param allowanceTarget An `allowanceTarget` instance, configured to have
/// the ZeroeEx contract as an authority.
/// @return success `MIGRATE_SUCCESS` on success.
function migrate(IAllowanceTarget allowanceTarget) external returns (bytes4 success) {
LibTokenSpenderStorage.getStorage().allowanceTarget = allowanceTarget;
ISimpleFunctionRegistry(address(this))
.extend(this.getAllowanceTarget.selector, _implementation);
ISimpleFunctionRegistry(address(this))
.extend(this._spendERC20Tokens.selector, _implementation);
ISimpleFunctionRegistry(address(this))
.extend(this.getSpendableERC20BalanceOf.selector, _implementation);
return LibMigrate.MIGRATE_SUCCESS;
}
/// @dev Transfers ERC20 tokens from `owner` to `to`. Only callable from within.
/// @param token The token to spend.
/// @param owner The owner of the tokens.
/// @param to The recipient of the tokens.
/// @param amount The amount of `token` to transfer.
function _spendERC20Tokens(
IERC20TokenV06 token,
address owner,
address to,
uint256 amount
)
external
override
onlySelf
{
IAllowanceTarget spender = LibTokenSpenderStorage.getStorage().allowanceTarget;
// Have the allowance target execute an ERC20 `transferFrom()`.
(bool didSucceed, bytes memory resultData) = address(spender).call(
abi.encodeWithSelector(
IAllowanceTarget.executeCall.selector,
address(token),
abi.encodeWithSelector(
IERC20TokenV06.transferFrom.selector,
owner,
to,
amount
)
)
);
if (didSucceed) {
resultData = abi.decode(resultData, (bytes));
}
if (!didSucceed || !LibERC20TokenV06.isSuccessfulResult(resultData)) {
LibSpenderRichErrors.SpenderERC20TransferFromFailedError(
address(token),
owner,
to,
amount,
resultData
).rrevert();
}
}
/// @dev Gets the maximum amount of an ERC20 token `token` that can be
/// pulled from `owner` by the token spender.
/// @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(IERC20TokenV06 token, address owner)
external
override
view
returns (uint256 amount)
{
return LibSafeMathV06.min256(
token.allowance(owner, address(LibTokenSpenderStorage.getStorage().allowanceTarget)),
token.balanceOf(owner)
);
}
/// @dev Get the address of the allowance target.
/// @return target The target of token allowances.
function getAllowanceTarget()
external
override
view
returns (address target)
{
return address(LibTokenSpenderStorage.getStorage().allowanceTarget);
}
}

View File

@ -0,0 +1,376 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
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/errors/LibRichErrorsV06.sol";
import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
import "../errors/LibTransformERC20RichErrors.sol";
import "../fixins/FixinCommon.sol";
import "../migrations/LibMigrate.sol";
import "../external/IFlashWallet.sol";
import "../external/FlashWallet.sol";
import "../storage/LibTransformERC20Storage.sol";
import "../transformers/IERC20Transformer.sol";
import "../transformers/LibERC20Transformer.sol";
import "./ITransformERC20.sol";
import "./ITokenSpender.sol";
import "./IFeature.sol";
import "./ISimpleFunctionRegistry.sol";
/// @dev Feature to composably transform between ERC20 tokens.
contract TransformERC20 is
IFeature,
ITransformERC20,
FixinCommon
{
// solhint-disable
/// @dev Name of this feature.
string public constant override FEATURE_NAME = "TransformERC20";
/// @dev Version of this feature.
uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 0);
/// @dev The trusted deployer for all transformers.
address public immutable transformDeployer;
/// @dev The implementation address of this feature.
address private immutable _implementation;
// solhint-enable
using LibSafeMathV06 for uint256;
using LibRichErrorsV06 for bytes;
constructor(address trustedDeployer_) public {
_implementation = address(this);
transformDeployer = trustedDeployer_;
}
/// @dev Initialize and register this feature.
/// Should be delegatecalled by `Migrate.migrate()`.
function migrate() external returns (bytes4 success) {
ISimpleFunctionRegistry(address(this))
.extend(this.getTransformerDeployer.selector, _implementation);
ISimpleFunctionRegistry(address(this))
.extend(this.createTransformWallet.selector, _implementation);
ISimpleFunctionRegistry(address(this))
.extend(this.getTransformWallet.selector, _implementation);
ISimpleFunctionRegistry(address(this))
.extend(this.transformERC20.selector, _implementation);
ISimpleFunctionRegistry(address(this))
.extend(this._transformERC20.selector, _implementation);
createTransformWallet();
return LibMigrate.MIGRATE_SUCCESS;
}
/// @dev Return the allowed deployer for transformers.
/// @return deployer The transform deployer address.
function getTransformerDeployer()
external
override
view
returns (address deployer)
{
return transformDeployer;
}
/// @dev Deploy a new wallet instance and replace the current one with it.
/// Useful if we somehow break the current wallet instance.
/// Anyone can call this.
/// @return wallet The new wallet instance.
function createTransformWallet()
public
override
returns (IFlashWallet wallet)
{
wallet = new FlashWallet();
LibTransformERC20Storage.getStorage().wallet = wallet;
}
/// @dev Executes a series of transformations to convert an ERC20 `inputToken`
/// to an ERC20 `outputToken`.
/// @param inputToken The token being provided by the sender.
/// If `0xeee...`, ETH is implied and should be provided with the call.`
/// @param outputToken The token to be acquired by the sender.
/// `0xeee...` implies ETH.
/// @param inputTokenAmount The amount of `inputToken` to take from the sender.
/// If set to `uint256(-1)`, the entire spendable balance of the taker
/// will be solt.
/// @param minOutputTokenAmount The minimum amount of `outputToken` the sender
/// must receive for the entire transformation to succeed. If set to zero,
/// the minimum output token transfer will not be asserted.
/// @param transformations The transformations to execute on the token balance(s)
/// in sequence.
/// @return outputTokenAmount The amount of `outputToken` received by the sender.
function transformERC20(
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 minOutputTokenAmount,
Transformation[] memory transformations
)
public
override
payable
returns (uint256 outputTokenAmount)
{
return _transformERC20Private(
keccak256(msg.data),
msg.sender,
inputToken,
outputToken,
inputTokenAmount,
minOutputTokenAmount,
transformations
);
}
/// @dev Internal version of `transformERC20()`. Only callable from within.
/// @param callDataHash Hash of the ingress calldata.
/// @param taker The taker address.
/// @param inputToken The token being provided by the taker.
/// If `0xeee...`, ETH is implied and should be provided with the call.`
/// @param outputToken The token to be acquired by the taker.
/// `0xeee...` implies ETH.
/// @param inputTokenAmount The amount of `inputToken` to take from the taker.
/// If set to `uint256(-1)`, the entire spendable balance of the taker
/// will be solt.
/// @param minOutputTokenAmount The minimum amount of `outputToken` the taker
/// must receive for the entire transformation to succeed. If set to zero,
/// the minimum output token transfer will not be asserted.
/// @param transformations The transformations to execute on the token balance(s)
/// in sequence.
/// @return outputTokenAmount The amount of `outputToken` received by the taker.
function _transformERC20(
bytes32 callDataHash,
address payable taker,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 minOutputTokenAmount,
Transformation[] memory transformations
)
public
override
payable
onlySelf
returns (uint256 outputTokenAmount)
{
return _transformERC20Private(
callDataHash,
taker,
inputToken,
outputToken,
inputTokenAmount,
minOutputTokenAmount,
transformations
);
}
/// @dev Private version of `transformERC20()`.
/// @param callDataHash Hash of the ingress calldata.
/// @param taker The taker address.
/// @param inputToken The token being provided by the taker.
/// If `0xeee...`, ETH is implied and should be provided with the call.`
/// @param outputToken The token to be acquired by the taker.
/// `0xeee...` implies ETH.
/// @param inputTokenAmount The amount of `inputToken` to take from the taker.
/// If set to `uint256(-1)`, the entire spendable balance of the taker
/// will be solt.
/// @param minOutputTokenAmount The minimum amount of `outputToken` the taker
/// must receive for the entire transformation to succeed. If set to zero,
/// the minimum output token transfer will not be asserted.
/// @param transformations The transformations to execute on the token balance(s)
/// in sequence.
/// @return outputTokenAmount The amount of `outputToken` received by the taker.
function _transformERC20Private(
bytes32 callDataHash,
address payable taker,
IERC20TokenV06 inputToken,
IERC20TokenV06 outputToken,
uint256 inputTokenAmount,
uint256 minOutputTokenAmount,
Transformation[] memory transformations
)
public
payable
returns (uint256 outputTokenAmount)
{
// If the input token amount is -1, transform the taker's entire
// spendable balance.
if (inputTokenAmount == uint256(-1)) {
inputTokenAmount = ITokenSpender(address(this))
.getSpendableERC20BalanceOf(inputToken, taker);
}
IFlashWallet wallet = getTransformWallet();
// Remember the initial output token balance of the taker.
uint256 takerOutputTokenBalanceBefore =
LibERC20Transformer.getTokenBalanceOf(outputToken, taker);
// Pull input tokens from the taker to the wallet and transfer attached ETH.
_transferInputTokensAndAttachedEth(inputToken, taker, address(wallet), inputTokenAmount);
// Perform transformations.
for (uint256 i = 0; i < transformations.length; ++i) {
_executeTransformation(wallet, transformations[i], taker, callDataHash);
}
// Compute how much output token has been transferred to the taker.
uint256 takerOutputTokenBalanceAfter =
LibERC20Transformer.getTokenBalanceOf(outputToken, taker);
if (takerOutputTokenBalanceAfter > takerOutputTokenBalanceBefore) {
outputTokenAmount = takerOutputTokenBalanceAfter.safeSub(
takerOutputTokenBalanceBefore
);
} else if (takerOutputTokenBalanceAfter < takerOutputTokenBalanceBefore) {
LibTransformERC20RichErrors.NegativeTransformERC20OutputError(
address(outputToken),
takerOutputTokenBalanceBefore - takerOutputTokenBalanceAfter
).rrevert();
}
// Ensure enough output token has been sent to the taker.
if (outputTokenAmount < minOutputTokenAmount) {
LibTransformERC20RichErrors.IncompleteTransformERC20Error(
address(outputToken),
outputTokenAmount,
minOutputTokenAmount
).rrevert();
}
// Emit an event.
emit TransformedERC20(
taker,
address(inputToken),
address(outputToken),
inputTokenAmount,
outputTokenAmount
);
}
/// @dev Return the current wallet instance that will serve as the execution
/// context for transformations.
/// @return wallet The wallet instance.
function getTransformWallet()
public
override
view
returns (IFlashWallet wallet)
{
return LibTransformERC20Storage.getStorage().wallet;
}
/// @dev Transfer input tokens from the taker and any attached ETH to `to`
/// @param inputToken The token to pull from the taker.
/// @param from The from (taker) address.
/// @param to The recipient of tokens and ETH.
/// @param amount Amount of `inputToken` tokens to transfer.
function _transferInputTokensAndAttachedEth(
IERC20TokenV06 inputToken,
address from,
address payable to,
uint256 amount
)
private
{
// Transfer any attached ETH.
if (msg.value != 0) {
to.transfer(msg.value);
}
// Transfer input tokens.
if (!LibERC20Transformer.isTokenETH(inputToken)) {
// Token is not ETH, so pull ERC20 tokens.
ITokenSpender(address(this))._spendERC20Tokens(
inputToken,
from,
to,
amount
);
} else if (msg.value < amount) {
// Token is ETH, so the caller must attach enough ETH to the call.
LibTransformERC20RichErrors.InsufficientEthAttachedError(
msg.value,
amount
).rrevert();
}
}
/// @dev Executs a transformer in the context of `wallet`.
/// @param wallet The wallet instance.
/// @param transformation The transformation.
/// @param taker The taker address.
/// @param callDataHash Hash of the calldata.
function _executeTransformation(
IFlashWallet wallet,
Transformation memory transformation,
address payable taker,
bytes32 callDataHash
)
private
{
// Call `transformer.transform()` as the wallet.
bytes memory resultData = wallet.executeDelegateCall(
// Call target.
address(uint160(address(transformation.transformer))),
// Call data.
abi.encodeWithSelector(
IERC20Transformer.transform.selector,
callDataHash,
taker,
transformation.data
)
);
// Ensure the transformer returned its valid rlp-encoded deployment nonce.
bytes memory rlpNonce = resultData.length == 0
? new bytes(0)
: abi.decode(resultData, (bytes));
if (_getExpectedDeployment(rlpNonce) != address(transformation.transformer)) {
LibTransformERC20RichErrors.UnauthorizedTransformerError(
address(transformation.transformer),
rlpNonce
).rrevert();
}
}
/// @dev Compute the expected deployment address by `transformDeployer` at
/// the nonce given by `rlpNonce`.
/// @param rlpNonce The RLP-encoded nonce that
/// the deployer had when deploying a contract.
/// @return deploymentAddress The deployment address.
function _getExpectedDeployment(bytes memory rlpNonce)
private
view
returns (address deploymentAddress)
{
// See https://github.com/ethereum/wiki/wiki/RLP for RLP encoding rules.
// The RLP-encoded nonce may be prefixed with a length byte.
// We only support nonces up to 32-bits.
if (rlpNonce.length == 0 || rlpNonce.length > 5) {
LibTransformERC20RichErrors.InvalidRLPNonceError(rlpNonce).rrevert();
}
return address(uint160(uint256(keccak256(abi.encodePacked(
byte(uint8(0xC0 + 21 + rlpNonce.length)),
byte(uint8(0x80 + 20)),
transformDeployer,
rlpNonce
)))));
}
}

View File

@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
import "../errors/LibCommonRichErrors.sol"; import "../errors/LibCommonRichErrors.sol";
import "../errors/LibOwnableRichErrors.sol"; import "../errors/LibOwnableRichErrors.sol";
import "../features/IOwnable.sol";
import "../storage/LibOwnableStorage.sol"; import "../storage/LibOwnableStorage.sol";
@ -31,7 +32,7 @@ contract FixinCommon {
using LibRichErrorsV06 for bytes; using LibRichErrorsV06 for bytes;
/// @dev The caller must be this contract. /// @dev The caller must be this contract.
modifier onlySelf() { modifier onlySelf() virtual {
if (msg.sender != address(this)) { if (msg.sender != address(this)) {
LibCommonRichErrors.OnlyCallableBySelfError(msg.sender).rrevert(); LibCommonRichErrors.OnlyCallableBySelfError(msg.sender).rrevert();
} }
@ -39,7 +40,7 @@ contract FixinCommon {
} }
/// @dev The caller of this function must be the owner. /// @dev The caller of this function must be the owner.
modifier onlyOwner() { modifier onlyOwner() virtual {
{ {
address owner = _getOwner(); address owner = _getOwner();
if (msg.sender != owner) { if (msg.sender != owner) {
@ -54,7 +55,22 @@ contract FixinCommon {
/// @dev Get the owner of this contract. /// @dev Get the owner of this contract.
/// @return owner The owner of this contract. /// @return owner The owner of this contract.
function _getOwner() internal view returns (address owner) { function _getOwner() internal virtual view returns (address owner) {
// We access Ownable's storage directly here instead of using the external
// API because `onlyOwner` needs to function during bootstrapping.
return LibOwnableStorage.getStorage().owner; return LibOwnableStorage.getStorage().owner;
} }
/// @dev Encode a feature version as a `uint256`.
/// @param major The major version number of the feature.
/// @param minor The minor version number of the feature.
/// @param revision The revision number of the feature.
/// @return encodedVersion The encoded version number.
function _encodeVersion(uint32 major, uint32 minor, uint32 revision)
internal
pure
returns (uint256 encodedVersion)
{
return (major << 64) | (minor << 32) | revision;
}
} }

View File

@ -0,0 +1,147 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "../ZeroEx.sol";
import "../features/IOwnable.sol";
import "../features/TokenSpender.sol";
import "../features/TransformERC20.sol";
import "../external/AllowanceTarget.sol";
import "./InitialMigration.sol";
/// @dev A contract for deploying and configuring the full ZeroEx contract.
contract FullMigration {
// solhint-disable no-empty-blocks,indent
/// @dev Features to add the the proxy contract.
struct Features {
SimpleFunctionRegistry registry;
Ownable ownable;
TokenSpender tokenSpender;
TransformERC20 transformERC20;
}
/// @dev The allowed caller of `deploy()`.
address public immutable deployer;
/// @dev The initial migration contract.
InitialMigration private _initialMigration;
/// @dev Instantiate this contract and set the allowed caller of `deploy()`
/// to `deployer`.
/// @param deployer_ The allowed caller of `deploy()`.
constructor(address payable deployer_)
public
{
deployer = deployer_;
// Create an initial migration contract with this contract set to the
// allowed deployer.
_initialMigration = new InitialMigration(address(this));
}
/// @dev Deploy the `ZeroEx` contract with the full feature set,
/// transfer ownership to `owner`, then self-destruct.
/// @param owner The owner of the contract.
/// @param features Features to add to the proxy.
/// @return zeroEx The deployed and configured `ZeroEx` contract.
function deploy(
address payable owner,
Features memory features
)
public
returns (ZeroEx zeroEx)
{
require(msg.sender == deployer, "FullMigration/INVALID_SENDER");
// Perform the initial migration with the owner set to this contract.
zeroEx = _initialMigration.deploy(
address(uint160(address(this))),
InitialMigration.BootstrapFeatures({
registry: features.registry,
ownable: features.ownable
})
);
// Add features.
_addFeatures(zeroEx, owner, features);
// Transfer ownership to the real owner.
IOwnable(address(zeroEx)).transferOwnership(owner);
// Self-destruct.
this.die(owner);
}
/// @dev Destroy this contract. Only callable from ourselves (from `deploy()`).
/// @param ethRecipient Receiver of any ETH in this contract.
function die(address payable ethRecipient)
external
virtual
{
require(msg.sender == address(this), "FullMigration/INVALID_SENDER");
// This contract should not hold any funds but we send
// them to the ethRecipient just in case.
selfdestruct(ethRecipient);
}
/// @dev Deploy and register features to the ZeroEx contract.
/// @param zeroEx The bootstrapped ZeroEx contract.
/// @param owner The ultimate owner of the ZeroEx contract.
/// @param features Features to add to the proxy.
function _addFeatures(
ZeroEx zeroEx,
address owner,
Features memory features
)
private
{
IOwnable ownable = IOwnable(address(zeroEx));
// TokenSpender
{
// Create the allowance target.
AllowanceTarget allowanceTarget = new AllowanceTarget();
// Let the ZeroEx contract use the allowance target.
allowanceTarget.addAuthorizedAddress(address(zeroEx));
// Transfer ownership of the allowance target to the (real) owner.
allowanceTarget.transferOwnership(owner);
// Register the feature.
ownable.migrate(
address(features.tokenSpender),
abi.encodeWithSelector(
TokenSpender.migrate.selector,
allowanceTarget
),
address(this)
);
}
// TransformERC20
{
// Register the feature.
ownable.migrate(
address(features.transformERC20),
abi.encodeWithSelector(
TransformERC20.migrate.selector
),
address(this)
);
}
}
}

View File

@ -29,6 +29,12 @@ import "./LibBootstrap.sol";
/// @dev A contract for deploying and configuring a minimal ZeroEx contract. /// @dev A contract for deploying and configuring a minimal ZeroEx contract.
contract InitialMigration { contract InitialMigration {
/// @dev Features to bootstrap into the the proxy contract.
struct BootstrapFeatures {
SimpleFunctionRegistry registry;
Ownable ownable;
}
/// @dev The allowed caller of `deploy()`. In production, this would be /// @dev The allowed caller of `deploy()`. In production, this would be
/// the governor. /// the governor.
address public immutable deployer; address public immutable deployer;
@ -47,8 +53,13 @@ contract InitialMigration {
/// transfers ownership to `owner`, then self-destructs. /// transfers ownership to `owner`, then self-destructs.
/// Only callable by `deployer` set in the contstructor. /// Only callable by `deployer` set in the contstructor.
/// @param owner The owner of the contract. /// @param owner The owner of the contract.
/// @param features Features to bootstrap into the proxy.
/// @return zeroEx The deployed and configured `ZeroEx` contract. /// @return zeroEx The deployed and configured `ZeroEx` contract.
function deploy(address payable owner) public virtual returns (ZeroEx zeroEx) { function deploy(address payable owner, BootstrapFeatures memory features)
public
virtual
returns (ZeroEx zeroEx)
{
// Must be called by the allowed deployer. // Must be called by the allowed deployer.
require(msg.sender == deployer, "InitialMigration/INVALID_SENDER"); require(msg.sender == deployer, "InitialMigration/INVALID_SENDER");
@ -58,7 +69,7 @@ contract InitialMigration {
// Bootstrap the initial feature set. // Bootstrap the initial feature set.
IBootstrap(address(zeroEx)).bootstrap( IBootstrap(address(zeroEx)).bootstrap(
address(this), address(this),
abi.encodeWithSelector(this.bootstrap.selector, owner) abi.encodeWithSelector(this.bootstrap.selector, owner, features)
); );
// Self-destruct. This contract should not hold any funds but we send // Self-destruct. This contract should not hold any funds but we send
@ -69,23 +80,30 @@ contract InitialMigration {
/// @dev Sets up the initial state of the `ZeroEx` contract. /// @dev Sets up the initial state of the `ZeroEx` contract.
/// The `ZeroEx` contract will delegatecall into this function. /// The `ZeroEx` contract will delegatecall into this function.
/// @param owner The new owner of the ZeroEx contract. /// @param owner The new owner of the ZeroEx contract.
/// @param features Features to bootstrap into the proxy.
/// @return success Magic bytes if successful. /// @return success Magic bytes if successful.
function bootstrap(address owner) public virtual returns (bytes4 success) { function bootstrap(address owner, BootstrapFeatures memory features)
public
virtual
returns (bytes4 success)
{
// Deploy and migrate the initial features. // Deploy and migrate the initial features.
// Order matters here. // Order matters here.
// Initialize Registry. // Initialize Registry.
SimpleFunctionRegistry registry = new SimpleFunctionRegistry();
LibBootstrap.delegatecallBootstrapFunction( LibBootstrap.delegatecallBootstrapFunction(
address(registry), address(features.registry),
abi.encodeWithSelector(registry.bootstrap.selector, address(registry)) abi.encodeWithSelector(
SimpleFunctionRegistry.bootstrap.selector
)
); );
// Initialize Ownable. // Initialize Ownable.
Ownable ownable = new Ownable();
LibBootstrap.delegatecallBootstrapFunction( LibBootstrap.delegatecallBootstrapFunction(
address(ownable), address(features.ownable),
abi.encodeWithSelector(ownable.bootstrap.selector, address(ownable)) abi.encodeWithSelector(
Ownable.bootstrap.selector
)
); );
// Transfer ownership to the real owner. // Transfer ownership to the real owner.

View File

@ -28,10 +28,13 @@ library LibStorage {
uint256 private constant STORAGE_SLOT_EXP = 128; uint256 private constant STORAGE_SLOT_EXP = 128;
/// @dev Storage IDs for feature storage buckets. /// @dev Storage IDs for feature storage buckets.
/// WARNING: APPEND-ONLY.
enum StorageId { enum StorageId {
Proxy, Proxy,
SimpleFunctionRegistry, SimpleFunctionRegistry,
Ownable Ownable,
TokenSpender,
TransformERC20
} }
/// @dev Get the storage slot given a storage ID. We assign unique, well-spaced /// @dev Get the storage slot given a storage ID. We assign unique, well-spaced

View File

@ -0,0 +1,42 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "./LibStorage.sol";
import "../external/IAllowanceTarget.sol";
/// @dev Storage helpers for the `TokenSpender` feature.
library LibTokenSpenderStorage {
/// @dev Storage bucket for this feature.
struct Storage {
// Allowance target contract.
IAllowanceTarget allowanceTarget;
}
/// @dev Get the storage bucket for this contract.
function getStorage() internal pure returns (Storage storage stor) {
uint256 storageSlot = LibStorage.getStorageSlot(
LibStorage.StorageId.TokenSpender
);
assembly { stor_slot := storageSlot }
}
}

View File

@ -0,0 +1,42 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "./LibStorage.sol";
import "../external/IFlashWallet.sol";
/// @dev Storage helpers for the `TokenSpender` feature.
library LibTransformERC20Storage {
/// @dev Storage bucket for this feature.
struct Storage {
// The current wallet instance.
IFlashWallet wallet;
}
/// @dev Get the storage bucket for this contract.
function getStorage() internal pure returns (Storage storage stor) {
uint256 storageSlot = LibStorage.getStorageSlot(
LibStorage.StorageId.TransformERC20
);
assembly { stor_slot := storageSlot }
}
}

View File

@ -0,0 +1,43 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
/// @dev A transformation callback used in `TransformERC20.transformERC20()`.
interface IERC20Transformer {
/// @dev Called from `TransformERC20.transformERC20()`. This will be
/// delegatecalled in the context of the FlashWallet instance being used.
/// @param callDataHash The hash of the `TransformERC20.transformERC20()` calldata.
/// @param taker The taker address (caller of `TransformERC20.transformERC20()`).
/// @param data Arbitrary data to pass to the transformer.
/// @return rlpDeploymentNonce RLP-encoded deployment nonce of the deployer
/// when this transformer was deployed. This is used to verify that
/// this transformer was deployed by a trusted contract.
function transform(
bytes32 callDataHash,
address payable taker,
bytes calldata data
)
external
returns (bytes memory rlpDeploymentNonce);
}

View File

@ -0,0 +1,73 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
library LibERC20Transformer {
/// @dev ETH pseudo-token address.
address constant internal ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
using LibERC20TokenV06 for IERC20TokenV06;
/// @dev Transfer ERC20 tokens and ETH.
/// @param token An ERC20 or the ETH pseudo-token address (`ETH_TOKEN_ADDRESS`).
/// @param to The recipient.
/// @param amount The transfer amount.
function transformerTransfer(
IERC20TokenV06 token,
address payable to,
uint256 amount
)
internal
{
if (isTokenETH(token)) {
to.transfer(amount);
} else {
token.compatTransfer(to, amount);
}
}
/// @dev Check if a token is the ETH pseudo-token.
/// @param token The token to check.
/// @return isETH `true` if the token is the ETH pseudo-token.
function isTokenETH(IERC20TokenV06 token)
internal
pure
returns (bool isETH)
{
return address(token) == ETH_TOKEN_ADDRESS;
}
/// @dev Check the balance of an ERC20 token or ETH.
/// @param token An ERC20 or the ETH pseudo-token address (`ETH_TOKEN_ADDRESS`).
/// @param owner Holder of the tokens.
/// @return tokenBalance The balance of `owner`.
function getTokenBalanceOf(IERC20TokenV06 token, address owner)
internal
view
returns (uint256 tokenBalance)
{
return isTokenETH(token) ? owner.balance : token.balanceOf(owner);
}
}

View File

@ -0,0 +1,51 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
contract TestCallTarget {
event CallTargetCalled(
address context,
address sender,
bytes data,
uint256 value
);
bytes4 private constant MAGIC_BYTES = 0x12345678;
bytes private constant REVERTING_DATA = hex"1337";
fallback() external payable {
if (keccak256(msg.data) == keccak256(REVERTING_DATA)) {
revert("TestCallTarget/REVERT");
}
emit CallTargetCalled(
address(this),
msg.sender,
msg.data,
msg.value
);
bytes4 rval = MAGIC_BYTES;
assembly {
mstore(0, rval)
return(0, 32)
}
}
}

View File

@ -0,0 +1,38 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "../src/ZeroEx.sol";
import "../src/features/IBootstrap.sol";
import "../src/migrations/FullMigration.sol";
contract TestFullMigration is
FullMigration
{
address public dieRecipient;
// solhint-disable-next-line no-empty-blocks
constructor(address payable deployer) public FullMigration(deployer) {}
function die(address payable ethRecipient) external override {
dieRecipient = ethRecipient;
}
}

View File

@ -37,12 +37,12 @@ contract TestInitialMigration is
IBootstrap(address(zeroEx)).bootstrap(address(this), new bytes(0)); IBootstrap(address(zeroEx)).bootstrap(address(this), new bytes(0));
} }
function getCodeSizeOf(address target) external view returns (uint256 codeSize) { function bootstrap(address owner, BootstrapFeatures memory features)
assembly { codeSize := extcodesize(target) } public
} override
returns (bytes4 success)
function bootstrap(address owner) public override returns (bytes4 success) { {
success = InitialMigration.bootstrap(owner); success = InitialMigration.bootstrap(owner, features);
// Snoop the bootstrap feature contract. // Snoop the bootstrap feature contract.
bootstrapFeature = ZeroEx(address(uint160(address(this)))) bootstrapFeature = ZeroEx(address(uint160(address(this))))
.getFunctionImplementation(IBootstrap.bootstrap.selector); .getFunctionImplementation(IBootstrap.bootstrap.selector);

View File

@ -0,0 +1,84 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
import "../src/transformers/IERC20Transformer.sol";
import "../src/transformers/LibERC20Transformer.sol";
import "./TestMintableERC20Token.sol";
contract TestMintTokenERC20Transformer is
IERC20Transformer
{
struct TransformData {
IERC20TokenV06 inputToken;
TestMintableERC20Token outputToken;
uint256 burnAmount;
uint256 mintAmount;
uint256 feeAmount;
bytes deploymentNonce;
}
event MintTransform(
address context,
address caller,
bytes32 callDataHash,
address taker,
bytes data,
uint256 inputTokenBalance,
uint256 ethBalance
);
function transform(
bytes32 callDataHash,
address payable taker,
bytes calldata data_
)
external
override
returns (bytes memory rlpDeploymentNonce)
{
TransformData memory data = abi.decode(data_, (TransformData));
emit MintTransform(
address(this),
msg.sender,
callDataHash,
taker,
data_,
data.inputToken.balanceOf(address(this)),
address(this).balance
);
// "Burn" input tokens.
data.inputToken.transfer(address(0), data.burnAmount);
// Mint output tokens.
if (LibERC20Transformer.isTokenETH(IERC20TokenV06(address(data.outputToken)))) {
taker.transfer(data.mintAmount);
} else {
data.outputToken.mint(
taker,
data.mintAmount
);
// Burn fees from output.
data.outputToken.burn(taker, data.feeAmount);
}
return data.deploymentNonce;
}
}

View File

@ -0,0 +1,77 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
contract TestMintableERC20Token {
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
function transfer(address to, uint256 amount)
external
virtual
returns (bool)
{
return transferFrom(msg.sender, to, amount);
}
function approve(address spender, uint256 amount)
external
virtual
returns (bool)
{
allowance[msg.sender][spender] = amount;
return true;
}
function mint(address owner, uint256 amount)
external
virtual
{
balanceOf[owner] += amount;
}
function burn(address owner, uint256 amount)
external
virtual
{
require(balanceOf[owner] >= amount, "TestMintableERC20Token/INSUFFICIENT_FUNDS");
balanceOf[owner] -= amount;
}
function transferFrom(address from, address to, uint256 amount)
public
virtual
returns (bool)
{
if (from != msg.sender) {
require(
allowance[from][msg.sender] >= amount,
"TestMintableERC20Token/INSUFFICIENT_ALLOWANCE"
);
allowance[from][msg.sender] -= amount;
}
require(balanceOf[from] >= amount, "TestMintableERC20Token/INSUFFICIENT_FUNDS");
balanceOf[from] -= amount;
balanceOf[to] += amount;
return true;
}
}

View File

@ -0,0 +1,30 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "../src/features/TokenSpender.sol";
contract TestTokenSpender is
TokenSpender
{
modifier onlySelf() override {
_;
}
}

View File

@ -0,0 +1,70 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "./TestMintableERC20Token.sol";
contract TestTokenSpenderERC20Token is
TestMintableERC20Token
{
event TransferFromCalled(
address sender,
address from,
address to,
uint256 amount
);
// `transferFrom()` behavior depends on the value of `amount`.
uint256 constant private EMPTY_RETURN_AMOUNT = 1337;
uint256 constant private FALSE_RETURN_AMOUNT = 1338;
uint256 constant private REVERT_RETURN_AMOUNT = 1339;
function transferFrom(address from, address to, uint256 amount)
public
override
returns (bool)
{
emit TransferFromCalled(msg.sender, from, to, amount);
if (amount == EMPTY_RETURN_AMOUNT) {
assembly { return(0, 0) }
}
if (amount == FALSE_RETURN_AMOUNT) {
return false;
}
if (amount == REVERT_RETURN_AMOUNT) {
revert("TestTokenSpenderERC20Token/Revert");
}
return true;
}
function setBalanceAndAllowanceOf(
address owner,
uint256 balance,
address spender,
uint256 allowance_
)
external
{
balanceOf[owner] = balance;
allowance[owner][spender] = allowance_;
}
}

View File

@ -0,0 +1,37 @@
/*
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.6.5;
pragma experimental ABIEncoderV2;
import "../src/features/TransformERC20.sol";
contract TestTransformERC20 is
TransformERC20
{
// solhint-disable no-empty-blocks
constructor(address trustedDeployer)
TransformERC20(trustedDeployer)
public
{}
modifier onlySelf() override {
_;
}
}

View File

@ -32,15 +32,15 @@
"test:circleci": "yarn test", "test:circleci": "yarn test",
"contracts:gen": "contracts-gen generate", "contracts:gen": "contracts-gen generate",
"contracts:copy": "contracts-gen copy", "contracts:copy": "contracts-gen copy",
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol", "lint-contracts": "#solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
"compile:truffle": "truffle compile", "compile:truffle": "truffle compile",
"docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json", "docs: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" "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
}, },
"config": { "config": {
"publicInterfaceContracts": "ZeroEx,IOwnable,ISimpleFunctionRegistry", "publicInterfaceContracts": "ZeroEx,FullMigration,InitialMigration,IFlashWallet,IAllowanceTarget,IERC20Transformer,IOwnable,ISimpleFunctionRegistry,ITokenSpender,ITransformERC20",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./test/generated-artifacts/@(Bootstrap|FixinCommon|IBootstrap|IFeature|IOwnable|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|InitialMigration|LibBootstrap|LibCommonRichErrors|LibMigrate|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|Ownable|SimpleFunctionRegistry|TestInitialMigration|TestMigrator|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestZeroExFeature|ZeroEx).json" "abis": "./test/generated-artifacts/@(AllowanceTarget|Bootstrap|FixinCommon|FlashWallet|FullMigration|IAllowanceTarget|IBootstrap|IERC20Transformer|IFeature|IFlashWallet|IOwnable|ISimpleFunctionRegistry|ITestSimpleFunctionRegistryFeature|ITokenSpender|ITransformERC20|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibMigrate|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibSpenderRichErrors|LibStorage|LibTokenSpenderStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|Ownable|SimpleFunctionRegistry|TestCallTarget|TestFullMigration|TestInitialMigration|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestTokenSpender|TestTokenSpenderERC20Token|TestTransformERC20|TestZeroExFeature|TokenSpender|TransformERC20|ZeroEx).json"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -62,6 +62,7 @@
"@0x/tslint-config": "^4.0.0", "@0x/tslint-config": "^4.0.0",
"@types/lodash": "4.14.104", "@types/lodash": "4.14.104",
"@types/mocha": "^5.2.7", "@types/mocha": "^5.2.7",
"lodash": "^4.17.11",
"mocha": "^6.2.0", "mocha": "^6.2.0",
"npm-run-all": "^4.1.2", "npm-run-all": "^4.1.2",
"shx": "^0.2.2", "shx": "^0.2.2",
@ -76,7 +77,9 @@
"@0x/types": "^3.1.2", "@0x/types": "^3.1.2",
"@0x/typescript-typings": "^5.0.2", "@0x/typescript-typings": "^5.0.2",
"@0x/utils": "^5.4.1", "@0x/utils": "^5.4.1",
"ethereum-types": "^3.1.0" "@0x/web3-wrapper": "^7.0.7",
"ethereum-types": "^3.1.0",
"ethereumjs-util": "^5.1.1"
}, },
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"

View File

@ -5,11 +5,25 @@
*/ */
import { ContractArtifact } from 'ethereum-types'; import { ContractArtifact } from 'ethereum-types';
import * as FullMigration from '../generated-artifacts/FullMigration.json';
import * as IAllowanceTarget from '../generated-artifacts/IAllowanceTarget.json';
import * as IERC20Transformer from '../generated-artifacts/IERC20Transformer.json';
import * as IFlashWallet from '../generated-artifacts/IFlashWallet.json';
import * as InitialMigration from '../generated-artifacts/InitialMigration.json';
import * as IOwnable from '../generated-artifacts/IOwnable.json'; import * as IOwnable from '../generated-artifacts/IOwnable.json';
import * as ISimpleFunctionRegistry from '../generated-artifacts/ISimpleFunctionRegistry.json'; import * as ISimpleFunctionRegistry from '../generated-artifacts/ISimpleFunctionRegistry.json';
import * as ITokenSpender from '../generated-artifacts/ITokenSpender.json';
import * as ITransformERC20 from '../generated-artifacts/ITransformERC20.json';
import * as ZeroEx from '../generated-artifacts/ZeroEx.json'; import * as ZeroEx from '../generated-artifacts/ZeroEx.json';
export const artifacts = { export const artifacts = {
ZeroEx: ZeroEx as ContractArtifact, ZeroEx: ZeroEx as ContractArtifact,
FullMigration: FullMigration as ContractArtifact,
InitialMigration: InitialMigration as ContractArtifact,
IFlashWallet: IFlashWallet as ContractArtifact,
IAllowanceTarget: IAllowanceTarget as ContractArtifact,
IERC20Transformer: IERC20Transformer as ContractArtifact,
IOwnable: IOwnable as ContractArtifact, IOwnable: IOwnable as ContractArtifact,
ISimpleFunctionRegistry: ISimpleFunctionRegistry as ContractArtifact, ISimpleFunctionRegistry: ISimpleFunctionRegistry as ContractArtifact,
ITokenSpender: ITokenSpender as ContractArtifact,
ITransformERC20: ITransformERC20 as ContractArtifact,
}; };

View File

@ -36,3 +36,4 @@ export {
TupleDataItem, TupleDataItem,
StateMutability, StateMutability,
} from 'ethereum-types'; } from 'ethereum-types';
export { rlpEncodeNonce } from './nonce_utils';

View File

@ -0,0 +1,25 @@
import { hexUtils } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as ethjs from 'ethereumjs-util';
/**
* Fetch and RLP encode the transaction count (nonce) of an account.
*/
export async function getRLPEncodedAccountNonceAsync(web3Wrapper: Web3Wrapper, address: string): Promise<string> {
const nonce = await web3Wrapper.getAccountNonceAsync(address);
return rlpEncodeNonce(nonce);
}
/**
* RLP encode the transaction count (nonce) of an account.
*/
export function rlpEncodeNonce(nonce: number): string {
if (nonce === 0) {
return '0x80';
} else if (nonce <= 0x7f) {
return ethjs.bufferToHex(ethjs.toBuffer(nonce));
} else {
const rlpNonce = ethjs.bufferToHex(ethjs.toBuffer(nonce));
return hexUtils.concat(rlpNonce.length + 0x80, rlpNonce);
}
}

View File

@ -3,6 +3,13 @@
* Warning: This file is auto-generated by contracts-gen. Don't edit manually. * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* ----------------------------------------------------------------------------- * -----------------------------------------------------------------------------
*/ */
export * from '../generated-wrappers/full_migration';
export * from '../generated-wrappers/i_allowance_target';
export * from '../generated-wrappers/i_erc20_transformer';
export * from '../generated-wrappers/i_flash_wallet';
export * from '../generated-wrappers/i_ownable'; export * from '../generated-wrappers/i_ownable';
export * from '../generated-wrappers/i_simple_function_registry'; export * from '../generated-wrappers/i_simple_function_registry';
export * from '../generated-wrappers/i_token_spender';
export * from '../generated-wrappers/i_transform_erc20';
export * from '../generated-wrappers/initial_migration';
export * from '../generated-wrappers/zero_ex'; export * from '../generated-wrappers/zero_ex';

View File

@ -0,0 +1,82 @@
import { blockchainTests, constants, expect, randomAddress, verifyEventsFromLogs } from '@0x/contracts-test-utils';
import { AuthorizableRevertErrors, hexUtils, StringRevertError } from '@0x/utils';
import { artifacts } from './artifacts';
import { AllowanceTargetContract, TestCallTargetContract, TestCallTargetEvents } from './wrappers';
blockchainTests.resets('AllowanceTarget', env => {
let owner: string;
let authority: string;
let allowanceTarget: AllowanceTargetContract;
let callTarget: TestCallTargetContract;
before(async () => {
[owner, authority] = await env.getAccountAddressesAsync();
allowanceTarget = await AllowanceTargetContract.deployFrom0xArtifactAsync(
artifacts.AllowanceTarget,
env.provider,
env.txDefaults,
artifacts,
);
await allowanceTarget.addAuthorizedAddress(authority).awaitTransactionSuccessAsync();
callTarget = await TestCallTargetContract.deployFrom0xArtifactAsync(
artifacts.TestCallTarget,
env.provider,
env.txDefaults,
artifacts,
);
});
const TARGET_RETURN_VALUE = hexUtils.rightPad('0x12345678');
const REVERTING_DATA = '0x1337';
describe('executeCall()', () => {
it('non-authority cannot call executeCall()', async () => {
const notAuthority = randomAddress();
const tx = allowanceTarget
.executeCall(randomAddress(), hexUtils.random())
.callAsync({ from: notAuthority });
return expect(tx).to.revertWith(new AuthorizableRevertErrors.SenderNotAuthorizedError(notAuthority));
});
it('authority can call executeCall()', async () => {
const targetData = hexUtils.random(128);
const receipt = await allowanceTarget
.executeCall(callTarget.address, targetData)
.awaitTransactionSuccessAsync({ from: authority });
verifyEventsFromLogs(
receipt.logs,
[
{
context: callTarget.address,
sender: allowanceTarget.address,
data: targetData,
value: constants.ZERO_AMOUNT,
},
],
TestCallTargetEvents.CallTargetCalled,
);
});
it('AllowanceTarget returns call result', async () => {
const result = await allowanceTarget
.executeCall(callTarget.address, hexUtils.random(128))
.callAsync({ from: authority });
expect(result).to.eq(TARGET_RETURN_VALUE);
});
it('AllowanceTarget returns raw call revert', async () => {
const tx = allowanceTarget.executeCall(callTarget.address, REVERTING_DATA).callAsync({ from: authority });
return expect(tx).to.revertWith(new StringRevertError('TestCallTarget/REVERT'));
});
it('AllowanceTarget cannot receive ETH', async () => {
const tx = env.web3Wrapper.sendTransactionAsync({
to: allowanceTarget.address,
from: owner,
value: 0,
});
return expect(tx).to.eventually.be.rejected();
});
});
});

View File

@ -5,16 +5,25 @@
*/ */
import { ContractArtifact } from 'ethereum-types'; import { ContractArtifact } from 'ethereum-types';
import * as AllowanceTarget from '../test/generated-artifacts/AllowanceTarget.json';
import * as Bootstrap from '../test/generated-artifacts/Bootstrap.json'; import * as Bootstrap from '../test/generated-artifacts/Bootstrap.json';
import * as FixinCommon from '../test/generated-artifacts/FixinCommon.json'; import * as FixinCommon from '../test/generated-artifacts/FixinCommon.json';
import * as FlashWallet from '../test/generated-artifacts/FlashWallet.json';
import * as FullMigration from '../test/generated-artifacts/FullMigration.json';
import * as IAllowanceTarget from '../test/generated-artifacts/IAllowanceTarget.json';
import * as IBootstrap from '../test/generated-artifacts/IBootstrap.json'; import * as IBootstrap from '../test/generated-artifacts/IBootstrap.json';
import * as IERC20Transformer from '../test/generated-artifacts/IERC20Transformer.json';
import * as IFeature from '../test/generated-artifacts/IFeature.json'; import * as IFeature from '../test/generated-artifacts/IFeature.json';
import * as IFlashWallet from '../test/generated-artifacts/IFlashWallet.json';
import * as InitialMigration from '../test/generated-artifacts/InitialMigration.json'; import * as InitialMigration from '../test/generated-artifacts/InitialMigration.json';
import * as IOwnable from '../test/generated-artifacts/IOwnable.json'; import * as IOwnable from '../test/generated-artifacts/IOwnable.json';
import * as ISimpleFunctionRegistry from '../test/generated-artifacts/ISimpleFunctionRegistry.json'; import * as ISimpleFunctionRegistry from '../test/generated-artifacts/ISimpleFunctionRegistry.json';
import * as ITestSimpleFunctionRegistryFeature from '../test/generated-artifacts/ITestSimpleFunctionRegistryFeature.json'; import * as ITestSimpleFunctionRegistryFeature from '../test/generated-artifacts/ITestSimpleFunctionRegistryFeature.json';
import * as ITokenSpender from '../test/generated-artifacts/ITokenSpender.json';
import * as ITransformERC20 from '../test/generated-artifacts/ITransformERC20.json';
import * as LibBootstrap from '../test/generated-artifacts/LibBootstrap.json'; import * as LibBootstrap from '../test/generated-artifacts/LibBootstrap.json';
import * as LibCommonRichErrors from '../test/generated-artifacts/LibCommonRichErrors.json'; import * as LibCommonRichErrors from '../test/generated-artifacts/LibCommonRichErrors.json';
import * as LibERC20Transformer from '../test/generated-artifacts/LibERC20Transformer.json';
import * as LibMigrate from '../test/generated-artifacts/LibMigrate.json'; import * as LibMigrate from '../test/generated-artifacts/LibMigrate.json';
import * as LibOwnableRichErrors from '../test/generated-artifacts/LibOwnableRichErrors.json'; import * as LibOwnableRichErrors from '../test/generated-artifacts/LibOwnableRichErrors.json';
import * as LibOwnableStorage from '../test/generated-artifacts/LibOwnableStorage.json'; import * as LibOwnableStorage from '../test/generated-artifacts/LibOwnableStorage.json';
@ -22,14 +31,28 @@ import * as LibProxyRichErrors from '../test/generated-artifacts/LibProxyRichErr
import * as LibProxyStorage from '../test/generated-artifacts/LibProxyStorage.json'; import * as LibProxyStorage from '../test/generated-artifacts/LibProxyStorage.json';
import * as LibSimpleFunctionRegistryRichErrors from '../test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json'; import * as LibSimpleFunctionRegistryRichErrors from '../test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json';
import * as LibSimpleFunctionRegistryStorage from '../test/generated-artifacts/LibSimpleFunctionRegistryStorage.json'; import * as LibSimpleFunctionRegistryStorage from '../test/generated-artifacts/LibSimpleFunctionRegistryStorage.json';
import * as LibSpenderRichErrors from '../test/generated-artifacts/LibSpenderRichErrors.json';
import * as LibStorage from '../test/generated-artifacts/LibStorage.json'; import * as LibStorage from '../test/generated-artifacts/LibStorage.json';
import * as LibTokenSpenderStorage from '../test/generated-artifacts/LibTokenSpenderStorage.json';
import * as LibTransformERC20RichErrors from '../test/generated-artifacts/LibTransformERC20RichErrors.json';
import * as LibTransformERC20Storage from '../test/generated-artifacts/LibTransformERC20Storage.json';
import * as LibWalletRichErrors from '../test/generated-artifacts/LibWalletRichErrors.json';
import * as Ownable from '../test/generated-artifacts/Ownable.json'; import * as Ownable from '../test/generated-artifacts/Ownable.json';
import * as SimpleFunctionRegistry from '../test/generated-artifacts/SimpleFunctionRegistry.json'; import * as SimpleFunctionRegistry from '../test/generated-artifacts/SimpleFunctionRegistry.json';
import * as TestCallTarget from '../test/generated-artifacts/TestCallTarget.json';
import * as TestFullMigration from '../test/generated-artifacts/TestFullMigration.json';
import * as TestInitialMigration from '../test/generated-artifacts/TestInitialMigration.json'; import * as TestInitialMigration from '../test/generated-artifacts/TestInitialMigration.json';
import * as TestMigrator from '../test/generated-artifacts/TestMigrator.json'; import * as TestMigrator from '../test/generated-artifacts/TestMigrator.json';
import * as TestMintableERC20Token from '../test/generated-artifacts/TestMintableERC20Token.json';
import * as TestMintTokenERC20Transformer from '../test/generated-artifacts/TestMintTokenERC20Transformer.json';
import * as TestSimpleFunctionRegistryFeatureImpl1 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl1.json'; import * as TestSimpleFunctionRegistryFeatureImpl1 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl1.json';
import * as TestSimpleFunctionRegistryFeatureImpl2 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json'; import * as TestSimpleFunctionRegistryFeatureImpl2 from '../test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json';
import * as TestTokenSpender from '../test/generated-artifacts/TestTokenSpender.json';
import * as TestTokenSpenderERC20Token from '../test/generated-artifacts/TestTokenSpenderERC20Token.json';
import * as TestTransformERC20 from '../test/generated-artifacts/TestTransformERC20.json';
import * as TestZeroExFeature from '../test/generated-artifacts/TestZeroExFeature.json'; import * as TestZeroExFeature from '../test/generated-artifacts/TestZeroExFeature.json';
import * as TokenSpender from '../test/generated-artifacts/TokenSpender.json';
import * as TransformERC20 from '../test/generated-artifacts/TransformERC20.json';
import * as ZeroEx from '../test/generated-artifacts/ZeroEx.json'; import * as ZeroEx from '../test/generated-artifacts/ZeroEx.json';
export const artifacts = { export const artifacts = {
ZeroEx: ZeroEx as ContractArtifact, ZeroEx: ZeroEx as ContractArtifact,
@ -37,14 +60,26 @@ export const artifacts = {
LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact, LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact,
LibProxyRichErrors: LibProxyRichErrors as ContractArtifact, LibProxyRichErrors: LibProxyRichErrors as ContractArtifact,
LibSimpleFunctionRegistryRichErrors: LibSimpleFunctionRegistryRichErrors as ContractArtifact, LibSimpleFunctionRegistryRichErrors: LibSimpleFunctionRegistryRichErrors as ContractArtifact,
LibSpenderRichErrors: LibSpenderRichErrors as ContractArtifact,
LibTransformERC20RichErrors: LibTransformERC20RichErrors as ContractArtifact,
LibWalletRichErrors: LibWalletRichErrors as ContractArtifact,
AllowanceTarget: AllowanceTarget as ContractArtifact,
FlashWallet: FlashWallet as ContractArtifact,
IAllowanceTarget: IAllowanceTarget as ContractArtifact,
IFlashWallet: IFlashWallet as ContractArtifact,
Bootstrap: Bootstrap as ContractArtifact, Bootstrap: Bootstrap as ContractArtifact,
IBootstrap: IBootstrap as ContractArtifact, IBootstrap: IBootstrap as ContractArtifact,
IFeature: IFeature as ContractArtifact, IFeature: IFeature as ContractArtifact,
IOwnable: IOwnable as ContractArtifact, IOwnable: IOwnable as ContractArtifact,
ISimpleFunctionRegistry: ISimpleFunctionRegistry as ContractArtifact, ISimpleFunctionRegistry: ISimpleFunctionRegistry as ContractArtifact,
ITokenSpender: ITokenSpender as ContractArtifact,
ITransformERC20: ITransformERC20 as ContractArtifact,
Ownable: Ownable as ContractArtifact, Ownable: Ownable as ContractArtifact,
SimpleFunctionRegistry: SimpleFunctionRegistry as ContractArtifact, SimpleFunctionRegistry: SimpleFunctionRegistry as ContractArtifact,
TokenSpender: TokenSpender as ContractArtifact,
TransformERC20: TransformERC20 as ContractArtifact,
FixinCommon: FixinCommon as ContractArtifact, FixinCommon: FixinCommon as ContractArtifact,
FullMigration: FullMigration as ContractArtifact,
InitialMigration: InitialMigration as ContractArtifact, InitialMigration: InitialMigration as ContractArtifact,
LibBootstrap: LibBootstrap as ContractArtifact, LibBootstrap: LibBootstrap as ContractArtifact,
LibMigrate: LibMigrate as ContractArtifact, LibMigrate: LibMigrate as ContractArtifact,
@ -52,10 +87,21 @@ export const artifacts = {
LibProxyStorage: LibProxyStorage as ContractArtifact, LibProxyStorage: LibProxyStorage as ContractArtifact,
LibSimpleFunctionRegistryStorage: LibSimpleFunctionRegistryStorage as ContractArtifact, LibSimpleFunctionRegistryStorage: LibSimpleFunctionRegistryStorage as ContractArtifact,
LibStorage: LibStorage as ContractArtifact, LibStorage: LibStorage as ContractArtifact,
LibTokenSpenderStorage: LibTokenSpenderStorage as ContractArtifact,
LibTransformERC20Storage: LibTransformERC20Storage as ContractArtifact,
IERC20Transformer: IERC20Transformer as ContractArtifact,
LibERC20Transformer: LibERC20Transformer as ContractArtifact,
ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact, ITestSimpleFunctionRegistryFeature: ITestSimpleFunctionRegistryFeature as ContractArtifact,
TestCallTarget: TestCallTarget as ContractArtifact,
TestFullMigration: TestFullMigration as ContractArtifact,
TestInitialMigration: TestInitialMigration as ContractArtifact, TestInitialMigration: TestInitialMigration as ContractArtifact,
TestMigrator: TestMigrator as ContractArtifact, TestMigrator: TestMigrator as ContractArtifact,
TestMintTokenERC20Transformer: TestMintTokenERC20Transformer as ContractArtifact,
TestMintableERC20Token: TestMintableERC20Token as ContractArtifact,
TestSimpleFunctionRegistryFeatureImpl1: TestSimpleFunctionRegistryFeatureImpl1 as ContractArtifact, TestSimpleFunctionRegistryFeatureImpl1: TestSimpleFunctionRegistryFeatureImpl1 as ContractArtifact,
TestSimpleFunctionRegistryFeatureImpl2: TestSimpleFunctionRegistryFeatureImpl2 as ContractArtifact, TestSimpleFunctionRegistryFeatureImpl2: TestSimpleFunctionRegistryFeatureImpl2 as ContractArtifact,
TestTokenSpender: TestTokenSpender as ContractArtifact,
TestTokenSpenderERC20Token: TestTokenSpenderERC20Token as ContractArtifact,
TestTransformERC20: TestTransformERC20 as ContractArtifact,
TestZeroExFeature: TestZeroExFeature as ContractArtifact, TestZeroExFeature: TestZeroExFeature as ContractArtifact,
}; };

View File

@ -0,0 +1,141 @@
import {
blockchainTests,
expect,
getRandomInteger,
randomAddress,
verifyEventsFromLogs,
} from '@0x/contracts-test-utils';
import { BigNumber, hexUtils, StringRevertError, ZeroExRevertErrors } from '@0x/utils';
import { artifacts } from '../artifacts';
import { abis } from '../utils/abis';
import { fullMigrateAsync } from '../utils/migration';
import {
TestTokenSpenderERC20TokenContract,
TestTokenSpenderERC20TokenEvents,
TokenSpenderContract,
ZeroExContract,
} from '../wrappers';
blockchainTests.resets('TokenSpender feature', env => {
let zeroEx: ZeroExContract;
let feature: TokenSpenderContract;
let token: TestTokenSpenderERC20TokenContract;
let allowanceTarget: string;
before(async () => {
const [owner] = await env.getAccountAddressesAsync();
zeroEx = await fullMigrateAsync(owner, env.provider, env.txDefaults, {
tokenSpender: await TokenSpenderContract.deployFrom0xArtifactAsync(
artifacts.TestTokenSpender,
env.provider,
env.txDefaults,
artifacts,
),
});
feature = new TokenSpenderContract(zeroEx.address, env.provider, env.txDefaults, abis);
token = await TestTokenSpenderERC20TokenContract.deployFrom0xArtifactAsync(
artifacts.TestTokenSpenderERC20Token,
env.provider,
env.txDefaults,
artifacts,
);
allowanceTarget = await feature.getAllowanceTarget().callAsync();
});
describe('_spendERC20Tokens()', () => {
const EMPTY_RETURN_AMOUNT = 1337;
const FALSE_RETURN_AMOUNT = 1338;
const REVERT_RETURN_AMOUNT = 1339;
it('_spendERC20Tokens() successfully calls compliant ERC20 token', async () => {
const tokenFrom = randomAddress();
const tokenTo = randomAddress();
const tokenAmount = new BigNumber(123456);
const receipt = await feature
._spendERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
.awaitTransactionSuccessAsync();
verifyEventsFromLogs(
receipt.logs,
[
{
sender: allowanceTarget,
from: tokenFrom,
to: tokenTo,
amount: tokenAmount,
},
],
TestTokenSpenderERC20TokenEvents.TransferFromCalled,
);
});
it('_spendERC20Tokens() successfully calls non-compliant ERC20 token', async () => {
const tokenFrom = randomAddress();
const tokenTo = randomAddress();
const tokenAmount = new BigNumber(EMPTY_RETURN_AMOUNT);
const receipt = await feature
._spendERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
.awaitTransactionSuccessAsync();
verifyEventsFromLogs(
receipt.logs,
[
{
sender: allowanceTarget,
from: tokenFrom,
to: tokenTo,
amount: tokenAmount,
},
],
TestTokenSpenderERC20TokenEvents.TransferFromCalled,
);
});
it('_spendERC20Tokens() reverts if ERC20 token reverts', async () => {
const tokenFrom = randomAddress();
const tokenTo = randomAddress();
const tokenAmount = new BigNumber(REVERT_RETURN_AMOUNT);
const tx = feature
._spendERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
.awaitTransactionSuccessAsync();
const expectedError = new ZeroExRevertErrors.Spender.SpenderERC20TransferFromFailedError(
token.address,
tokenFrom,
tokenTo,
tokenAmount,
new StringRevertError('TestTokenSpenderERC20Token/Revert').encode(),
);
return expect(tx).to.revertWith(expectedError);
});
it('_spendERC20Tokens() reverts if ERC20 token returns false', async () => {
const tokenFrom = randomAddress();
const tokenTo = randomAddress();
const tokenAmount = new BigNumber(FALSE_RETURN_AMOUNT);
const tx = feature
._spendERC20Tokens(token.address, tokenFrom, tokenTo, tokenAmount)
.awaitTransactionSuccessAsync();
return expect(tx).to.revertWith(
new ZeroExRevertErrors.Spender.SpenderERC20TransferFromFailedError(
token.address,
tokenFrom,
tokenTo,
tokenAmount,
hexUtils.leftPad(0),
),
);
});
});
describe('getSpendableERC20BalanceOf()', () => {
it("returns the minimum of the owner's balance and allowance", async () => {
const balance = getRandomInteger(1, '1e18');
const allowance = getRandomInteger(1, '1e18');
const tokenOwner = randomAddress();
await token
.setBalanceAndAllowanceOf(tokenOwner, balance, allowanceTarget, allowance)
.awaitTransactionSuccessAsync();
const spendableBalance = await feature.getSpendableERC20BalanceOf(token.address, tokenOwner).callAsync();
expect(spendableBalance).to.bignumber.eq(BigNumber.min(balance, allowance));
});
});
});

View File

@ -0,0 +1,526 @@
import {
blockchainTests,
constants,
expect,
getRandomInteger,
getRandomPortion,
Numberish,
randomAddress,
verifyEventsFromLogs,
} from '@0x/contracts-test-utils';
import { AbiEncoder, hexUtils, ZeroExRevertErrors } from '@0x/utils';
import { getRLPEncodedAccountNonceAsync } from '../../src/nonce_utils';
import { artifacts } from '../artifacts';
import { abis } from '../utils/abis';
import { fullMigrateAsync } from '../utils/migration';
import {
FlashWalletContract,
ITokenSpenderContract,
TestMintableERC20TokenContract,
TestMintTokenERC20TransformerContract,
TestMintTokenERC20TransformerEvents,
TransformERC20Contract,
TransformERC20Events,
ZeroExContract,
} from '../wrappers';
blockchainTests.resets('TransformERC20 feature', env => {
let taker: string;
let transformerDeployer: string;
let zeroEx: ZeroExContract;
let feature: TransformERC20Contract;
let wallet: FlashWalletContract;
let allowanceTarget: string;
before(async () => {
let owner;
[owner, taker, transformerDeployer] = await env.getAccountAddressesAsync();
zeroEx = await fullMigrateAsync(owner, env.provider, env.txDefaults, {
transformERC20: await TransformERC20Contract.deployFrom0xArtifactAsync(
artifacts.TestTransformERC20,
env.provider,
env.txDefaults,
artifacts,
transformerDeployer,
),
});
feature = new TransformERC20Contract(zeroEx.address, env.provider, env.txDefaults, abis);
wallet = new FlashWalletContract(await feature.getTransformWallet().callAsync(), env.provider, env.txDefaults);
allowanceTarget = await new ITokenSpenderContract(zeroEx.address, env.provider, env.txDefaults)
.getAllowanceTarget()
.callAsync();
});
const { MAX_UINT256, NULL_BYTES, ZERO_AMOUNT } = constants;
describe('wallets', () => {
it('createTransformWallet() replaces the current wallet', async () => {
const newWalletAddress = await feature.createTransformWallet().callAsync();
expect(newWalletAddress).to.not.eq(wallet.address);
await feature.createTransformWallet().awaitTransactionSuccessAsync();
return expect(feature.getTransformWallet().callAsync()).to.eventually.eq(newWalletAddress);
});
});
describe('_transformERC20()', () => {
let inputToken: TestMintableERC20TokenContract;
let outputToken: TestMintableERC20TokenContract;
let mintTransformer: TestMintTokenERC20TransformerContract;
let rlpNonce: string;
before(async () => {
inputToken = await TestMintableERC20TokenContract.deployFrom0xArtifactAsync(
artifacts.TestMintableERC20Token,
env.provider,
env.txDefaults,
artifacts,
);
outputToken = await TestMintableERC20TokenContract.deployFrom0xArtifactAsync(
artifacts.TestMintableERC20Token,
env.provider,
env.txDefaults,
artifacts,
);
rlpNonce = await getRLPEncodedAccountNonceAsync(env.web3Wrapper, transformerDeployer);
mintTransformer = await TestMintTokenERC20TransformerContract.deployFrom0xArtifactAsync(
artifacts.TestMintTokenERC20Transformer,
env.provider,
{
...env.txDefaults,
from: transformerDeployer,
},
artifacts,
);
await inputToken.approve(allowanceTarget, MAX_UINT256).awaitTransactionSuccessAsync({ from: taker });
});
interface Transformation {
transformer: string;
data: string;
}
const transformDataEncoder = AbiEncoder.create([
{
name: 'data',
type: 'tuple',
components: [
{ name: 'inputToken', type: 'address' },
{ name: 'outputToken', type: 'address' },
{ name: 'burnAmount', type: 'uint256' },
{ name: 'mintAmount', type: 'uint256' },
{ name: 'feeAmount', type: 'uint256' },
{ name: 'deploymentNonce', type: 'bytes' },
],
},
]);
function createMintTokenTransformation(
opts: Partial<{
transformer: string;
outputTokenAddress: string;
inputTokenAddress: string;
inputTokenBurnAmunt: Numberish;
outputTokenMintAmount: Numberish;
outputTokenFeeAmount: Numberish;
rlpNonce: string;
}> = {},
): Transformation {
const _opts = {
rlpNonce,
outputTokenAddress: outputToken.address,
inputTokenAddress: inputToken.address,
inputTokenBurnAmunt: ZERO_AMOUNT,
outputTokenMintAmount: ZERO_AMOUNT,
outputTokenFeeAmount: ZERO_AMOUNT,
transformer: mintTransformer.address,
...opts,
};
return {
transformer: _opts.transformer,
data: transformDataEncoder.encode([
{
inputToken: _opts.inputTokenAddress,
outputToken: _opts.outputTokenAddress,
burnAmount: _opts.inputTokenBurnAmunt,
mintAmount: _opts.outputTokenMintAmount,
feeAmount: _opts.outputTokenFeeAmount,
deploymentNonce: _opts.rlpNonce,
},
]),
};
}
it("succeeds if taker's output token balance increases by exactly minOutputTokenAmount", async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(0, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount;
const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
const transformation = createMintTokenTransformation({
outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount,
});
const receipt = await feature
._transformERC20(
callDataHash,
taker,
inputToken.address,
outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
[transformation],
)
.awaitTransactionSuccessAsync({ value: callValue });
verifyEventsFromLogs(
receipt.logs,
[
{
taker,
inputTokenAmount,
outputTokenAmount: outputTokenMintAmount,
inputToken: inputToken.address,
outputToken: outputToken.address,
},
],
TransformERC20Events.TransformedERC20,
);
verifyEventsFromLogs(
receipt.logs,
[
{
callDataHash,
taker,
context: wallet.address,
caller: zeroEx.address,
data: transformation.data,
inputTokenBalance: inputTokenAmount,
ethBalance: callValue,
},
],
TestMintTokenERC20TransformerEvents.MintTransform,
);
});
const ETH_TOKEN_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
it("succeeds if taker's output token balance increases by exactly minOutputTokenAmount, with ETH", async () => {
const startingInputTokenBalance = getRandomInteger(0, '100e18');
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount;
const callValue = outputTokenMintAmount.times(2);
const callDataHash = hexUtils.random();
const transformation = createMintTokenTransformation({
outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount,
outputTokenAddress: ETH_TOKEN_ADDRESS,
});
const startingOutputTokenBalance = await env.web3Wrapper.getBalanceInWeiAsync(taker);
const receipt = await feature
._transformERC20(
callDataHash,
taker,
inputToken.address,
ETH_TOKEN_ADDRESS,
inputTokenAmount,
minOutputTokenAmount,
[transformation],
)
.awaitTransactionSuccessAsync({ value: callValue });
verifyEventsFromLogs(
receipt.logs,
[
{
taker,
inputTokenAmount,
outputTokenAmount: outputTokenMintAmount,
inputToken: inputToken.address,
outputToken: ETH_TOKEN_ADDRESS,
},
],
TransformERC20Events.TransformedERC20,
);
verifyEventsFromLogs(
receipt.logs,
[
{
callDataHash,
taker,
context: wallet.address,
caller: zeroEx.address,
data: transformation.data,
inputTokenBalance: inputTokenAmount,
ethBalance: callValue,
},
],
TestMintTokenERC20TransformerEvents.MintTransform,
);
expect(await env.web3Wrapper.getBalanceInWeiAsync(taker)).to.bignumber.eq(
startingOutputTokenBalance.plus(outputTokenMintAmount),
);
});
it("succeeds if taker's output token balance increases by more than minOutputTokenAmount", async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(0, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount.plus(1);
const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
const transformation = createMintTokenTransformation({
outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount,
});
const receipt = await feature
._transformERC20(
callDataHash,
taker,
inputToken.address,
outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
[transformation],
)
.awaitTransactionSuccessAsync({ value: callValue });
verifyEventsFromLogs(
receipt.logs,
[
{
taker,
inputTokenAmount,
outputTokenAmount: outputTokenMintAmount,
inputToken: inputToken.address,
outputToken: outputToken.address,
},
],
TransformERC20Events.TransformedERC20,
);
verifyEventsFromLogs(
receipt.logs,
[
{
callDataHash,
taker,
context: wallet.address,
caller: zeroEx.address,
data: transformation.data,
inputTokenBalance: inputTokenAmount,
ethBalance: callValue,
},
],
TestMintTokenERC20TransformerEvents.MintTransform,
);
});
it("throws if taker's output token balance increases by less than minOutputTokenAmount", async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(0, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(1, '1e18');
const outputTokenMintAmount = minOutputTokenAmount.minus(1);
const callValue = getRandomInteger(1, '1e18');
const tx = feature
._transformERC20(
hexUtils.random(),
taker,
inputToken.address,
outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
[
createMintTokenTransformation({
outputTokenMintAmount,
inputTokenBurnAmunt: inputTokenAmount,
}),
],
)
.awaitTransactionSuccessAsync({ value: callValue });
const expectedError = new ZeroExRevertErrors.TransformERC20.IncompleteTransformERC20Error(
outputToken.address,
outputTokenMintAmount,
minOutputTokenAmount,
);
return expect(tx).to.revertWith(expectedError);
});
it("throws if taker's output token balance decreases", async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(0, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = ZERO_AMOUNT;
const outputTokenFeeAmount = 1;
const callValue = getRandomInteger(1, '1e18');
const tx = feature
._transformERC20(
hexUtils.random(),
taker,
inputToken.address,
outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
[
createMintTokenTransformation({
outputTokenFeeAmount,
inputTokenBurnAmunt: inputTokenAmount,
}),
],
)
.awaitTransactionSuccessAsync({ value: callValue });
const expectedError = new ZeroExRevertErrors.TransformERC20.NegativeTransformERC20OutputError(
outputToken.address,
outputTokenFeeAmount,
);
return expect(tx).to.revertWith(expectedError);
});
it('can call multiple transformers', async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(2, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(2, '1e18');
const outputTokenMintAmount = minOutputTokenAmount;
const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
// Split the total minting between two transformers.
const transformations = [
createMintTokenTransformation({
inputTokenBurnAmunt: 1,
outputTokenMintAmount: 1,
}),
createMintTokenTransformation({
inputTokenBurnAmunt: inputTokenAmount.minus(1),
outputTokenMintAmount: outputTokenMintAmount.minus(1),
}),
];
const receipt = await feature
._transformERC20(
callDataHash,
taker,
inputToken.address,
outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
transformations,
)
.awaitTransactionSuccessAsync({ value: callValue });
verifyEventsFromLogs(
receipt.logs,
[
{
callDataHash,
taker,
context: wallet.address,
caller: zeroEx.address,
data: transformations[0].data,
inputTokenBalance: inputTokenAmount,
ethBalance: callValue,
},
{
callDataHash,
taker,
context: wallet.address,
caller: zeroEx.address,
data: transformations[1].data,
inputTokenBalance: inputTokenAmount.minus(1),
ethBalance: callValue,
},
],
TestMintTokenERC20TransformerEvents.MintTransform,
);
});
it('fails with third-party transformer', async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(2, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(2, '1e18');
const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
const transformations = [createMintTokenTransformation({ transformer: randomAddress() })];
const tx = feature
._transformERC20(
callDataHash,
taker,
inputToken.address,
outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
transformations,
)
.awaitTransactionSuccessAsync({ value: callValue });
return expect(tx).to.revertWith(new ZeroExRevertErrors.TransformERC20.InvalidRLPNonceError(NULL_BYTES));
});
it('fails with incorrect transformer RLP nonce', async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(2, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(2, '1e18');
const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
const badRlpNonce = '0x00';
const transformations = [createMintTokenTransformation({ rlpNonce: badRlpNonce })];
const tx = feature
._transformERC20(
callDataHash,
taker,
inputToken.address,
outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
transformations,
)
.awaitTransactionSuccessAsync({ value: callValue });
return expect(tx).to.revertWith(
new ZeroExRevertErrors.TransformERC20.UnauthorizedTransformerError(
transformations[0].transformer,
badRlpNonce,
),
);
});
it('fails with invalid transformer RLP nonce', async () => {
const startingOutputTokenBalance = getRandomInteger(0, '100e18');
const startingInputTokenBalance = getRandomInteger(2, '100e18');
await outputToken.mint(taker, startingOutputTokenBalance).awaitTransactionSuccessAsync();
await inputToken.mint(taker, startingInputTokenBalance).awaitTransactionSuccessAsync();
const inputTokenAmount = getRandomPortion(startingInputTokenBalance);
const minOutputTokenAmount = getRandomInteger(2, '1e18');
const callValue = getRandomInteger(1, '1e18');
const callDataHash = hexUtils.random();
const badRlpNonce = '0x010203040506';
const transformations = [createMintTokenTransformation({ rlpNonce: badRlpNonce })];
const tx = feature
._transformERC20(
callDataHash,
taker,
inputToken.address,
outputToken.address,
inputTokenAmount,
minOutputTokenAmount,
transformations,
)
.awaitTransactionSuccessAsync({ value: callValue });
return expect(tx).to.revertWith(new ZeroExRevertErrors.TransformERC20.InvalidRLPNonceError(badRlpNonce));
});
});
});

View File

@ -0,0 +1,211 @@
import {
blockchainTests,
constants,
expect,
getRandomInteger,
randomAddress,
verifyEventsFromLogs,
} from '@0x/contracts-test-utils';
import { hexUtils, OwnableRevertErrors, StringRevertError, ZeroExRevertErrors } from '@0x/utils';
import { artifacts } from './artifacts';
import { FlashWalletContract, TestCallTargetContract, TestCallTargetEvents } from './wrappers';
blockchainTests.resets('FlashWallet', env => {
let owner: string;
let wallet: FlashWalletContract;
let callTarget: TestCallTargetContract;
before(async () => {
[owner] = await env.getAccountAddressesAsync();
wallet = await FlashWalletContract.deployFrom0xArtifactAsync(
artifacts.FlashWallet,
env.provider,
{
...env.txDefaults,
from: owner,
},
artifacts,
);
callTarget = await TestCallTargetContract.deployFrom0xArtifactAsync(
artifacts.TestCallTarget,
env.provider,
env.txDefaults,
artifacts,
);
});
const TARGET_RETURN_VALUE = hexUtils.rightPad('0x12345678');
const REVERTING_DATA = '0x1337';
it('owned by deployer', () => {
return expect(wallet.owner().callAsync()).to.eventually.eq(owner);
});
describe('executeCall()', () => {
it('non-owner cannot call executeCall()', async () => {
const notOwner = randomAddress();
const tx = wallet
.executeCall(randomAddress(), hexUtils.random(), getRandomInteger(0, '100e18'))
.callAsync({ from: notOwner });
return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(notOwner));
});
it('owner can call executeCall()', async () => {
const targetData = hexUtils.random(128);
const receipt = await wallet
.executeCall(callTarget.address, targetData, constants.ZERO_AMOUNT)
.awaitTransactionSuccessAsync({ from: owner });
verifyEventsFromLogs(
receipt.logs,
[
{
context: callTarget.address,
sender: wallet.address,
data: targetData,
value: constants.ZERO_AMOUNT,
},
],
TestCallTargetEvents.CallTargetCalled,
);
});
it('owner can call executeCall() with attached ETH', async () => {
const targetData = hexUtils.random(128);
const callValue = getRandomInteger(1, '1e18');
const receipt = await wallet
.executeCall(callTarget.address, targetData, callValue)
.awaitTransactionSuccessAsync({ from: owner, value: callValue });
verifyEventsFromLogs(
receipt.logs,
[
{
context: callTarget.address,
sender: wallet.address,
data: targetData,
value: callValue,
},
],
TestCallTargetEvents.CallTargetCalled,
);
});
it('owner can call executeCall() can transfer less ETH than attached', async () => {
const targetData = hexUtils.random(128);
const callValue = getRandomInteger(1, '1e18');
const receipt = await wallet
.executeCall(callTarget.address, targetData, callValue.minus(1))
.awaitTransactionSuccessAsync({ from: owner, value: callValue });
verifyEventsFromLogs(
receipt.logs,
[
{
context: callTarget.address,
sender: wallet.address,
data: targetData,
value: callValue.minus(1),
},
],
TestCallTargetEvents.CallTargetCalled,
);
});
it('wallet returns call result', async () => {
const result = await wallet
.executeCall(callTarget.address, hexUtils.random(128), constants.ZERO_AMOUNT)
.callAsync({ from: owner });
expect(result).to.eq(TARGET_RETURN_VALUE);
});
it('wallet wraps call revert', async () => {
const tx = wallet
.executeCall(callTarget.address, REVERTING_DATA, constants.ZERO_AMOUNT)
.callAsync({ from: owner });
return expect(tx).to.revertWith(
new ZeroExRevertErrors.Wallet.WalletExecuteCallFailedError(
wallet.address,
callTarget.address,
REVERTING_DATA,
constants.ZERO_AMOUNT,
new StringRevertError('TestCallTarget/REVERT').encode(),
),
);
});
it('wallet can receive ETH', async () => {
await env.web3Wrapper.sendTransactionAsync({
to: wallet.address,
from: owner,
value: 1,
});
const bal = await env.web3Wrapper.getBalanceInWeiAsync(wallet.address);
expect(bal).to.bignumber.eq(1);
});
});
describe('executeDelegateCall()', () => {
it('non-owner cannot call executeDelegateCall()', async () => {
const notOwner = randomAddress();
const tx = wallet.executeDelegateCall(randomAddress(), hexUtils.random()).callAsync({ from: notOwner });
return expect(tx).to.revertWith(new OwnableRevertErrors.OnlyOwnerError(notOwner));
});
it('owner can call executeDelegateCall()', async () => {
const targetData = hexUtils.random(128);
const receipt = await wallet
.executeDelegateCall(callTarget.address, targetData)
.awaitTransactionSuccessAsync({ from: owner });
verifyEventsFromLogs(
receipt.logs,
[
{
context: wallet.address,
sender: owner,
data: targetData,
value: constants.ZERO_AMOUNT,
},
],
TestCallTargetEvents.CallTargetCalled,
);
});
it('executeDelegateCall() is payable', async () => {
const targetData = hexUtils.random(128);
const callValue = getRandomInteger(1, '1e18');
const receipt = await wallet
.executeDelegateCall(callTarget.address, targetData)
.awaitTransactionSuccessAsync({ from: owner, value: callValue });
verifyEventsFromLogs(
receipt.logs,
[
{
context: wallet.address,
sender: owner,
data: targetData,
value: callValue,
},
],
TestCallTargetEvents.CallTargetCalled,
);
});
it('wallet returns call result', async () => {
const result = await wallet
.executeDelegateCall(callTarget.address, hexUtils.random(128))
.callAsync({ from: owner });
expect(result).to.eq(TARGET_RETURN_VALUE);
});
it('wallet wraps call revert', async () => {
const tx = wallet.executeDelegateCall(callTarget.address, REVERTING_DATA).callAsync({ from: owner });
return expect(tx).to.revertWith(
new ZeroExRevertErrors.Wallet.WalletExecuteDelegateCallFailedError(
wallet.address,
callTarget.address,
REVERTING_DATA,
new StringRevertError('TestCallTarget/REVERT').encode(),
),
);
});
});
});

View File

@ -0,0 +1,165 @@
import { BaseContract } from '@0x/base-contract';
import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils';
import { BigNumber, hexUtils, ZeroExRevertErrors } from '@0x/utils';
import { DataItem, MethodAbi } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from './artifacts';
import { abis } from './utils/abis';
import { deployFullFeaturesAsync, FullFeatures, toFeatureAdddresses } from './utils/migration';
import {
AllowanceTargetContract,
IOwnableContract,
ITokenSpenderContract,
ITransformERC20Contract,
TestFullMigrationContract,
ZeroExContract,
} from './wrappers';
const { NULL_ADDRESS } = constants;
blockchainTests.resets('Full migration', env => {
let owner: string;
let zeroEx: ZeroExContract;
let features: FullFeatures;
let migrator: TestFullMigrationContract;
before(async () => {
[owner] = await env.getAccountAddressesAsync();
features = await deployFullFeaturesAsync(env.provider, env.txDefaults);
migrator = await TestFullMigrationContract.deployFrom0xArtifactAsync(
artifacts.TestFullMigration,
env.provider,
env.txDefaults,
artifacts,
env.txDefaults.from as string,
);
const deployCall = migrator.deploy(owner, toFeatureAdddresses(features));
zeroEx = new ZeroExContract(await deployCall.callAsync(), env.provider, env.txDefaults);
await deployCall.awaitTransactionSuccessAsync();
});
it('ZeroEx has the correct owner', async () => {
const ownable = new IOwnableContract(zeroEx.address, env.provider, env.txDefaults);
const actualOwner = await ownable.owner().callAsync();
expect(actualOwner).to.eq(owner);
});
it('FullMigration contract self-destructs', async () => {
const dieRecipient = await migrator.dieRecipient().callAsync();
expect(dieRecipient).to.eq(owner);
});
it('Non-deployer cannot call deploy()', async () => {
const notDeployer = randomAddress();
const tx = migrator.deploy(owner, toFeatureAdddresses(features)).callAsync({ from: notDeployer });
return expect(tx).to.revertWith('FullMigration/INVALID_SENDER');
});
const FEATURE_FNS = {
TokenSpender: {
contractType: ITokenSpenderContract,
fns: ['_spendERC20Tokens'],
},
TransformERC20: {
contractType: ITransformERC20Contract,
fns: ['transformERC20', '_transformERC20', 'createTransformWallet', 'getTransformWallet'],
},
};
function createFakeInputs(inputs: DataItem[] | DataItem): any | any[] {
if ((inputs as DataItem[]).length !== undefined) {
return (inputs as DataItem[]).map(i => createFakeInputs(i));
}
const item = inputs as DataItem;
// TODO(dorothy-zbornak): Support fixed-length arrays.
if (/\[]$/.test(item.type)) {
return _.times(_.random(0, 8), () =>
createFakeInputs({
...item,
type: item.type.substring(0, item.type.length - 2),
}),
);
}
if (/^tuple$/.test(item.type)) {
const tuple = {} as any;
for (const comp of item.components as DataItem[]) {
tuple[comp.name] = createFakeInputs(comp);
}
return tuple;
}
if (item.type === 'address') {
return randomAddress();
}
if (item.type === 'byte') {
return hexUtils.random(1);
}
if (/^bytes$/.test(item.type)) {
return hexUtils.random(_.random(0, 128));
}
if (/^bytes\d+$/.test(item.type)) {
return hexUtils.random(parseInt(/\d+$/.exec(item.type)![0], 10));
}
if (/^uint\d+$/.test(item.type)) {
return new BigNumber(hexUtils.random(parseInt(/\d+$/.exec(item.type)![0], 10) / 8));
}
if (/^int\d+$/.test(item.type)) {
return new BigNumber(hexUtils.random(parseInt(/\d+$/.exec(item.type)![0], 10) / 8))
.div(2)
.times(_.sample([-1, 1])!);
}
throw new Error(`Unhandled input type: '${item.type}'`);
}
for (const [featureName, featureInfo] of Object.entries(FEATURE_FNS)) {
describe(`${featureName} feature`, () => {
let contract: BaseContract & { getSelector(name: string): string };
before(async () => {
contract = new featureInfo.contractType(zeroEx.address, env.provider, env.txDefaults, abis);
});
for (const fn of featureInfo.fns) {
it(`${fn} is registered`, async () => {
const selector = contract.getSelector(fn);
const impl = await zeroEx.getFunctionImplementation(selector).callAsync();
expect(impl).to.not.eq(NULL_ADDRESS);
});
if (fn.startsWith('_')) {
it(`${fn} cannot be called from outside`, async () => {
const method = contract.abi.find(
d => d.type === 'function' && (d as MethodAbi).name === fn,
) as MethodAbi;
const inputs = createFakeInputs(method.inputs);
const tx = (contract as any)[fn](...inputs).callAsync();
return expect(tx).to.revertWith(
new ZeroExRevertErrors.Common.OnlyCallableBySelfError(env.txDefaults.from),
);
});
}
}
});
}
describe("TokenSpender's allowance target", () => {
let allowanceTarget: AllowanceTargetContract;
before(async () => {
const contract = new ITokenSpenderContract(zeroEx.address, env.provider, env.txDefaults);
allowanceTarget = new AllowanceTargetContract(
await contract.getAllowanceTarget().callAsync(),
env.provider,
env.txDefaults,
);
});
it('is owned by owner', async () => {
return expect(allowanceTarget.owner().callAsync()).to.become(owner);
});
it('Proxy is authorized', async () => {
return expect(allowanceTarget.authorized(zeroEx.address).callAsync()).to.become(true);
});
});
});

View File

@ -2,6 +2,7 @@ import { blockchainTests, expect, randomAddress } from '@0x/contracts-test-utils
import { ZeroExRevertErrors } from '@0x/utils'; import { ZeroExRevertErrors } from '@0x/utils';
import { artifacts } from './artifacts'; import { artifacts } from './artifacts';
import { BootstrapFeatures, deployBootstrapFeaturesAsync, toFeatureAdddresses } from './utils/migration';
import { import {
IBootstrapContract, IBootstrapContract,
InitialMigrationContract, InitialMigrationContract,
@ -15,9 +16,11 @@ blockchainTests.resets('Initial migration', env => {
let zeroEx: ZeroExContract; let zeroEx: ZeroExContract;
let migrator: TestInitialMigrationContract; let migrator: TestInitialMigrationContract;
let bootstrapFeature: IBootstrapContract; let bootstrapFeature: IBootstrapContract;
let features: BootstrapFeatures;
before(async () => { before(async () => {
[owner] = await env.getAccountAddressesAsync(); [owner] = await env.getAccountAddressesAsync();
features = await deployBootstrapFeaturesAsync(env.provider, env.txDefaults);
migrator = await TestInitialMigrationContract.deployFrom0xArtifactAsync( migrator = await TestInitialMigrationContract.deployFrom0xArtifactAsync(
artifacts.TestInitialMigration, artifacts.TestInitialMigration,
env.provider, env.provider,
@ -31,7 +34,7 @@ blockchainTests.resets('Initial migration', env => {
env.txDefaults, env.txDefaults,
{}, {},
); );
const deployCall = migrator.deploy(owner); const deployCall = migrator.deploy(owner, toFeatureAdddresses(features));
zeroEx = new ZeroExContract(await deployCall.callAsync(), env.provider, env.txDefaults); zeroEx = new ZeroExContract(await deployCall.callAsync(), env.provider, env.txDefaults);
await deployCall.awaitTransactionSuccessAsync(); await deployCall.awaitTransactionSuccessAsync();
}); });
@ -43,7 +46,7 @@ blockchainTests.resets('Initial migration', env => {
it('Non-deployer cannot call deploy()', async () => { it('Non-deployer cannot call deploy()', async () => {
const notDeployer = randomAddress(); const notDeployer = randomAddress();
const tx = migrator.deploy(owner).callAsync({ from: notDeployer }); const tx = migrator.deploy(owner, toFeatureAdddresses(features)).callAsync({ from: notDeployer });
return expect(tx).to.revertWith('InitialMigration/INVALID_SENDER'); return expect(tx).to.revertWith('InitialMigration/INVALID_SENDER');
}); });
@ -67,8 +70,8 @@ blockchainTests.resets('Initial migration', env => {
}); });
it('Bootstrap feature self destructs after deployment', async () => { it('Bootstrap feature self destructs after deployment', async () => {
const codeSize = await migrator.getCodeSizeOf(bootstrapFeature.address).callAsync(); const doesExist = await env.web3Wrapper.doesContractExistAtAddressAsync(bootstrapFeature.address);
expect(codeSize).to.bignumber.eq(0); expect(doesExist).to.eq(false);
}); });
}); });

View File

@ -0,0 +1,5 @@
import * as _ from 'lodash';
import { artifacts } from '../artifacts';
export const abis = _.mapValues(artifacts, v => v.compilerOutput.abi);

View File

@ -1,15 +1,53 @@
import { BaseContract } from '@0x/base-contract';
import { SupportedProvider } from '@0x/subproviders'; import { SupportedProvider } from '@0x/subproviders';
import { TxData } from 'ethereum-types'; import { TxData } from 'ethereum-types';
import * as _ from 'lodash';
import { artifacts } from '../artifacts'; import { artifacts } from '../artifacts';
import { InitialMigrationContract, ZeroExContract } from '../wrappers'; import {
FullMigrationContract,
InitialMigrationContract,
OwnableContract,
SimpleFunctionRegistryContract,
TokenSpenderContract,
TransformERC20Contract,
ZeroExContract,
} from '../wrappers';
// tslint:disable: completed-docs // tslint:disable: completed-docs
export interface BootstrapFeatures {
registry: SimpleFunctionRegistryContract;
ownable: OwnableContract;
}
export async function deployBootstrapFeaturesAsync(
provider: SupportedProvider,
txDefaults: Partial<TxData>,
features: Partial<BootstrapFeatures> = {},
): Promise<BootstrapFeatures> {
return {
registry:
features.registry ||
(await SimpleFunctionRegistryContract.deployFrom0xArtifactAsync(
artifacts.SimpleFunctionRegistry,
provider,
txDefaults,
artifacts,
)),
ownable:
features.ownable ||
(await OwnableContract.deployFrom0xArtifactAsync(artifacts.Ownable, provider, txDefaults, artifacts)),
};
}
export async function initialMigrateAsync( export async function initialMigrateAsync(
owner: string, owner: string,
provider: SupportedProvider, provider: SupportedProvider,
txDefaults: Partial<TxData>, txDefaults: Partial<TxData>,
features: Partial<BootstrapFeatures> = {},
): Promise<ZeroExContract> { ): Promise<ZeroExContract> {
const _features = await deployBootstrapFeaturesAsync(provider, txDefaults, features);
const migrator = await InitialMigrationContract.deployFrom0xArtifactAsync( const migrator = await InitialMigrationContract.deployFrom0xArtifactAsync(
artifacts.InitialMigration, artifacts.InitialMigration,
provider, provider,
@ -17,8 +55,74 @@ export async function initialMigrateAsync(
artifacts, artifacts,
txDefaults.from as string, txDefaults.from as string,
); );
const deployCall = migrator.deploy(owner); const deployCall = migrator.deploy(owner, toFeatureAdddresses(_features));
const zeroEx = new ZeroExContract(await deployCall.callAsync(), provider, {}); const zeroEx = new ZeroExContract(await deployCall.callAsync(), provider, {});
await deployCall.awaitTransactionSuccessAsync(); await deployCall.awaitTransactionSuccessAsync();
return zeroEx; return zeroEx;
} }
export interface FullFeatures extends BootstrapFeatures {
tokenSpender: TokenSpenderContract;
transformERC20: TransformERC20Contract;
}
export interface FullMigrationOpts {
transformDeployer: string;
}
export async function deployFullFeaturesAsync(
provider: SupportedProvider,
txDefaults: Partial<TxData>,
features: Partial<FullFeatures> = {},
opts: Partial<FullMigrationOpts> = {},
): Promise<FullFeatures> {
return {
...(await deployBootstrapFeaturesAsync(provider, txDefaults)),
tokenSpender:
features.tokenSpender ||
(await TokenSpenderContract.deployFrom0xArtifactAsync(
artifacts.TokenSpender,
provider,
txDefaults,
artifacts,
)),
transformERC20:
features.transformERC20 ||
(await TransformERC20Contract.deployFrom0xArtifactAsync(
artifacts.TransformERC20,
provider,
txDefaults,
artifacts,
opts.transformDeployer || (txDefaults.from as string),
)),
};
}
export async function fullMigrateAsync(
owner: string,
provider: SupportedProvider,
txDefaults: Partial<TxData>,
features: Partial<FullFeatures> = {},
opts: Partial<FullMigrationOpts> = {},
): Promise<ZeroExContract> {
const _features = await deployFullFeaturesAsync(provider, txDefaults, features, opts);
const migrator = await FullMigrationContract.deployFrom0xArtifactAsync(
artifacts.FullMigration,
provider,
txDefaults,
artifacts,
txDefaults.from as string,
);
const deployCall = migrator.deploy(owner, toFeatureAdddresses(_features));
const zeroEx = new ZeroExContract(await deployCall.callAsync(), provider, {});
await deployCall.awaitTransactionSuccessAsync();
return zeroEx;
}
// tslint:disable:space-before-function-parent one-line
export function toFeatureAdddresses<T extends BootstrapFeatures | FullFeatures | (BootstrapFeatures & FullFeatures)>(
features: T,
): { [name in keyof T]: string } {
// TS can't figure this out.
return _.mapValues(features, (c: BaseContract) => c.address) as any;
}

View File

@ -3,16 +3,25 @@
* Warning: This file is auto-generated by contracts-gen. Don't edit manually. * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
* ----------------------------------------------------------------------------- * -----------------------------------------------------------------------------
*/ */
export * from '../test/generated-wrappers/allowance_target';
export * from '../test/generated-wrappers/bootstrap'; export * from '../test/generated-wrappers/bootstrap';
export * from '../test/generated-wrappers/fixin_common'; export * from '../test/generated-wrappers/fixin_common';
export * from '../test/generated-wrappers/flash_wallet';
export * from '../test/generated-wrappers/full_migration';
export * from '../test/generated-wrappers/i_allowance_target';
export * from '../test/generated-wrappers/i_bootstrap'; export * from '../test/generated-wrappers/i_bootstrap';
export * from '../test/generated-wrappers/i_erc20_transformer';
export * from '../test/generated-wrappers/i_feature'; export * from '../test/generated-wrappers/i_feature';
export * from '../test/generated-wrappers/i_flash_wallet';
export * from '../test/generated-wrappers/i_ownable'; export * from '../test/generated-wrappers/i_ownable';
export * from '../test/generated-wrappers/i_simple_function_registry'; export * from '../test/generated-wrappers/i_simple_function_registry';
export * from '../test/generated-wrappers/i_test_simple_function_registry_feature'; export * from '../test/generated-wrappers/i_test_simple_function_registry_feature';
export * from '../test/generated-wrappers/i_token_spender';
export * from '../test/generated-wrappers/i_transform_erc20';
export * from '../test/generated-wrappers/initial_migration'; export * from '../test/generated-wrappers/initial_migration';
export * from '../test/generated-wrappers/lib_bootstrap'; export * from '../test/generated-wrappers/lib_bootstrap';
export * from '../test/generated-wrappers/lib_common_rich_errors'; export * from '../test/generated-wrappers/lib_common_rich_errors';
export * from '../test/generated-wrappers/lib_erc20_transformer';
export * from '../test/generated-wrappers/lib_migrate'; export * from '../test/generated-wrappers/lib_migrate';
export * from '../test/generated-wrappers/lib_ownable_rich_errors'; export * from '../test/generated-wrappers/lib_ownable_rich_errors';
export * from '../test/generated-wrappers/lib_ownable_storage'; export * from '../test/generated-wrappers/lib_ownable_storage';
@ -20,12 +29,26 @@ export * from '../test/generated-wrappers/lib_proxy_rich_errors';
export * from '../test/generated-wrappers/lib_proxy_storage'; export * from '../test/generated-wrappers/lib_proxy_storage';
export * from '../test/generated-wrappers/lib_simple_function_registry_rich_errors'; export * from '../test/generated-wrappers/lib_simple_function_registry_rich_errors';
export * from '../test/generated-wrappers/lib_simple_function_registry_storage'; export * from '../test/generated-wrappers/lib_simple_function_registry_storage';
export * from '../test/generated-wrappers/lib_spender_rich_errors';
export * from '../test/generated-wrappers/lib_storage'; export * from '../test/generated-wrappers/lib_storage';
export * from '../test/generated-wrappers/lib_token_spender_storage';
export * from '../test/generated-wrappers/lib_transform_erc20_rich_errors';
export * from '../test/generated-wrappers/lib_transform_erc20_storage';
export * from '../test/generated-wrappers/lib_wallet_rich_errors';
export * from '../test/generated-wrappers/ownable'; export * from '../test/generated-wrappers/ownable';
export * from '../test/generated-wrappers/simple_function_registry'; export * from '../test/generated-wrappers/simple_function_registry';
export * from '../test/generated-wrappers/test_call_target';
export * from '../test/generated-wrappers/test_full_migration';
export * from '../test/generated-wrappers/test_initial_migration'; export * from '../test/generated-wrappers/test_initial_migration';
export * from '../test/generated-wrappers/test_migrator'; export * from '../test/generated-wrappers/test_migrator';
export * from '../test/generated-wrappers/test_mint_token_erc20_transformer';
export * from '../test/generated-wrappers/test_mintable_erc20_token';
export * from '../test/generated-wrappers/test_simple_function_registry_feature_impl1'; export * from '../test/generated-wrappers/test_simple_function_registry_feature_impl1';
export * from '../test/generated-wrappers/test_simple_function_registry_feature_impl2'; export * from '../test/generated-wrappers/test_simple_function_registry_feature_impl2';
export * from '../test/generated-wrappers/test_token_spender';
export * from '../test/generated-wrappers/test_token_spender_erc20_token';
export * from '../test/generated-wrappers/test_transform_erc20';
export * from '../test/generated-wrappers/test_zero_ex_feature'; export * from '../test/generated-wrappers/test_zero_ex_feature';
export * from '../test/generated-wrappers/token_spender';
export * from '../test/generated-wrappers/transform_erc20';
export * from '../test/generated-wrappers/zero_ex'; export * from '../test/generated-wrappers/zero_ex';

View File

@ -3,19 +3,35 @@
"compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true }, "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"], "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [ "files": [
"generated-artifacts/FullMigration.json",
"generated-artifacts/IAllowanceTarget.json",
"generated-artifacts/IERC20Transformer.json",
"generated-artifacts/IFlashWallet.json",
"generated-artifacts/IOwnable.json", "generated-artifacts/IOwnable.json",
"generated-artifacts/ISimpleFunctionRegistry.json", "generated-artifacts/ISimpleFunctionRegistry.json",
"generated-artifacts/ITokenSpender.json",
"generated-artifacts/ITransformERC20.json",
"generated-artifacts/InitialMigration.json",
"generated-artifacts/ZeroEx.json", "generated-artifacts/ZeroEx.json",
"test/generated-artifacts/AllowanceTarget.json",
"test/generated-artifacts/Bootstrap.json", "test/generated-artifacts/Bootstrap.json",
"test/generated-artifacts/FixinCommon.json", "test/generated-artifacts/FixinCommon.json",
"test/generated-artifacts/FlashWallet.json",
"test/generated-artifacts/FullMigration.json",
"test/generated-artifacts/IAllowanceTarget.json",
"test/generated-artifacts/IBootstrap.json", "test/generated-artifacts/IBootstrap.json",
"test/generated-artifacts/IERC20Transformer.json",
"test/generated-artifacts/IFeature.json", "test/generated-artifacts/IFeature.json",
"test/generated-artifacts/IFlashWallet.json",
"test/generated-artifacts/IOwnable.json", "test/generated-artifacts/IOwnable.json",
"test/generated-artifacts/ISimpleFunctionRegistry.json", "test/generated-artifacts/ISimpleFunctionRegistry.json",
"test/generated-artifacts/ITestSimpleFunctionRegistryFeature.json", "test/generated-artifacts/ITestSimpleFunctionRegistryFeature.json",
"test/generated-artifacts/ITokenSpender.json",
"test/generated-artifacts/ITransformERC20.json",
"test/generated-artifacts/InitialMigration.json", "test/generated-artifacts/InitialMigration.json",
"test/generated-artifacts/LibBootstrap.json", "test/generated-artifacts/LibBootstrap.json",
"test/generated-artifacts/LibCommonRichErrors.json", "test/generated-artifacts/LibCommonRichErrors.json",
"test/generated-artifacts/LibERC20Transformer.json",
"test/generated-artifacts/LibMigrate.json", "test/generated-artifacts/LibMigrate.json",
"test/generated-artifacts/LibOwnableRichErrors.json", "test/generated-artifacts/LibOwnableRichErrors.json",
"test/generated-artifacts/LibOwnableStorage.json", "test/generated-artifacts/LibOwnableStorage.json",
@ -23,14 +39,28 @@
"test/generated-artifacts/LibProxyStorage.json", "test/generated-artifacts/LibProxyStorage.json",
"test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json", "test/generated-artifacts/LibSimpleFunctionRegistryRichErrors.json",
"test/generated-artifacts/LibSimpleFunctionRegistryStorage.json", "test/generated-artifacts/LibSimpleFunctionRegistryStorage.json",
"test/generated-artifacts/LibSpenderRichErrors.json",
"test/generated-artifacts/LibStorage.json", "test/generated-artifacts/LibStorage.json",
"test/generated-artifacts/LibTokenSpenderStorage.json",
"test/generated-artifacts/LibTransformERC20RichErrors.json",
"test/generated-artifacts/LibTransformERC20Storage.json",
"test/generated-artifacts/LibWalletRichErrors.json",
"test/generated-artifacts/Ownable.json", "test/generated-artifacts/Ownable.json",
"test/generated-artifacts/SimpleFunctionRegistry.json", "test/generated-artifacts/SimpleFunctionRegistry.json",
"test/generated-artifacts/TestCallTarget.json",
"test/generated-artifacts/TestFullMigration.json",
"test/generated-artifacts/TestInitialMigration.json", "test/generated-artifacts/TestInitialMigration.json",
"test/generated-artifacts/TestMigrator.json", "test/generated-artifacts/TestMigrator.json",
"test/generated-artifacts/TestMintTokenERC20Transformer.json",
"test/generated-artifacts/TestMintableERC20Token.json",
"test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl1.json", "test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl1.json",
"test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json", "test/generated-artifacts/TestSimpleFunctionRegistryFeatureImpl2.json",
"test/generated-artifacts/TestTokenSpender.json",
"test/generated-artifacts/TestTokenSpenderERC20Token.json",
"test/generated-artifacts/TestTransformERC20.json",
"test/generated-artifacts/TestZeroExFeature.json", "test/generated-artifacts/TestZeroExFeature.json",
"test/generated-artifacts/TokenSpender.json",
"test/generated-artifacts/TransformERC20.json",
"test/generated-artifacts/ZeroEx.json" "test/generated-artifacts/ZeroEx.json"
], ],
"exclude": ["./deploy/solc/solc_bin"] "exclude": ["./deploy/solc/solc_bin"]

View File

@ -2,7 +2,10 @@
"extends": ["@0x/tslint-config"], "extends": ["@0x/tslint-config"],
"rules": { "rules": {
"custom-no-magic-numbers": false, "custom-no-magic-numbers": false,
"max-file-line-count": false "max-file-line-count": false,
"no-non-null-assertion": false,
"no-unnecessary-type-assertion": false,
"number-literal-format": false
}, },
"linterOptions": { "linterOptions": {
"exclude": ["src/artifacts.ts", "test/artifacts.ts"] "exclude": ["src/artifacts.ts", "test/artifacts.ts"]

View File

@ -1,4 +1,13 @@
[ [
{
"version": "6.1.0",
"changes": [
{
"note": "Update ganache-core",
"pr": 2545
}
]
},
{ {
"timestamp": 1582623685, "timestamp": 1582623685,
"version": "6.0.8", "version": "6.0.8",

View File

@ -48,7 +48,7 @@
"ethereum-types": "^3.1.0", "ethereum-types": "^3.1.0",
"ethereumjs-tx": "^1.3.5", "ethereumjs-tx": "^1.3.5",
"ethereumjs-util": "^5.1.1", "ethereumjs-util": "^5.1.1",
"ganache-core": "^2.9.0-istanbul.0", "ganache-core": "^2.10.2",
"hdkey": "^0.7.1", "hdkey": "^0.7.1",
"json-rpc-error": "2.0.0", "json-rpc-error": "2.0.0",
"lodash": "^4.17.11", "lodash": "^4.17.11",

View File

@ -17,6 +17,10 @@
{ {
"note": "`instanceof Array` => `Array.isArray`", "note": "`instanceof Array` => `Array.isArray`",
"pr": 2567 "pr": 2567
},
{
"note": "Add more `ZeroExRevertErrors`",
"pr": 2545
} }
] ]
}, },

View File

@ -49,4 +49,7 @@ export const ZeroExRevertErrors = {
Proxy: require('./revert_errors/zero-ex/proxy_revert_errors'), Proxy: require('./revert_errors/zero-ex/proxy_revert_errors'),
SimpleFunctionRegistry: require('./revert_errors/zero-ex/simple_function_registry_revert_errors'), SimpleFunctionRegistry: require('./revert_errors/zero-ex/simple_function_registry_revert_errors'),
Ownable: require('./revert_errors/zero-ex/ownable_revert_errors'), Ownable: require('./revert_errors/zero-ex/ownable_revert_errors'),
Spender: require('./revert_errors/zero-ex/spender_revert_errors'),
TransformERC20: require('./revert_errors/zero-ex/transform_erc20_revert_errors'),
Wallet: require('./revert_errors/zero-ex/wallet_revert_errors'),
}; };

View File

@ -9,7 +9,16 @@ import { BigNumber } from './configured_bignumber';
// tslint:disable: max-classes-per-file // tslint:disable: max-classes-per-file
type ArgTypes = string | BigNumber | number | boolean | BigNumber[] | string[] | number[] | boolean[]; type ArgTypes =
| string
| BigNumber
| number
| boolean
| BigNumber[]
| string[]
| number[]
| boolean[]
| Array<BigNumber | number | string>;
type ValueMap = ObjectMap<ArgTypes | undefined>; type ValueMap = ObjectMap<ArgTypes | undefined>;
type RevertErrorDecoder = (hex: string) => ValueMap; type RevertErrorDecoder = (hex: string) => ValueMap;

View File

@ -9,6 +9,13 @@ export class OnlyCallableBySelfError extends RevertError {
} }
} }
// This is identical to the one in utils.
// export class IllegalReentrancyError extends RevertError {
// constructor() {
// super('IllegalReentrancyError', 'IllegalReentrancyError()', {});
// }
// }
const types = [OnlyCallableBySelfError]; const types = [OnlyCallableBySelfError];
// Register the types we've defined. // Register the types we've defined.

View File

@ -16,7 +16,23 @@ export class MigrateCallFailedError extends RevertError {
} }
} }
const types = [AlreadyMigratingError, MigrateCallFailedError]; export class OnlyOwnerError extends RevertError {
constructor(sender?: string, owner?: string) {
super('OnlyOwnerError', 'OnlyOwnerError(address sender, bytes owner)', {
sender,
owner,
});
}
}
// This is identical to the one in utils.
// export class TransferOwnerToZeroError extends RevertError {
// constructor() {
// super('TransferOwnerToZeroError', 'TransferOwnerToZeroError()', {});
// }
// }
const types = [AlreadyMigratingError, MigrateCallFailedError, OnlyOwnerError];
// Register the types we've defined. // Register the types we've defined.
for (const type of types) { for (const type of types) {

View File

@ -0,0 +1,26 @@
import { RevertError } from '../../revert_error';
import { Numberish } from '../../types';
// tslint:disable:max-classes-per-file
export class SpenderERC20TransferFromFailedError extends RevertError {
constructor(token?: string, owner?: string, to?: string, amount?: Numberish, errorData?: string) {
super(
'SpenderERC20TransferFromFailedError',
'SpenderERC20TransferFromFailedError(address token, address owner, address to, uint256 amount, bytes errorData)',
{
token,
owner,
to,
amount,
errorData,
},
);
}
}
const types = [SpenderERC20TransferFromFailedError];
// Register the types we've defined.
for (const type of types) {
RevertError.registerType(type);
}

View File

@ -0,0 +1,153 @@
import { RevertError } from '../../revert_error';
import { Numberish } from '../../types';
// tslint:disable:max-classes-per-file
export class InsufficientEthAttachedError extends RevertError {
constructor(ethAttached?: Numberish, ethNeeded?: Numberish) {
super('InsufficientEthAttachedError', 'InsufficientEthAttachedError(uint256 ethAttached, uint256 ethNeeded)', {
ethAttached,
ethNeeded,
});
}
}
export class IncompleteTransformERC20Error extends RevertError {
constructor(outputToken?: string, outputTokenAmount?: Numberish, minOutputTokenAmount?: Numberish) {
super(
'IncompleteTransformERC20Error',
'IncompleteTransformERC20Error(address outputToken, uint256 outputTokenAmount, uint256 minOutputTokenAmount)',
{
outputToken,
outputTokenAmount,
minOutputTokenAmount,
},
);
}
}
export class NegativeTransformERC20OutputError extends RevertError {
constructor(outputToken?: string, outputTokenLostAmount?: Numberish) {
super(
'NegativeTransformERC20OutputError',
'NegativeTransformERC20OutputError(address outputToken, uint256 outputTokenLostAmount)',
{
outputToken,
outputTokenLostAmount,
},
);
}
}
export class UnauthorizedTransformerError extends RevertError {
constructor(transformer?: string, rlpNonce?: string) {
super('UnauthorizedTransformerError', 'UnauthorizedTransformerError(address transformer, bytes rlpNonce)', {
transformer,
rlpNonce,
});
}
}
export class InvalidRLPNonceError extends RevertError {
constructor(rlpNonce?: string) {
super('InvalidRLPNonceError', 'InvalidRLPNonceError(bytes rlpNonce)', { rlpNonce });
}
}
export class IncompleteFillSellQuoteError extends RevertError {
constructor(sellToken?: string, soldAmount?: Numberish, sellAmount?: Numberish) {
super(
'IncompleteFillSellQuoteError',
'IncompleteFillSellQuoteError(address sellToken, address[] soldAmount, uint256[] sellAmount)',
{
sellToken,
soldAmount,
sellAmount,
},
);
}
}
export class IncompleteFillBuyQuoteError extends RevertError {
constructor(buyToken?: string, boughtAmount?: Numberish, buyAmount?: Numberish) {
super(
'IncompleteFillBuyQuoteError',
'IncompleteFillBuyQuoteError(address buyToken, address[] boughtAmount, uint256[] buyAmount)',
{
buyToken,
boughtAmount,
buyAmount,
},
);
}
}
export class InsufficientTakerTokenError extends RevertError {
constructor(tokenBalance?: Numberish, tokensNeeded?: Numberish) {
super(
'InsufficientTakerTokenError',
'InsufficientTakerTokenError(uint256 tokenBalance, uint256 tokensNeeded)',
{
tokenBalance,
tokensNeeded,
},
);
}
}
export class InsufficientProtocolFeeError extends RevertError {
constructor(ethBalance?: Numberish, ethNeeded?: Numberish) {
super('InsufficientProtocolFeeError', 'InsufficientProtocolFeeError(uint256 ethBalance, uint256 ethNeeded)', {
ethBalance,
ethNeeded,
});
}
}
export class InvalidERC20AssetDataError extends RevertError {
constructor(assetData?: string) {
super('InvalidERC20AssetDataError', 'InvalidERC20AssetDataError(bytes assetData)', {
assetData,
});
}
}
export class WrongNumberOfTokensReceivedError extends RevertError {
constructor(actual?: Numberish, expected?: Numberish) {
super(
'WrongNumberOfTokensReceivedError',
'WrongNumberOfTokensReceivedError(uint256 actual, uint256 expected)',
{
actual,
expected,
},
);
}
}
export class InvalidTokenReceivedError extends RevertError {
constructor(token?: string) {
super('InvalidTokenReceivedError', 'InvalidTokenReceivedError(address token)', {
token,
});
}
}
const types = [
InsufficientEthAttachedError,
IncompleteTransformERC20Error,
NegativeTransformERC20OutputError,
UnauthorizedTransformerError,
InvalidRLPNonceError,
IncompleteFillSellQuoteError,
IncompleteFillBuyQuoteError,
InsufficientTakerTokenError,
InsufficientProtocolFeeError,
InvalidERC20AssetDataError,
WrongNumberOfTokensReceivedError,
InvalidTokenReceivedError,
];
// Register the types we've defined.
for (const type of types) {
RevertError.registerType(type);
}

View File

@ -0,0 +1,41 @@
import { RevertError } from '../../revert_error';
import { Numberish } from '../../types';
// tslint:disable:max-classes-per-file
export class WalletExecuteCallFailedError extends RevertError {
constructor(wallet?: string, callTarget?: string, callData?: string, callValue?: Numberish, errorData?: string) {
super(
'WalletExecuteCallFailedError',
'WalletExecuteCallFailedError(address wallet, address callTarget, bytes callData, uint256 callValue, bytes errorData)',
{
wallet,
callTarget,
callData,
callValue,
errorData,
},
);
}
}
export class WalletExecuteDelegateCallFailedError extends RevertError {
constructor(wallet?: string, callTarget?: string, callData?: string, errorData?: string) {
super(
'WalletExecuteDelegateCallFailedError',
'WalletExecuteDelegateCallFailedError(address wallet, address callTarget, bytes callData, bytes errorData)',
{
wallet,
callTarget,
callData,
errorData,
},
);
}
}
const types = [WalletExecuteCallFailedError, WalletExecuteDelegateCallFailedError];
// Register the types we've defined.
for (const type of types) {
RevertError.registerType(type);
}

View File

@ -1,4 +1,17 @@
[ [
{
"version": "7.1.0",
"changes": [
{
"note": "Add `getAccountNonce()` to `Web3Wrapper`",
"pr": 2545
},
{
"note": "Update ganache-core",
"pr": 2545
}
]
},
{ {
"timestamp": 1582623685, "timestamp": 1582623685,
"version": "7.0.7", "version": "7.0.7",

View File

@ -47,7 +47,7 @@
"chai-as-promised": "^7.1.0", "chai-as-promised": "^7.1.0",
"chai-bignumber": "^3.0.0", "chai-bignumber": "^3.0.0",
"dirty-chai": "^2.0.1", "dirty-chai": "^2.0.1",
"ganache-core": "^2.9.0-istanbul.0", "ganache-core": "^2.10.2",
"make-promises-safe": "^1.1.0", "make-promises-safe": "^1.1.0",
"mocha": "^6.2.0", "mocha": "^6.2.0",
"npm-run-all": "^4.1.2", "npm-run-all": "^4.1.2",

View File

@ -360,6 +360,27 @@ export class Web3Wrapper {
const blockNumber = utils.convertHexToNumberOrNull(blockNumberHex); const blockNumber = utils.convertHexToNumberOrNull(blockNumberHex);
return blockNumber as number; return blockNumber as number;
} }
/**
* Fetches the nonce for an account (transaction count for EOAs).
* @param address Address of account.
* @param defaultBlock Block height at which to make the call. Defaults to `latest`
* @returns Account nonce.
*/
public async getAccountNonceAsync(address: string, defaultBlock?: BlockParam): Promise<number> {
assert.isETHAddressHex('address', address);
if (defaultBlock !== undefined) {
Web3Wrapper._assertBlockParam(defaultBlock);
}
const marshalledDefaultBlock = marshaller.marshalBlockParam(defaultBlock);
const encodedAddress = marshaller.marshalAddress(address);
const nonceHex = await this.sendRawPayloadAsync<string>({
method: 'eth_getTransactionCount',
params: [encodedAddress, marshalledDefaultBlock],
});
assert.isHexString('nonce', nonceHex);
// tslint:disable-next-line:custom-no-magic-numbers
return parseInt(nonceHex.substr(2), 16);
}
/** /**
* Fetch a specific Ethereum block without transaction data * Fetch a specific Ethereum block without transaction data
* @param blockParam The block you wish to fetch (blockHash, blockNumber or blockLiteral) * @param blockParam The block you wish to fetch (blockHash, blockNumber or blockLiteral)

View File

@ -35,8 +35,7 @@ describe('Web3Wrapper tests', () => {
describe('#getNodeVersionAsync', () => { describe('#getNodeVersionAsync', () => {
it('gets the node version', async () => { it('gets the node version', async () => {
const nodeVersion = await web3Wrapper.getNodeVersionAsync(); const nodeVersion = await web3Wrapper.getNodeVersionAsync();
const NODE_VERSION = 'EthereumJS TestRPC/v2.9.0-istanbul.0/ethereum-js'; expect(nodeVersion).to.be.match(/EthereumJS TestRPC\/.+\/ethereum-js$/);
expect(nodeVersion).to.be.equal(NODE_VERSION);
}); });
}); });
describe('#getNetworkIdAsync', () => { describe('#getNetworkIdAsync', () => {

486
yarn.lock
View File

@ -1971,6 +1971,13 @@
dependencies: dependencies:
"@babel/types" "^7.3.0" "@babel/types" "^7.3.0"
"@types/bignumber.js@^5.0.0":
version "5.0.0"
resolved "https://registry.yarnpkg.com/@types/bignumber.js/-/bignumber.js-5.0.0.tgz#d9f1a378509f3010a3255e9cc822ad0eeb4ab969"
integrity sha512-0DH7aPGCClywOFaxxjE6UwpN2kQYe9LwuDQMv+zYA97j5GkOMo8e66LYT+a8JYU7jfmUFRZLa9KycxHDsKXJCA==
dependencies:
bignumber.js "*"
"@types/bip39@^2.4.0": "@types/bip39@^2.4.0":
version "2.4.0" version "2.4.0"
resolved "https://registry.yarnpkg.com/@types/bip39/-/bip39-2.4.0.tgz#eee31a14abc8ebbb41a1ff14575c447b18346cbc" resolved "https://registry.yarnpkg.com/@types/bip39/-/bip39-2.4.0.tgz#eee31a14abc8ebbb41a1ff14575c447b18346cbc"
@ -2285,6 +2292,25 @@
dependencies: dependencies:
"@types/yargs-parser" "*" "@types/yargs-parser" "*"
"@web3-js/scrypt-shim@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@web3-js/scrypt-shim/-/scrypt-shim-0.1.0.tgz#0bf7529ab6788311d3e07586f7d89107c3bea2cc"
integrity sha512-ZtZeWCc/s0nMcdx/+rZwY1EcuRdemOK9ag21ty9UsHkFxsNb/AaoucUz0iPuyGe0Ku+PFuRmWZG7Z7462p9xPw==
dependencies:
scryptsy "^2.1.0"
semver "^6.3.0"
"@web3-js/websocket@^1.0.29":
version "1.0.30"
resolved "https://registry.yarnpkg.com/@web3-js/websocket/-/websocket-1.0.30.tgz#9ea15b7b582cf3bf3e8bc1f4d3d54c0731a87f87"
integrity sha512-fDwrD47MiDrzcJdSeTLF75aCcxVVt8B1N74rA+vh2XCAvFy4tEWJjtnUtj2QG7/zlQ6g9cQ88bZFBxwd9/FmtA==
dependencies:
debug "^2.2.0"
es5-ext "^0.10.50"
nan "^2.14.0"
typedarray-to-buffer "^3.1.5"
yaeti "^0.0.6"
"@webassemblyjs/ast@1.7.8": "@webassemblyjs/ast@1.7.8":
version "1.7.8" version "1.7.8"
resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.8.tgz#f31f480debeef957f01b623f27eabc695fa4fe8f" resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.8.tgz#f31f480debeef957f01b623f27eabc695fa4fe8f"
@ -3802,6 +3828,10 @@ big.js@^5.2.2:
version "5.2.2" version "5.2.2"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
bignumber.js@*, bignumber.js@~9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075"
bignumber.js@7.2.1: bignumber.js@7.2.1:
version "7.2.1" version "7.2.1"
resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz#80c048759d826800807c4bfd521e50edbba57a5f" resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz#80c048759d826800807c4bfd521e50edbba57a5f"
@ -3814,10 +3844,6 @@ bignumber.js@~8.0.2:
version "8.0.2" version "8.0.2"
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-8.0.2.tgz#d8c4e1874359573b1ef03011a2d861214aeef137" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-8.0.2.tgz#d8c4e1874359573b1ef03011a2d861214aeef137"
bignumber.js@~9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075"
binary-extensions@^1.0.0: binary-extensions@^1.0.0:
version "1.11.0" version "1.11.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205"
@ -6691,6 +6717,13 @@ ethashjs@~0.0.7:
ethereumjs-util "^4.0.1" ethereumjs-util "^4.0.1"
miller-rabin "^4.0.0" miller-rabin "^4.0.0"
ethereum-bloom-filters@^1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.7.tgz#b7b80735e385dbb7f944ce6b4533e24511306060"
integrity sha512-cDcJJSJ9GMAcURiAWO3DxIEhTL/uWqlQnvgKpuYQzYPrt/izuGU+1ntQmHt0IRq6ADoSYHFnB+aCEFIldjhkMQ==
dependencies:
js-sha3 "^0.8.0"
ethereum-common@0.2.0: ethereum-common@0.2.0:
version "0.2.0" version "0.2.0"
resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.2.0.tgz#13bf966131cce1eeade62a1b434249bb4cb120ca" resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.2.0.tgz#13bf966131cce1eeade62a1b434249bb4cb120ca"
@ -6749,13 +6782,14 @@ ethereumjs-account@^2.0.3:
ethereumjs-util "^4.0.1" ethereumjs-util "^4.0.1"
rlp "^2.0.0" rlp "^2.0.0"
ethereumjs-block@2.2.0, ethereumjs-block@~2.2.0: ethereumjs-block@2.2.2, ethereumjs-block@^2.2.2, ethereumjs-block@~2.2.2:
version "2.2.0" version "2.2.2"
resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.0.tgz#8c6c3ab4a5eff0a16d9785fbeedbe643f4dbcbef" resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz#c7654be7e22df489fda206139ecd63e2e9c04965"
integrity sha512-2p49ifhek3h2zeg/+da6XpdFR3GlqY3BIEiqxGF8j9aSRIgkb7M1Ky+yULBKJOu8PAZxfhsYA+HxUk2aCQp3vg==
dependencies: dependencies:
async "^2.0.1" async "^2.0.1"
ethereumjs-common "^1.1.0" ethereumjs-common "^1.5.0"
ethereumjs-tx "^1.2.2" ethereumjs-tx "^2.1.1"
ethereumjs-util "^5.0.0" ethereumjs-util "^5.0.0"
merkle-patricia-tree "^2.1.2" merkle-patricia-tree "^2.1.2"
@ -6769,6 +6803,16 @@ ethereumjs-block@^1.2.2, ethereumjs-block@^1.4.1, ethereumjs-block@^1.6.0, ether
ethereumjs-util "^5.0.0" ethereumjs-util "^5.0.0"
merkle-patricia-tree "^2.1.2" merkle-patricia-tree "^2.1.2"
ethereumjs-block@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.0.tgz#8c6c3ab4a5eff0a16d9785fbeedbe643f4dbcbef"
dependencies:
async "^2.0.1"
ethereumjs-common "^1.1.0"
ethereumjs-tx "^1.2.2"
ethereumjs-util "^5.0.0"
merkle-patricia-tree "^2.1.2"
ethereumjs-blockchain@^4.0.1: ethereumjs-blockchain@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/ethereumjs-blockchain/-/ethereumjs-blockchain-4.0.1.tgz#db113dfed4fcc5197d223391f10adbc5a1b3536b" resolved "https://registry.yarnpkg.com/ethereumjs-blockchain/-/ethereumjs-blockchain-4.0.1.tgz#db113dfed4fcc5197d223391f10adbc5a1b3536b"
@ -6784,6 +6828,22 @@ ethereumjs-blockchain@^4.0.1:
rlp "^2.2.2" rlp "^2.2.2"
semaphore "^1.1.0" semaphore "^1.1.0"
ethereumjs-blockchain@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/ethereumjs-blockchain/-/ethereumjs-blockchain-4.0.3.tgz#e013034633a30ad2006728e8e2b21956b267b773"
integrity sha512-0nJWbyA+Gu0ZKZr/cywMtB/77aS/4lOVsIKbgUN2sFQYscXO5rPbUfrEe7G2Zhjp86/a0VqLllemDSTHvx3vZA==
dependencies:
async "^2.6.1"
ethashjs "~0.0.7"
ethereumjs-block "~2.2.2"
ethereumjs-common "^1.5.0"
ethereumjs-util "~6.1.0"
flow-stoplight "^1.0.0"
level-mem "^3.0.1"
lru-cache "^5.1.1"
rlp "^2.2.2"
semaphore "^1.1.0"
ethereumjs-blockstream@^7.0.0: ethereumjs-blockstream@^7.0.0:
version "7.0.0" version "7.0.0"
resolved "https://registry.yarnpkg.com/ethereumjs-blockstream/-/ethereumjs-blockstream-7.0.0.tgz#b8d7b6257dd1100bc6ddb36d6bef58c2490f9999" resolved "https://registry.yarnpkg.com/ethereumjs-blockstream/-/ethereumjs-blockstream-7.0.0.tgz#b8d7b6257dd1100bc6ddb36d6bef58c2490f9999"
@ -6792,6 +6852,10 @@ ethereumjs-blockstream@^7.0.0:
source-map-support "0.5.6" source-map-support "0.5.6"
uuid "3.2.1" uuid "3.2.1"
ethereumjs-common@1.5.0, ethereumjs-common@^1.3.1, ethereumjs-common@^1.3.2, ethereumjs-common@^1.5.0:
version "1.5.0"
resolved "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.0.tgz#d3e82fc7c47c0cef95047f431a99485abc9bb1cd"
ethereumjs-common@^1.1.0: ethereumjs-common@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.1.0.tgz#5ec9086c314d619d8f05e79a0525829fcb0e93cb" resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.1.0.tgz#5ec9086c314d619d8f05e79a0525829fcb0e93cb"
@ -6800,16 +6864,13 @@ ethereumjs-common@^1.3.0:
version "1.3.1" version "1.3.1"
resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.3.1.tgz#a5cffac41beb7ad393283b2e5aa71fadf8a9cc73" resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.3.1.tgz#a5cffac41beb7ad393283b2e5aa71fadf8a9cc73"
ethereumjs-common@^1.3.1, ethereumjs-common@^1.3.2: ethereumjs-tx@2.1.2, ethereumjs-tx@^2.1.2:
version "1.5.0" version "2.1.2"
resolved "https://registry.npmjs.org/ethereumjs-common/-/ethereumjs-common-1.5.0.tgz#d3e82fc7c47c0cef95047f431a99485abc9bb1cd" resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed"
integrity sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw==
ethereumjs-tx@1.3.7:
version "1.3.7"
resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz#88323a2d875b10549b8347e09f4862b546f3d89a"
dependencies: dependencies:
ethereum-common "^0.0.18" ethereumjs-common "^1.5.0"
ethereumjs-util "^5.0.0" ethereumjs-util "^6.0.0"
ethereumjs-tx@^1.1.1, ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.3, ethereumjs-tx@^1.3.5: ethereumjs-tx@^1.1.1, ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.3, ethereumjs-tx@^1.3.5:
version "1.3.5" version "1.3.5"
@ -6844,6 +6905,18 @@ ethereumjs-util@6.1.0, ethereumjs-util@^6.0.0, ethereumjs-util@^6.1.0, ethereumj
safe-buffer "^5.1.1" safe-buffer "^5.1.1"
secp256k1 "^3.0.1" secp256k1 "^3.0.1"
ethereumjs-util@6.2.0, ethereumjs-util@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.0.tgz#23ec79b2488a7d041242f01e25f24e5ad0357960"
dependencies:
"@types/bn.js" "^4.11.3"
bn.js "^4.11.0"
create-hash "^1.1.2"
ethjs-util "0.1.6"
keccak "^2.0.0"
rlp "^2.2.3"
secp256k1 "^3.0.1"
ethereumjs-util@^4.0.1, ethereumjs-util@^4.3.0: ethereumjs-util@^4.0.1, ethereumjs-util@^4.3.0:
version "4.5.0" version "4.5.0"
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz#3e9428b317eebda3d7260d854fddda954b1f1bc6" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz#3e9428b317eebda3d7260d854fddda954b1f1bc6"
@ -6866,31 +6939,20 @@ ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereum
safe-buffer "^5.1.1" safe-buffer "^5.1.1"
secp256k1 "^3.0.1" secp256k1 "^3.0.1"
ethereumjs-util@^6.2.0: ethereumjs-vm@4.1.3:
version "6.2.0" version "4.1.3"
resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.0.tgz#23ec79b2488a7d041242f01e25f24e5ad0357960" resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-4.1.3.tgz#dc8eb45f47d775da9f0b2437d5e20896fdf66f37"
dependencies: integrity sha512-RTrD0y7My4O6Qr1P2ZIsMfD6RzL6kU/RhBZ0a5XrPzAeR61crBS7or66ohDrvxDI/rDBxMi+6SnsELih6fzalw==
"@types/bn.js" "^4.11.3"
bn.js "^4.11.0"
create-hash "^1.1.2"
ethjs-util "0.1.6"
keccak "^2.0.0"
rlp "^2.2.3"
secp256k1 "^3.0.1"
ethereumjs-vm@4.1.0:
version "4.1.0"
resolved "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-4.1.0.tgz#359ed3592636390a5b2909a28d955c908830daa5"
dependencies: dependencies:
async "^2.1.2" async "^2.1.2"
async-eventemitter "^0.2.2" async-eventemitter "^0.2.2"
core-js-pure "^3.0.1" core-js-pure "^3.0.1"
ethereumjs-account "^3.0.0" ethereumjs-account "^3.0.0"
ethereumjs-block "~2.2.0" ethereumjs-block "^2.2.2"
ethereumjs-blockchain "^4.0.1" ethereumjs-blockchain "^4.0.3"
ethereumjs-common "^1.3.2" ethereumjs-common "^1.5.0"
ethereumjs-tx "^2.1.1" ethereumjs-tx "^2.1.2"
ethereumjs-util "^6.1.0" ethereumjs-util "^6.2.0"
fake-merkle-patricia-tree "^1.0.1" fake-merkle-patricia-tree "^1.0.1"
functional-red-black-tree "^1.0.1" functional-red-black-tree "^1.0.1"
merkle-patricia-tree "^2.3.2" merkle-patricia-tree "^2.3.2"
@ -7917,9 +7979,10 @@ ganache-cli@6.8.0-istanbul.0:
source-map-support "0.5.12" source-map-support "0.5.12"
yargs "13.2.4" yargs "13.2.4"
ganache-core@^2.9.0-istanbul.0: ganache-core@^2.10.2:
version "2.9.0-istanbul.0" version "2.10.2"
resolved "https://registry.npmjs.org/ganache-core/-/ganache-core-2.9.0-istanbul.0.tgz#bc336c770775a2b9fb06f5cae827088ecc194283" resolved "https://registry.yarnpkg.com/ganache-core/-/ganache-core-2.10.2.tgz#17c171c6c0195b6734a0dd741a9d2afd4f74e292"
integrity sha512-4XEO0VsqQ1+OW7Za5fQs9/Kk7o8M0T1sRfFSF8h9NeJ2ABaqMO5waqxf567ZMcSkRKaTjUucBSz83xNfZv1HDg==
dependencies: dependencies:
abstract-leveldown "3.0.0" abstract-leveldown "3.0.0"
async "2.6.2" async "2.6.2"
@ -7931,10 +7994,11 @@ ganache-core@^2.9.0-istanbul.0:
eth-sig-util "2.3.0" eth-sig-util "2.3.0"
ethereumjs-abi "0.6.7" ethereumjs-abi "0.6.7"
ethereumjs-account "3.0.0" ethereumjs-account "3.0.0"
ethereumjs-block "2.2.0" ethereumjs-block "2.2.2"
ethereumjs-tx "1.3.7" ethereumjs-common "1.5.0"
ethereumjs-util "6.1.0" ethereumjs-tx "2.1.2"
ethereumjs-vm "4.1.0" ethereumjs-util "6.2.0"
ethereumjs-vm "4.1.3"
heap "0.2.6" heap "0.2.6"
level-sublevel "6.6.4" level-sublevel "6.6.4"
levelup "3.1.1" levelup "3.1.1"
@ -7947,7 +8011,7 @@ ganache-core@^2.9.0-istanbul.0:
websocket "1.0.29" websocket "1.0.29"
optionalDependencies: optionalDependencies:
ethereumjs-wallet "0.6.3" ethereumjs-wallet "0.6.3"
web3 "1.2.1" web3 "1.2.4"
gauge@~1.2.5: gauge@~1.2.5:
version "1.2.7" version "1.2.7"
@ -10383,6 +10447,11 @@ js-sha3@^0.7.0:
version "0.7.0" version "0.7.0"
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.7.0.tgz#0a5c57b36f79882573b2d84051f8bb85dd1bd63a" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.7.0.tgz#0a5c57b36f79882573b2d84051f8bb85dd1bd63a"
js-sha3@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
js-tokens@^3.0.0, js-tokens@^3.0.2: js-tokens@^3.0.0, js-tokens@^3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
@ -14757,16 +14826,17 @@ scrypt@^6.0.2:
dependencies: dependencies:
nan "^2.0.8" nan "^2.0.8"
scryptsy@2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790"
scryptsy@^1.2.1: scryptsy@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163"
dependencies: dependencies:
pbkdf2 "^3.0.3" pbkdf2 "^3.0.3"
scryptsy@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790"
integrity sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w==
secp256k1@^3.0.1: secp256k1@^3.0.1:
version "3.5.0" version "3.5.0"
resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.5.0.tgz#677d3b8a8e04e1a5fa381a1ae437c54207b738d0" resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.5.0.tgz#677d3b8a8e04e1a5fa381a1ae437c54207b738d0"
@ -14847,10 +14917,6 @@ semver-sort@0.0.4:
version "5.5.0" version "5.5.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
semver@6.2.0:
version "6.2.0"
resolved "https://registry.npmjs.org/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db"
semver@^5.5.1: semver@^5.5.1:
version "5.6.0" version "5.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
@ -14859,7 +14925,7 @@ semver@^5.6.0, semver@^5.7.0:
version "5.7.0" version "5.7.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
semver@^6.0.0, semver@^6.2.0: semver@^6.0.0, semver@^6.2.0, semver@^6.3.0:
version "6.3.0" version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
@ -17041,10 +17107,12 @@ wcwidth@^1.0.0:
dependencies: dependencies:
defaults "^1.0.3" defaults "^1.0.3"
web3-bzz@1.2.1: web3-bzz@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.2.1.tgz#c3bd1e8f0c02a13cd6d4e3c3e9e1713f144f6f0d" resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.2.4.tgz#a4adb7a8cba3d260de649bdb1f14ed359bfb3821"
integrity sha512-MqhAo/+0iQSMBtt3/QI1rU83uvF08sYq8r25+OUZ+4VtihnYsmkkca+rdU0QbRyrXY2/yGIpI46PFdh0khD53A==
dependencies: dependencies:
"@types/node" "^10.12.18"
got "9.6.0" got "9.6.0"
swarm-js "0.1.39" swarm-js "0.1.39"
underscore "1.9.1" underscore "1.9.1"
@ -17057,13 +17125,14 @@ web3-core-helpers@1.0.0-beta.34:
web3-eth-iban "1.0.0-beta.34" web3-eth-iban "1.0.0-beta.34"
web3-utils "1.0.0-beta.34" web3-utils "1.0.0-beta.34"
web3-core-helpers@1.2.1: web3-core-helpers@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.2.1.tgz#f5f32d71c60a4a3bd14786118e633ce7ca6d5d0d" resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.2.4.tgz#ffd425861f4d66b3f38df032afdb39ea0971fc0f"
integrity sha512-U7wbsK8IbZvF3B7S+QMSNP0tni/6VipnJkB0tZVEpHEIV2WWeBHYmZDnULWcsS/x/jn9yKhJlXIxWGsEAMkjiw==
dependencies: dependencies:
underscore "1.9.1" underscore "1.9.1"
web3-eth-iban "1.2.1" web3-eth-iban "1.2.4"
web3-utils "1.2.1" web3-utils "1.2.4"
web3-core-helpers@2.0.0-alpha: web3-core-helpers@2.0.0-alpha:
version "2.0.0-alpha" version "2.0.0-alpha"
@ -17075,15 +17144,16 @@ web3-core-helpers@2.0.0-alpha:
web3-eth-iban "2.0.0-alpha" web3-eth-iban "2.0.0-alpha"
web3-utils "2.0.0-alpha" web3-utils "2.0.0-alpha"
web3-core-method@1.2.1: web3-core-method@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.2.1.tgz#9df1bafa2cd8be9d9937e01c6a47fc768d15d90a" resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.2.4.tgz#a0fbc50b8ff5fd214021435cc2c6d1e115807aed"
integrity sha512-8p9kpL7di2qOVPWgcM08kb+yKom0rxRCMv6m/K+H+yLSxev9TgMbCgMSbPWAHlyiF3SJHw7APFKahK5Z+8XT5A==
dependencies: dependencies:
underscore "1.9.1" underscore "1.9.1"
web3-core-helpers "1.2.1" web3-core-helpers "1.2.4"
web3-core-promievent "1.2.1" web3-core-promievent "1.2.4"
web3-core-subscriptions "1.2.1" web3-core-subscriptions "1.2.4"
web3-utils "1.2.1" web3-utils "1.2.4"
web3-core-method@2.0.0-alpha: web3-core-method@2.0.0-alpha:
version "2.0.0-alpha" version "2.0.0-alpha"
@ -17098,30 +17168,33 @@ web3-core-method@2.0.0-alpha:
web3-core-subscriptions "2.0.0-alpha" web3-core-subscriptions "2.0.0-alpha"
web3-utils "2.0.0-alpha" web3-utils "2.0.0-alpha"
web3-core-promievent@1.2.1: web3-core-promievent@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.2.1.tgz#003e8a3eb82fb27b6164a6d5b9cad04acf733838" resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.2.4.tgz#75e5c0f2940028722cdd21ba503ebd65272df6cb"
integrity sha512-gEUlm27DewUsfUgC3T8AxkKi8Ecx+e+ZCaunB7X4Qk3i9F4C+5PSMGguolrShZ7Zb6717k79Y86f3A00O0VAZw==
dependencies: dependencies:
any-promise "1.3.0" any-promise "1.3.0"
eventemitter3 "3.1.2" eventemitter3 "3.1.2"
web3-core-requestmanager@1.2.1: web3-core-requestmanager@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.2.1.tgz#fa2e2206c3d738db38db7c8fe9c107006f5c6e3d" resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.4.tgz#0a7020a23fb91c6913c611dfd3d8c398d1e4b4a8"
integrity sha512-eZJDjyNTDtmSmzd3S488nR/SMJtNnn/GuwxnMh3AzYCqG3ZMfOylqTad2eYJPvc2PM5/Gj1wAMQcRpwOjjLuPg==
dependencies: dependencies:
underscore "1.9.1" underscore "1.9.1"
web3-core-helpers "1.2.1" web3-core-helpers "1.2.4"
web3-providers-http "1.2.1" web3-providers-http "1.2.4"
web3-providers-ipc "1.2.1" web3-providers-ipc "1.2.4"
web3-providers-ws "1.2.1" web3-providers-ws "1.2.4"
web3-core-subscriptions@1.2.1: web3-core-subscriptions@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.2.1.tgz#8c2368a839d4eec1c01a4b5650bbeb82d0e4a099" resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.4.tgz#0dc095b5cfd82baa527a39796e3515a846b21b99"
integrity sha512-3D607J2M8ymY9V+/WZq4MLlBulwCkwEjjC2U+cXqgVO1rCyVqbxZNCmHyNYHjDDCxSEbks9Ju5xqJxDSxnyXEw==
dependencies: dependencies:
eventemitter3 "3.1.2" eventemitter3 "3.1.2"
underscore "1.9.1" underscore "1.9.1"
web3-core-helpers "1.2.1" web3-core-helpers "1.2.4"
web3-core-subscriptions@2.0.0-alpha: web3-core-subscriptions@2.0.0-alpha:
version "2.0.0-alpha" version "2.0.0-alpha"
@ -17131,14 +17204,18 @@ web3-core-subscriptions@2.0.0-alpha:
eventemitter3 "^3.1.0" eventemitter3 "^3.1.0"
lodash "^4.17.11" lodash "^4.17.11"
web3-core@1.2.1: web3-core@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-core/-/web3-core-1.2.1.tgz#7278b58fb6495065e73a77efbbce781a7fddf1a9" resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.2.4.tgz#2df13b978dcfc59c2abaa887d27f88f21ad9a9d6"
integrity sha512-CHc27sMuET2cs1IKrkz7xzmTdMfZpYswe7f0HcuyneTwS1yTlTnHyqjAaTy0ZygAb/x4iaVox+Gvr4oSAqSI+A==
dependencies: dependencies:
web3-core-helpers "1.2.1" "@types/bignumber.js" "^5.0.0"
web3-core-method "1.2.1" "@types/bn.js" "^4.11.4"
web3-core-requestmanager "1.2.1" "@types/node" "^12.6.1"
web3-utils "1.2.1" web3-core-helpers "1.2.4"
web3-core-method "1.2.4"
web3-core-requestmanager "1.2.4"
web3-utils "1.2.4"
web3-core@2.0.0-alpha: web3-core@2.0.0-alpha:
version "2.0.0-alpha" version "2.0.0-alpha"
@ -17152,13 +17229,14 @@ web3-core@2.0.0-alpha:
web3-providers "2.0.0-alpha" web3-providers "2.0.0-alpha"
web3-utils "2.0.0-alpha" web3-utils "2.0.0-alpha"
web3-eth-abi@1.2.1: web3-eth-abi@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.2.1.tgz#9b915b1c9ebf82f70cca631147035d5419064689" resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.2.4.tgz#5b73e5ef70b03999227066d5d1310b168845e2b8"
integrity sha512-8eLIY4xZKoU3DSVu1pORluAw9Ru0/v4CGdw5so31nn+7fR8zgHMgwbFe0aOqWQ5VU42PzMMXeIJwt4AEi2buFg==
dependencies: dependencies:
ethers "4.0.0-beta.3" ethers "4.0.0-beta.3"
underscore "1.9.1" underscore "1.9.1"
web3-utils "1.2.1" web3-utils "1.2.4"
web3-eth-abi@^1.0.0-beta.24: web3-eth-abi@^1.0.0-beta.24:
version "1.0.0-beta.34" version "1.0.0-beta.34"
@ -17169,47 +17247,52 @@ web3-eth-abi@^1.0.0-beta.24:
web3-core-helpers "1.0.0-beta.34" web3-core-helpers "1.0.0-beta.34"
web3-utils "1.0.0-beta.34" web3-utils "1.0.0-beta.34"
web3-eth-accounts@1.2.1: web3-eth-accounts@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.2.1.tgz#2741a8ef337a7219d57959ac8bd118b9d68d63cf" resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.2.4.tgz#ada6edc49542354328a85cafab067acd7f88c288"
integrity sha512-04LzT/UtWmRFmi4hHRewP5Zz43fWhuHiK5XimP86sUQodk/ByOkXQ3RoXyGXFMNoRxdcAeRNxSfA2DpIBc9xUw==
dependencies: dependencies:
"@web3-js/scrypt-shim" "^0.1.0"
any-promise "1.3.0" any-promise "1.3.0"
crypto-browserify "3.12.0" crypto-browserify "3.12.0"
eth-lib "0.2.7" eth-lib "0.2.7"
scryptsy "2.1.0" ethereumjs-common "^1.3.2"
semver "6.2.0" ethereumjs-tx "^2.1.1"
underscore "1.9.1" underscore "1.9.1"
uuid "3.3.2" uuid "3.3.2"
web3-core "1.2.1" web3-core "1.2.4"
web3-core-helpers "1.2.1" web3-core-helpers "1.2.4"
web3-core-method "1.2.1" web3-core-method "1.2.4"
web3-utils "1.2.1" web3-utils "1.2.4"
web3-eth-contract@1.2.1: web3-eth-contract@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.2.1.tgz#3542424f3d341386fd9ff65e78060b85ac0ea8c4" resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.2.4.tgz#68ef7cc633232779b0a2c506a810fbe903575886"
integrity sha512-b/9zC0qjVetEYnzRA1oZ8gF1OSSUkwSYi5LGr4GeckLkzXP7osEnp9lkO/AQcE4GpG+l+STnKPnASXJGZPgBRQ==
dependencies: dependencies:
"@types/bn.js" "^4.11.4"
underscore "1.9.1" underscore "1.9.1"
web3-core "1.2.1" web3-core "1.2.4"
web3-core-helpers "1.2.1" web3-core-helpers "1.2.4"
web3-core-method "1.2.1" web3-core-method "1.2.4"
web3-core-promievent "1.2.1" web3-core-promievent "1.2.4"
web3-core-subscriptions "1.2.1" web3-core-subscriptions "1.2.4"
web3-eth-abi "1.2.1" web3-eth-abi "1.2.4"
web3-utils "1.2.1" web3-utils "1.2.4"
web3-eth-ens@1.2.1: web3-eth-ens@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.2.1.tgz#a0e52eee68c42a8b9865ceb04e5fb022c2d971d5" resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.2.4.tgz#b95b3aa99fb1e35c802b9e02a44c3046a3fa065e"
integrity sha512-g8+JxnZlhdsCzCS38Zm6R/ngXhXzvc3h7bXlxgKU4coTzLLoMpgOAEz71GxyIJinWTFbLXk/WjNY0dazi9NwVw==
dependencies: dependencies:
eth-ens-namehash "2.0.8" eth-ens-namehash "2.0.8"
underscore "1.9.1" underscore "1.9.1"
web3-core "1.2.1" web3-core "1.2.4"
web3-core-helpers "1.2.1" web3-core-helpers "1.2.4"
web3-core-promievent "1.2.1" web3-core-promievent "1.2.4"
web3-eth-abi "1.2.1" web3-eth-abi "1.2.4"
web3-eth-contract "1.2.1" web3-eth-contract "1.2.4"
web3-utils "1.2.1" web3-utils "1.2.4"
web3-eth-iban@1.0.0-beta.34: web3-eth-iban@1.0.0-beta.34:
version "1.0.0-beta.34" version "1.0.0-beta.34"
@ -17218,12 +17301,13 @@ web3-eth-iban@1.0.0-beta.34:
bn.js "4.11.6" bn.js "4.11.6"
web3-utils "1.0.0-beta.34" web3-utils "1.0.0-beta.34"
web3-eth-iban@1.2.1: web3-eth-iban@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.2.1.tgz#2c3801718946bea24e9296993a975c80b5acf880" resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.2.4.tgz#8e0550fd3fd8e47a39357d87fe27dee9483ee476"
integrity sha512-D9HIyctru/FLRpXakRwmwdjb5bWU2O6UE/3AXvRm6DCOf2e+7Ve11qQrPtaubHfpdW3KWjDKvlxV9iaFv/oTMQ==
dependencies: dependencies:
bn.js "4.11.8" bn.js "4.11.8"
web3-utils "1.2.1" web3-utils "1.2.4"
web3-eth-iban@2.0.0-alpha: web3-eth-iban@2.0.0-alpha:
version "2.0.0-alpha" version "2.0.0-alpha"
@ -17233,41 +17317,45 @@ web3-eth-iban@2.0.0-alpha:
bn.js "4.11.8" bn.js "4.11.8"
web3-utils "2.0.0-alpha" web3-utils "2.0.0-alpha"
web3-eth-personal@1.2.1: web3-eth-personal@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.2.1.tgz#244e9911b7b482dc17c02f23a061a627c6e47faf" resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.2.4.tgz#3224cca6851c96347d9799b12c1b67b2a6eb232b"
integrity sha512-5Russ7ZECwHaZXcN3DLuLS7390Vzgrzepl4D87SD6Sn1DHsCZtvfdPIYwoTmKNp69LG3mORl7U23Ga5YxqkICw==
dependencies: dependencies:
web3-core "1.2.1" "@types/node" "^12.6.1"
web3-core-helpers "1.2.1" web3-core "1.2.4"
web3-core-method "1.2.1" web3-core-helpers "1.2.4"
web3-net "1.2.1" web3-core-method "1.2.4"
web3-utils "1.2.1" web3-net "1.2.4"
web3-utils "1.2.4"
web3-eth@1.2.1: web3-eth@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-eth/-/web3-eth-1.2.1.tgz#b9989e2557c73a9e8ffdc107c6dafbe72c79c1b0" resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.2.4.tgz#24c3b1f1ac79351bbfb808b2ab5c585fa57cdd00"
integrity sha512-+j+kbfmZsbc3+KJpvHM16j1xRFHe2jBAniMo1BHKc3lho6A8Sn9Buyut6odubguX2AxoRArCdIDCkT9hjUERpA==
dependencies: dependencies:
underscore "1.9.1" underscore "1.9.1"
web3-core "1.2.1" web3-core "1.2.4"
web3-core-helpers "1.2.1" web3-core-helpers "1.2.4"
web3-core-method "1.2.1" web3-core-method "1.2.4"
web3-core-subscriptions "1.2.1" web3-core-subscriptions "1.2.4"
web3-eth-abi "1.2.1" web3-eth-abi "1.2.4"
web3-eth-accounts "1.2.1" web3-eth-accounts "1.2.4"
web3-eth-contract "1.2.1" web3-eth-contract "1.2.4"
web3-eth-ens "1.2.1" web3-eth-ens "1.2.4"
web3-eth-iban "1.2.1" web3-eth-iban "1.2.4"
web3-eth-personal "1.2.1" web3-eth-personal "1.2.4"
web3-net "1.2.1" web3-net "1.2.4"
web3-utils "1.2.1" web3-utils "1.2.4"
web3-net@1.2.1: web3-net@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-net/-/web3-net-1.2.1.tgz#edd249503315dd5ab4fa00220f6509d95bb7ab10" resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.2.4.tgz#1d246406d3aaffbf39c030e4e98bce0ca5f25458"
integrity sha512-wKOsqhyXWPSYTGbp7ofVvni17yfRptpqoUdp3SC8RAhDmGkX6irsiT9pON79m6b3HUHfLoBilFQyt/fTUZOf7A==
dependencies: dependencies:
web3-core "1.2.1" web3-core "1.2.4"
web3-core-method "1.2.1" web3-core-method "1.2.4"
web3-utils "1.2.1" web3-utils "1.2.4"
web3-provider-engine@14.0.6: web3-provider-engine@14.0.6:
version "14.0.6" version "14.0.6"
@ -17344,28 +17432,31 @@ web3-provider-engine@^13.3.2:
xhr "^2.2.0" xhr "^2.2.0"
xtend "^4.0.1" xtend "^4.0.1"
web3-providers-http@1.2.1: web3-providers-http@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.2.1.tgz#c93ea003a42e7b894556f7e19dd3540f947f5013" resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.2.4.tgz#514fcad71ae77832c2c15574296282fbbc5f4a67"
integrity sha512-dzVCkRrR/cqlIrcrWNiPt9gyt0AZTE0J+MfAu9rR6CyIgtnm1wFUVVGaxYRxuTGQRO4Dlo49gtoGwaGcyxqiTw==
dependencies: dependencies:
web3-core-helpers "1.2.1" web3-core-helpers "1.2.4"
xhr2-cookies "1.1.0" xhr2-cookies "1.1.0"
web3-providers-ipc@1.2.1: web3-providers-ipc@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.2.1.tgz#017bfc687a8fc5398df2241eb98f135e3edd672c" resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.2.4.tgz#9d6659f8d44943fb369b739f48df09092be459bd"
integrity sha512-8J3Dguffin51gckTaNrO3oMBo7g+j0UNk6hXmdmQMMNEtrYqw4ctT6t06YOf9GgtOMjSAc1YEh3LPrvgIsR7og==
dependencies: dependencies:
oboe "2.1.4" oboe "2.1.4"
underscore "1.9.1" underscore "1.9.1"
web3-core-helpers "1.2.1" web3-core-helpers "1.2.4"
web3-providers-ws@1.2.1: web3-providers-ws@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.2.1.tgz#2d941eaf3d5a8caa3214eff8dc16d96252b842cb" resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.2.4.tgz#099ee271ee03f6ea4f5df9cfe969e83f4ce0e36f"
integrity sha512-F/vQpDzeK+++oeeNROl1IVTufFCwCR2hpWe5yRXN0ApLwHqXrMI7UwQNdJ9iyibcWjJf/ECbauEEQ8CHgE+MYQ==
dependencies: dependencies:
"@web3-js/websocket" "^1.0.29"
underscore "1.9.1" underscore "1.9.1"
web3-core-helpers "1.2.1" web3-core-helpers "1.2.4"
websocket "github:web3-js/WebSocket-Node#polyfill/globalThis"
web3-providers@2.0.0-alpha: web3-providers@2.0.0-alpha:
version "2.0.0-alpha" version "2.0.0-alpha"
@ -17383,14 +17474,15 @@ web3-providers@2.0.0-alpha:
websocket "^1.0.28" websocket "^1.0.28"
xhr2-cookies "1.1.0" xhr2-cookies "1.1.0"
web3-shh@1.2.1: web3-shh@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-shh/-/web3-shh-1.2.1.tgz#4460e3c1e07faf73ddec24ccd00da46f89152b0c" resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.2.4.tgz#5c8ff5ab624a3b14f08af0d24d2b16c10e9f70dd"
integrity sha512-z+9SCw0dE+69Z/Hv8809XDbLj7lTfEv9Sgu8eKEIdGntZf4v7ewj5rzN5bZZSz8aCvfK7Y6ovz1PBAu4QzS4IQ==
dependencies: dependencies:
web3-core "1.2.1" web3-core "1.2.4"
web3-core-method "1.2.1" web3-core-method "1.2.4"
web3-core-subscriptions "1.2.1" web3-core-subscriptions "1.2.4"
web3-net "1.2.1" web3-net "1.2.4"
web3-typescript-typings@^0.10.2: web3-typescript-typings@^0.10.2:
version "0.10.2" version "0.10.2"
@ -17410,15 +17502,17 @@ web3-utils@1.0.0-beta.34:
underscore "1.8.3" underscore "1.8.3"
utf8 "2.1.1" utf8 "2.1.1"
web3-utils@1.2.1: web3-utils@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3-utils/-/web3-utils-1.2.1.tgz#21466e38291551de0ab34558de21512ac4274534" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.2.4.tgz#96832a39a66b05bf8862a5b0bdad2799d709d951"
integrity sha512-+S86Ip+jqfIPQWvw2N/xBQq5JNqCO0dyvukGdJm8fEWHZbckT4WxSpHbx+9KLEWY4H4x9pUwnoRkK87pYyHfgQ==
dependencies: dependencies:
bn.js "4.11.8" bn.js "4.11.8"
eth-lib "0.2.7" eth-lib "0.2.7"
ethereum-bloom-filters "^1.0.6"
ethjs-unit "0.1.6" ethjs-unit "0.1.6"
number-to-bn "1.7.0" number-to-bn "1.7.0"
randomhex "0.1.5" randombytes "^2.1.0"
underscore "1.9.1" underscore "1.9.1"
utf8 "3.0.0" utf8 "3.0.0"
@ -17437,17 +17531,19 @@ web3-utils@2.0.0-alpha:
randombytes "^2.1.0" randombytes "^2.1.0"
utf8 "2.1.1" utf8 "2.1.1"
web3@1.2.1: web3@1.2.4:
version "1.2.1" version "1.2.4"
resolved "https://registry.npmjs.org/web3/-/web3-1.2.1.tgz#5d8158bcca47838ab8c2b784a2dee4c3ceb4179b" resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.4.tgz#6e7ab799eefc9b4648c2dab63003f704a1d5e7d9"
integrity sha512-xPXGe+w0x0t88Wj+s/dmAdASr3O9wmA9mpZRtixGZxmBexAF0MjfqYM+MS4tVl5s11hMTN3AZb8cDD4VLfC57A==
dependencies: dependencies:
web3-bzz "1.2.1" "@types/node" "^12.6.1"
web3-core "1.2.1" web3-bzz "1.2.4"
web3-eth "1.2.1" web3-core "1.2.4"
web3-eth-personal "1.2.1" web3-eth "1.2.4"
web3-net "1.2.1" web3-eth-personal "1.2.4"
web3-shh "1.2.1" web3-net "1.2.4"
web3-utils "1.2.1" web3-shh "1.2.4"
web3-utils "1.2.4"
webidl-conversions@^4.0.2: webidl-conversions@^4.0.2:
version "4.0.2" version "4.0.2"
@ -17606,16 +17702,6 @@ websocket@^1.0.26:
typedarray-to-buffer "^3.1.5" typedarray-to-buffer "^3.1.5"
yaeti "^0.0.6" yaeti "^0.0.6"
"websocket@github:web3-js/WebSocket-Node#polyfill/globalThis":
version "1.0.29"
resolved "https://codeload.github.com/web3-js/WebSocket-Node/tar.gz/905deb4812572b344f5801f8c9ce8bb02799d82e"
dependencies:
debug "^2.2.0"
es5-ext "^0.10.50"
nan "^2.14.0"
typedarray-to-buffer "^3.1.5"
yaeti "^0.0.6"
whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3:
version "1.0.5" version "1.0.5"
resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"