diff --git a/contracts/staking/contracts/test/TestLibSafeDowncast.sol b/contracts/staking/contracts/test/TestLibSafeDowncast.sol new file mode 100644 index 0000000000..43d1bc8fce --- /dev/null +++ b/contracts/staking/contracts/test/TestLibSafeDowncast.sol @@ -0,0 +1,41 @@ +/* + + Copyright 2019 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity ^0.5.9; + +import "../src/libs/LibSafeDowncast.sol"; + + +contract TestLibSafeDowncast { + + function downcastToUint96(uint256 a) + external + pure + returns (uint96) + { + return LibSafeDowncast.downcastToUint96(a); + } + + function downcastToUint64(uint256 a) + external + pure + returns (uint64) + { + return LibSafeDowncast.downcastToUint64(a); + } +} diff --git a/contracts/staking/package.json b/contracts/staking/package.json index ecd2653581..2f545b94d8 100644 --- a/contracts/staking/package.json +++ b/contracts/staking/package.json @@ -37,7 +37,7 @@ }, "config": { "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./generated-artifacts/@(EthVault|IEthVault|IStaking|IStakingEvents|IStakingPoolRewardVault|IStakingProxy|IStorageInit|IStructs|IVaultCore|IZrxVault|LibFixedMath|LibFixedMathRichErrors|LibProxy|LibSafeDowncast|LibStakingRichErrors|MixinConstants|MixinDeploymentConstants|MixinEthVault|MixinExchangeFees|MixinExchangeManager|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolRewardVault|MixinStakingPoolRewards|MixinStorage|MixinVaultCore|MixinZrxVault|ReadOnlyProxy|Staking|StakingPoolRewardVault|StakingProxy|TestCobbDouglas|TestInitTarget|TestLibFixedMath|TestLibProxy|TestLibProxyReceiver|TestProtocolFees|TestProtocolFeesERC20Proxy|TestStaking|TestStakingProxy|TestStorageLayout|ZrxVault).json" + "abis": "./generated-artifacts/@(EthVault|IEthVault|IStaking|IStakingEvents|IStakingPoolRewardVault|IStakingProxy|IStorageInit|IStructs|IVaultCore|IZrxVault|LibFixedMath|LibFixedMathRichErrors|LibProxy|LibSafeDowncast|LibStakingRichErrors|MixinConstants|MixinDeploymentConstants|MixinEthVault|MixinExchangeFees|MixinExchangeManager|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolRewardVault|MixinStakingPoolRewards|MixinStorage|MixinVaultCore|MixinZrxVault|ReadOnlyProxy|Staking|StakingPoolRewardVault|StakingProxy|TestCobbDouglas|TestInitTarget|TestLibFixedMath|TestLibProxy|TestLibProxyReceiver|TestLibSafeDowncast|TestProtocolFees|TestProtocolFeesERC20Proxy|TestStaking|TestStakingProxy|TestStorageLayout|ZrxVault).json" }, "repository": { "type": "git", diff --git a/contracts/staking/src/artifacts.ts b/contracts/staking/src/artifacts.ts index 44a2d26f5d..81d40d7bac 100644 --- a/contracts/staking/src/artifacts.ts +++ b/contracts/staking/src/artifacts.ts @@ -45,6 +45,7 @@ import * as TestInitTarget from '../generated-artifacts/TestInitTarget.json'; import * as TestLibFixedMath from '../generated-artifacts/TestLibFixedMath.json'; import * as TestLibProxy from '../generated-artifacts/TestLibProxy.json'; import * as TestLibProxyReceiver from '../generated-artifacts/TestLibProxyReceiver.json'; +import * as TestLibSafeDowncast from '../generated-artifacts/TestLibSafeDowncast.json'; import * as TestProtocolFees from '../generated-artifacts/TestProtocolFees.json'; import * as TestProtocolFeesERC20Proxy from '../generated-artifacts/TestProtocolFeesERC20Proxy.json'; import * as TestStaking from '../generated-artifacts/TestStaking.json'; @@ -93,6 +94,7 @@ export const artifacts = { TestLibFixedMath: TestLibFixedMath as ContractArtifact, TestLibProxy: TestLibProxy as ContractArtifact, TestLibProxyReceiver: TestLibProxyReceiver as ContractArtifact, + TestLibSafeDowncast: TestLibSafeDowncast as ContractArtifact, TestProtocolFees: TestProtocolFees as ContractArtifact, TestProtocolFeesERC20Proxy: TestProtocolFeesERC20Proxy as ContractArtifact, TestStaking: TestStaking as ContractArtifact, diff --git a/contracts/staking/src/wrappers.ts b/contracts/staking/src/wrappers.ts index cd338d092d..7d5c94e6f7 100644 --- a/contracts/staking/src/wrappers.ts +++ b/contracts/staking/src/wrappers.ts @@ -43,6 +43,7 @@ export * from '../generated-wrappers/test_init_target'; export * from '../generated-wrappers/test_lib_fixed_math'; export * from '../generated-wrappers/test_lib_proxy'; export * from '../generated-wrappers/test_lib_proxy_receiver'; +export * from '../generated-wrappers/test_lib_safe_downcast'; export * from '../generated-wrappers/test_protocol_fees'; export * from '../generated-wrappers/test_protocol_fees_erc20_proxy'; export * from '../generated-wrappers/test_staking'; diff --git a/contracts/staking/test/unit_tests/lib_proxy_unit_test.ts b/contracts/staking/test/unit_tests/lib_proxy_unit_test.ts index d3595fd94e..a967a4528a 100644 --- a/contracts/staking/test/unit_tests/lib_proxy_unit_test.ts +++ b/contracts/staking/test/unit_tests/lib_proxy_unit_test.ts @@ -11,7 +11,7 @@ import { StakingRevertErrors } from '@0x/order-utils'; import { artifacts, TestLibProxyContract, TestLibProxyReceiverContract } from '../../src'; -blockchainTests.resets.only('LibProxy', env => { +blockchainTests.resets('LibProxy', env => { let proxy: TestLibProxyContract; let receiver: TestLibProxyReceiverContract; diff --git a/contracts/staking/test/unit_tests/lib_safe_downcast_test.ts b/contracts/staking/test/unit_tests/lib_safe_downcast_test.ts new file mode 100644 index 0000000000..359450e29b --- /dev/null +++ b/contracts/staking/test/unit_tests/lib_safe_downcast_test.ts @@ -0,0 +1,83 @@ +import { blockchainTests, expect, Numberish } from '@0x/contracts-test-utils'; +import { BigNumber, SafeMathRevertErrors } from '@0x/utils'; + +import { artifacts, TestLibSafeDowncastContract } from '../../src/'; + +blockchainTests('LibSafeDowncast', env => { + let testContract: TestLibSafeDowncastContract; + + before(async () => { + testContract = await TestLibSafeDowncastContract.deployFrom0xArtifactAsync( + artifacts.TestLibSafeDowncast, + env.provider, + env.txDefaults, + artifacts, + ); + }); + + const MAX_UINT_64 = new BigNumber(2).pow(64).minus(1); + const MAX_UINT_96 = new BigNumber(2).pow(96).minus(1); + const MAX_UINT_256 = new BigNumber(2).pow(256).minus(1); + + describe('downcastToUint96', () => { + async function verifyCorrectDowncastAsync(n: Numberish): Promise { + const actual = await testContract.downcastToUint96.callAsync(new BigNumber(n)); + expect(actual).to.bignumber.eq(n); + } + function toDowncastError(n: Numberish): SafeMathRevertErrors.Uint256DowncastError { + return new SafeMathRevertErrors.Uint256DowncastError( + SafeMathRevertErrors.DowncastErrorCodes.ValueTooLargeToDowncastToUint96, + new BigNumber(n), + ); + } + + it('correctly downcasts 0', async () => { + return verifyCorrectDowncastAsync(0); + }); + it('correctly downcasts 1337', async () => { + return verifyCorrectDowncastAsync(1337); + }); + it('correctly downcasts MAX_UINT_96', async () => { + return verifyCorrectDowncastAsync(MAX_UINT_96); + }); + it('reverts on MAX_UINT_96 + 1', async () => { + const n = MAX_UINT_96.plus(1); + return expect(verifyCorrectDowncastAsync(n)).to.revertWith(toDowncastError(n)); + }); + it('reverts on MAX_UINT_256', async () => { + const n = MAX_UINT_256; + return expect(verifyCorrectDowncastAsync(n)).to.revertWith(toDowncastError(n)); + }); + }); + + describe('downcastToUint64', () => { + async function verifyCorrectDowncastAsync(n: Numberish): Promise { + const actual = await testContract.downcastToUint64.callAsync(new BigNumber(n)); + expect(actual).to.bignumber.eq(n); + } + function toDowncastError(n: Numberish): SafeMathRevertErrors.Uint256DowncastError { + return new SafeMathRevertErrors.Uint256DowncastError( + SafeMathRevertErrors.DowncastErrorCodes.ValueTooLargeToDowncastToUint64, + new BigNumber(n), + ); + } + + it('correctly downcasts 0', async () => { + return verifyCorrectDowncastAsync(0); + }); + it('correctly downcasts 1337', async () => { + return verifyCorrectDowncastAsync(1337); + }); + it('correctly downcasts MAX_UINT_64', async () => { + return verifyCorrectDowncastAsync(MAX_UINT_64); + }); + it('reverts on MAX_UINT_64 + 1', async () => { + const n = MAX_UINT_64.plus(1); + return expect(verifyCorrectDowncastAsync(n)).to.revertWith(toDowncastError(n)); + }); + it('reverts on MAX_UINT_256', async () => { + const n = MAX_UINT_256; + return expect(verifyCorrectDowncastAsync(n)).to.revertWith(toDowncastError(n)); + }); + }); +}); diff --git a/contracts/staking/test/utils/constants.ts b/contracts/staking/test/utils/constants.ts index e7221d63e6..3093a86623 100644 --- a/contracts/staking/test/utils/constants.ts +++ b/contracts/staking/test/utils/constants.ts @@ -3,7 +3,6 @@ import { BigNumber } from '@0x/utils'; const TWO_WEEKS = 14 * 24 * 60 * 60; export const constants = { - MAX_UINT_64: new BigNumber(2).pow(256).minus(1), TOKEN_MULTIPLIER: testConstants.DUMMY_TOKEN_DECIMALS, INITIAL_POOL_ID: '0x0000000000000000000000000000000100000000000000000000000000000000', SECOND_POOL_ID: '0x0000000000000000000000000000000200000000000000000000000000000000', diff --git a/contracts/staking/tsconfig.json b/contracts/staking/tsconfig.json index d4b56977a6..fd993162f4 100644 --- a/contracts/staking/tsconfig.json +++ b/contracts/staking/tsconfig.json @@ -43,6 +43,7 @@ "generated-artifacts/TestLibFixedMath.json", "generated-artifacts/TestLibProxy.json", "generated-artifacts/TestLibProxyReceiver.json", + "generated-artifacts/TestLibSafeDowncast.json", "generated-artifacts/TestProtocolFees.json", "generated-artifacts/TestProtocolFeesERC20Proxy.json", "generated-artifacts/TestStaking.json",