@0x/contracts-utils
: Add LibERC20Token
.
This commit is contained in:
@@ -73,6 +73,10 @@
|
||||
{
|
||||
"note": "Replaced `SafeMath` with `LibSafeMath`",
|
||||
"pr": 2254
|
||||
},
|
||||
{
|
||||
"note": "Create `LibERC20Token`",
|
||||
"pr": 2309
|
||||
}
|
||||
],
|
||||
"timestamp": 1570135330
|
||||
|
112
contracts/utils/contracts/src/LibERC20Token.sol
Normal file
112
contracts/utils/contracts/src/LibERC20Token.sol
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
library LibERC20Token {
|
||||
|
||||
/// @dev Calls `IERC20Token(token).approve()`. Does not revert if
|
||||
/// no data is returned.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param spender The address that receives an allowance.
|
||||
/// @param allowance The allowance to set.
|
||||
function approve(
|
||||
address token,
|
||||
address spender,
|
||||
uint256 allowance
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
0x095ea7b3,
|
||||
spender,
|
||||
allowance
|
||||
);
|
||||
_callWithOptionalBooleanResult(token, callData);
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20Token(token).transfer()`. Does not revert if
|
||||
/// no data is returned.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param to The address that receives the tokens
|
||||
/// @param amount Number of tokens to transfer.
|
||||
function transfer(
|
||||
address token,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
0xa9059cbb,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
_callWithOptionalBooleanResult(token, callData);
|
||||
}
|
||||
|
||||
/// @dev Calls `IERC20Token(token).transferFrom()`. Does not revert if
|
||||
/// no data is returned.
|
||||
/// @param token The address of the token contract.
|
||||
/// @param from The owner of the tokens.
|
||||
/// @param to The address that receives the tokens
|
||||
/// @param amount Number of tokens to transfer.
|
||||
function transferFrom(
|
||||
address token,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
internal
|
||||
{
|
||||
bytes memory callData = abi.encodeWithSelector(
|
||||
0x23b872dd,
|
||||
from,
|
||||
to,
|
||||
amount
|
||||
);
|
||||
_callWithOptionalBooleanResult(token, callData);
|
||||
}
|
||||
|
||||
/// @dev Executes a call on address `target` with calldata `callData`
|
||||
/// and asserts that either nothing was returned or a single boolean
|
||||
/// was returned equal to `true`.
|
||||
/// @param target The call target.
|
||||
/// @param callData The abi-encoded call data.
|
||||
function _callWithOptionalBooleanResult(
|
||||
address target,
|
||||
bytes memory callData
|
||||
)
|
||||
private
|
||||
{
|
||||
(bool didSucceed, bytes memory resultData) = target.call(callData);
|
||||
if (didSucceed) {
|
||||
if (resultData.length == 0) {
|
||||
return;
|
||||
}
|
||||
if (resultData.length == 32) {
|
||||
uint256 result = abi.decode(resultData, (uint256));
|
||||
if (result == 1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
assembly { revert(add(resultData, 0x20), mload(resultData)) }
|
||||
}
|
||||
}
|
72
contracts/utils/contracts/test/TestLibERC20Token.sol
Normal file
72
contracts/utils/contracts/test/TestLibERC20Token.sol
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
import "../src/LibERC20Token.sol";
|
||||
import "./TestLibERC20TokenTarget.sol";
|
||||
|
||||
|
||||
contract TestLibERC20Token {
|
||||
|
||||
TestLibERC20TokenTarget public target;
|
||||
|
||||
constructor() public {
|
||||
target = new TestLibERC20TokenTarget();
|
||||
}
|
||||
|
||||
function testApprove(
|
||||
bool shouldRevert,
|
||||
bytes calldata revertData,
|
||||
bytes calldata returnData,
|
||||
address spender,
|
||||
uint256 allowance
|
||||
)
|
||||
external
|
||||
{
|
||||
target.setBehavior(shouldRevert, revertData, returnData);
|
||||
LibERC20Token.approve(address(target), spender, allowance);
|
||||
}
|
||||
|
||||
function testTransfer(
|
||||
bool shouldRevert,
|
||||
bytes calldata revertData,
|
||||
bytes calldata returnData,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
{
|
||||
target.setBehavior(shouldRevert, revertData, returnData);
|
||||
LibERC20Token.transfer(address(target), to, amount);
|
||||
}
|
||||
|
||||
function testTransferFrom(
|
||||
bool shouldRevert,
|
||||
bytes calldata revertData,
|
||||
bytes calldata returnData,
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
{
|
||||
target.setBehavior(shouldRevert, revertData, returnData);
|
||||
LibERC20Token.transferFrom(address(target), from, to, amount);
|
||||
}
|
||||
}
|
98
contracts/utils/contracts/test/TestLibERC20TokenTarget.sol
Normal file
98
contracts/utils/contracts/test/TestLibERC20TokenTarget.sol
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 ZeroEx Intl.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
pragma solidity ^0.5.9;
|
||||
|
||||
|
||||
contract TestLibERC20TokenTarget {
|
||||
|
||||
event ApproveCalled(
|
||||
address spender,
|
||||
uint256 allowance
|
||||
);
|
||||
|
||||
event TransferCalled(
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
event TransferFromCalled(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
);
|
||||
|
||||
bool private _shouldRevert;
|
||||
bytes private _revertData;
|
||||
bytes private _returnData;
|
||||
|
||||
function setBehavior(
|
||||
bool shouldRevert,
|
||||
bytes calldata revertData,
|
||||
bytes calldata returnData
|
||||
)
|
||||
external
|
||||
{
|
||||
_shouldRevert = shouldRevert;
|
||||
_revertData = revertData;
|
||||
_returnData = returnData;
|
||||
}
|
||||
|
||||
function approve(
|
||||
address spender,
|
||||
uint256 allowance
|
||||
)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
emit ApproveCalled(spender, allowance);
|
||||
_execute();
|
||||
}
|
||||
|
||||
function transfer(
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
emit TransferCalled(to, amount);
|
||||
_execute();
|
||||
}
|
||||
|
||||
function transferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
)
|
||||
external
|
||||
returns (bool)
|
||||
{
|
||||
emit TransferFromCalled(from, to, amount);
|
||||
_execute();
|
||||
}
|
||||
|
||||
function _execute() private view {
|
||||
if (_shouldRevert) {
|
||||
bytes memory revertData = _revertData;
|
||||
assembly { revert(add(revertData, 0x20), mload(revertData)) }
|
||||
}
|
||||
bytes memory returnData = _returnData;
|
||||
assembly { return(add(returnData, 0x20), mload(returnData)) }
|
||||
}
|
||||
}
|
@@ -36,7 +36,7 @@
|
||||
},
|
||||
"config": {
|
||||
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
|
||||
"abis": "./generated-artifacts/@(Authorizable|IAuthorizable|IOwnable|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibBytes|LibBytesRichErrors|LibEIP1271|LibEIP712|LibFractions|LibOwnableRichErrors|LibReentrancyGuardRichErrors|LibRichErrors|LibSafeMath|LibSafeMathRichErrors|Ownable|ReentrancyGuard|Refundable|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibRichErrors|TestLibSafeMath|TestLogDecoding|TestLogDecodingDownstream|TestOwnable|TestReentrancyGuard|TestRefundable|TestRefundableReceiver).json"
|
||||
"abis": "./generated-artifacts/@(Authorizable|IAuthorizable|IOwnable|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibBytes|LibBytesRichErrors|LibEIP1271|LibEIP712|LibERC20Token|LibFractions|LibOwnableRichErrors|LibReentrancyGuardRichErrors|LibRichErrors|LibSafeMath|LibSafeMathRichErrors|Ownable|ReentrancyGuard|Refundable|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibERC20Token|TestLibERC20TokenTarget|TestLibRichErrors|TestLibSafeMath|TestLogDecoding|TestLogDecodingDownstream|TestOwnable|TestReentrancyGuard|TestRefundable|TestRefundableReceiver).json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@@ -16,6 +16,7 @@ import * as LibBytes from '../generated-artifacts/LibBytes.json';
|
||||
import * as LibBytesRichErrors from '../generated-artifacts/LibBytesRichErrors.json';
|
||||
import * as LibEIP1271 from '../generated-artifacts/LibEIP1271.json';
|
||||
import * as LibEIP712 from '../generated-artifacts/LibEIP712.json';
|
||||
import * as LibERC20Token from '../generated-artifacts/LibERC20Token.json';
|
||||
import * as LibFractions from '../generated-artifacts/LibFractions.json';
|
||||
import * as LibOwnableRichErrors from '../generated-artifacts/LibOwnableRichErrors.json';
|
||||
import * as LibReentrancyGuardRichErrors from '../generated-artifacts/LibReentrancyGuardRichErrors.json';
|
||||
@@ -29,6 +30,8 @@ import * as TestLibAddress from '../generated-artifacts/TestLibAddress.json';
|
||||
import * as TestLibAddressArray from '../generated-artifacts/TestLibAddressArray.json';
|
||||
import * as TestLibBytes from '../generated-artifacts/TestLibBytes.json';
|
||||
import * as TestLibEIP712 from '../generated-artifacts/TestLibEIP712.json';
|
||||
import * as TestLibERC20Token from '../generated-artifacts/TestLibERC20Token.json';
|
||||
import * as TestLibERC20TokenTarget from '../generated-artifacts/TestLibERC20TokenTarget.json';
|
||||
import * as TestLibRichErrors from '../generated-artifacts/TestLibRichErrors.json';
|
||||
import * as TestLibSafeMath from '../generated-artifacts/TestLibSafeMath.json';
|
||||
import * as TestLogDecoding from '../generated-artifacts/TestLogDecoding.json';
|
||||
@@ -47,6 +50,7 @@ export const artifacts = {
|
||||
LibBytesRichErrors: LibBytesRichErrors as ContractArtifact,
|
||||
LibEIP1271: LibEIP1271 as ContractArtifact,
|
||||
LibEIP712: LibEIP712 as ContractArtifact,
|
||||
LibERC20Token: LibERC20Token as ContractArtifact,
|
||||
LibFractions: LibFractions as ContractArtifact,
|
||||
LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact,
|
||||
LibReentrancyGuardRichErrors: LibReentrancyGuardRichErrors as ContractArtifact,
|
||||
@@ -62,6 +66,8 @@ export const artifacts = {
|
||||
TestLibAddressArray: TestLibAddressArray as ContractArtifact,
|
||||
TestLibBytes: TestLibBytes as ContractArtifact,
|
||||
TestLibEIP712: TestLibEIP712 as ContractArtifact,
|
||||
TestLibERC20Token: TestLibERC20Token as ContractArtifact,
|
||||
TestLibERC20TokenTarget: TestLibERC20TokenTarget as ContractArtifact,
|
||||
TestLibRichErrors: TestLibRichErrors as ContractArtifact,
|
||||
TestLibSafeMath: TestLibSafeMath as ContractArtifact,
|
||||
TestLogDecoding: TestLogDecoding as ContractArtifact,
|
||||
|
@@ -14,6 +14,7 @@ export * from '../generated-wrappers/lib_bytes';
|
||||
export * from '../generated-wrappers/lib_bytes_rich_errors';
|
||||
export * from '../generated-wrappers/lib_e_i_p1271';
|
||||
export * from '../generated-wrappers/lib_e_i_p712';
|
||||
export * from '../generated-wrappers/lib_erc20_token';
|
||||
export * from '../generated-wrappers/lib_fractions';
|
||||
export * from '../generated-wrappers/lib_ownable_rich_errors';
|
||||
export * from '../generated-wrappers/lib_reentrancy_guard_rich_errors';
|
||||
@@ -27,6 +28,8 @@ export * from '../generated-wrappers/test_lib_address';
|
||||
export * from '../generated-wrappers/test_lib_address_array';
|
||||
export * from '../generated-wrappers/test_lib_bytes';
|
||||
export * from '../generated-wrappers/test_lib_e_i_p712';
|
||||
export * from '../generated-wrappers/test_lib_erc20_token';
|
||||
export * from '../generated-wrappers/test_lib_erc20_token_target';
|
||||
export * from '../generated-wrappers/test_lib_rich_errors';
|
||||
export * from '../generated-wrappers/test_lib_safe_math';
|
||||
export * from '../generated-wrappers/test_log_decoding';
|
||||
|
442
contracts/utils/test/lib_erc20_token.ts
Normal file
442
contracts/utils/test/lib_erc20_token.ts
Normal file
@@ -0,0 +1,442 @@
|
||||
import {
|
||||
blockchainTests,
|
||||
constants,
|
||||
expect,
|
||||
filterLogsToArguments,
|
||||
getRandomInteger,
|
||||
hexLeftPad,
|
||||
randomAddress,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { RawRevertError, StringRevertError } from '@0x/utils';
|
||||
|
||||
import {
|
||||
artifacts,
|
||||
TestLibERC20TokenContract,
|
||||
TestLibERC20TokenTargetApproveCalledEventArgs as ApproveCalled,
|
||||
TestLibERC20TokenTargetEvents,
|
||||
TestLibERC20TokenTargetTransferCalledEventArgs as TransferCalled,
|
||||
TestLibERC20TokenTargetTransferFromCalledEventArgs as TransferFromCalled,
|
||||
} from '../src';
|
||||
|
||||
blockchainTests('LibERC20Token', env => {
|
||||
let testContract: TestLibERC20TokenContract;
|
||||
const REVERT_STRING = 'WHOOPSIE';
|
||||
const ENCODED_TRUE = hexLeftPad(1);
|
||||
const ENCODED_FALSE = hexLeftPad(0);
|
||||
const ENCODED_TWO = hexLeftPad(2);
|
||||
const ENCODED_SHORT_TRUE = hexLeftPad(2, 31);
|
||||
const ENCODED_LONG_TRUE = hexLeftPad(2, 33);
|
||||
|
||||
before(async () => {
|
||||
testContract = await TestLibERC20TokenContract.deployFrom0xArtifactAsync(
|
||||
artifacts.TestLibERC20Token,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
function encodeRevert(message: string): string {
|
||||
return new StringRevertError(message).encode();
|
||||
}
|
||||
|
||||
describe('approve()', () => {
|
||||
it('calls the target with the correct arguments', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const { logs } = await testContract.testApprove.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_TRUE,
|
||||
spender,
|
||||
allowance,
|
||||
);
|
||||
expect(logs).to.be.length(1);
|
||||
const [event] = filterLogsToArguments<ApproveCalled>(logs, TestLibERC20TokenTargetEvents.ApproveCalled);
|
||||
expect(event).to.deep.eq({
|
||||
spender,
|
||||
allowance,
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds if the target returns true', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
await testContract.testApprove.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_TRUE,
|
||||
spender,
|
||||
allowance,
|
||||
);
|
||||
});
|
||||
|
||||
it('succeeds if the target returns nothing', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
await testContract.testApprove.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
constants.NULL_BYTES,
|
||||
spender,
|
||||
allowance,
|
||||
);
|
||||
});
|
||||
|
||||
it('fails if the target returns false', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testApprove.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_FALSE,
|
||||
spender,
|
||||
allowance,
|
||||
);
|
||||
const expectedError = new RawRevertError(ENCODED_FALSE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns nonzero and not true', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testApprove.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_TWO,
|
||||
spender,
|
||||
allowance,
|
||||
);
|
||||
const expectedError = new RawRevertError(ENCODED_TWO);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns less than 32 bytes', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testApprove.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_SHORT_TRUE,
|
||||
spender,
|
||||
allowance,
|
||||
);
|
||||
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns greater than 32 bytes', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testApprove.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_LONG_TRUE,
|
||||
spender,
|
||||
allowance,
|
||||
);
|
||||
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target reverts', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testApprove.awaitTransactionSuccessAsync(
|
||||
true,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_TRUE,
|
||||
spender,
|
||||
allowance,
|
||||
);
|
||||
return expect(tx).to.revertWith(REVERT_STRING);
|
||||
});
|
||||
|
||||
it('fails if the target reverts with no data', async () => {
|
||||
const spender = randomAddress();
|
||||
const allowance = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testApprove.awaitTransactionSuccessAsync(
|
||||
true,
|
||||
constants.NULL_BYTES,
|
||||
ENCODED_TRUE,
|
||||
spender,
|
||||
allowance,
|
||||
);
|
||||
return expect(tx).to.be.rejectedWith('revert');
|
||||
});
|
||||
});
|
||||
|
||||
describe('transfer()', () => {
|
||||
it('calls the target with the correct arguments', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const { logs } = await testContract.testTransfer.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_TRUE,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
expect(logs).to.be.length(1);
|
||||
const [event] = filterLogsToArguments<TransferCalled>(logs, TestLibERC20TokenTargetEvents.TransferCalled);
|
||||
expect(event).to.deep.eq({
|
||||
to,
|
||||
amount,
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds if the target returns true', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
await testContract.testTransfer.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_TRUE,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
});
|
||||
|
||||
it('succeeds if the target returns nothing', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
await testContract.testTransfer.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
constants.NULL_BYTES,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
});
|
||||
|
||||
it('fails if the target returns false', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testTransfer.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_FALSE,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
const expectedError = new RawRevertError(ENCODED_FALSE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns nonzero and not true', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testTransfer.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_TWO,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
const expectedError = new RawRevertError(ENCODED_TWO);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns less than 32 bytes', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testTransfer.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_SHORT_TRUE,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns greater than 32 bytes', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testTransfer.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_LONG_TRUE,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target reverts', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testTransfer.awaitTransactionSuccessAsync(
|
||||
true,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_TRUE,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
return expect(tx).to.revertWith(REVERT_STRING);
|
||||
});
|
||||
|
||||
it('fails if the target reverts with no data', async () => {
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testTransfer.awaitTransactionSuccessAsync(
|
||||
true,
|
||||
constants.NULL_BYTES,
|
||||
ENCODED_TRUE,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
return expect(tx).to.be.rejectedWith('revert');
|
||||
});
|
||||
});
|
||||
|
||||
describe('transferFrom()', () => {
|
||||
it('calls the target with the correct arguments', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const { logs } = await testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_TRUE,
|
||||
owner,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
expect(logs).to.be.length(1);
|
||||
const [event] = filterLogsToArguments<TransferFromCalled>(
|
||||
logs,
|
||||
TestLibERC20TokenTargetEvents.TransferFromCalled,
|
||||
);
|
||||
expect(event).to.deep.eq({
|
||||
from: owner,
|
||||
to,
|
||||
amount,
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds if the target returns true', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
await testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_TRUE,
|
||||
owner,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
});
|
||||
|
||||
it('succeeds if the target returns nothing', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
await testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
constants.NULL_BYTES,
|
||||
owner,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
});
|
||||
|
||||
it('fails if the target returns false', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_FALSE,
|
||||
owner,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
const expectedError = new RawRevertError(ENCODED_FALSE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns nonzero and not true', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_TWO,
|
||||
owner,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
const expectedError = new RawRevertError(ENCODED_TWO);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns less than 32 bytes', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_SHORT_TRUE,
|
||||
owner,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target returns greater than 32 bytes', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
||||
false,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_LONG_TRUE,
|
||||
owner,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('fails if the target reverts', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
||||
true,
|
||||
encodeRevert(REVERT_STRING),
|
||||
ENCODED_TRUE,
|
||||
owner,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
return expect(tx).to.revertWith(REVERT_STRING);
|
||||
});
|
||||
|
||||
it('fails if the target reverts with no data', async () => {
|
||||
const owner = randomAddress();
|
||||
const to = randomAddress();
|
||||
const amount = getRandomInteger(0, 100e18);
|
||||
const tx = testContract.testTransferFrom.awaitTransactionSuccessAsync(
|
||||
true,
|
||||
constants.NULL_BYTES,
|
||||
ENCODED_TRUE,
|
||||
owner,
|
||||
to,
|
||||
amount,
|
||||
);
|
||||
return expect(tx).to.be.rejectedWith('revert');
|
||||
});
|
||||
});
|
||||
});
|
@@ -14,6 +14,7 @@
|
||||
"generated-artifacts/LibBytesRichErrors.json",
|
||||
"generated-artifacts/LibEIP1271.json",
|
||||
"generated-artifacts/LibEIP712.json",
|
||||
"generated-artifacts/LibERC20Token.json",
|
||||
"generated-artifacts/LibFractions.json",
|
||||
"generated-artifacts/LibOwnableRichErrors.json",
|
||||
"generated-artifacts/LibReentrancyGuardRichErrors.json",
|
||||
@@ -27,6 +28,8 @@
|
||||
"generated-artifacts/TestLibAddressArray.json",
|
||||
"generated-artifacts/TestLibBytes.json",
|
||||
"generated-artifacts/TestLibEIP712.json",
|
||||
"generated-artifacts/TestLibERC20Token.json",
|
||||
"generated-artifacts/TestLibERC20TokenTarget.json",
|
||||
"generated-artifacts/TestLibRichErrors.json",
|
||||
"generated-artifacts/TestLibSafeMath.json",
|
||||
"generated-artifacts/TestLogDecoding.json",
|
||||
|
Reference in New Issue
Block a user