@0x:contracts-staking
Added tests for simpleProxyCallWithData()
This commit is contained in:
parent
2ed63970d4
commit
1fc57baac1
@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pragma solidity ^0.5.9;
|
pragma solidity ^0.5.9;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
import "@0x/contracts-utils/contracts/src/Ownable.sol";
|
||||||
import "./libs/LibProxy.sol";
|
import "./libs/LibProxy.sol";
|
||||||
@ -72,6 +73,30 @@ contract StakingProxy is
|
|||||||
_attachStakingContract(_stakingContract);
|
_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.
|
/// @dev Batch executes a series of calls to the exchange contract.
|
||||||
/// @param data An array of data that encodes a sequence of functions to
|
/// @param data An array of data that encodes a sequence of functions to
|
||||||
/// call in the staking contracts.
|
/// call in the staking contracts.
|
||||||
@ -99,31 +124,7 @@ contract StakingProxy is
|
|||||||
batchReturnData[i] = returnData;
|
batchReturnData[i] = returnData;
|
||||||
}
|
}
|
||||||
|
|
||||||
return batchReturnData
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Attach a staking contract; future calls will be delegated to the staking contract.
|
/// @dev Attach a staking contract; future calls will be delegated to the staking contract.
|
||||||
|
@ -122,7 +122,7 @@ library LibProxy {
|
|||||||
{
|
{
|
||||||
if (destination == address(0)) {
|
if (destination == address(0)) {
|
||||||
LibRichErrors.rrevert(
|
LibRichErrors.rrevert(
|
||||||
LibStakingRichErrors.ProxyDestinationCannotBeNil()
|
LibStakingRichErrors.ProxyDestinationCannotBeNilError()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,4 +71,14 @@ contract TestLibProxy {
|
|||||||
proxyCallArgs = args;
|
proxyCallArgs = args;
|
||||||
(success, returnData) = address(this).call(data);
|
(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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import { StakingRevertErrors } from '@0x/order-utils';
|
|||||||
|
|
||||||
import { artifacts, TestLibProxyContract, TestLibProxyReceiverContract } from '../../src';
|
import { artifacts, TestLibProxyContract, TestLibProxyReceiverContract } from '../../src';
|
||||||
|
|
||||||
blockchainTests.resets.only('LibProxy', env => {
|
blockchainTests.resets('LibProxy', env => {
|
||||||
let proxy: TestLibProxyContract;
|
let proxy: TestLibProxyContract;
|
||||||
let receiver: TestLibProxyReceiverContract;
|
let receiver: TestLibProxyReceiverContract;
|
||||||
|
|
||||||
@ -37,6 +37,14 @@ blockchainTests.resets.only('LibProxy', env => {
|
|||||||
NeverRevert,
|
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
|
// 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
|
// that it does not call `externalProxyCall` by accident. This calldata will make the fallback
|
||||||
// in `TestLibProxyReceiver` fail because it is 4 bytes long.
|
// in `TestLibProxyReceiver` fail because it is 4 bytes long.
|
||||||
@ -51,14 +59,6 @@ blockchainTests.resets.only('LibProxy', env => {
|
|||||||
return hexConcat('0x00', hexRandom(35));
|
return hexConcat('0x00', hexRandom(35));
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PublicProxyCallArgs {
|
|
||||||
destination: string;
|
|
||||||
revertRule: RevertRule;
|
|
||||||
customEgressSelector: string;
|
|
||||||
ignoreIngressSelector: boolean;
|
|
||||||
calldata: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exposes `publicProxyCall()` with useful default arguments.
|
// Exposes `publicProxyCall()` with useful default arguments.
|
||||||
async function publicProxyCallAsync(args: Partial<PublicProxyCallArgs>): Promise<[boolean, string]> {
|
async function publicProxyCallAsync(args: Partial<PublicProxyCallArgs>): Promise<[boolean, string]> {
|
||||||
return proxy.publicProxyCall.callAsync(
|
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', () => {
|
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', () => {
|
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 () => {
|
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 () => {
|
it('should revert when the destination is address zero and revertRule == AlwaysRevert', async () => {
|
||||||
checkDestinationZeroError(
|
verifyDestinationZeroError(
|
||||||
await publicProxyCallAsync({
|
await publicProxyCallAsync({
|
||||||
destination: constants.NULL_ADDRESS,
|
destination: constants.NULL_ADDRESS,
|
||||||
revertRule: RevertRule.AlwaysRevert,
|
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 () => {
|
it('should revert when the destination is address zero and revertRule == NeverRevert', async () => {
|
||||||
checkDestinationZeroError(
|
verifyDestinationZeroError(
|
||||||
await publicProxyCallAsync({
|
await publicProxyCallAsync({
|
||||||
destination: constants.NULL_ADDRESS,
|
destination: constants.NULL_ADDRESS,
|
||||||
revertRule: RevertRule.NeverRevert,
|
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,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user