From f9986a6342ab68f6fdf347afee05c798384d7195 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Fri, 18 Jan 2019 11:11:27 -0800 Subject: Move LibAddressArray to utils package --- contracts/libs/contracts/libs/LibAddressArray.sol | 84 --- contracts/libs/contracts/libs/LibFillResults.sol | 2 +- contracts/libs/contracts/libs/LibMath.sol | 2 +- contracts/libs/contracts/test/TestLibs.sol | 152 ++++++ .../libs/contracts/test/TestLibs/TestLibs.sol | 152 ------ contracts/libs/test/exchange/libs.ts | 125 ----- contracts/libs/test/exchange_libs.ts | 125 +++++ contracts/utils/contracts/test/TestConstants.sol | 57 +++ .../contracts/test/TestConstants/TestConstants.sol | 57 --- contracts/utils/contracts/test/TestLibBytes.sol | 269 ++++++++++ .../contracts/test/TestLibBytes/TestLibBytes.sol | 269 ---------- .../utils/contracts/utils/LibAddressArray.sol | 84 +++ contracts/utils/contracts/utils/LibBytes.sol | 567 +++++++++++++++++++++ .../utils/contracts/utils/LibBytes/LibBytes.sol | 567 --------------------- contracts/utils/contracts/utils/Ownable.sol | 33 ++ .../utils/contracts/utils/Ownable/IOwnable.sol | 8 - .../utils/contracts/utils/Ownable/Ownable.sol | 33 -- .../utils/contracts/utils/ReentrancyGuard.sol | 45 ++ .../utils/ReentrancyGuard/ReentrancyGuard.sol | 45 -- contracts/utils/contracts/utils/SafeMath.sol | 87 ++++ .../utils/contracts/utils/SafeMath/SafeMath.sol | 87 ---- .../utils/contracts/utils/interfaces/IOwnable.sol | 8 + 22 files changed, 1429 insertions(+), 1429 deletions(-) delete mode 100644 contracts/libs/contracts/libs/LibAddressArray.sol create mode 100644 contracts/libs/contracts/test/TestLibs.sol delete mode 100644 contracts/libs/contracts/test/TestLibs/TestLibs.sol delete mode 100644 contracts/libs/test/exchange/libs.ts create mode 100644 contracts/libs/test/exchange_libs.ts create mode 100644 contracts/utils/contracts/test/TestConstants.sol delete mode 100644 contracts/utils/contracts/test/TestConstants/TestConstants.sol create mode 100644 contracts/utils/contracts/test/TestLibBytes.sol delete mode 100644 contracts/utils/contracts/test/TestLibBytes/TestLibBytes.sol create mode 100644 contracts/utils/contracts/utils/LibAddressArray.sol create mode 100644 contracts/utils/contracts/utils/LibBytes.sol delete mode 100644 contracts/utils/contracts/utils/LibBytes/LibBytes.sol create mode 100644 contracts/utils/contracts/utils/Ownable.sol delete mode 100644 contracts/utils/contracts/utils/Ownable/IOwnable.sol delete mode 100644 contracts/utils/contracts/utils/Ownable/Ownable.sol create mode 100644 contracts/utils/contracts/utils/ReentrancyGuard.sol delete mode 100644 contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol create mode 100644 contracts/utils/contracts/utils/SafeMath.sol delete mode 100644 contracts/utils/contracts/utils/SafeMath/SafeMath.sol create mode 100644 contracts/utils/contracts/utils/interfaces/IOwnable.sol diff --git a/contracts/libs/contracts/libs/LibAddressArray.sol b/contracts/libs/contracts/libs/LibAddressArray.sol deleted file mode 100644 index 997ce85fa..000000000 --- a/contracts/libs/contracts/libs/LibAddressArray.sol +++ /dev/null @@ -1,84 +0,0 @@ -/* - - Copyright 2018 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.4.24; - -import "@0x/contracts-utils/contracts/utils/LibBytes/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 - /// memory location of `addressArray`. - /// @param addressToAppend Address to append. - /// @return Array of addresses: [... addressArray, addressToAppend] - function append(address[] memory addressArray, address addressToAppend) - internal pure - returns (address[]) - { - // Get stats on address array and free memory - uint256 freeMemPtr = 0; - uint256 addressArrayBeginPtr = 0; - uint256 addressArrayEndPtr = 0; - uint256 addressArrayLength = addressArray.length; - uint256 addressArrayMemSizeInBytes = 32 + (32 * addressArrayLength); - assembly { - freeMemPtr := mload(0x40) - addressArrayBeginPtr := addressArray - addressArrayEndPtr := add(addressArray, addressArrayMemSizeInBytes) - } - - // Cases for `freeMemPtr`: - // `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 free memory begins at the end of `addressArray` - // then we can append `addressToAppend` directly. - // Otherwise, we must copy the array to free memory - // before appending new values to it. - if (freeMemPtr > addressArrayEndPtr) { - LibBytes.memCopy(freeMemPtr, addressArrayBeginPtr, addressArrayMemSizeInBytes); - assembly { - addressArray := freeMemPtr - addressArrayBeginPtr := addressArray - } - } - - // Append `addressToAppend` - addressArrayLength += 1; - addressArrayMemSizeInBytes += 32; - addressArrayEndPtr = addressArrayBeginPtr + addressArrayMemSizeInBytes; - freeMemPtr = addressArrayEndPtr; - assembly { - // Store new array length - mstore(addressArray, addressArrayLength) - - // Update `freeMemPtr` - mstore(0x40, freeMemPtr) - } - addressArray[addressArrayLength - 1] = addressToAppend; - return addressArray; - } -} diff --git a/contracts/libs/contracts/libs/LibFillResults.sol b/contracts/libs/contracts/libs/LibFillResults.sol index 74b7f7984..09053664c 100644 --- a/contracts/libs/contracts/libs/LibFillResults.sol +++ b/contracts/libs/contracts/libs/LibFillResults.sol @@ -18,7 +18,7 @@ pragma solidity ^0.4.24; -import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol"; +import "@0x/contracts-utils/contracts/utils/SafeMath.sol"; contract LibFillResults is diff --git a/contracts/libs/contracts/libs/LibMath.sol b/contracts/libs/contracts/libs/LibMath.sol index f14b1b34d..4b62b6f62 100644 --- a/contracts/libs/contracts/libs/LibMath.sol +++ b/contracts/libs/contracts/libs/LibMath.sol @@ -18,7 +18,7 @@ pragma solidity ^0.4.24; -import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol"; +import "@0x/contracts-utils/contracts/utils/SafeMath.sol"; contract LibMath is diff --git a/contracts/libs/contracts/test/TestLibs.sol b/contracts/libs/contracts/test/TestLibs.sol new file mode 100644 index 000000000..30d2ad2ac --- /dev/null +++ b/contracts/libs/contracts/test/TestLibs.sol @@ -0,0 +1,152 @@ +/* + + Copyright 2018 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.4.24; +pragma experimental ABIEncoderV2; + +import "../libs/LibMath.sol"; +import "../libs/LibOrder.sol"; +import "../libs/LibFillResults.sol"; +import "../libs/LibAbiEncoder.sol"; + + +contract TestLibs is + LibMath, + LibOrder, + LibFillResults, + LibAbiEncoder +{ + function publicAbiEncodeFillOrder( + Order memory order, + uint256 takerAssetFillAmount, + bytes memory signature + ) + public + pure + returns (bytes memory fillOrderCalldata) + { + fillOrderCalldata = abiEncodeFillOrder( + order, + takerAssetFillAmount, + signature + ); + return fillOrderCalldata; + } + + function publicGetPartialAmountFloor( + uint256 numerator, + uint256 denominator, + uint256 target + ) + public + pure + returns (uint256 partialAmount) + { + partialAmount = getPartialAmountFloor( + numerator, + denominator, + target + ); + return partialAmount; + } + + function publicGetPartialAmountCeil( + uint256 numerator, + uint256 denominator, + uint256 target + ) + public + pure + returns (uint256 partialAmount) + { + partialAmount = getPartialAmountCeil( + numerator, + denominator, + target + ); + return partialAmount; + } + + function publicIsRoundingErrorFloor( + uint256 numerator, + uint256 denominator, + uint256 target + ) + public + pure + returns (bool isError) + { + isError = isRoundingErrorFloor( + numerator, + denominator, + target + ); + return isError; + } + + function publicIsRoundingErrorCeil( + uint256 numerator, + uint256 denominator, + uint256 target + ) + public + pure + returns (bool isError) + { + isError = isRoundingErrorCeil( + numerator, + denominator, + target + ); + return isError; + } + + function publicGetOrderHash(Order memory order) + public + view + returns (bytes32 orderHash) + { + orderHash = getOrderHash(order); + return orderHash; + } + + function getOrderSchemaHash() + public + pure + returns (bytes32) + { + return EIP712_ORDER_SCHEMA_HASH; + } + + function getDomainSeparatorSchemaHash() + public + pure + returns (bytes32) + { + return EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH; + } + + function publicAddFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults) + public + pure + returns (FillResults memory) + { + addFillResults(totalFillResults, singleFillResults); + return totalFillResults; + } +} diff --git a/contracts/libs/contracts/test/TestLibs/TestLibs.sol b/contracts/libs/contracts/test/TestLibs/TestLibs.sol deleted file mode 100644 index bd5f9f9da..000000000 --- a/contracts/libs/contracts/test/TestLibs/TestLibs.sol +++ /dev/null @@ -1,152 +0,0 @@ -/* - - Copyright 2018 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.4.24; -pragma experimental ABIEncoderV2; - -import "../../libs/LibMath.sol"; -import "../../libs/LibOrder.sol"; -import "../../libs/LibFillResults.sol"; -import "../../libs/LibAbiEncoder.sol"; - - -contract TestLibs is - LibMath, - LibOrder, - LibFillResults, - LibAbiEncoder -{ - function publicAbiEncodeFillOrder( - Order memory order, - uint256 takerAssetFillAmount, - bytes memory signature - ) - public - pure - returns (bytes memory fillOrderCalldata) - { - fillOrderCalldata = abiEncodeFillOrder( - order, - takerAssetFillAmount, - signature - ); - return fillOrderCalldata; - } - - function publicGetPartialAmountFloor( - uint256 numerator, - uint256 denominator, - uint256 target - ) - public - pure - returns (uint256 partialAmount) - { - partialAmount = getPartialAmountFloor( - numerator, - denominator, - target - ); - return partialAmount; - } - - function publicGetPartialAmountCeil( - uint256 numerator, - uint256 denominator, - uint256 target - ) - public - pure - returns (uint256 partialAmount) - { - partialAmount = getPartialAmountCeil( - numerator, - denominator, - target - ); - return partialAmount; - } - - function publicIsRoundingErrorFloor( - uint256 numerator, - uint256 denominator, - uint256 target - ) - public - pure - returns (bool isError) - { - isError = isRoundingErrorFloor( - numerator, - denominator, - target - ); - return isError; - } - - function publicIsRoundingErrorCeil( - uint256 numerator, - uint256 denominator, - uint256 target - ) - public - pure - returns (bool isError) - { - isError = isRoundingErrorCeil( - numerator, - denominator, - target - ); - return isError; - } - - function publicGetOrderHash(Order memory order) - public - view - returns (bytes32 orderHash) - { - orderHash = getOrderHash(order); - return orderHash; - } - - function getOrderSchemaHash() - public - pure - returns (bytes32) - { - return EIP712_ORDER_SCHEMA_HASH; - } - - function getDomainSeparatorSchemaHash() - public - pure - returns (bytes32) - { - return EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH; - } - - function publicAddFillResults(FillResults memory totalFillResults, FillResults memory singleFillResults) - public - pure - returns (FillResults memory) - { - addFillResults(totalFillResults, singleFillResults); - return totalFillResults; - } -} diff --git a/contracts/libs/test/exchange/libs.ts b/contracts/libs/test/exchange/libs.ts deleted file mode 100644 index 44ff6a844..000000000 --- a/contracts/libs/test/exchange/libs.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { - addressUtils, - chaiSetup, - constants, - OrderFactory, - provider, - txDefaults, - web3Wrapper, -} from '@0x/contracts-test-utils'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; - -import { TestLibsContract } from '../../generated-wrappers/test_libs'; -import { artifacts } from '../../src/artifacts'; - -chaiSetup.configure(); -const expect = chai.expect; - -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('Exchange libs', () => { - let signedOrder: SignedOrder; - let orderFactory: OrderFactory; - let libs: TestLibsContract; - - before(async () => { - await blockchainLifecycle.startAsync(); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - before(async () => { - const accounts = await web3Wrapper.getAvailableAddressesAsync(); - const makerAddress = accounts[0]; - libs = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults); - - const defaultOrderParams = { - ...constants.STATIC_ORDER_PARAMS, - exchangeAddress: libs.address, - makerAddress, - feeRecipientAddress: addressUtils.generatePseudoRandomAddress(), - makerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()), - takerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()), - }; - const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; - orderFactory = new OrderFactory(privateKey, defaultOrderParams); - }); - - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - // Note(albrow): These tests are designed to be supplemental to the - // combinatorial tests in test/exchange/internal. They test specific edge - // cases that are not covered by the combinatorial tests. - describe('LibMath', () => { - describe('isRoundingError', () => { - it('should return true if there is a rounding error of 0.1%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(999); - const target = new BigNumber(50); - // rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1% - const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.true(); - }); - it('should return false if there is a rounding of 0.09%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(9991); - const target = new BigNumber(500); - // rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09% - const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.false(); - }); - it('should return true if there is a rounding error of 0.11%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(9989); - const target = new BigNumber(500); - // rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011% - const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.true(); - }); - }); - describe('isRoundingErrorCeil', () => { - it('should return true if there is a rounding error of 0.1%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(1001); - const target = new BigNumber(50); - // rounding error = (ceil(20*50/1001) - (20*50/1001)) / (20*50/1001) = 0.1% - const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.true(); - }); - it('should return false if there is a rounding of 0.09%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(10009); - const target = new BigNumber(500); - // rounding error = (ceil(20*500/10009) - (20*500/10009)) / (20*500/10009) = 0.09% - const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.false(); - }); - it('should return true if there is a rounding error of 0.11%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(10011); - const target = new BigNumber(500); - // rounding error = (ceil(20*500/10011) - (20*500/10011)) / (20*500/10011) = 0.11% - const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.true(); - }); - }); - }); - - describe('LibOrder', () => { - describe('getOrderHash', () => { - it('should output the correct orderHash', async () => { - signedOrder = await orderFactory.newSignedOrderAsync(); - const orderHashHex = await libs.publicGetOrderHash.callAsync(signedOrder); - expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(orderHashHex); - }); - }); - }); -}); diff --git a/contracts/libs/test/exchange_libs.ts b/contracts/libs/test/exchange_libs.ts new file mode 100644 index 000000000..b61323189 --- /dev/null +++ b/contracts/libs/test/exchange_libs.ts @@ -0,0 +1,125 @@ +import { + addressUtils, + chaiSetup, + constants, + OrderFactory, + provider, + txDefaults, + web3Wrapper, +} from '@0x/contracts-test-utils'; +import { BlockchainLifecycle } from '@0x/dev-utils'; +import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; +import { SignedOrder } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import * as chai from 'chai'; + +import { TestLibsContract } from '../generated-wrappers/test_libs'; +import { artifacts } from '../src/artifacts'; + +chaiSetup.configure(); +const expect = chai.expect; + +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); + +describe('Exchange libs', () => { + let signedOrder: SignedOrder; + let orderFactory: OrderFactory; + let libs: TestLibsContract; + + before(async () => { + await blockchainLifecycle.startAsync(); + }); + after(async () => { + await blockchainLifecycle.revertAsync(); + }); + before(async () => { + const accounts = await web3Wrapper.getAvailableAddressesAsync(); + const makerAddress = accounts[0]; + libs = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults); + + const defaultOrderParams = { + ...constants.STATIC_ORDER_PARAMS, + exchangeAddress: libs.address, + makerAddress, + feeRecipientAddress: addressUtils.generatePseudoRandomAddress(), + makerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()), + takerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()), + }; + const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; + orderFactory = new OrderFactory(privateKey, defaultOrderParams); + }); + + beforeEach(async () => { + await blockchainLifecycle.startAsync(); + }); + afterEach(async () => { + await blockchainLifecycle.revertAsync(); + }); + // Note(albrow): These tests are designed to be supplemental to the + // combinatorial tests in test/exchange/internal. They test specific edge + // cases that are not covered by the combinatorial tests. + describe('LibMath', () => { + describe('isRoundingError', () => { + it('should return true if there is a rounding error of 0.1%', async () => { + const numerator = new BigNumber(20); + const denominator = new BigNumber(999); + const target = new BigNumber(50); + // rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1% + const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target); + expect(isRoundingError).to.be.true(); + }); + it('should return false if there is a rounding of 0.09%', async () => { + const numerator = new BigNumber(20); + const denominator = new BigNumber(9991); + const target = new BigNumber(500); + // rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09% + const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target); + expect(isRoundingError).to.be.false(); + }); + it('should return true if there is a rounding error of 0.11%', async () => { + const numerator = new BigNumber(20); + const denominator = new BigNumber(9989); + const target = new BigNumber(500); + // rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011% + const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target); + expect(isRoundingError).to.be.true(); + }); + }); + describe('isRoundingErrorCeil', () => { + it('should return true if there is a rounding error of 0.1%', async () => { + const numerator = new BigNumber(20); + const denominator = new BigNumber(1001); + const target = new BigNumber(50); + // rounding error = (ceil(20*50/1001) - (20*50/1001)) / (20*50/1001) = 0.1% + const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target); + expect(isRoundingError).to.be.true(); + }); + it('should return false if there is a rounding of 0.09%', async () => { + const numerator = new BigNumber(20); + const denominator = new BigNumber(10009); + const target = new BigNumber(500); + // rounding error = (ceil(20*500/10009) - (20*500/10009)) / (20*500/10009) = 0.09% + const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target); + expect(isRoundingError).to.be.false(); + }); + it('should return true if there is a rounding error of 0.11%', async () => { + const numerator = new BigNumber(20); + const denominator = new BigNumber(10011); + const target = new BigNumber(500); + // rounding error = (ceil(20*500/10011) - (20*500/10011)) / (20*500/10011) = 0.11% + const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target); + expect(isRoundingError).to.be.true(); + }); + }); + }); + + describe('LibOrder', () => { + describe('getOrderHash', () => { + it('should output the correct orderHash', async () => { + signedOrder = await orderFactory.newSignedOrderAsync(); + const orderHashHex = await libs.publicGetOrderHash.callAsync(signedOrder); + expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(orderHashHex); + }); + }); + }); +}); diff --git a/contracts/utils/contracts/test/TestConstants.sol b/contracts/utils/contracts/test/TestConstants.sol new file mode 100644 index 000000000..372e0af24 --- /dev/null +++ b/contracts/utils/contracts/test/TestConstants.sol @@ -0,0 +1,57 @@ +/* + + Copyright 2018 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.4.24; + +import "../utils/LibBytes.sol"; + + +// solhint-disable max-line-length +contract TestConstants { + + using LibBytes for bytes; + + bytes4 constant internal ERC20_PROXY_ID = bytes4(keccak256("ERC20Token(address)")); + + address constant internal KOVAN_ZRX_ADDRESS = 0x6Ff6C0Ff1d68b964901F986d4C9FA3ac68346570; + bytes constant internal KOVAN_ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6f\xf6\xc0\xff\x1d\x68\xb9\x64\x90\x1f\x98\x6d\x4c\x9f\xa3\xac\x68\x34\x65\x70"; + + address constant internal MAINNET_ZRX_ADDRESS = 0xE41d2489571d322189246DaFA5ebDe1F4699F498; + bytes constant public MAINNET_ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98"; + + function assertValidZrxAssetData() + public + pure + returns (bool) + { + bytes memory kovanZrxAssetData = abi.encodeWithSelector(ERC20_PROXY_ID, KOVAN_ZRX_ADDRESS); + require( + kovanZrxAssetData.equals(KOVAN_ZRX_ASSET_DATA), + "INVALID_KOVAN_ZRX_ASSET_DATA" + ); + + bytes memory mainetZrxAssetData = abi.encodeWithSelector(ERC20_PROXY_ID, MAINNET_ZRX_ADDRESS); + require( + mainetZrxAssetData.equals(MAINNET_ZRX_ASSET_DATA), + "INVALID_MAINNET_ZRX_ASSET_DATA" + ); + + return true; + } +} +// solhint-enable max-line-length \ No newline at end of file diff --git a/contracts/utils/contracts/test/TestConstants/TestConstants.sol b/contracts/utils/contracts/test/TestConstants/TestConstants.sol deleted file mode 100644 index 3c852173b..000000000 --- a/contracts/utils/contracts/test/TestConstants/TestConstants.sol +++ /dev/null @@ -1,57 +0,0 @@ -/* - - Copyright 2018 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.4.24; - -import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; - - -// solhint-disable max-line-length -contract TestConstants { - - using LibBytes for bytes; - - bytes4 constant internal ERC20_PROXY_ID = bytes4(keccak256("ERC20Token(address)")); - - address constant internal KOVAN_ZRX_ADDRESS = 0x6Ff6C0Ff1d68b964901F986d4C9FA3ac68346570; - bytes constant internal KOVAN_ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x6f\xf6\xc0\xff\x1d\x68\xb9\x64\x90\x1f\x98\x6d\x4c\x9f\xa3\xac\x68\x34\x65\x70"; - - address constant internal MAINNET_ZRX_ADDRESS = 0xE41d2489571d322189246DaFA5ebDe1F4699F498; - bytes constant public MAINNET_ZRX_ASSET_DATA = "\xf4\x72\x61\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\x1d\x24\x89\x57\x1d\x32\x21\x89\x24\x6d\xaf\xa5\xeb\xde\x1f\x46\x99\xf4\x98"; - - function assertValidZrxAssetData() - public - pure - returns (bool) - { - bytes memory kovanZrxAssetData = abi.encodeWithSelector(ERC20_PROXY_ID, KOVAN_ZRX_ADDRESS); - require( - kovanZrxAssetData.equals(KOVAN_ZRX_ASSET_DATA), - "INVALID_KOVAN_ZRX_ASSET_DATA" - ); - - bytes memory mainetZrxAssetData = abi.encodeWithSelector(ERC20_PROXY_ID, MAINNET_ZRX_ADDRESS); - require( - mainetZrxAssetData.equals(MAINNET_ZRX_ASSET_DATA), - "INVALID_MAINNET_ZRX_ASSET_DATA" - ); - - return true; - } -} -// solhint-enable max-line-length \ No newline at end of file diff --git a/contracts/utils/contracts/test/TestLibBytes.sol b/contracts/utils/contracts/test/TestLibBytes.sol new file mode 100644 index 000000000..c1a5866d0 --- /dev/null +++ b/contracts/utils/contracts/test/TestLibBytes.sol @@ -0,0 +1,269 @@ +/* + + Copyright 2018 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.4.24; + +import "../utils/LibBytes.sol"; + + +contract TestLibBytes { + + using LibBytes for bytes; + + /// @dev Pops the last byte off of a byte array by modifying its length. + /// @param b Byte array that will be modified. + /// @return The byte that was popped off. + function publicPopLastByte(bytes memory b) + public + pure + returns (bytes memory, bytes1 result) + { + result = b.popLastByte(); + return (b, result); + } + + /// @dev Pops the last 20 bytes off of a byte array by modifying its length. + /// @param b Byte array that will be modified. + /// @return The 20 byte address that was popped off. + function publicPopLast20Bytes(bytes memory b) + public + pure + returns (bytes memory, address result) + { + result = b.popLast20Bytes(); + return (b, result); + } + + /// @dev Tests equality of two byte arrays. + /// @param lhs First byte array to compare. + /// @param rhs Second byte array to compare. + /// @return True if arrays are the same. False otherwise. + function publicEquals(bytes memory lhs, bytes memory rhs) + public + pure + returns (bool equal) + { + equal = lhs.equals(rhs); + return equal; + } + + function publicEqualsPop1(bytes memory lhs, bytes memory rhs) + public + pure + returns (bool equal) + { + lhs.popLastByte(); + rhs.popLastByte(); + equal = lhs.equals(rhs); + return equal; + } + + /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length. + /// @param dest Byte array that will be overwritten with source bytes. + /// @param source Byte array to copy onto dest bytes. + function publicDeepCopyBytes( + bytes memory dest, + bytes memory source + ) + public + pure + returns (bytes memory) + { + LibBytes.deepCopyBytes(dest, source); + return dest; + } + + /// @dev Reads an address from a position in a byte array. + /// @param b Byte array containing an address. + /// @param index Index in byte array of address. + /// @return address from byte array. + function publicReadAddress( + bytes memory b, + uint256 index + ) + public + pure + returns (address result) + { + result = b.readAddress(index); + return result; + } + + /// @dev Writes an address into a specific position in a byte array. + /// @param b Byte array to insert address into. + /// @param index Index in byte array of address. + /// @param input Address to put into byte array. + function publicWriteAddress( + bytes memory b, + uint256 index, + address input + ) + public + pure + returns (bytes memory) + { + b.writeAddress(index, input); + return b; + } + + /// @dev Reads a bytes32 value from a position in a byte array. + /// @param b Byte array containing a bytes32 value. + /// @param index Index in byte array of bytes32 value. + /// @return bytes32 value from byte array. + function publicReadBytes32( + bytes memory b, + uint256 index + ) + public + pure + returns (bytes32 result) + { + result = b.readBytes32(index); + return result; + } + + /// @dev Writes a bytes32 into a specific position in a byte array. + /// @param b Byte array to insert into. + /// @param index Index in byte array of . + /// @param input bytes32 to put into byte array. + function publicWriteBytes32( + bytes memory b, + uint256 index, + bytes32 input + ) + public + pure + returns (bytes memory) + { + b.writeBytes32(index, input); + return b; + } + + /// @dev Reads a uint256 value from a position in a byte array. + /// @param b Byte array containing a uint256 value. + /// @param index Index in byte array of uint256 value. + /// @return uint256 value from byte array. + function publicReadUint256( + bytes memory b, + uint256 index + ) + public + pure + returns (uint256 result) + { + result = b.readUint256(index); + return result; + } + + /// @dev Writes a uint256 into a specific position in a byte array. + /// @param b Byte array to insert into. + /// @param index Index in byte array of . + /// @param input uint256 to put into byte array. + function publicWriteUint256( + bytes memory b, + uint256 index, + uint256 input + ) + public + pure + returns (bytes memory) + { + b.writeUint256(index, input); + return b; + } + + /// @dev Reads an unpadded bytes4 value from a position in a byte array. + /// @param b Byte array containing a bytes4 value. + /// @param index Index in byte array of bytes4 value. + /// @return bytes4 value from byte array. + function publicReadBytes4( + bytes memory b, + uint256 index + ) + public + pure + returns (bytes4 result) + { + result = b.readBytes4(index); + return result; + } + + /// @dev Reads nested bytes from a specific position. + /// @param b Byte array containing nested bytes. + /// @param index Index of nested bytes. + /// @return result Nested bytes. + function publicReadBytesWithLength( + bytes memory b, + uint256 index + ) + public + pure + returns (bytes memory result) + { + result = b.readBytesWithLength(index); + return result; + } + + /// @dev Inserts bytes at a specific position in a byte array. + /// @param b Byte array to insert into. + /// @param index Index in byte array of . + /// @param input bytes to insert. + /// @return b Updated input byte array + function publicWriteBytesWithLength( + bytes memory b, + uint256 index, + bytes memory input + ) + public + pure + returns (bytes memory) + { + b.writeBytesWithLength(index, input); + return b; + } + + /// @dev Copies a block of memory from one location to another. + /// @param mem Memory contents we want to apply memCopy to + /// @param dest Destination offset into . + /// @param source Source offset into . + /// @param length Length of bytes to copy from to + /// @return mem Memory contents after calling memCopy. + function testMemcpy( + bytes mem, + uint256 dest, + uint256 source, + uint256 length + ) + public // not external, we need input in memory + pure + returns (bytes) + { + // Sanity check. Overflows are not checked. + require(source + length <= mem.length); + require(dest + length <= mem.length); + + // Get pointer to memory contents + uint256 offset = mem.contentAddress(); + + // Execute memCopy adjusted for memory array location + LibBytes.memCopy(offset + dest, offset + source, length); + + // Return modified memory contents + return mem; + } +} diff --git a/contracts/utils/contracts/test/TestLibBytes/TestLibBytes.sol b/contracts/utils/contracts/test/TestLibBytes/TestLibBytes.sol deleted file mode 100644 index 444a3e717..000000000 --- a/contracts/utils/contracts/test/TestLibBytes/TestLibBytes.sol +++ /dev/null @@ -1,269 +0,0 @@ -/* - - Copyright 2018 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.4.24; - -import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol"; - - -contract TestLibBytes { - - using LibBytes for bytes; - - /// @dev Pops the last byte off of a byte array by modifying its length. - /// @param b Byte array that will be modified. - /// @return The byte that was popped off. - function publicPopLastByte(bytes memory b) - public - pure - returns (bytes memory, bytes1 result) - { - result = b.popLastByte(); - return (b, result); - } - - /// @dev Pops the last 20 bytes off of a byte array by modifying its length. - /// @param b Byte array that will be modified. - /// @return The 20 byte address that was popped off. - function publicPopLast20Bytes(bytes memory b) - public - pure - returns (bytes memory, address result) - { - result = b.popLast20Bytes(); - return (b, result); - } - - /// @dev Tests equality of two byte arrays. - /// @param lhs First byte array to compare. - /// @param rhs Second byte array to compare. - /// @return True if arrays are the same. False otherwise. - function publicEquals(bytes memory lhs, bytes memory rhs) - public - pure - returns (bool equal) - { - equal = lhs.equals(rhs); - return equal; - } - - function publicEqualsPop1(bytes memory lhs, bytes memory rhs) - public - pure - returns (bool equal) - { - lhs.popLastByte(); - rhs.popLastByte(); - equal = lhs.equals(rhs); - return equal; - } - - /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length. - /// @param dest Byte array that will be overwritten with source bytes. - /// @param source Byte array to copy onto dest bytes. - function publicDeepCopyBytes( - bytes memory dest, - bytes memory source - ) - public - pure - returns (bytes memory) - { - LibBytes.deepCopyBytes(dest, source); - return dest; - } - - /// @dev Reads an address from a position in a byte array. - /// @param b Byte array containing an address. - /// @param index Index in byte array of address. - /// @return address from byte array. - function publicReadAddress( - bytes memory b, - uint256 index - ) - public - pure - returns (address result) - { - result = b.readAddress(index); - return result; - } - - /// @dev Writes an address into a specific position in a byte array. - /// @param b Byte array to insert address into. - /// @param index Index in byte array of address. - /// @param input Address to put into byte array. - function publicWriteAddress( - bytes memory b, - uint256 index, - address input - ) - public - pure - returns (bytes memory) - { - b.writeAddress(index, input); - return b; - } - - /// @dev Reads a bytes32 value from a position in a byte array. - /// @param b Byte array containing a bytes32 value. - /// @param index Index in byte array of bytes32 value. - /// @return bytes32 value from byte array. - function publicReadBytes32( - bytes memory b, - uint256 index - ) - public - pure - returns (bytes32 result) - { - result = b.readBytes32(index); - return result; - } - - /// @dev Writes a bytes32 into a specific position in a byte array. - /// @param b Byte array to insert into. - /// @param index Index in byte array of . - /// @param input bytes32 to put into byte array. - function publicWriteBytes32( - bytes memory b, - uint256 index, - bytes32 input - ) - public - pure - returns (bytes memory) - { - b.writeBytes32(index, input); - return b; - } - - /// @dev Reads a uint256 value from a position in a byte array. - /// @param b Byte array containing a uint256 value. - /// @param index Index in byte array of uint256 value. - /// @return uint256 value from byte array. - function publicReadUint256( - bytes memory b, - uint256 index - ) - public - pure - returns (uint256 result) - { - result = b.readUint256(index); - return result; - } - - /// @dev Writes a uint256 into a specific position in a byte array. - /// @param b Byte array to insert into. - /// @param index Index in byte array of . - /// @param input uint256 to put into byte array. - function publicWriteUint256( - bytes memory b, - uint256 index, - uint256 input - ) - public - pure - returns (bytes memory) - { - b.writeUint256(index, input); - return b; - } - - /// @dev Reads an unpadded bytes4 value from a position in a byte array. - /// @param b Byte array containing a bytes4 value. - /// @param index Index in byte array of bytes4 value. - /// @return bytes4 value from byte array. - function publicReadBytes4( - bytes memory b, - uint256 index - ) - public - pure - returns (bytes4 result) - { - result = b.readBytes4(index); - return result; - } - - /// @dev Reads nested bytes from a specific position. - /// @param b Byte array containing nested bytes. - /// @param index Index of nested bytes. - /// @return result Nested bytes. - function publicReadBytesWithLength( - bytes memory b, - uint256 index - ) - public - pure - returns (bytes memory result) - { - result = b.readBytesWithLength(index); - return result; - } - - /// @dev Inserts bytes at a specific position in a byte array. - /// @param b Byte array to insert into. - /// @param index Index in byte array of . - /// @param input bytes to insert. - /// @return b Updated input byte array - function publicWriteBytesWithLength( - bytes memory b, - uint256 index, - bytes memory input - ) - public - pure - returns (bytes memory) - { - b.writeBytesWithLength(index, input); - return b; - } - - /// @dev Copies a block of memory from one location to another. - /// @param mem Memory contents we want to apply memCopy to - /// @param dest Destination offset into . - /// @param source Source offset into . - /// @param length Length of bytes to copy from to - /// @return mem Memory contents after calling memCopy. - function testMemcpy( - bytes mem, - uint256 dest, - uint256 source, - uint256 length - ) - public // not external, we need input in memory - pure - returns (bytes) - { - // Sanity check. Overflows are not checked. - require(source + length <= mem.length); - require(dest + length <= mem.length); - - // Get pointer to memory contents - uint256 offset = mem.contentAddress(); - - // Execute memCopy adjusted for memory array location - LibBytes.memCopy(offset + dest, offset + source, length); - - // Return modified memory contents - return mem; - } -} diff --git a/contracts/utils/contracts/utils/LibAddressArray.sol b/contracts/utils/contracts/utils/LibAddressArray.sol new file mode 100644 index 000000000..892c486f1 --- /dev/null +++ b/contracts/utils/contracts/utils/LibAddressArray.sol @@ -0,0 +1,84 @@ +/* + + Copyright 2018 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.4.24; + +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 + /// memory location of `addressArray`. + /// @param addressToAppend Address to append. + /// @return Array of addresses: [... addressArray, addressToAppend] + function append(address[] memory addressArray, address addressToAppend) + internal pure + returns (address[]) + { + // Get stats on address array and free memory + uint256 freeMemPtr = 0; + uint256 addressArrayBeginPtr = 0; + uint256 addressArrayEndPtr = 0; + uint256 addressArrayLength = addressArray.length; + uint256 addressArrayMemSizeInBytes = 32 + (32 * addressArrayLength); + assembly { + freeMemPtr := mload(0x40) + addressArrayBeginPtr := addressArray + addressArrayEndPtr := add(addressArray, addressArrayMemSizeInBytes) + } + + // Cases for `freeMemPtr`: + // `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 free memory begins at the end of `addressArray` + // then we can append `addressToAppend` directly. + // Otherwise, we must copy the array to free memory + // before appending new values to it. + if (freeMemPtr > addressArrayEndPtr) { + LibBytes.memCopy(freeMemPtr, addressArrayBeginPtr, addressArrayMemSizeInBytes); + assembly { + addressArray := freeMemPtr + addressArrayBeginPtr := addressArray + } + } + + // Append `addressToAppend` + addressArrayLength += 1; + addressArrayMemSizeInBytes += 32; + addressArrayEndPtr = addressArrayBeginPtr + addressArrayMemSizeInBytes; + freeMemPtr = addressArrayEndPtr; + assembly { + // Store new array length + mstore(addressArray, addressArrayLength) + + // Update `freeMemPtr` + mstore(0x40, freeMemPtr) + } + addressArray[addressArrayLength - 1] = addressToAppend; + return addressArray; + } +} diff --git a/contracts/utils/contracts/utils/LibBytes.sol b/contracts/utils/contracts/utils/LibBytes.sol new file mode 100644 index 000000000..4ee6228d5 --- /dev/null +++ b/contracts/utils/contracts/utils/LibBytes.sol @@ -0,0 +1,567 @@ +/* + + Copyright 2018 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.4.24; + + +library LibBytes { + + using LibBytes for bytes; + + /// @dev Gets the memory address for a byte array. + /// @param input Byte array to lookup. + /// @return memoryAddress Memory address of byte array. This + /// points to the header of the byte array which contains + /// the length. + function rawAddress(bytes memory input) + internal + pure + returns (uint256 memoryAddress) + { + assembly { + memoryAddress := input + } + return memoryAddress; + } + + /// @dev Gets the memory address for the contents of a byte array. + /// @param input Byte array to lookup. + /// @return memoryAddress Memory address of the contents of the byte array. + function contentAddress(bytes memory input) + internal + pure + returns (uint256 memoryAddress) + { + assembly { + memoryAddress := add(input, 32) + } + return memoryAddress; + } + + /// @dev Copies `length` bytes from memory location `source` to `dest`. + /// @param dest memory address to copy bytes to. + /// @param source memory address to copy bytes from. + /// @param length number of bytes to copy. + function memCopy( + uint256 dest, + uint256 source, + uint256 length + ) + internal + pure + { + if (length < 32) { + // Handle a partial word by reading destination and masking + // off the bits we are interested in. + // This correctly handles overlap, zero lengths and source == dest + assembly { + let mask := sub(exp(256, sub(32, length)), 1) + let s := and(mload(source), not(mask)) + let d := and(mload(dest), mask) + mstore(dest, or(s, d)) + } + } else { + // Skip the O(length) loop when source == dest. + if (source == dest) { + return; + } + + // For large copies we copy whole words at a time. The final + // word is aligned to the end of the range (instead of after the + // previous) to handle partial words. So a copy will look like this: + // + // #### + // #### + // #### + // #### + // + // We handle overlap in the source and destination range by + // changing the copying direction. This prevents us from + // overwriting parts of source that we still need to copy. + // + // This correctly handles source == dest + // + if (source > dest) { + assembly { + // We subtract 32 from `sEnd` and `dEnd` because it + // is easier to compare with in the loop, and these + // are also the addresses we need for copying the + // last bytes. + length := sub(length, 32) + let sEnd := add(source, length) + let dEnd := add(dest, length) + + // Remember the last 32 bytes of source + // This needs to be done here and not after the loop + // because we may have overwritten the last bytes in + // source already due to overlap. + let last := mload(sEnd) + + // Copy whole words front to back + // Note: the first check is always true, + // this could have been a do-while loop. + // solhint-disable-next-line no-empty-blocks + for {} lt(source, sEnd) {} { + mstore(dest, mload(source)) + source := add(source, 32) + dest := add(dest, 32) + } + + // Write the last 32 bytes + mstore(dEnd, last) + } + } else { + assembly { + // We subtract 32 from `sEnd` and `dEnd` because those + // are the starting points when copying a word at the end. + length := sub(length, 32) + let sEnd := add(source, length) + let dEnd := add(dest, length) + + // Remember the first 32 bytes of source + // This needs to be done here and not after the loop + // because we may have overwritten the first bytes in + // source already due to overlap. + let first := mload(source) + + // Copy whole words back to front + // We use a signed comparisson here to allow dEnd to become + // negative (happens when source and dest < 32). Valid + // addresses in local memory will never be larger than + // 2**255, so they can be safely re-interpreted as signed. + // Note: the first check is always true, + // this could have been a do-while loop. + // solhint-disable-next-line no-empty-blocks + for {} slt(dest, dEnd) {} { + mstore(dEnd, mload(sEnd)) + sEnd := sub(sEnd, 32) + dEnd := sub(dEnd, 32) + } + + // Write the first 32 bytes + mstore(dest, first) + } + } + } + } + + /// @dev Returns a slices from a byte array. + /// @param b The byte array to take a slice from. + /// @param from The starting index for the slice (inclusive). + /// @param to The final index for the slice (exclusive). + /// @return result The slice containing bytes at indices [from, to) + function slice( + bytes memory b, + uint256 from, + uint256 to + ) + internal + pure + returns (bytes memory result) + { + require( + from <= to, + "FROM_LESS_THAN_TO_REQUIRED" + ); + require( + to < b.length, + "TO_LESS_THAN_LENGTH_REQUIRED" + ); + + // Create a new bytes structure and copy contents + result = new bytes(to - from); + memCopy( + result.contentAddress(), + b.contentAddress() + from, + result.length + ); + return result; + } + + /// @dev Returns a slice from a byte array without preserving the input. + /// @param b The byte array to take a slice from. Will be destroyed in the process. + /// @param from The starting index for the slice (inclusive). + /// @param to The final index for the slice (exclusive). + /// @return result The slice containing bytes at indices [from, to) + /// @dev When `from == 0`, the original array will match the slice. In other cases its state will be corrupted. + function sliceDestructive( + bytes memory b, + uint256 from, + uint256 to + ) + internal + pure + returns (bytes memory result) + { + require( + from <= to, + "FROM_LESS_THAN_TO_REQUIRED" + ); + require( + to < b.length, + "TO_LESS_THAN_LENGTH_REQUIRED" + ); + + // Create a new bytes structure around [from, to) in-place. + assembly { + result := add(b, from) + mstore(result, sub(to, from)) + } + return result; + } + + /// @dev Pops the last byte off of a byte array by modifying its length. + /// @param b Byte array that will be modified. + /// @return The byte that was popped off. + function popLastByte(bytes memory b) + internal + pure + returns (bytes1 result) + { + require( + b.length > 0, + "GREATER_THAN_ZERO_LENGTH_REQUIRED" + ); + + // Store last byte. + result = b[b.length - 1]; + + assembly { + // Decrement length of byte array. + let newLen := sub(mload(b), 1) + mstore(b, newLen) + } + return result; + } + + /// @dev Pops the last 20 bytes off of a byte array by modifying its length. + /// @param b Byte array that will be modified. + /// @return The 20 byte address that was popped off. + function popLast20Bytes(bytes memory b) + internal + pure + returns (address result) + { + require( + b.length >= 20, + "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED" + ); + + // Store last 20 bytes. + result = readAddress(b, b.length - 20); + + assembly { + // Subtract 20 from byte array length. + let newLen := sub(mload(b), 20) + mstore(b, newLen) + } + return result; + } + + /// @dev Tests equality of two byte arrays. + /// @param lhs First byte array to compare. + /// @param rhs Second byte array to compare. + /// @return True if arrays are the same. False otherwise. + function equals( + bytes memory lhs, + bytes memory rhs + ) + internal + pure + returns (bool equal) + { + // Keccak gas cost is 30 + numWords * 6. This is a cheap way to compare. + // We early exit on unequal lengths, but keccak would also correctly + // handle this. + return lhs.length == rhs.length && keccak256(lhs) == keccak256(rhs); + } + + /// @dev Reads an address from a position in a byte array. + /// @param b Byte array containing an address. + /// @param index Index in byte array of address. + /// @return address from byte array. + function readAddress( + bytes memory b, + uint256 index + ) + internal + pure + returns (address result) + { + require( + b.length >= index + 20, // 20 is length of address + "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED" + ); + + // Add offset to index: + // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index) + // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index) + index += 20; + + // Read address from array memory + assembly { + // 1. Add index to address of bytes array + // 2. Load 32-byte word from memory + // 3. Apply 20-byte mask to obtain address + result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff) + } + return result; + } + + /// @dev Writes an address into a specific position in a byte array. + /// @param b Byte array to insert address into. + /// @param index Index in byte array of address. + /// @param input Address to put into byte array. + function writeAddress( + bytes memory b, + uint256 index, + address input + ) + internal + pure + { + require( + b.length >= index + 20, // 20 is length of address + "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED" + ); + + // Add offset to index: + // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index) + // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index) + index += 20; + + // Store address into array memory + assembly { + // The address occupies 20 bytes and mstore stores 32 bytes. + // First fetch the 32-byte word where we'll be storing the address, then + // apply a mask so we have only the bytes in the word that the address will not occupy. + // Then combine these bytes with the address and store the 32 bytes back to memory with mstore. + + // 1. Add index to address of bytes array + // 2. Load 32-byte word from memory + // 3. Apply 12-byte mask to obtain extra bytes occupying word of memory where we'll store the address + let neighbors := and( + mload(add(b, index)), + 0xffffffffffffffffffffffff0000000000000000000000000000000000000000 + ) + + // Make sure input address is clean. + // (Solidity does not guarantee this) + input := and(input, 0xffffffffffffffffffffffffffffffffffffffff) + + // Store the neighbors and address into memory + mstore(add(b, index), xor(input, neighbors)) + } + } + + /// @dev Reads a bytes32 value from a position in a byte array. + /// @param b Byte array containing a bytes32 value. + /// @param index Index in byte array of bytes32 value. + /// @return bytes32 value from byte array. + function readBytes32( + bytes memory b, + uint256 index + ) + internal + pure + returns (bytes32 result) + { + require( + b.length >= index + 32, + "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED" + ); + + // Arrays are prefixed by a 256 bit length parameter + index += 32; + + // Read the bytes32 from array memory + assembly { + result := mload(add(b, index)) + } + return result; + } + + /// @dev Writes a bytes32 into a specific position in a byte array. + /// @param b Byte array to insert into. + /// @param index Index in byte array of . + /// @param input bytes32 to put into byte array. + function writeBytes32( + bytes memory b, + uint256 index, + bytes32 input + ) + internal + pure + { + require( + b.length >= index + 32, + "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED" + ); + + // Arrays are prefixed by a 256 bit length parameter + index += 32; + + // Read the bytes32 from array memory + assembly { + mstore(add(b, index), input) + } + } + + /// @dev Reads a uint256 value from a position in a byte array. + /// @param b Byte array containing a uint256 value. + /// @param index Index in byte array of uint256 value. + /// @return uint256 value from byte array. + function readUint256( + bytes memory b, + uint256 index + ) + internal + pure + returns (uint256 result) + { + result = uint256(readBytes32(b, index)); + return result; + } + + /// @dev Writes a uint256 into a specific position in a byte array. + /// @param b Byte array to insert into. + /// @param index Index in byte array of . + /// @param input uint256 to put into byte array. + function writeUint256( + bytes memory b, + uint256 index, + uint256 input + ) + internal + pure + { + writeBytes32(b, index, bytes32(input)); + } + + /// @dev Reads an unpadded bytes4 value from a position in a byte array. + /// @param b Byte array containing a bytes4 value. + /// @param index Index in byte array of bytes4 value. + /// @return bytes4 value from byte array. + function readBytes4( + bytes memory b, + uint256 index + ) + internal + pure + returns (bytes4 result) + { + require( + b.length >= index + 4, + "GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED" + ); + + // Arrays are prefixed by a 32 byte length field + index += 32; + + // Read the bytes4 from array memory + assembly { + result := mload(add(b, index)) + // Solidity does not require us to clean the trailing bytes. + // We do it anyway + result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000) + } + return result; + } + + /// @dev Reads nested bytes from a specific position. + /// @dev NOTE: the returned value overlaps with the input value. + /// Both should be treated as immutable. + /// @param b Byte array containing nested bytes. + /// @param index Index of nested bytes. + /// @return result Nested bytes. + function readBytesWithLength( + bytes memory b, + uint256 index + ) + internal + pure + returns (bytes memory result) + { + // Read length of nested bytes + uint256 nestedBytesLength = readUint256(b, index); + index += 32; + + // Assert length of is valid, given + // length of nested bytes + require( + b.length >= index + nestedBytesLength, + "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED" + ); + + // Return a pointer to the byte array as it exists inside `b` + assembly { + result := add(b, index) + } + return result; + } + + /// @dev Inserts bytes at a specific position in a byte array. + /// @param b Byte array to insert into. + /// @param index Index in byte array of . + /// @param input bytes to insert. + function writeBytesWithLength( + bytes memory b, + uint256 index, + bytes memory input + ) + internal + pure + { + // Assert length of is valid, given + // length of input + require( + b.length >= index + 32 + input.length, // 32 bytes to store length + "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED" + ); + + // Copy into + memCopy( + b.contentAddress() + index, + input.rawAddress(), // includes length of + input.length + 32 // +32 bytes to store length + ); + } + + /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length. + /// @param dest Byte array that will be overwritten with source bytes. + /// @param source Byte array to copy onto dest bytes. + function deepCopyBytes( + bytes memory dest, + bytes memory source + ) + internal + pure + { + uint256 sourceLen = source.length; + // Dest length must be >= source length, or some bytes would not be copied. + require( + dest.length >= sourceLen, + "GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED" + ); + memCopy( + dest.contentAddress(), + source.contentAddress(), + sourceLen + ); + } +} diff --git a/contracts/utils/contracts/utils/LibBytes/LibBytes.sol b/contracts/utils/contracts/utils/LibBytes/LibBytes.sol deleted file mode 100644 index 4ee6228d5..000000000 --- a/contracts/utils/contracts/utils/LibBytes/LibBytes.sol +++ /dev/null @@ -1,567 +0,0 @@ -/* - - Copyright 2018 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.4.24; - - -library LibBytes { - - using LibBytes for bytes; - - /// @dev Gets the memory address for a byte array. - /// @param input Byte array to lookup. - /// @return memoryAddress Memory address of byte array. This - /// points to the header of the byte array which contains - /// the length. - function rawAddress(bytes memory input) - internal - pure - returns (uint256 memoryAddress) - { - assembly { - memoryAddress := input - } - return memoryAddress; - } - - /// @dev Gets the memory address for the contents of a byte array. - /// @param input Byte array to lookup. - /// @return memoryAddress Memory address of the contents of the byte array. - function contentAddress(bytes memory input) - internal - pure - returns (uint256 memoryAddress) - { - assembly { - memoryAddress := add(input, 32) - } - return memoryAddress; - } - - /// @dev Copies `length` bytes from memory location `source` to `dest`. - /// @param dest memory address to copy bytes to. - /// @param source memory address to copy bytes from. - /// @param length number of bytes to copy. - function memCopy( - uint256 dest, - uint256 source, - uint256 length - ) - internal - pure - { - if (length < 32) { - // Handle a partial word by reading destination and masking - // off the bits we are interested in. - // This correctly handles overlap, zero lengths and source == dest - assembly { - let mask := sub(exp(256, sub(32, length)), 1) - let s := and(mload(source), not(mask)) - let d := and(mload(dest), mask) - mstore(dest, or(s, d)) - } - } else { - // Skip the O(length) loop when source == dest. - if (source == dest) { - return; - } - - // For large copies we copy whole words at a time. The final - // word is aligned to the end of the range (instead of after the - // previous) to handle partial words. So a copy will look like this: - // - // #### - // #### - // #### - // #### - // - // We handle overlap in the source and destination range by - // changing the copying direction. This prevents us from - // overwriting parts of source that we still need to copy. - // - // This correctly handles source == dest - // - if (source > dest) { - assembly { - // We subtract 32 from `sEnd` and `dEnd` because it - // is easier to compare with in the loop, and these - // are also the addresses we need for copying the - // last bytes. - length := sub(length, 32) - let sEnd := add(source, length) - let dEnd := add(dest, length) - - // Remember the last 32 bytes of source - // This needs to be done here and not after the loop - // because we may have overwritten the last bytes in - // source already due to overlap. - let last := mload(sEnd) - - // Copy whole words front to back - // Note: the first check is always true, - // this could have been a do-while loop. - // solhint-disable-next-line no-empty-blocks - for {} lt(source, sEnd) {} { - mstore(dest, mload(source)) - source := add(source, 32) - dest := add(dest, 32) - } - - // Write the last 32 bytes - mstore(dEnd, last) - } - } else { - assembly { - // We subtract 32 from `sEnd` and `dEnd` because those - // are the starting points when copying a word at the end. - length := sub(length, 32) - let sEnd := add(source, length) - let dEnd := add(dest, length) - - // Remember the first 32 bytes of source - // This needs to be done here and not after the loop - // because we may have overwritten the first bytes in - // source already due to overlap. - let first := mload(source) - - // Copy whole words back to front - // We use a signed comparisson here to allow dEnd to become - // negative (happens when source and dest < 32). Valid - // addresses in local memory will never be larger than - // 2**255, so they can be safely re-interpreted as signed. - // Note: the first check is always true, - // this could have been a do-while loop. - // solhint-disable-next-line no-empty-blocks - for {} slt(dest, dEnd) {} { - mstore(dEnd, mload(sEnd)) - sEnd := sub(sEnd, 32) - dEnd := sub(dEnd, 32) - } - - // Write the first 32 bytes - mstore(dest, first) - } - } - } - } - - /// @dev Returns a slices from a byte array. - /// @param b The byte array to take a slice from. - /// @param from The starting index for the slice (inclusive). - /// @param to The final index for the slice (exclusive). - /// @return result The slice containing bytes at indices [from, to) - function slice( - bytes memory b, - uint256 from, - uint256 to - ) - internal - pure - returns (bytes memory result) - { - require( - from <= to, - "FROM_LESS_THAN_TO_REQUIRED" - ); - require( - to < b.length, - "TO_LESS_THAN_LENGTH_REQUIRED" - ); - - // Create a new bytes structure and copy contents - result = new bytes(to - from); - memCopy( - result.contentAddress(), - b.contentAddress() + from, - result.length - ); - return result; - } - - /// @dev Returns a slice from a byte array without preserving the input. - /// @param b The byte array to take a slice from. Will be destroyed in the process. - /// @param from The starting index for the slice (inclusive). - /// @param to The final index for the slice (exclusive). - /// @return result The slice containing bytes at indices [from, to) - /// @dev When `from == 0`, the original array will match the slice. In other cases its state will be corrupted. - function sliceDestructive( - bytes memory b, - uint256 from, - uint256 to - ) - internal - pure - returns (bytes memory result) - { - require( - from <= to, - "FROM_LESS_THAN_TO_REQUIRED" - ); - require( - to < b.length, - "TO_LESS_THAN_LENGTH_REQUIRED" - ); - - // Create a new bytes structure around [from, to) in-place. - assembly { - result := add(b, from) - mstore(result, sub(to, from)) - } - return result; - } - - /// @dev Pops the last byte off of a byte array by modifying its length. - /// @param b Byte array that will be modified. - /// @return The byte that was popped off. - function popLastByte(bytes memory b) - internal - pure - returns (bytes1 result) - { - require( - b.length > 0, - "GREATER_THAN_ZERO_LENGTH_REQUIRED" - ); - - // Store last byte. - result = b[b.length - 1]; - - assembly { - // Decrement length of byte array. - let newLen := sub(mload(b), 1) - mstore(b, newLen) - } - return result; - } - - /// @dev Pops the last 20 bytes off of a byte array by modifying its length. - /// @param b Byte array that will be modified. - /// @return The 20 byte address that was popped off. - function popLast20Bytes(bytes memory b) - internal - pure - returns (address result) - { - require( - b.length >= 20, - "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED" - ); - - // Store last 20 bytes. - result = readAddress(b, b.length - 20); - - assembly { - // Subtract 20 from byte array length. - let newLen := sub(mload(b), 20) - mstore(b, newLen) - } - return result; - } - - /// @dev Tests equality of two byte arrays. - /// @param lhs First byte array to compare. - /// @param rhs Second byte array to compare. - /// @return True if arrays are the same. False otherwise. - function equals( - bytes memory lhs, - bytes memory rhs - ) - internal - pure - returns (bool equal) - { - // Keccak gas cost is 30 + numWords * 6. This is a cheap way to compare. - // We early exit on unequal lengths, but keccak would also correctly - // handle this. - return lhs.length == rhs.length && keccak256(lhs) == keccak256(rhs); - } - - /// @dev Reads an address from a position in a byte array. - /// @param b Byte array containing an address. - /// @param index Index in byte array of address. - /// @return address from byte array. - function readAddress( - bytes memory b, - uint256 index - ) - internal - pure - returns (address result) - { - require( - b.length >= index + 20, // 20 is length of address - "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED" - ); - - // Add offset to index: - // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index) - // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index) - index += 20; - - // Read address from array memory - assembly { - // 1. Add index to address of bytes array - // 2. Load 32-byte word from memory - // 3. Apply 20-byte mask to obtain address - result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff) - } - return result; - } - - /// @dev Writes an address into a specific position in a byte array. - /// @param b Byte array to insert address into. - /// @param index Index in byte array of address. - /// @param input Address to put into byte array. - function writeAddress( - bytes memory b, - uint256 index, - address input - ) - internal - pure - { - require( - b.length >= index + 20, // 20 is length of address - "GREATER_OR_EQUAL_TO_20_LENGTH_REQUIRED" - ); - - // Add offset to index: - // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index) - // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index) - index += 20; - - // Store address into array memory - assembly { - // The address occupies 20 bytes and mstore stores 32 bytes. - // First fetch the 32-byte word where we'll be storing the address, then - // apply a mask so we have only the bytes in the word that the address will not occupy. - // Then combine these bytes with the address and store the 32 bytes back to memory with mstore. - - // 1. Add index to address of bytes array - // 2. Load 32-byte word from memory - // 3. Apply 12-byte mask to obtain extra bytes occupying word of memory where we'll store the address - let neighbors := and( - mload(add(b, index)), - 0xffffffffffffffffffffffff0000000000000000000000000000000000000000 - ) - - // Make sure input address is clean. - // (Solidity does not guarantee this) - input := and(input, 0xffffffffffffffffffffffffffffffffffffffff) - - // Store the neighbors and address into memory - mstore(add(b, index), xor(input, neighbors)) - } - } - - /// @dev Reads a bytes32 value from a position in a byte array. - /// @param b Byte array containing a bytes32 value. - /// @param index Index in byte array of bytes32 value. - /// @return bytes32 value from byte array. - function readBytes32( - bytes memory b, - uint256 index - ) - internal - pure - returns (bytes32 result) - { - require( - b.length >= index + 32, - "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED" - ); - - // Arrays are prefixed by a 256 bit length parameter - index += 32; - - // Read the bytes32 from array memory - assembly { - result := mload(add(b, index)) - } - return result; - } - - /// @dev Writes a bytes32 into a specific position in a byte array. - /// @param b Byte array to insert into. - /// @param index Index in byte array of . - /// @param input bytes32 to put into byte array. - function writeBytes32( - bytes memory b, - uint256 index, - bytes32 input - ) - internal - pure - { - require( - b.length >= index + 32, - "GREATER_OR_EQUAL_TO_32_LENGTH_REQUIRED" - ); - - // Arrays are prefixed by a 256 bit length parameter - index += 32; - - // Read the bytes32 from array memory - assembly { - mstore(add(b, index), input) - } - } - - /// @dev Reads a uint256 value from a position in a byte array. - /// @param b Byte array containing a uint256 value. - /// @param index Index in byte array of uint256 value. - /// @return uint256 value from byte array. - function readUint256( - bytes memory b, - uint256 index - ) - internal - pure - returns (uint256 result) - { - result = uint256(readBytes32(b, index)); - return result; - } - - /// @dev Writes a uint256 into a specific position in a byte array. - /// @param b Byte array to insert into. - /// @param index Index in byte array of . - /// @param input uint256 to put into byte array. - function writeUint256( - bytes memory b, - uint256 index, - uint256 input - ) - internal - pure - { - writeBytes32(b, index, bytes32(input)); - } - - /// @dev Reads an unpadded bytes4 value from a position in a byte array. - /// @param b Byte array containing a bytes4 value. - /// @param index Index in byte array of bytes4 value. - /// @return bytes4 value from byte array. - function readBytes4( - bytes memory b, - uint256 index - ) - internal - pure - returns (bytes4 result) - { - require( - b.length >= index + 4, - "GREATER_OR_EQUAL_TO_4_LENGTH_REQUIRED" - ); - - // Arrays are prefixed by a 32 byte length field - index += 32; - - // Read the bytes4 from array memory - assembly { - result := mload(add(b, index)) - // Solidity does not require us to clean the trailing bytes. - // We do it anyway - result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000) - } - return result; - } - - /// @dev Reads nested bytes from a specific position. - /// @dev NOTE: the returned value overlaps with the input value. - /// Both should be treated as immutable. - /// @param b Byte array containing nested bytes. - /// @param index Index of nested bytes. - /// @return result Nested bytes. - function readBytesWithLength( - bytes memory b, - uint256 index - ) - internal - pure - returns (bytes memory result) - { - // Read length of nested bytes - uint256 nestedBytesLength = readUint256(b, index); - index += 32; - - // Assert length of is valid, given - // length of nested bytes - require( - b.length >= index + nestedBytesLength, - "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED" - ); - - // Return a pointer to the byte array as it exists inside `b` - assembly { - result := add(b, index) - } - return result; - } - - /// @dev Inserts bytes at a specific position in a byte array. - /// @param b Byte array to insert into. - /// @param index Index in byte array of . - /// @param input bytes to insert. - function writeBytesWithLength( - bytes memory b, - uint256 index, - bytes memory input - ) - internal - pure - { - // Assert length of is valid, given - // length of input - require( - b.length >= index + 32 + input.length, // 32 bytes to store length - "GREATER_OR_EQUAL_TO_NESTED_BYTES_LENGTH_REQUIRED" - ); - - // Copy into - memCopy( - b.contentAddress() + index, - input.rawAddress(), // includes length of - input.length + 32 // +32 bytes to store length - ); - } - - /// @dev Performs a deep copy of a byte array onto another byte array of greater than or equal length. - /// @param dest Byte array that will be overwritten with source bytes. - /// @param source Byte array to copy onto dest bytes. - function deepCopyBytes( - bytes memory dest, - bytes memory source - ) - internal - pure - { - uint256 sourceLen = source.length; - // Dest length must be >= source length, or some bytes would not be copied. - require( - dest.length >= sourceLen, - "GREATER_OR_EQUAL_TO_SOURCE_BYTES_LENGTH_REQUIRED" - ); - memCopy( - dest.contentAddress(), - source.contentAddress(), - sourceLen - ); - } -} diff --git a/contracts/utils/contracts/utils/Ownable.sol b/contracts/utils/contracts/utils/Ownable.sol new file mode 100644 index 000000000..f67f241a4 --- /dev/null +++ b/contracts/utils/contracts/utils/Ownable.sol @@ -0,0 +1,33 @@ +pragma solidity ^0.4.24; + +import "./interfaces/IOwnable.sol"; + + +contract Ownable is + IOwnable +{ + address public owner; + + constructor () + public + { + owner = msg.sender; + } + + modifier onlyOwner() { + require( + msg.sender == owner, + "ONLY_CONTRACT_OWNER" + ); + _; + } + + function transferOwnership(address newOwner) + public + onlyOwner + { + if (newOwner != address(0)) { + owner = newOwner; + } + } +} diff --git a/contracts/utils/contracts/utils/Ownable/IOwnable.sol b/contracts/utils/contracts/utils/Ownable/IOwnable.sol deleted file mode 100644 index c0cbfddfd..000000000 --- a/contracts/utils/contracts/utils/Ownable/IOwnable.sol +++ /dev/null @@ -1,8 +0,0 @@ -pragma solidity ^0.4.24; - - -contract IOwnable { - - function transferOwnership(address newOwner) - public; -} diff --git a/contracts/utils/contracts/utils/Ownable/Ownable.sol b/contracts/utils/contracts/utils/Ownable/Ownable.sol deleted file mode 100644 index aa74a72d2..000000000 --- a/contracts/utils/contracts/utils/Ownable/Ownable.sol +++ /dev/null @@ -1,33 +0,0 @@ -pragma solidity ^0.4.24; - -import "./IOwnable.sol"; - - -contract Ownable is - IOwnable -{ - address public owner; - - constructor () - public - { - owner = msg.sender; - } - - modifier onlyOwner() { - require( - msg.sender == owner, - "ONLY_CONTRACT_OWNER" - ); - _; - } - - function transferOwnership(address newOwner) - public - onlyOwner - { - if (newOwner != address(0)) { - owner = newOwner; - } - } -} diff --git a/contracts/utils/contracts/utils/ReentrancyGuard.sol b/contracts/utils/contracts/utils/ReentrancyGuard.sol new file mode 100644 index 000000000..1a02c88a4 --- /dev/null +++ b/contracts/utils/contracts/utils/ReentrancyGuard.sol @@ -0,0 +1,45 @@ +/* + + Copyright 2018 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.4.24; + + +contract ReentrancyGuard { + + // 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() { + // Ensure mutex is unlocked + require( + !locked, + "REENTRANCY_ILLEGAL" + ); + + // Lock mutex before function call + locked = true; + + // Perform function call + _; + + // Unlock mutex after function call + locked = false; + } +} diff --git a/contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol b/contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol deleted file mode 100644 index 1a02c88a4..000000000 --- a/contracts/utils/contracts/utils/ReentrancyGuard/ReentrancyGuard.sol +++ /dev/null @@ -1,45 +0,0 @@ -/* - - Copyright 2018 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.4.24; - - -contract ReentrancyGuard { - - // 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() { - // Ensure mutex is unlocked - require( - !locked, - "REENTRANCY_ILLEGAL" - ); - - // Lock mutex before function call - locked = true; - - // Perform function call - _; - - // Unlock mutex after function call - locked = false; - } -} diff --git a/contracts/utils/contracts/utils/SafeMath.sol b/contracts/utils/contracts/utils/SafeMath.sol new file mode 100644 index 000000000..d7a4a603e --- /dev/null +++ b/contracts/utils/contracts/utils/SafeMath.sol @@ -0,0 +1,87 @@ +pragma solidity ^0.4.24; + + +contract SafeMath { + + function safeMul(uint256 a, uint256 b) + internal + pure + returns (uint256) + { + if (a == 0) { + return 0; + } + uint256 c = a * b; + require( + c / a == b, + "UINT256_OVERFLOW" + ); + return c; + } + + function safeDiv(uint256 a, uint256 b) + internal + pure + returns (uint256) + { + uint256 c = a / b; + return c; + } + + function safeSub(uint256 a, uint256 b) + internal + pure + returns (uint256) + { + require( + b <= a, + "UINT256_UNDERFLOW" + ); + return a - b; + } + + function safeAdd(uint256 a, uint256 b) + internal + pure + returns (uint256) + { + uint256 c = a + b; + require( + c >= a, + "UINT256_OVERFLOW" + ); + return c; + } + + function max64(uint64 a, uint64 b) + internal + pure + returns (uint256) + { + return a >= b ? a : b; + } + + function min64(uint64 a, uint64 b) + internal + pure + returns (uint256) + { + return a < b ? a : b; + } + + 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; + } +} diff --git a/contracts/utils/contracts/utils/SafeMath/SafeMath.sol b/contracts/utils/contracts/utils/SafeMath/SafeMath.sol deleted file mode 100644 index d7a4a603e..000000000 --- a/contracts/utils/contracts/utils/SafeMath/SafeMath.sol +++ /dev/null @@ -1,87 +0,0 @@ -pragma solidity ^0.4.24; - - -contract SafeMath { - - function safeMul(uint256 a, uint256 b) - internal - pure - returns (uint256) - { - if (a == 0) { - return 0; - } - uint256 c = a * b; - require( - c / a == b, - "UINT256_OVERFLOW" - ); - return c; - } - - function safeDiv(uint256 a, uint256 b) - internal - pure - returns (uint256) - { - uint256 c = a / b; - return c; - } - - function safeSub(uint256 a, uint256 b) - internal - pure - returns (uint256) - { - require( - b <= a, - "UINT256_UNDERFLOW" - ); - return a - b; - } - - function safeAdd(uint256 a, uint256 b) - internal - pure - returns (uint256) - { - uint256 c = a + b; - require( - c >= a, - "UINT256_OVERFLOW" - ); - return c; - } - - function max64(uint64 a, uint64 b) - internal - pure - returns (uint256) - { - return a >= b ? a : b; - } - - function min64(uint64 a, uint64 b) - internal - pure - returns (uint256) - { - return a < b ? a : b; - } - - 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; - } -} diff --git a/contracts/utils/contracts/utils/interfaces/IOwnable.sol b/contracts/utils/contracts/utils/interfaces/IOwnable.sol new file mode 100644 index 000000000..c0cbfddfd --- /dev/null +++ b/contracts/utils/contracts/utils/interfaces/IOwnable.sol @@ -0,0 +1,8 @@ +pragma solidity ^0.4.24; + + +contract IOwnable { + + function transferOwnership(address newOwner) + public; +} -- cgit