@0x:contracts-staking Added tests for simpleProxyCallWithData()

This commit is contained in:
Alex Towle 2019-09-12 17:38:18 -07:00
parent 2ed63970d4
commit 1fc57baac1
4 changed files with 91 additions and 51 deletions

View File

@ -17,6 +17,7 @@
*/
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "./libs/LibProxy.sol";
@ -72,6 +73,30 @@ contract StakingProxy is
_attachStakingContract(_stakingContract);
}
/// @dev Detach the current staking contract.
/// Note that this is callable only by this contract's owner.
function detachStakingContract()
external
onlyOwner
{
stakingContract = NIL_ADDRESS;
emit StakingContractDetachedFromProxy();
}
/// @dev Set read-only mode (state cannot be changed).
function setReadOnlyMode(bool readOnlyMode)
external
onlyOwner
{
if (readOnlyMode) {
stakingContract = readOnlyProxy;
} else {
stakingContract = readOnlyProxyCallee;
}
emit ReadOnlyModeSet(readOnlyMode);
}
/// @dev Batch executes a series of calls to the exchange contract.
/// @param data An array of data that encodes a sequence of functions to
/// call in the staking contracts.
@ -99,31 +124,7 @@ contract StakingProxy is
batchReturnData[i] = returnData;
}
return batchReturnData
}
/// @dev Detach the current staking contract.
/// Note that this is callable only by this contract's owner.
function detachStakingContract()
external
onlyOwner
{
stakingContract = NIL_ADDRESS;
emit StakingContractDetachedFromProxy();
}
/// @dev Set read-only mode (state cannot be changed).
function setReadOnlyMode(bool readOnlyMode)
external
onlyOwner
{
if (readOnlyMode) {
stakingContract = readOnlyProxy;
} else {
stakingContract = readOnlyProxyCallee;
}
emit ReadOnlyModeSet(readOnlyMode);
return batchReturnData;
}
/// @dev Attach a staking contract; future calls will be delegated to the staking contract.

View File

@ -122,7 +122,7 @@ library LibProxy {
{
if (destination == address(0)) {
LibRichErrors.rrevert(
LibStakingRichErrors.ProxyDestinationCannotBeNil()
LibStakingRichErrors.ProxyDestinationCannotBeNilError()
);
}

View File

@ -71,4 +71,14 @@ contract TestLibProxy {
proxyCallArgs = args;
(success, returnData) = address(this).call(data);
}
/// @dev Calls the destination with the provided calldata.
/// @param destination The contract that should be called by the proxy call.
/// @param data The bytes that should be used to call into the destination contract.
function publicSimpleProxyCallWithData(address destination, bytes memory data)
public
returns (bool success, bytes memory returnData)
{
return destination.simpleProxyCallWithData(data);
}
}

View File

@ -11,7 +11,7 @@ import { StakingRevertErrors } from '@0x/order-utils';
import { artifacts, TestLibProxyContract, TestLibProxyReceiverContract } from '../../src';
blockchainTests.resets.only('LibProxy', env => {
blockchainTests.resets('LibProxy', env => {
let proxy: TestLibProxyContract;
let receiver: TestLibProxyReceiverContract;
@ -37,6 +37,14 @@ blockchainTests.resets.only('LibProxy', env => {
NeverRevert,
}
interface PublicProxyCallArgs {
destination: string;
revertRule: RevertRule;
customEgressSelector: string;
ignoreIngressSelector: boolean;
calldata: string;
}
// Choose a random 4 byte string of calldata to send and prepend with `0x00` to ensure
// that it does not call `externalProxyCall` by accident. This calldata will make the fallback
// in `TestLibProxyReceiver` fail because it is 4 bytes long.
@ -51,14 +59,6 @@ blockchainTests.resets.only('LibProxy', env => {
return hexConcat('0x00', hexRandom(35));
}
interface PublicProxyCallArgs {
destination: string;
revertRule: RevertRule;
customEgressSelector: string;
ignoreIngressSelector: boolean;
calldata: string;
}
// Exposes `publicProxyCall()` with useful default arguments.
async function publicProxyCallAsync(args: Partial<PublicProxyCallArgs>): Promise<[boolean, string]> {
return proxy.publicProxyCall.callAsync(
@ -72,27 +72,27 @@ blockchainTests.resets.only('LibProxy', env => {
);
}
// Verifies that the result of a given call to `proxyCall()` results in specified outcome
function verifyPostConditions(result: [boolean, string], success: boolean, calldata: string): void {
expect(result[0]).to.be.eq(success);
expect(result[1]).to.be.eq(calldata);
}
// Verifies that the result of a given call to `proxyCall()` results in `ProxyDestinationCannotBeNilError`
function verifyDestinationZeroError(result: [boolean, string]): void {
const expectedError = new StakingRevertErrors.ProxyDestinationCannotBeNilError();
expect(result[0]).to.be.false();
expect(result[1]).to.be.eq(expectedError.encode());
}
describe('proxyCall', () => {
// Verifies that the result of a given call to `proxyCall()` results in specified outcome
function verifyPostConditions(result: [boolean, string], success: boolean, calldata: string): void {
expect(result[0]).to.be.eq(success);
expect(result[1]).to.be.eq(calldata);
}
describe('Failure Conditions', () => {
// Verifies that the result of a given call to `proxyCall()` results in `ProxyDestinationCannotBeNilError`
function checkDestinationZeroError(result: [boolean, string]): void {
const expectedError = new StakingRevertErrors.ProxyDestinationCannotBeNilError();
expect(result[0]).to.be.false();
expect(result[1]).to.be.eq(expectedError.encode());
}
it('should revert when the destination is address zero', async () => {
checkDestinationZeroError(await publicProxyCallAsync({ destination: constants.NULL_ADDRESS }));
verifyDestinationZeroError(await publicProxyCallAsync({ destination: constants.NULL_ADDRESS }));
});
it('should revert when the destination is address zero and revertRule == AlwaysRevert', async () => {
checkDestinationZeroError(
verifyDestinationZeroError(
await publicProxyCallAsync({
destination: constants.NULL_ADDRESS,
revertRule: RevertRule.AlwaysRevert,
@ -101,7 +101,7 @@ blockchainTests.resets.only('LibProxy', env => {
});
it('should revert when the destination is address zero and revertRule == NeverRevert', async () => {
checkDestinationZeroError(
verifyDestinationZeroError(
await publicProxyCallAsync({
destination: constants.NULL_ADDRESS,
revertRule: RevertRule.NeverRevert,
@ -271,4 +271,33 @@ blockchainTests.resets.only('LibProxy', env => {
]);
});
});
describe('simpleProxyCallWithData', () => {
it('should revert if address zero is the destination', async () => {
const expectedError = new StakingRevertErrors.ProxyDestinationCannotBeNilError();
const tx = proxy.publicSimpleProxyCallWithData.awaitTransactionSuccessAsync(
constants.NULL_ADDRESS,
constants.NULL_BYTES,
);
return expect(tx).to.revertWith(expectedError);
});
it('should call the receiver with the correct calldata and report a success when the receiver succeeds', async () => {
const calldata = constructRandomSuccessCalldata();
verifyPostConditions(
await proxy.publicSimpleProxyCallWithData.callAsync(receiver.address, calldata),
true,
calldata,
);
});
it('should call the receiver with the correct calldata and report a success when the receiver succeeds', async () => {
const calldata = constructRandomFailureCalldata();
verifyPostConditions(
await proxy.publicSimpleProxyCallWithData.callAsync(receiver.address, calldata),
false,
calldata,
);
});
});
});