diff --git a/contracts/solidity/cryptomath/Arithmetic.sol b/contracts/solidity/cryptomath/Arithmetic.sol new file mode 100644 index 000000000..a348b1cea --- /dev/null +++ b/contracts/solidity/cryptomath/Arithmetic.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +contract Arithmetic { + string public name = "Arithmetic"; + uint256 maxUint = type(uint256).max; + uint256 minUint = type(uint256).min; + + function checkName() external view returns (string memory){ + return name; + } + + function add() external { + name = "Arithmetic check if NOT reverted"; + maxUint = maxUint + 1; + } + + function add2() external { + uint256 tmp = maxUint; + name = "Arithmetic check if NOT reverted"; + tmp += 100; + } + + function mul() external { + uint8 maxUint8 = type(uint8).max; + name = "Arithmetic check if NOT reverted"; + maxUint8 * 2; + } + + function dec() external { + // This subtraction will revert on underflow. + name = "Arithmetic check if NOT reverted"; + minUint--; + } + + function sub() external { + uint256 tmp = minUint; + name = "Arithmetic check if NOT reverted"; + tmp -= 1; + } + + function negativeHasMoreValues() external { + int tmp; + int x = type(int).min; + name = "Arithmetic check if NOT reverted"; + tmp = -x; + } + + function uncheckedAdd() external view returns (bool) { + unchecked { + uint256 tmp; + tmp = maxUint + 1; + + return true; + } + } + + function uncheckedSub() external view returns (bool) { + unchecked { + uint256 tmp = minUint; + tmp -= 1; + + return true; + } + } + +} diff --git a/test/constants.js b/test/constants.js index ac78e8e25..0380eabfb 100644 --- a/test/constants.js +++ b/test/constants.js @@ -112,6 +112,7 @@ const Contract = { FunctionsChild: 'FunctionsChild', FunctionsParent: 'FunctionsParent', Scoping: 'Scoping', + Arithmetic: "Arithmetic" } const CALL_EXCEPTION = 'CALL_EXCEPTION' diff --git a/test/solidity/cryptomath/CryptoMath.js b/test/solidity/cryptomath/CryptoMath.js index a94c304b8..0c4b5df43 100644 --- a/test/solidity/cryptomath/CryptoMath.js +++ b/test/solidity/cryptomath/CryptoMath.js @@ -24,7 +24,6 @@ const Constants = require('../../constants') describe('@solidityevmequiv1 CryptoMath Test Suite', function () { let cryptoMathContract, provider, signers; - before(async function () { signers = await ethers.getSigners(); provider = ethers.getDefaultProvider(); diff --git a/test/solidity/cryptomath/arithmetic.js b/test/solidity/cryptomath/arithmetic.js new file mode 100644 index 000000000..2f0f0c43b --- /dev/null +++ b/test/solidity/cryptomath/arithmetic.js @@ -0,0 +1,126 @@ +/*- + * + * Hedera Smart Contracts + * + * Copyright (C) 2023 Hedera Hashgraph, LLC + * + * 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. + * + */ +const { expect } = require('chai') +const { ethers } = require('hardhat') +const Constants = require('../../constants') + +describe('Arithmetic Test Suite', function () { + let contract; + + before(async function () { + const factory = await ethers.getContractFactory(Constants.Contract.Arithmetic) + contract = await factory.deploy() + }); + + it('it should confirm solidity functionality: Arithmetic, checked overflow - confirm revert add', async function () { + let hasError = false; + try { + const res = await contract.add() + await res.wait() + } catch (error) { + hasError = true; + expect(error).to.exist + const name = await contract.checkName() + expect(name).to.equal('Arithmetic') + } + expect(hasError).to.be.true; + }); + + it('it should confirm solidity functionality: Arithmetic, checked overflow - confirm revert add2', async function () { + let hasError = false; + try { + const res = await contract.add2() + await res.wait() + } catch (error) { + hasError = true; + expect(error).to.exist + const name = await contract.checkName() + expect(name).to.equal('Arithmetic') + } + expect(hasError).to.be.true; + }); + + it('it should confirm solidity functionality: Arithmetic, checked overflow - confirm revert mul', async function () { + let hasError = false; + try { + const res = await contract.mul() + await res.wait() + } catch (error) { + hasError = true; + expect(error).to.exist + const name = await contract.checkName() + expect(name).to.equal('Arithmetic') + } + expect(hasError).to.be.true; + }); + + it('it should confirm solidity functionality: Arithmetic, checked underflow - confirm revert sub', async function () { + let hasError = false; + try { + const res = await contract.sub() + await res.wait() + } catch (error) { + hasError = true; + expect(error).to.exist + const name = await contract.checkName() + expect(name).to.equal('Arithmetic') + } + expect(hasError).to.be.true; + }); + + it('it should confirm solidity functionality: Arithmetic, checked underflow - confirm revert dec', async function () { + let hasError = false; + try { + const res = await contract.dec() + await res.wait() + } catch (error) { + hasError = true; + expect(error).to.exist + const name = await contract.checkName() + expect(name).to.equal('Arithmetic') + } + expect(hasError).to.be.true; + }); + + it('it should confirm solidity functionality: Arithmetic, checked underflow - confirm revert negativeHasMoreValues', async function () { + let hasError = false; + try { + const res = await contract.negativeHasMoreValues() + await res.wait() + } catch (error) { + hasError = true; + expect(error).to.exist + const name = await contract.checkName() + expect(name).to.equal('Arithmetic') + } + expect(hasError).to.be.true; + }); + + it('it should confirm solidity functionality: Arithmetic, unchecked overflow - confirm wrap uncheckedAdd', async function () { + const res = await contract.uncheckedAdd() + expect(res).to.be.true + }); + + it('it should confirm solidity functionality: Arithmetic, unchecked underflow - confirm wrap uncheckedSub', async function () { + const res = await contract.uncheckedSub() + expect(res).to.be.true + }); + +}) diff --git a/utils/helpers.js b/utils/helpers.js index 17eb5254d..b334af79f 100644 --- a/utils/helpers.js +++ b/utils/helpers.js @@ -102,7 +102,7 @@ const pollForNewERC721Owner = async(erc721Contract, tokenId, ownerBefore) => { return ownerAfter; // Ownership changed } - delay(); + await delay(); } throw new Error(`Ownership did not change after ${process.env.MAX_RETRY} tries`); @@ -132,7 +132,7 @@ const pollForNewERC721HollowWalletOwner = async(erc721Contract, nftTokenAddress, return ownerAfter; // Ownership changed } - delay(); + await delay(); } throw new Error(`Ownership did not change after ${process.env.MAX_RETRY} tries`); @@ -162,7 +162,7 @@ const pollForNewHollowWalletBalance = async (provider, walletAddress, balanceBef return balanceAfter; // Balance changed } - delay(); + await delay(); } throw new Error(`Failed to get a different balance value after ${process.env.MAX_RETRY} tries`);