diff --git a/contracts/utils/contracts/src/LibAddressArray.sol b/contracts/utils/contracts/src/LibAddressArray.sol index 2206cb6678..aa10ea4945 100644 --- a/contracts/utils/contracts/src/LibAddressArray.sol +++ b/contracts/utils/contracts/src/LibAddressArray.sol @@ -18,11 +18,13 @@ pragma solidity ^0.5.9; +import "./LibAddressArrayRichErrors.sol"; import "./LibBytes.sol"; library LibAddressArray { + /// @dev Append a new address to an array of addresses. /// The `addressArray` may need to be reallocated to make space /// for the new address. Because of this we return the resulting @@ -51,10 +53,12 @@ library LibAddressArray { // `freeMemPtr` == `addressArrayEndPtr`: Nothing occupies memory after `addressArray` // `freeMemPtr` > `addressArrayEndPtr`: Some value occupies memory after `addressArray` // `freeMemPtr` < `addressArrayEndPtr`: Memory has not been managed properly. - require( - freeMemPtr >= addressArrayEndPtr, - "INVALID_FREE_MEMORY_PTR" - ); + if (freeMemPtr < addressArrayEndPtr) { + LibAddressArrayRichErrors.MismanagedMemoryErrorRevert( + freeMemPtr, + addressArrayEndPtr + ); + } // If free memory begins at the end of `addressArray` // then we can append `addressToAppend` directly. diff --git a/contracts/utils/contracts/src/LibAddressArrayRichErrors.sol b/contracts/utils/contracts/src/LibAddressArrayRichErrors.sol new file mode 100644 index 0000000000..304d8036b3 --- /dev/null +++ b/contracts/utils/contracts/src/LibAddressArrayRichErrors.sol @@ -0,0 +1,46 @@ +/* + + Copyright 2019 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.5.9; + +import "./LibRichErrors.sol"; + + +library LibAddressArrayRichErrors { + + using LibRichErrors for *; + + // bytes4(keccak256("MismanagedMemoryError(uint256,uint256)")) + bytes4 internal constant MISMANAGED_MEMORY_ERROR_SELECTOR = + 0x5fc83722; + + // solhint-disable func-name-mixedcase + function MismanagedMemoryErrorRevert( + uint256 freeMemPtr, + uint256 addressArrayEndPtr + ) + internal + pure + { + abi.encodeWithSelector( + MISMANAGED_MEMORY_ERROR_SELECTOR, + freeMemPtr, + addressArrayEndPtr + )._rrevert(); + } +} diff --git a/contracts/utils/test/lib_address_array.ts b/contracts/utils/test/lib_address_array.ts index bb0d441a5c..e88fe892ed 100644 --- a/contracts/utils/test/lib_address_array.ts +++ b/contracts/utils/test/lib_address_array.ts @@ -1,14 +1,12 @@ import { addressUtils, chaiSetup, - expectContractCallFailedAsync, provider, txDefaults, web3Wrapper, } from '@0x/contracts-test-utils'; import { BlockchainLifecycle } from '@0x/dev-utils'; -import { RevertReason } from '@0x/types'; -import { BigNumber } from '@0x/utils'; +import { BigNumber, LibAddressArrayRevertErrors } from '@0x/utils'; import * as chai from 'chai'; import * as _ from 'lodash'; @@ -54,10 +52,12 @@ describe('LibAddressArray', () => { const arr = _.times(3, () => addressUtils.generatePseudoRandomAddress()); const addr = addressUtils.generatePseudoRandomAddress(); const freeMemOffset = new BigNumber(-1); - return expectContractCallFailedAsync( - lib.testAppendRealloc.callAsync(arr, freeMemOffset, addr), - RevertReason.InvalidFreeMemoryPtr, + const addressArrayEndPtr = new BigNumber(256); + const expectedError = new LibAddressArrayRevertErrors.MismanagedMemoryError( + addressArrayEndPtr.plus(freeMemOffset), + addressArrayEndPtr, ); + return expect(lib.testAppendRealloc.callAsync(arr, freeMemOffset, addr)).to.revertWith(expectedError); }); it('should keep the same memory address if free memory pointer does not move', async () => { diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 77c2b7de22..b7b9efcde8 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -1,3 +1,4 @@ +import * as LibAddressArrayRevertErrors from './lib_address_array_revert_errors'; import * as LibBytesRevertErrors from './lib_bytes_revert_errors'; import * as OwnableRevertErrors from './ownable_revert_errors'; import * as SafeMathRevertErrors from './safe_math_revert_errors'; @@ -29,4 +30,4 @@ export { AnyRevertError, } from './revert_error'; -export { LibBytesRevertErrors, OwnableRevertErrors, SafeMathRevertErrors }; +export { LibAddressArrayRevertErrors, LibBytesRevertErrors, OwnableRevertErrors, SafeMathRevertErrors }; diff --git a/packages/utils/src/lib_address_array_revert_errors.ts b/packages/utils/src/lib_address_array_revert_errors.ts new file mode 100644 index 0000000000..22ec284cd9 --- /dev/null +++ b/packages/utils/src/lib_address_array_revert_errors.ts @@ -0,0 +1,18 @@ +import { BigNumber } from './configured_bignumber'; +import { RevertError } from './revert_error'; + +export class MismanagedMemoryError extends RevertError { + constructor(freeMemPtr?: BigNumber, addressArrayEndPtr?: BigNumber) { + super( + 'MismanagedMemoryError', + 'MismanagedMemoryError(uint256 freeMemPtr, uint256 addressArrayEndPtr)', + { + freeMemPtr, + addressArrayEndPtr, + }, + ); + } +} + +// Register the InvalidByteOperationError type +RevertError.registerType(MismanagedMemoryError);