diff --git a/forge-cache/solidity-files-cache.json b/forge-cache/solidity-files-cache.json index 450e488..67f7e2e 100644 --- a/forge-cache/solidity-files-cache.json +++ b/forge-cache/solidity-files-cache.json @@ -1 +1 @@ -{"_format":"ethers-rs-sol-cache-3","paths":{"artifacts":"out","build_infos":"out/build-info","sources":"contracts","tests":"contracts/tests","scripts":"script","libraries":["lib","node_modules"]},"files":{"contracts/Babylonian.sol":{"lastModificationDate":1701586212381,"contentHash":"bd18f618a3c820d4623d7a8e3bddbe63","sourceName":"contracts/Babylonian.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":"=0.8.23","artifacts":{"Babylonian":{"0.8.23+commit.f704f362.Darwin.appleclang":"Babylonian.sol/Babylonian.json"}}},"contracts/CodeCheck.sol":{"lastModificationDate":1701590282246,"contentHash":"3d8f68b63eb9430789c1288d982b07bf","sourceName":"contracts/CodeCheck.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol","contracts/SimpleFarm.sol","contracts/TokenWrapper.sol"],"versionRequirement":"=0.8.23","artifacts":{"FarmCodeCheck":{"0.8.23+commit.f704f362.Darwin.appleclang":"CodeCheck.sol/FarmCodeCheck.json"}}},"contracts/Counter.sol":{"lastModificationDate":1701590282246,"contentHash":"c83e6a3311a087bd294d46cd309a9f0d","sourceName":"contracts/Counter.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":"=0.8.23","artifacts":{"Counter":{"0.8.23+commit.f704f362.Darwin.appleclang":"Counter.sol/Counter.json"}}},"contracts/Counter.t.sol":{"lastModificationDate":1701590282247,"contentHash":"15c0313dc392f31e0a33349fb5973926","sourceName":"contracts/Counter.t.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Counter.sol","lib/forge-std/lib/ds-test/src/test.sol","lib/forge-std/src/Base.sol","lib/forge-std/src/StdAssertions.sol","lib/forge-std/src/StdChains.sol","lib/forge-std/src/StdCheats.sol","lib/forge-std/src/StdError.sol","lib/forge-std/src/StdInvariant.sol","lib/forge-std/src/StdJson.sol","lib/forge-std/src/StdMath.sol","lib/forge-std/src/StdStorage.sol","lib/forge-std/src/StdStyle.sol","lib/forge-std/src/StdUtils.sol","lib/forge-std/src/Test.sol","lib/forge-std/src/Vm.sol","lib/forge-std/src/console.sol","lib/forge-std/src/console2.sol","lib/forge-std/src/interfaces/IMulticall3.sol","lib/forge-std/src/safeconsole.sol"],"versionRequirement":"=0.8.23","artifacts":{"CounterTest":{"0.8.23+commit.f704f362.Darwin.appleclang":"Counter.t.sol/CounterTest.json"}}},"contracts/IERC20.sol":{"lastModificationDate":1701590282247,"contentHash":"6c9fb0a691cd823570d0e46ad59d66fa","sourceName":"contracts/IERC20.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":"=0.8.23","artifacts":{"IERC20":{"0.8.23+commit.f704f362.Darwin.appleclang":"IERC20.sol/IERC20.json"}}},"contracts/PrivateFarm2X.sol":{"lastModificationDate":1701590282247,"contentHash":"3fc72246617d4e6d4cf1b05cb13b2dc8","sourceName":"contracts/PrivateFarm2X.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol","contracts/TokenWrapper.sol"],"versionRequirement":"=0.8.23","artifacts":{"PrivateFarm2X":{"0.8.23+commit.f704f362.Darwin.appleclang":"PrivateFarm2X.sol/PrivateFarm2X.json"}}},"contracts/PrivateFarm2X.t.sol":{"lastModificationDate":1701590282247,"contentHash":"1e4f601265144ec409bbcb4484940e5a","sourceName":"contracts/PrivateFarm2X.t.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/PrivateFarm2X.sol","contracts/SafeERC20.sol","contracts/TokenWrapper.sol","lib/forge-std/lib/ds-test/src/test.sol","lib/forge-std/src/Base.sol","lib/forge-std/src/StdAssertions.sol","lib/forge-std/src/StdChains.sol","lib/forge-std/src/StdCheats.sol","lib/forge-std/src/StdError.sol","lib/forge-std/src/StdInvariant.sol","lib/forge-std/src/StdJson.sol","lib/forge-std/src/StdMath.sol","lib/forge-std/src/StdStorage.sol","lib/forge-std/src/StdStyle.sol","lib/forge-std/src/StdUtils.sol","lib/forge-std/src/Test.sol","lib/forge-std/src/Vm.sol","lib/forge-std/src/console.sol","lib/forge-std/src/console2.sol","lib/forge-std/src/interfaces/IMulticall3.sol","lib/forge-std/src/safeconsole.sol"],"versionRequirement":"=0.8.23","artifacts":{"PrivateFarmTest":{"0.8.23+commit.f704f362.Darwin.appleclang":"PrivateFarm2X.t.sol/PrivateFarmTest.json"}}},"contracts/SafeERC20.sol":{"lastModificationDate":1701586212399,"contentHash":"8e8f737fe9e711fc49002753702d837d","sourceName":"contracts/SafeERC20.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/IERC20.sol"],"versionRequirement":"=0.8.23","artifacts":{"SafeERC20":{"0.8.23+commit.f704f362.Darwin.appleclang":"SafeERC20.sol/SafeERC20.json"}}},"contracts/SimpleFarm.sol":{"lastModificationDate":1701590282248,"contentHash":"eb01d8814dd6b360acb6065de01ee8c1","sourceName":"contracts/SimpleFarm.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol","contracts/TokenWrapper.sol"],"versionRequirement":"=0.8.23","artifacts":{"SimpleFarm":{"0.8.23+commit.f704f362.Darwin.appleclang":"SimpleFarm.sol/SimpleFarm.json"}}},"contracts/SimpleFarm2X.sol":{"lastModificationDate":1701590282248,"contentHash":"4a754572073852b71395ce40b9c2df21","sourceName":"contracts/SimpleFarm2X.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol","contracts/TokenWrapper.sol"],"versionRequirement":"=0.8.23","artifacts":{"SimpleFarm2X":{"0.8.23+commit.f704f362.Darwin.appleclang":"SimpleFarm2X.sol/SimpleFarm2X.json"}}},"contracts/SimpleManager.sol":{"lastModificationDate":1701586212366,"contentHash":"fbaa8375b6727f142c1e65c06db072a5","sourceName":"contracts/SimpleManager.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":"=0.8.23","artifacts":{"IERC20":{"0.8.23+commit.f704f362.Darwin.appleclang":"SimpleManager.sol/IERC20.json"},"ISimpleFarm":{"0.8.23+commit.f704f362.Darwin.appleclang":"SimpleManager.sol/ISimpleFarm.json"},"SimpleManager":{"0.8.23+commit.f704f362.Darwin.appleclang":"SimpleManager.sol/SimpleManager.json"}}},"contracts/TestToken.sol":{"lastModificationDate":1701586212381,"contentHash":"d078a2df587236839ffc49d8635b6aec","sourceName":"contracts/TestToken.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":"=0.8.23","artifacts":{"TestToken":{"0.8.23+commit.f704f362.Darwin.appleclang":"TestToken.sol/TestToken.json"}}},"contracts/TimeLockFarm.sol":{"lastModificationDate":1701590282249,"contentHash":"1accbdbc1b709c31ccec6dc0800e5100","sourceName":"contracts/TimeLockFarm.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol","contracts/TokenWrapper.sol"],"versionRequirement":"=0.8.23","artifacts":{"TimeLockFarm":{"0.8.23+commit.f704f362.Darwin.appleclang":"TimeLockFarm.sol/TimeLockFarm.json"}}},"contracts/TimeLockFarmV2.sol":{"lastModificationDate":1701590282249,"contentHash":"fa7bc8b1c708f15f3d08ae43f0dd935f","sourceName":"contracts/TimeLockFarmV2.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol","contracts/TokenWrapper.sol"],"versionRequirement":"=0.8.23","artifacts":{"TimeLockFarmV2":{"0.8.23+commit.f704f362.Darwin.appleclang":"TimeLockFarmV2.sol/TimeLockFarmV2.json"}}},"contracts/TokenWrapper.sol":{"lastModificationDate":1701586212368,"contentHash":"765791087955f31cc0623591b2b5ec40","sourceName":"contracts/TokenWrapper.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol"],"versionRequirement":"=0.8.23","artifacts":{"TokenWrapper":{"0.8.23+commit.f704f362.Darwin.appleclang":"TokenWrapper.sol/TokenWrapper.json"}}},"lib/forge-std/lib/ds-test/src/test.sol":{"lastModificationDate":1698510340910,"contentHash":"9febff9d09f18af5306669dc276c4c43","sourceName":"lib/forge-std/lib/ds-test/src/test.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.5.0","artifacts":{"DSTest":{"0.8.23+commit.f704f362.Darwin.appleclang":"test.sol/DSTest.json"}}},"lib/forge-std/src/Base.sol":{"lastModificationDate":1698510340911,"contentHash":"ee13c050b1914464f1d3f90cde90204b","sourceName":"lib/forge-std/src/Base.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/StdStorage.sol","lib/forge-std/src/Vm.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"CommonBase":{"0.8.23+commit.f704f362.Darwin.appleclang":"Base.sol/CommonBase.json"},"ScriptBase":{"0.8.23+commit.f704f362.Darwin.appleclang":"Base.sol/ScriptBase.json"},"TestBase":{"0.8.23+commit.f704f362.Darwin.appleclang":"Base.sol/TestBase.json"}}},"lib/forge-std/src/Script.sol":{"lastModificationDate":1701590282252,"contentHash":"a8896f13ebff9ed23cce0fcb7f8f1984","sourceName":"lib/forge-std/src/Script.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Base.sol","lib/forge-std/src/StdChains.sol","lib/forge-std/src/StdCheats.sol","lib/forge-std/src/StdJson.sol","lib/forge-std/src/StdMath.sol","lib/forge-std/src/StdStorage.sol","lib/forge-std/src/StdStyle.sol","lib/forge-std/src/StdUtils.sol","lib/forge-std/src/Vm.sol","lib/forge-std/src/console.sol","lib/forge-std/src/console2.sol","lib/forge-std/src/interfaces/IMulticall3.sol","lib/forge-std/src/safeconsole.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"Script":{"0.8.23+commit.f704f362.Darwin.appleclang":"Script.sol/Script.json"}}},"lib/forge-std/src/StdAssertions.sol":{"lastModificationDate":1701590282253,"contentHash":"63f205c799095f747b34a55be19922d5","sourceName":"lib/forge-std/src/StdAssertions.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/lib/ds-test/src/test.sol","lib/forge-std/src/StdMath.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"StdAssertions":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdAssertions.sol/StdAssertions.json"}}},"lib/forge-std/src/StdChains.sol":{"lastModificationDate":1698510340911,"contentHash":"aff0685683a41d8e314d64aef646fe6f","sourceName":"lib/forge-std/src/StdChains.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Vm.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"StdChains":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdChains.sol/StdChains.json"}}},"lib/forge-std/src/StdCheats.sol":{"lastModificationDate":1698510340912,"contentHash":"27745bb24c5568c75c3043277ee18bcb","sourceName":"lib/forge-std/src/StdCheats.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/StdStorage.sol","lib/forge-std/src/Vm.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"StdCheats":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdCheats.sol/StdCheats.json"},"StdCheatsSafe":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdCheats.sol/StdCheatsSafe.json"}}},"lib/forge-std/src/StdError.sol":{"lastModificationDate":1698510340913,"contentHash":"64c896e1276a291776e5ea5aecb3870a","sourceName":"lib/forge-std/src/StdError.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"stdError":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdError.sol/stdError.json"}}},"lib/forge-std/src/StdInvariant.sol":{"lastModificationDate":1698510340913,"contentHash":"6d12d54c05754ad4e03066726dca3a84","sourceName":"lib/forge-std/src/StdInvariant.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"StdInvariant":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdInvariant.sol/StdInvariant.json"}}},"lib/forge-std/src/StdJson.sol":{"lastModificationDate":1698510340913,"contentHash":"2e1d13674e152408867795362d833c24","sourceName":"lib/forge-std/src/StdJson.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Vm.sol"],"versionRequirement":">=0.6.0, <0.9.0","artifacts":{"stdJson":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdJson.sol/stdJson.json"}}},"lib/forge-std/src/StdMath.sol":{"lastModificationDate":1698510340913,"contentHash":"9da8f453eba6bb98f3d75bc6822bfb29","sourceName":"lib/forge-std/src/StdMath.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"stdMath":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdMath.sol/stdMath.json"}}},"lib/forge-std/src/StdStorage.sol":{"lastModificationDate":1698510340913,"contentHash":"4fc0ff0cb196a405e5a4c9fa1c6acccb","sourceName":"lib/forge-std/src/StdStorage.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Vm.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"stdStorage":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdStorage.sol/stdStorage.json"},"stdStorageSafe":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdStorage.sol/stdStorageSafe.json"}}},"lib/forge-std/src/StdStyle.sol":{"lastModificationDate":1698510340914,"contentHash":"6281165a12aa639705c691fccefd855e","sourceName":"lib/forge-std/src/StdStyle.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Vm.sol"],"versionRequirement":">=0.4.22, <0.9.0","artifacts":{"StdStyle":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdStyle.sol/StdStyle.json"}}},"lib/forge-std/src/StdUtils.sol":{"lastModificationDate":1698510340914,"contentHash":"3255e5d80b9b77eb0880890ff827fda2","sourceName":"lib/forge-std/src/StdUtils.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Vm.sol","lib/forge-std/src/interfaces/IMulticall3.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"StdUtils":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdUtils.sol/StdUtils.json"}}},"lib/forge-std/src/Test.sol":{"lastModificationDate":1701590282255,"contentHash":"19f6346af0ea03c20ac5399cba7c4c62","sourceName":"lib/forge-std/src/Test.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/lib/ds-test/src/test.sol","lib/forge-std/src/Base.sol","lib/forge-std/src/StdAssertions.sol","lib/forge-std/src/StdChains.sol","lib/forge-std/src/StdCheats.sol","lib/forge-std/src/StdError.sol","lib/forge-std/src/StdInvariant.sol","lib/forge-std/src/StdJson.sol","lib/forge-std/src/StdMath.sol","lib/forge-std/src/StdStorage.sol","lib/forge-std/src/StdStyle.sol","lib/forge-std/src/StdUtils.sol","lib/forge-std/src/Vm.sol","lib/forge-std/src/console.sol","lib/forge-std/src/console2.sol","lib/forge-std/src/interfaces/IMulticall3.sol","lib/forge-std/src/safeconsole.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"Test":{"0.8.23+commit.f704f362.Darwin.appleclang":"Test.sol/Test.json"}}},"lib/forge-std/src/Vm.sol":{"lastModificationDate":1698510340914,"contentHash":"b098c2721502365797aae8d0ee1babb8","sourceName":"lib/forge-std/src/Vm.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"Vm":{"0.8.23+commit.f704f362.Darwin.appleclang":"Vm.sol/Vm.json"},"VmSafe":{"0.8.23+commit.f704f362.Darwin.appleclang":"Vm.sol/VmSafe.json"}}},"lib/forge-std/src/console.sol":{"lastModificationDate":1698510340915,"contentHash":"100b8a33b917da1147740d7ab8b0ded3","sourceName":"lib/forge-std/src/console.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.4.22, <0.9.0","artifacts":{"console":{"0.8.23+commit.f704f362.Darwin.appleclang":"console.sol/console.json"}}},"lib/forge-std/src/console2.sol":{"lastModificationDate":1698510340916,"contentHash":"491ca717c1915995e78cc361485a3067","sourceName":"lib/forge-std/src/console2.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.4.22, <0.9.0","artifacts":{"console2":{"0.8.23+commit.f704f362.Darwin.appleclang":"console2.sol/console2.json"}}},"lib/forge-std/src/interfaces/IMulticall3.sol":{"lastModificationDate":1698510340918,"contentHash":"7b131ca1ca32ef6378b7b9ad5488b901","sourceName":"lib/forge-std/src/interfaces/IMulticall3.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"IMulticall3":{"0.8.23+commit.f704f362.Darwin.appleclang":"IMulticall3.sol/IMulticall3.json"}}},"lib/forge-std/src/safeconsole.sol":{"lastModificationDate":1698510340919,"contentHash":"ac3b1bf5a444db5db3656021830258a8","sourceName":"lib/forge-std/src/safeconsole.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"safeconsole":{"0.8.23+commit.f704f362.Darwin.appleclang":"safeconsole.sol/safeconsole.json"}}},"script/Counter.s.sol":{"lastModificationDate":1701590282315,"contentHash":"7539680fbd3ad49c6632713cc2bb6bf6","sourceName":"script/Counter.s.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Base.sol","lib/forge-std/src/Script.sol","lib/forge-std/src/StdChains.sol","lib/forge-std/src/StdCheats.sol","lib/forge-std/src/StdJson.sol","lib/forge-std/src/StdMath.sol","lib/forge-std/src/StdStorage.sol","lib/forge-std/src/StdStyle.sol","lib/forge-std/src/StdUtils.sol","lib/forge-std/src/Vm.sol","lib/forge-std/src/console.sol","lib/forge-std/src/console2.sol","lib/forge-std/src/interfaces/IMulticall3.sol","lib/forge-std/src/safeconsole.sol"],"versionRequirement":"^0.8.13","artifacts":{"CounterScript":{"0.8.23+commit.f704f362.Darwin.appleclang":"Counter.s.sol/CounterScript.json"}}}}} \ No newline at end of file +{"_format":"ethers-rs-sol-cache-3","paths":{"artifacts":"out","build_infos":"out/build-info","sources":"contracts","tests":"contracts/tests","scripts":"script","libraries":["lib","node_modules"]},"files":{"contracts/Babylonian.sol":{"lastModificationDate":1701586212381,"contentHash":"bd18f618a3c820d4623d7a8e3bddbe63","sourceName":"contracts/Babylonian.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":"=0.8.23","artifacts":{"Babylonian":{"0.8.23+commit.f704f362.Darwin.appleclang":"Babylonian.sol/Babylonian.json"}}},"contracts/CodeCheck.sol":{"lastModificationDate":1701590282246,"contentHash":"3d8f68b63eb9430789c1288d982b07bf","sourceName":"contracts/CodeCheck.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol","contracts/SimpleFarm.sol","contracts/TokenWrapper.sol"],"versionRequirement":"=0.8.23","artifacts":{"FarmCodeCheck":{"0.8.23+commit.f704f362.Darwin.appleclang":"CodeCheck.sol/FarmCodeCheck.json"}}},"contracts/Counter.sol":{"lastModificationDate":1701590282246,"contentHash":"c83e6a3311a087bd294d46cd309a9f0d","sourceName":"contracts/Counter.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":"=0.8.23","artifacts":{"Counter":{"0.8.23+commit.f704f362.Darwin.appleclang":"Counter.sol/Counter.json"}}},"contracts/Counter.t.sol":{"lastModificationDate":1701591368089,"contentHash":"70e9b8c7535152412af5e3882b276b2e","sourceName":"contracts/Counter.t.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Counter.sol","lib/forge-std/lib/ds-test/src/test.sol","lib/forge-std/src/Base.sol","lib/forge-std/src/StdAssertions.sol","lib/forge-std/src/StdChains.sol","lib/forge-std/src/StdCheats.sol","lib/forge-std/src/StdError.sol","lib/forge-std/src/StdInvariant.sol","lib/forge-std/src/StdJson.sol","lib/forge-std/src/StdMath.sol","lib/forge-std/src/StdStorage.sol","lib/forge-std/src/StdStyle.sol","lib/forge-std/src/StdUtils.sol","lib/forge-std/src/Test.sol","lib/forge-std/src/Vm.sol","lib/forge-std/src/console.sol","lib/forge-std/src/console2.sol","lib/forge-std/src/interfaces/IMulticall3.sol","lib/forge-std/src/safeconsole.sol"],"versionRequirement":"=0.8.23","artifacts":{"CounterTest":{"0.8.23+commit.f704f362.Darwin.appleclang":"Counter.t.sol/CounterTest.json"}}},"contracts/IERC20.sol":{"lastModificationDate":1701590282247,"contentHash":"6c9fb0a691cd823570d0e46ad59d66fa","sourceName":"contracts/IERC20.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":"=0.8.23","artifacts":{"IERC20":{"0.8.23+commit.f704f362.Darwin.appleclang":"IERC20.sol/IERC20.json"}}},"contracts/ManagerSetup.sol":{"lastModificationDate":1702616162660,"contentHash":"e46c8774fd4faafeff04f7befd5a4dba","sourceName":"contracts/ManagerSetup.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/IERC20.sol"],"versionRequirement":"=0.8.23","artifacts":{"ITimeLockFarmV2Dual":{"0.8.23+commit.f704f362.Darwin.appleclang":"ManagerSetup.sol/ITimeLockFarmV2Dual.json"},"ManagerSetup":{"0.8.23+commit.f704f362.Darwin.appleclang":"ManagerSetup.sol/ManagerSetup.json"}}},"contracts/PrivateFarm2X.sol":{"lastModificationDate":1701799380456,"contentHash":"729a55a9003f5130a28693f82d760a8b","sourceName":"contracts/PrivateFarm2X.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol","contracts/TokenWrapper.sol"],"versionRequirement":"=0.8.23","artifacts":{"PrivateFarm2X":{"0.8.23+commit.f704f362.Darwin.appleclang":"PrivateFarm2X.sol/PrivateFarm2X.json"}}},"contracts/PrivateFarm2X.t.sol":{"lastModificationDate":1701591637985,"contentHash":"80364ef9936ea2cad72315fb69133d9c","sourceName":"contracts/PrivateFarm2X.t.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/PrivateFarm2X.sol","contracts/SafeERC20.sol","contracts/TokenWrapper.sol","lib/forge-std/lib/ds-test/src/test.sol","lib/forge-std/src/Base.sol","lib/forge-std/src/StdAssertions.sol","lib/forge-std/src/StdChains.sol","lib/forge-std/src/StdCheats.sol","lib/forge-std/src/StdError.sol","lib/forge-std/src/StdInvariant.sol","lib/forge-std/src/StdJson.sol","lib/forge-std/src/StdMath.sol","lib/forge-std/src/StdStorage.sol","lib/forge-std/src/StdStyle.sol","lib/forge-std/src/StdUtils.sol","lib/forge-std/src/Test.sol","lib/forge-std/src/Vm.sol","lib/forge-std/src/console.sol","lib/forge-std/src/console2.sol","lib/forge-std/src/interfaces/IMulticall3.sol","lib/forge-std/src/safeconsole.sol"],"versionRequirement":"=0.8.23","artifacts":{"PrivateFarmTest":{"0.8.23+commit.f704f362.Darwin.appleclang":"PrivateFarm2X.t.sol/PrivateFarmTest.json"}}},"contracts/SafeERC20.sol":{"lastModificationDate":1701586212399,"contentHash":"8e8f737fe9e711fc49002753702d837d","sourceName":"contracts/SafeERC20.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/IERC20.sol"],"versionRequirement":"=0.8.23","artifacts":{"SafeERC20":{"0.8.23+commit.f704f362.Darwin.appleclang":"SafeERC20.sol/SafeERC20.json"}}},"contracts/SimpleFarm.sol":{"lastModificationDate":1701623259320,"contentHash":"f984160d62212ad98c6817b49093486f","sourceName":"contracts/SimpleFarm.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol","contracts/TokenWrapper.sol"],"versionRequirement":"=0.8.23","artifacts":{"SimpleFarm":{"0.8.23+commit.f704f362.Darwin.appleclang":"SimpleFarm.sol/SimpleFarm.json"}}},"contracts/SimpleFarm2X.sol":{"lastModificationDate":1701590282248,"contentHash":"4a754572073852b71395ce40b9c2df21","sourceName":"contracts/SimpleFarm2X.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol","contracts/TokenWrapper.sol"],"versionRequirement":"=0.8.23","artifacts":{"SimpleFarm2X":{"0.8.23+commit.f704f362.Darwin.appleclang":"SimpleFarm2X.sol/SimpleFarm2X.json"}}},"contracts/SimpleManager.sol":{"lastModificationDate":1701586212366,"contentHash":"fbaa8375b6727f142c1e65c06db072a5","sourceName":"contracts/SimpleManager.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":"=0.8.23","artifacts":{"IERC20":{"0.8.23+commit.f704f362.Darwin.appleclang":"SimpleManager.sol/IERC20.json"},"ISimpleFarm":{"0.8.23+commit.f704f362.Darwin.appleclang":"SimpleManager.sol/ISimpleFarm.json"},"SimpleManager":{"0.8.23+commit.f704f362.Darwin.appleclang":"SimpleManager.sol/SimpleManager.json"}}},"contracts/TestToken.sol":{"lastModificationDate":1701586212381,"contentHash":"d078a2df587236839ffc49d8635b6aec","sourceName":"contracts/TestToken.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":"=0.8.23","artifacts":{"TestToken":{"0.8.23+commit.f704f362.Darwin.appleclang":"TestToken.sol/TestToken.json"}}},"contracts/TimeLockFarm.sol":{"lastModificationDate":1701590282249,"contentHash":"1accbdbc1b709c31ccec6dc0800e5100","sourceName":"contracts/TimeLockFarm.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol","contracts/TokenWrapper.sol"],"versionRequirement":"=0.8.23","artifacts":{"TimeLockFarm":{"0.8.23+commit.f704f362.Darwin.appleclang":"TimeLockFarm.sol/TimeLockFarm.json"}}},"contracts/TimeLockFarmV2.sol":{"lastModificationDate":1701590282249,"contentHash":"fa7bc8b1c708f15f3d08ae43f0dd935f","sourceName":"contracts/TimeLockFarmV2.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol","contracts/TokenWrapper.sol"],"versionRequirement":"=0.8.23","artifacts":{"TimeLockFarmV2":{"0.8.23+commit.f704f362.Darwin.appleclang":"TimeLockFarmV2.sol/TimeLockFarmV2.json"}}},"contracts/TimeLockFarmV2Dual.sol":{"lastModificationDate":1702616408954,"contentHash":"f00f8af165a6992a1b054e35db928730","sourceName":"contracts/TimeLockFarmV2Dual.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol","contracts/TokenWrapper.sol"],"versionRequirement":"=0.8.23","artifacts":{"TimeLockFarmV2Dual":{"0.8.23+commit.f704f362.Darwin.appleclang":"TimeLockFarmV2Dual.sol/TimeLockFarmV2Dual.json"}}},"contracts/TokenWrapper.sol":{"lastModificationDate":1702464145710,"contentHash":"02ea81f13a2d0bf531d5ea71c2708309","sourceName":"contracts/TokenWrapper.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["contracts/Babylonian.sol","contracts/IERC20.sol","contracts/SafeERC20.sol"],"versionRequirement":"=0.8.23","artifacts":{"TokenWrapper":{"0.8.23+commit.f704f362.Darwin.appleclang":"TokenWrapper.sol/TokenWrapper.json"}}},"lib/forge-std/lib/ds-test/src/test.sol":{"lastModificationDate":1698510340910,"contentHash":"9febff9d09f18af5306669dc276c4c43","sourceName":"lib/forge-std/lib/ds-test/src/test.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.5.0","artifacts":{"DSTest":{"0.8.23+commit.f704f362.Darwin.appleclang":"test.sol/DSTest.json"}}},"lib/forge-std/src/Base.sol":{"lastModificationDate":1698510340911,"contentHash":"ee13c050b1914464f1d3f90cde90204b","sourceName":"lib/forge-std/src/Base.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/StdStorage.sol","lib/forge-std/src/Vm.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"CommonBase":{"0.8.23+commit.f704f362.Darwin.appleclang":"Base.sol/CommonBase.json"},"ScriptBase":{"0.8.23+commit.f704f362.Darwin.appleclang":"Base.sol/ScriptBase.json"},"TestBase":{"0.8.23+commit.f704f362.Darwin.appleclang":"Base.sol/TestBase.json"}}},"lib/forge-std/src/Script.sol":{"lastModificationDate":1701590282252,"contentHash":"a8896f13ebff9ed23cce0fcb7f8f1984","sourceName":"lib/forge-std/src/Script.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Base.sol","lib/forge-std/src/StdChains.sol","lib/forge-std/src/StdCheats.sol","lib/forge-std/src/StdJson.sol","lib/forge-std/src/StdMath.sol","lib/forge-std/src/StdStorage.sol","lib/forge-std/src/StdStyle.sol","lib/forge-std/src/StdUtils.sol","lib/forge-std/src/Vm.sol","lib/forge-std/src/console.sol","lib/forge-std/src/console2.sol","lib/forge-std/src/interfaces/IMulticall3.sol","lib/forge-std/src/safeconsole.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"Script":{"0.8.23+commit.f704f362.Darwin.appleclang":"Script.sol/Script.json"}}},"lib/forge-std/src/StdAssertions.sol":{"lastModificationDate":1701591736251,"contentHash":"6cc2858240bcd443debbbf075490e325","sourceName":"lib/forge-std/src/StdAssertions.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/lib/ds-test/src/test.sol","lib/forge-std/src/StdMath.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"StdAssertions":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdAssertions.sol/StdAssertions.json"}}},"lib/forge-std/src/StdChains.sol":{"lastModificationDate":1698510340911,"contentHash":"aff0685683a41d8e314d64aef646fe6f","sourceName":"lib/forge-std/src/StdChains.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Vm.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"StdChains":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdChains.sol/StdChains.json"}}},"lib/forge-std/src/StdCheats.sol":{"lastModificationDate":1698510340912,"contentHash":"27745bb24c5568c75c3043277ee18bcb","sourceName":"lib/forge-std/src/StdCheats.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/StdStorage.sol","lib/forge-std/src/Vm.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"StdCheats":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdCheats.sol/StdCheats.json"},"StdCheatsSafe":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdCheats.sol/StdCheatsSafe.json"}}},"lib/forge-std/src/StdError.sol":{"lastModificationDate":1698510340913,"contentHash":"64c896e1276a291776e5ea5aecb3870a","sourceName":"lib/forge-std/src/StdError.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"stdError":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdError.sol/stdError.json"}}},"lib/forge-std/src/StdInvariant.sol":{"lastModificationDate":1698510340913,"contentHash":"6d12d54c05754ad4e03066726dca3a84","sourceName":"lib/forge-std/src/StdInvariant.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"StdInvariant":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdInvariant.sol/StdInvariant.json"}}},"lib/forge-std/src/StdJson.sol":{"lastModificationDate":1698510340913,"contentHash":"2e1d13674e152408867795362d833c24","sourceName":"lib/forge-std/src/StdJson.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Vm.sol"],"versionRequirement":">=0.6.0, <0.9.0","artifacts":{"stdJson":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdJson.sol/stdJson.json"}}},"lib/forge-std/src/StdMath.sol":{"lastModificationDate":1698510340913,"contentHash":"9da8f453eba6bb98f3d75bc6822bfb29","sourceName":"lib/forge-std/src/StdMath.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"stdMath":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdMath.sol/stdMath.json"}}},"lib/forge-std/src/StdStorage.sol":{"lastModificationDate":1698510340913,"contentHash":"4fc0ff0cb196a405e5a4c9fa1c6acccb","sourceName":"lib/forge-std/src/StdStorage.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Vm.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"stdStorage":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdStorage.sol/stdStorage.json"},"stdStorageSafe":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdStorage.sol/stdStorageSafe.json"}}},"lib/forge-std/src/StdStyle.sol":{"lastModificationDate":1698510340914,"contentHash":"6281165a12aa639705c691fccefd855e","sourceName":"lib/forge-std/src/StdStyle.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Vm.sol"],"versionRequirement":">=0.4.22, <0.9.0","artifacts":{"StdStyle":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdStyle.sol/StdStyle.json"}}},"lib/forge-std/src/StdUtils.sol":{"lastModificationDate":1698510340914,"contentHash":"3255e5d80b9b77eb0880890ff827fda2","sourceName":"lib/forge-std/src/StdUtils.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Vm.sol","lib/forge-std/src/interfaces/IMulticall3.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"StdUtils":{"0.8.23+commit.f704f362.Darwin.appleclang":"StdUtils.sol/StdUtils.json"}}},"lib/forge-std/src/Test.sol":{"lastModificationDate":1701591736261,"contentHash":"c67db2c47c2e757cc33d38d6db0b1562","sourceName":"lib/forge-std/src/Test.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/lib/ds-test/src/test.sol","lib/forge-std/src/Base.sol","lib/forge-std/src/StdAssertions.sol","lib/forge-std/src/StdChains.sol","lib/forge-std/src/StdCheats.sol","lib/forge-std/src/StdError.sol","lib/forge-std/src/StdInvariant.sol","lib/forge-std/src/StdJson.sol","lib/forge-std/src/StdMath.sol","lib/forge-std/src/StdStorage.sol","lib/forge-std/src/StdStyle.sol","lib/forge-std/src/StdUtils.sol","lib/forge-std/src/Vm.sol","lib/forge-std/src/console.sol","lib/forge-std/src/console2.sol","lib/forge-std/src/interfaces/IMulticall3.sol","lib/forge-std/src/safeconsole.sol"],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"Test":{"0.8.23+commit.f704f362.Darwin.appleclang":"Test.sol/Test.json"}}},"lib/forge-std/src/Vm.sol":{"lastModificationDate":1698510340914,"contentHash":"b098c2721502365797aae8d0ee1babb8","sourceName":"lib/forge-std/src/Vm.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"Vm":{"0.8.23+commit.f704f362.Darwin.appleclang":"Vm.sol/Vm.json"},"VmSafe":{"0.8.23+commit.f704f362.Darwin.appleclang":"Vm.sol/VmSafe.json"}}},"lib/forge-std/src/console.sol":{"lastModificationDate":1698510340915,"contentHash":"100b8a33b917da1147740d7ab8b0ded3","sourceName":"lib/forge-std/src/console.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.4.22, <0.9.0","artifacts":{"console":{"0.8.23+commit.f704f362.Darwin.appleclang":"console.sol/console.json"}}},"lib/forge-std/src/console2.sol":{"lastModificationDate":1698510340916,"contentHash":"491ca717c1915995e78cc361485a3067","sourceName":"lib/forge-std/src/console2.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.4.22, <0.9.0","artifacts":{"console2":{"0.8.23+commit.f704f362.Darwin.appleclang":"console2.sol/console2.json"}}},"lib/forge-std/src/interfaces/IMulticall3.sol":{"lastModificationDate":1698510340918,"contentHash":"7b131ca1ca32ef6378b7b9ad5488b901","sourceName":"lib/forge-std/src/interfaces/IMulticall3.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"IMulticall3":{"0.8.23+commit.f704f362.Darwin.appleclang":"IMulticall3.sol/IMulticall3.json"}}},"lib/forge-std/src/safeconsole.sol":{"lastModificationDate":1698510340919,"contentHash":"ac3b1bf5a444db5db3656021830258a8","sourceName":"lib/forge-std/src/safeconsole.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":[],"versionRequirement":">=0.6.2, <0.9.0","artifacts":{"safeconsole":{"0.8.23+commit.f704f362.Darwin.appleclang":"safeconsole.sol/safeconsole.json"}}},"script/Counter.s.sol":{"lastModificationDate":1701590282315,"contentHash":"7539680fbd3ad49c6632713cc2bb6bf6","sourceName":"script/Counter.s.sol","solcConfig":{"settings":{"optimizer":{"enabled":true,"runs":2},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"shanghai","libraries":{}}},"imports":["lib/forge-std/src/Base.sol","lib/forge-std/src/Script.sol","lib/forge-std/src/StdChains.sol","lib/forge-std/src/StdCheats.sol","lib/forge-std/src/StdJson.sol","lib/forge-std/src/StdMath.sol","lib/forge-std/src/StdStorage.sol","lib/forge-std/src/StdStyle.sol","lib/forge-std/src/StdUtils.sol","lib/forge-std/src/Vm.sol","lib/forge-std/src/console.sol","lib/forge-std/src/console2.sol","lib/forge-std/src/interfaces/IMulticall3.sol","lib/forge-std/src/safeconsole.sol"],"versionRequirement":"^0.8.13","artifacts":{"CounterScript":{"0.8.23+commit.f704f362.Darwin.appleclang":"Counter.s.sol/CounterScript.json"}}}}} \ No newline at end of file diff --git a/gasreport.ansi b/gasreport.ansi index 8f6a83d..d09fcfe 100644 --- a/gasreport.ansi +++ b/gasreport.ansi @@ -1,15 +1,15 @@ -Compiling 14 files with 0.8.23 -Solc 0.8.23 finished in 2.37s +Compiling 13 files with 0.8.23 +Solc 0.8.23 finished in 2.84s Compiler run successful! Running 2 tests for contracts/Counter.t.sol:CounterTest [PASS] testIncrement() (gas: 30943) -[PASS] testSetNumber(uint256) (runs: 256, μ: 27063, ~: 28463) -Test result: ok. 2 passed; 0 failed; 0 skipped; finished in 21.69ms +[PASS] testSetNumber(uint256) (runs: 256, μ: 27841, ~: 28463) +Test result: ok. 2 passed; 0 failed; 0 skipped; finished in 19.51ms Running 1 test for contracts/PrivateFarm2X.t.sol:PrivateFarmTest -[PASS] testChangeDuration() (gas: 20056) -Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 5.22s +[PASS] testChangeDuration() (gas: 20166) +Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.97s | contracts/Counter.sol:Counter contract | | | | | | |----------------------------------------|-----------------|-------|--------|-------|---------| | Deployment Cost | Deployment Size | | | | | @@ -23,10 +23,10 @@ Test result: ok. 1 passed; 0 failed; 0 skipp | contracts/PrivateFarm2X.sol:PrivateFarm2X contract | | | | | | |----------------------------------------------------|-----------------|------|--------|------|---------| | Deployment Cost | Deployment Size | | | | | -| 1695577 | 8672 | | | | | +| 1649928 | 8444 | | | | | | Function Name | min | avg | median | max | # calls | -| rewardDuration | 1218 | 2218 | 2218 | 3218 | 2 | -| setRewardDuration | 9209 | 9209 | 9209 | 9209 | 1 | +| rewardDuration | 1262 | 2262 | 2262 | 3262 | 2 | +| setRewardDuration | 9231 | 9231 | 9231 | 9231 | 1 | diff --git a/test/private-v2.test.js b/test/private-v2.test.js index 722e11a..b1d2165 100644 --- a/test/private-v2.test.js +++ b/test/private-v2.test.js @@ -479,7 +479,6 @@ contract("SimpleFarm", ([ console.log(unlockableAfterTime2.toString(), 'unlockableAfterTime2'); - await time.increase( defaultDuration + 1 ); @@ -511,6 +510,60 @@ contract("SimpleFarm", ([ console.log(unlockableAfterTime5.toString(), 'unlockableAfterTime2'); }); + it("should have correct unlockable amount based on time", async () => { + + const defaultDuration = await farm.rewardDuration(); + const expectedDefaultDuration = defaultDurationInSeconds; + const lockDuration = 86400; + + assert.equal( + defaultDuration, + expectedDefaultDuration + ); + + await farm.makeDepositForUser( + alice, + tokens("20"), + 0 + ); + + await farm.makeDepositForUser( + alice, + tokens("80"), + lockDuration + ); + + const totalSupply = await farm.totalSupply(); + const totalSupplySQR = await farm.totalSupplySQR(); + + console.log(totalSupply.toString(), 'totalSupply'); + console.log(totalSupplySQR.toString(), 'totalSupplySQR'); + + const globalLockedTrue = await farm.globalLocked( + true + ); + + const globalLockedFalse = await farm.globalLocked( + false + ); + + const timestampFlag = await farm.uniqueStamps(0); + + const unlockRate = await farm.unlockRates( + timestampFlag + ); + + const unlockRateSQRT = await farm.unlockRatesSQRT( + timestampFlag + ); + + console.log(globalLockedTrue.toString(), 'globalLockedTrue'); + console.log(globalLockedFalse.toString(), 'globalLockedFalse'); + + console.log(unlockRate.toString(), 'unlockRate'); + console.log(unlockRateSQRT.toString(), 'unlockRateSQRT'); + }); + it("should not be able to change farm duration during distribution", async () => { const defaultDuration = await farm.rewardDuration(); diff --git a/test/timelock-v2-dual.test.js b/test/timelock-v2-dual.test.js new file mode 100644 index 0000000..6276117 --- /dev/null +++ b/test/timelock-v2-dual.test.js @@ -0,0 +1,3606 @@ +const Token = artifacts.require("TestToken"); +const Farm = artifacts.require("TimeLockFarmV2Dual"); +const { expectRevert, time } = require('@openzeppelin/test-helpers'); + +require("./utils"); + +const _BN = web3.utils.BN; +const BN = (value) => { + return new _BN( + value + ); +} + +const tokens = (value) => { + return web3.utils.toWei( + value + ); +} + +const ONE_TOKEN = tokens("1"); +const TWO_TOKENS = tokens("2"); +const FIVE_TOKENS = tokens("5"); + +const MAX_VALUE = BN(2) + .pow(BN(256)) + .sub(BN(1)); + +const getLastEvent = async (eventName, instance) => { + const events = await instance.getPastEvents(eventName, { + fromBlock: 0, + toBlock: "latest", + }); + return events.pop().returnValues; +}; + +contract("TimeLockFarmV2", ([owner, alice, bob, chad, random]) => { + + const setupScenario = async (inputParams = {}) => { + + stakeToken = await Token.new(); + rewardTokenA = await Token.new(); + rewardTokenB = await Token.new(); + + defaultUnlockTime = 150; + defaultApprovalAmount = 100; + defaultDurationInSeconds = 300; + + farm = await Farm.new( + stakeToken.address, + rewardTokenA.address, + rewardTokenB.address, + owner, + owner, + defaultDurationInSeconds, + defaultUnlockTime + ); + + if (inputParams.approval) { + + const approvalAmount = tokens( + defaultApprovalAmount.toString() + ); + + await stakeToken.approve( + farm.address, + approvalAmount + ); + + await rewardTokenA.approve( + farm.address, + approvalAmount + ); + + await rewardTokenB.approve( + farm.address, + approvalAmount + ); + } + + if (inputParams.deposit) { + await farm.farmDeposit( + inputParams.deposit + ); + } + + if (inputParams.rate) { + await farm.setRewardRate( + inputParams.rate + ); + } + + return { + stakeToken, + rewardToken, + farm + } + } + + describe("Farm initial values", () => { + + beforeEach(async () => { + + const result = await setupScenario(); + + stakeToken = result.stakeToken; + rewardToken = result.rewardToken; + farm = result.farm; + }); + + it("should have correct farm name", async () => { + const name = await farm.name(); + assert.equal( + name, + "VerseFarm" + ); + }); + + it("should have correct farm symbol", async () => { + const symbol = await farm.symbol(); + assert.equal( + symbol, + "VFARM" + ); + }); + + it("should have correct farm decimals", async () => { + const decimals = await farm.decimals(); + assert.equal( + decimals, + 18 + ); + }); + + it("should have correct farm supply", async () => { + + const defaultSupplyValue = await farm.totalSupply(); + const expectedDefaultValue = 0; + + assert.equal( + defaultSupplyValue, + expectedDefaultValue + ); + }); + + it("should return receipt balance for the given account", async () => { + + const defaultBalance = await farm.balanceOf( + owner + ); + + const expectedDefaultBalance = 0; + + assert.equal( + defaultBalance, + expectedDefaultBalance + ); + }); + + it("should return the correct allowance for the given spender", async () => { + + const defaultAllowance = await farm.allowance( + owner, + bob + ); + + const expectedDefaultAllowance = 0; + + assert.equal( + defaultAllowance, + expectedDefaultAllowance + ); + }); + + it("should have correct staking token address", async () => { + + const stakeTokenValue = await farm.stakeToken(); + + assert.equal( + stakeTokenValue, + stakeToken.address + ); + }); + + it("should have correct reward token address", async () => { + + const rewardTokenValue = await farm.rewardTokenA(); + + assert.equal( + rewardTokenValue, + rewardToken.address + ); + }); + + it("should have correct owner address", async () => { + + const ownerAddress = await farm.ownerAddress(); + + assert.equal( + ownerAddress, + owner + ); + }); + + it("should have correct manager address", async () => { + + const managerAddress = await farm.managerAddress(); + + assert.equal( + managerAddress, + owner + ); + }); + + it("should have correct perTokenStored value", async () => { + + const perTokenStored = await farm.perTokenStored(); + const expectedDefaultValue = 0; + + assert.equal( + perTokenStored, + expectedDefaultValue + ); + }); + + it("should have correct lastUpdateTime value", async () => { + + const lastUpdateTime = await farm.lastUpdateTime(); + const expectedDefaultValue = 0; + + assert.equal( + lastUpdateTime, + expectedDefaultValue + ); + }); + + it("should have correct duration value", async () => { + + const defaultDurationValue = await farm.rewardDuration(); + + assert.equal( + defaultDurationValue, + defaultDurationInSeconds + ); + }); + + it("should have correct timeLock value", async () => { + + const farmTimeLock = await farm.timeLock(); + + assert.equal( + farmTimeLock, + defaultUnlockTime + ); + }); + + it("should not be able to deploy with wrong default duration value", async () => { + + const invalidDuration = 0; + const correctDuration = 1; + + await expectRevert( + Farm.new( + stakeToken.address, + rewardToken.address, + owner, + owner, + invalidDuration, + correctDuration + ), + "TimeLockFarmV2: INVALID_DURATION" + ); + + await Farm.new( + stakeToken.address, + rewardToken.address, + owner, + owner, + correctDuration, + correctDuration + ); + + assert.isAbove( + correctDuration, + invalidDuration + ); + }); + }); + + describe("Duration initial functionality", () => { + + beforeEach(async () => { + const result = await setupScenario({ + approval: true + }); + stakeToken = result.stakeToken; + rewardToken = result.rewardToken; + farm = result.farm; + }); + + it("should be able to change farm duration value", async () => { + + const defaultDuration = await farm.rewardDuration(); + const expectedDefaultDuration = defaultDurationInSeconds; + const newDurationValueIncrease = 600; + const newDurationValueDecrease = 100; + + assert.equal( + defaultDuration, + expectedDefaultDuration + ); + + assert.isAbove( + newDurationValueIncrease, + parseInt(defaultDuration) + ); + + assert.isBelow( + newDurationValueDecrease, + parseInt(defaultDuration) + ); + + await farm.setRewardDuration( + newDurationValueDecrease + ); + + const durationValueDecreased = await farm.rewardDuration(); + + assert.equal( + durationValueDecreased, + newDurationValueDecrease + ); + + assert.isBelow( + parseInt(durationValueDecreased), + parseInt(defaultDuration) + ); + + await farm.setRewardDuration( + newDurationValueIncrease + ); + + const durationValueIncreased = await farm.rewardDuration(); + + assert.equal( + durationValueIncreased, + durationValueIncreased + ); + + assert.isAbove( + parseInt(durationValueIncreased), + parseInt(defaultDuration) + ); + }); + + it("should be able to change farm duration value only by manager", async () => { + + const newDurationValue = 10; + const actualManager = await farm.managerAddress(); + const wrongManager = bob; + const correctManager = owner; + + await expectRevert( + farm.setRewardDuration( + newDurationValue, + { + from: wrongManager + } + ), + "TimeLockFarmV2: INVALID_MANAGER" + ); + + assert.notEqual( + wrongManager, + actualManager + ); + + await farm.setRewardDuration( + newDurationValue, + { + from: correctManager + } + ); + + assert.equal( + correctManager, + actualManager + ); + + const durationValueChanged = await farm.rewardDuration(); + + assert.equal( + durationValueChanged, + newDurationValue + ); + }); + + it("should not be able to change farm duration value to 0", async () => { + + const defaultDuration = await farm.rewardDuration(); + const expectedDefaultDuration = defaultDurationInSeconds; + + assert.equal( + defaultDuration, + expectedDefaultDuration + ); + + const newDurationWrongValue = 0; + const newDurationRightValue = 1; + + await expectRevert( + farm.setRewardDuration( + newDurationWrongValue + ), + "TimeLockFarmV2: INVALID_DURATION" + ); + + await farm.setRewardDuration( + newDurationRightValue + ); + + assert.isAbove( + newDurationRightValue, + newDurationWrongValue + ); + }); + + it("should not be able to change farm duration during distribution", async () => { + + const defaultDuration = await farm.rewardDuration(); + const expectedDefaultDuration = defaultDurationInSeconds; + const newDurationWrongValue = 100; + + assert.equal( + defaultDuration, + expectedDefaultDuration + ); + + await farm.farmDeposit( + 10 + ); + + await farm.setRewardRate( + 10 + ); + + await expectRevert( + farm.setRewardDuration( + newDurationWrongValue + ), + "TimeLockFarmV2: ONGOING_DISTRIBUTION" + ); + + await time.increase( + defaultDuration + 1 + ); + + await farm.setRewardDuration( + newDurationWrongValue + ); + + const newDuration = await farm.rewardDuration(); + + assert.equal( + newDuration, + newDurationWrongValue + ); + }); + }); + + describe("Reward allocation initial functionality by manager", () => { + + beforeEach(async () => { + + const result = await setupScenario({ + approval: true + }); + + stakeToken = result.stakeToken; + rewardToken = result.rewardToken; + farm = result.farm; + }); + + it("should not be able to set rate to 0", async () => { + + await farm.farmDeposit( + ONE_TOKEN + ); + + await expectRevert( + farm.setRewardRate( + 0 + ), + "TimeLockFarmV2: INVALID_RATE" + ); + + await farm.setRewardRate( + 1 + ); + }); + + it("should correctly set the periodFinished date value", async () => { + + const initialPeriod = await farm.periodFinished(); + const expectedDuration = await farm.rewardDuration(); + const initialRate = 10; + const expectedInitialValue = 0; + + assert.equal( + initialPeriod, + expectedInitialValue + ); + + await farm.farmDeposit( + ONE_TOKEN + ); + + await farm.setRewardRate( + initialRate + ); + + const initialTimestamp = await rewardToken.timestamp(); + const valueAfterChange = await farm.periodFinished(); + + assert.isAbove( + parseInt(valueAfterChange), + parseInt(initialPeriod) + ); + + assert.equal( + parseInt(valueAfterChange), + parseInt(initialTimestamp) + parseInt(expectedDuration) + ); + }); + + it("should increase perTokenStored value", async () => { + + const perTokenStoredDefault = await farm.perTokenStored(); + const expectedDefaultValue = 0; + const initialRate = 10; + + assert.equal( + perTokenStoredDefault, + expectedDefaultValue + ); + + await farm.farmDeposit( + ONE_TOKEN + ); + + await farm.setRewardRate( + initialRate + ); + + await time.increase( + 1 + ); + + await farm.farmDeposit( + ONE_TOKEN + ); + + const perTokenStoredNew = await farm.perTokenStored(); + + assert.isAbove( + parseInt(perTokenStoredNew), + parseInt(perTokenStoredDefault) + ); + }); + + it("should emit correct RewardAdded event", async () => { + + const initialRate = 10; + const rewardDuration = await farm.rewardDuration(); + const expectedAmount = rewardDuration * initialRate; + + await farm.farmDeposit( + ONE_TOKEN + ); + + await farm.setRewardRate( + initialRate + ); + + const rewardEvent = await getLastEvent( + "RewardAdded", + farm + ); + + assert.equal( + expectedAmount, + rewardEvent.tokenAmount + ); + }); + + it("manager should be able to set rewards rate only if stakers exist", async () => { + + const newRewardRate = 10; + const expectedNewRate = newRewardRate; + + await expectRevert( + farm.setRewardRate( + newRewardRate + ), + "TimeLockFarmV2: NO_STAKERS" + ); + + await farm.farmDeposit( + ONE_TOKEN + ); + + await farm.setRewardRate( + newRewardRate + ); + + const rateAfterChanged = await farm.rewardRate(); + + assert.equal( + rateAfterChanged, + expectedNewRate + ); + }); + + it("manager should fund the farm during reward rate announcement", async () => { + + const newRewardRate = 10; + const expectedDuration = await farm.rewardDuration(); + const currentManager = await farm.managerAddress(); + + const expectedTransferAmount = newRewardRate + * expectedDuration; + + const managerBalance = await rewardToken.balanceOf( + currentManager + ); + + assert.isAbove( + parseInt(managerBalance), + expectedTransferAmount + ); + + await farm.farmDeposit( + ONE_TOKEN + ); + + await farm.setRewardRate( + newRewardRate + ); + + const transferData = await getLastEvent( + "Transfer", + rewardToken + ); + + assert.equal( + transferData.from, + currentManager + ); + + assert.equal( + transferData.to, + farm.address + ); + + assert.equal( + transferData.value, + expectedTransferAmount + ); + + const afterTransferManager = await rewardToken.balanceOf( + currentManager + ); + + const afterTransferFarm = await rewardToken.balanceOf( + farm.address + ); + + assert.equal( + managerBalance, + parseInt(afterTransferManager) + parseInt(expectedTransferAmount) + ); + + assert.equal( + expectedTransferAmount, + afterTransferFarm + ); + }); + + it("manager should be able to increase rate any time", async () => { + + const initialRate = 10; + const increasedRewardRate = 11; + + assert.isAbove( + increasedRewardRate, + initialRate + ); + + await farm.farmDeposit( + ONE_TOKEN + ); + + await farm.setRewardRate( + initialRate + ); + + const rateBeforeChanged = await farm.rewardRate(); + + assert.equal( + rateBeforeChanged, + initialRate + ); + + await farm.setRewardRate( + increasedRewardRate + ); + + const rateAfterChanged = await farm.rewardRate(); + + assert.equal( + rateAfterChanged, + increasedRewardRate + ); + }); + + it("manager should be able to decrease rate only after distribution finished", async () => { + + const initialRate = 10; + const decreasedRewardRate = 9; + + assert.isBelow( + decreasedRewardRate, + initialRate + ); + + await farm.farmDeposit( + ONE_TOKEN + ); + + await farm.setRewardRate( + initialRate + ); + + const rateAfterChanged = await farm.rewardRate(); + + assert.equal( + rateAfterChanged, + initialRate + ); + + await expectRevert( + farm.setRewardRate( + decreasedRewardRate + ), + "TimeLockFarmV2: RATE_CANT_DECREASE" + ); + + const currentDuration = await farm.rewardDuration(); + + await time.increase( + currentDuration + ); + + await farm.setRewardRate( + decreasedRewardRate + ); + + const newRate = await farm.rewardRate(); + + assert.equal( + parseInt(newRate), + decreasedRewardRate + ); + }); + }); + + describe("Deposit initial functionality", () => { + + beforeEach(async () => { + + const result = await setupScenario({ + approval: true + }); + + stakeToken = result.stakeToken; + rewardToken = result.rewardToken; + farm = result.farm; + }); + + it("should transfer correct amount from farmer to farm", async () => { + + const depositValue = ONE_TOKEN; + const depositAddress = bob; + + await stakeToken.mint( + depositValue, + { + from: depositAddress + } + ); + + //@TODO: test without approve + await stakeToken.approve( + farm.address, + depositValue, + { + from: depositAddress + } + ); + + const balanceBefore = await stakeToken.balanceOf( + depositAddress + ); + + await farm.farmDeposit( + depositValue, + { + from: depositAddress + } + ); + + const balanceAfter = await stakeToken.balanceOf( + depositAddress + ); + + assert.equal( + parseInt(balanceAfter), + parseInt(balanceBefore) - parseInt(depositValue) + ); + }); + + it("should increase the balance of the wallet thats deposits the tokens", async () => { + + const depositAmount = ONE_TOKEN; + + const supplyBefore = await farm.balanceOf( + owner + ); + + await farm.farmDeposit( + depositAmount, + { + from: owner + } + ); + + const supplyAfter = await farm.balanceOf( + owner + ); + + assert.equal( + parseInt(supplyAfter), + parseInt(supplyBefore) + parseInt(depositAmount) + ); + }); + + it("should add the correct amount to the total supply", async () => { + + const supplyBefore = await farm.balanceOf(owner); + const depositAmount = ONE_TOKEN; + + await farm.farmDeposit( + depositAmount, + { + from: owner + } + ); + + const totalSupply = await farm.totalSupply(); + + assert.equal( + totalSupply.toString(), + (BN(supplyBefore).add(BN(depositAmount))).toString() + ); + }); + + it("should not be able to deposit if not appored enough", async () => { + + const allowance = await stakeToken.allowance( + owner, + farm.address + ); + + const depositAmount = tokens("2000"); + + assert.isAbove( + parseInt(depositAmount), + parseInt(allowance) + ); + + await expectRevert.unspecified( + farm.farmDeposit( + depositAmount, + { + from: owner + } + ), + "SafeERC20: CALL_FAILED" + ); + }); + }); + + describe("Receipt token approve functionality", () => { + + beforeEach(async () => { + + const result = await setupScenario({ + approval: true, + deposit: ONE_TOKEN + }); + + farm = result.farm; + + }); + + it("should be able to increase allowance", async () => { + + const initialAllowance = await farm.allowance( + owner, + bob + ); + const increaseValue = ONE_TOKEN; + + await farm.increaseAllowance( + bob, + increaseValue + ); + + const allowanceIncreased = await farm.allowance( + owner, + bob + ); + + assert.isAbove( + parseInt(allowanceIncreased), + parseInt(initialAllowance) + ); + + assert.equal( + parseInt(allowanceIncreased), + parseInt(initialAllowance) + parseInt(increaseValue) + ); + }); + + it("should be able to decrease allowance", async () => { + + await farm.approve( + bob, + ONE_TOKEN + ); + + const initialAllowance = await farm.allowance( + owner, + bob + ); + + const decreaseValue = ONE_TOKEN; + + await farm.decreaseAllowance( + bob, + decreaseValue + ); + + const allowanceDecreased = await farm.allowance( + owner, + bob + ); + + assert.isBelow( + parseInt(allowanceDecreased), + parseInt(initialAllowance) + ); + + assert.equal( + parseInt(allowanceDecreased), + parseInt(initialAllowance) - parseInt(decreaseValue) + ); + }); + + it("should not change allowance if its at maximum", async () => { + + const approvalValue = MAX_VALUE; + const transferValue = ONE_TOKEN; + + await stakeToken.mint( + transferValue, + { + from: bob + } + ); + + await stakeToken.approve( + farm.address, + approvalValue, + { + from: bob + } + ); + + await farm.farmDeposit( + ONE_TOKEN, + { + from: bob + } + ); + + await farm.approve( + bob, + approvalValue + ); + + const allowanceValueBefore = await farm.allowance( + owner, + bob + ); + + assert.equal( + MAX_VALUE.toString(), + allowanceValueBefore.toString() + ); + + await time.increase( + defaultUnlockTime + ); + + await farm.transferFrom( + owner, + alice, + transferValue, + { + from: bob + } + ); + + const allowanceValueAfter = await farm.allowance( + owner, + bob + ); + + assert.equal( + allowanceValueBefore.toString(), + allowanceValueAfter.toString() + ); + + assert.equal( + MAX_VALUE.toString(), + allowanceValueAfter.toString() + ); + }); + + it("should revert if the sender has spent more than their approved amount", async () => { + + const approvedValue = ONE_TOKEN; + const transferValue = TWO_TOKENS; + const approvedWallet = alice; + + await farm.approve( + approvedWallet, + approvedValue + ); + + await expectRevert.unspecified( + farm.transferFrom( + owner, + bob, + transferValue, + { + from: approvedWallet + } + ) + ); + }); + }); + + describe("Receipt token burn/mint functionality", () => { + + beforeEach(async () => { + + const result = await setupScenario({ + approval: true + }); + + farm = result.farm; + defaultTokenAmount = TWO_TOKENS; + ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; + }); + + it("should emit correct event when minting receipt tokens (during deposit)", async () => { + + const depositor = owner; + + await farm.farmDeposit( + defaultTokenAmount, + { + from: depositor + } + ); + + const { from, to, value } = await getLastEvent( + "Transfer", + farm + ); + + assert.equal( + value, + defaultTokenAmount + ); + + assert.equal( + from, + ZERO_ADDRESS + ); + + assert.equal( + to, + depositor + ); + }); + + it("should emit correct event when burning receipt tokens (during withdraw)", async () => { + + const depositor = owner; + + await farm.farmDeposit( + defaultTokenAmount, + { + from: depositor + } + ); + + await time.increase( + defaultUnlockTime + ); + + await farm.farmWithdraw( + defaultTokenAmount, + { + from: depositor + } + ); + + const { from, to, value } = await getLastEvent( + "Transfer", + farm + ); + + assert.equal( + value, + defaultTokenAmount + ); + + assert.equal( + from, + depositor + ); + + assert.equal( + to, + ZERO_ADDRESS + ); + }); + }); + + describe("Receipt token transfer functionality", () => { + + beforeEach(async () => { + + const result = await setupScenario({ + approval: true + }); + + stakeToken = result.stakeToken; + rewardToken = result.rewardToken; + farm = result.farm; + + defaultTokenAmount = TWO_TOKENS; + + await farm.farmDeposit( + defaultTokenAmount + ); + }); + + it("should transfer correct amount from walletA to walletB", async () => { + + const transferValue = defaultTokenAmount; + const balanceBefore = await farm.balanceOf(bob); + + await time.increase( + defaultUnlockTime + ); + + await farm.transfer( + bob, + transferValue, + { + from: owner + } + ); + + const balanceAfter = await farm.balanceOf(bob); + + assert.equal( + parseInt(balanceAfter), + parseInt(balanceBefore) + parseInt(transferValue) + ); + }); + + it("should revert if not enough balance in the wallet", async () => { + + const balanceBefore = await farm.balanceOf(alice); + + await expectRevert.unspecified( + farm.transfer( + bob, + parseInt(balanceBefore) + 1, + { + from: alice + } + ) + ); + }); + + it("if tokens unlocked should reduce wallets balance after transfer", async () => { + + const transferValue = defaultTokenAmount; + const balanceBefore = await farm.balanceOf(owner); + + await expectRevert( + farm.transfer( + bob, + transferValue, + { + from: owner + } + ), + "TimeLockFarmV2: UNLOCK_INSUFFICIENT" + ); + + await time.increase( + defaultUnlockTime + ); + + await farm.transfer( + bob, + transferValue, + { + from: owner + } + ); + + const balanceAfter = await farm.balanceOf(owner); + + assert.equal( + parseInt(balanceAfter), + parseInt(balanceBefore) - parseInt(transferValue) + ); + }); + + it("if tokens unlocked should emit correct Transfer event", async () => { + + const transferValue = defaultTokenAmount; + const expectedRecepient = bob; + + await expectRevert( + farm.transfer( + expectedRecepient, + transferValue, + { + from: owner + } + ), + "TimeLockFarmV2: UNLOCK_INSUFFICIENT" + ); + + await time.increase( + defaultUnlockTime + ); + + await farm.transfer( + expectedRecepient, + transferValue, + { + from: owner + } + ); + + const { from, to, value } = await getLastEvent( + "Transfer", + farm + ); + + assert.equal( + from, + owner + ); + + assert.equal( + to, + expectedRecepient + ); + + assert.equal( + value, + transferValue + ); + }); + + it("if tokens unlocked should update the balance of the recipient when using transferFrom", async () => { + + const transferValue = defaultTokenAmount; + const expectedRecipient = bob; + const balanceBefore = await farm.balanceOf(bob); + + await farm.approve( + owner, + transferValue + ); + + await expectRevert( + farm.transferFrom( + owner, + expectedRecipient, + transferValue, + ), + "TimeLockFarmV2: UNLOCK_INSUFFICIENT" + ); + + await time.increase( + defaultUnlockTime + ); + + await farm.transferFrom( + owner, + expectedRecipient, + transferValue, + ); + + const balanceAfter = await farm.balanceOf(bob); + + assert.equal( + parseInt(balanceAfter), + parseInt(balanceBefore) + parseInt(transferValue) + ); + }); + + it("if tokens unlocked should deduct from the balance of the sender when using transferFrom", async () => { + + const transferValue = defaultTokenAmount; + const expectedRecipient = bob; + const balanceBefore = await farm.balanceOf(owner); + + await farm.approve( + owner, + transferValue + ); + + await expectRevert( + farm.transferFrom( + owner, + expectedRecipient, + transferValue, + ), + "TimeLockFarmV2: UNLOCK_INSUFFICIENT" + ); + + await time.increase( + defaultUnlockTime + ); + + await farm.transferFrom( + owner, + expectedRecipient, + transferValue, + ); + + const balanceAfter = await farm.balanceOf(owner); + + assert.equal( + parseInt(balanceAfter), + parseInt(balanceBefore) - parseInt(transferValue) + ); + }); + + it("should revert if there is no approval when using transferFrom", async () => { + + const transferValue = defaultTokenAmount; + const expectedRecipient = bob; + + await expectRevert.unspecified( + farm.transferFrom( + owner, + expectedRecipient, + transferValue + ) + ); + }); + + it("should revert if the sender has spent more than their approved amount when using transferFrom", async () => { + + const approvedValue = ONE_TOKEN; + const transferValue = TWO_TOKENS; + const expectedRecipient = bob; + + await farm.approve( + alice, + approvedValue + ); + + await expectRevert.unspecified( + farm.transferFrom( + owner, + expectedRecipient, + transferValue, + { + from: alice + } + ) + ); + }); + }); + + describe("Witharaw initial functionality", () => { + + beforeEach(async () => { + + const result = await setupScenario({ + approval: true + }); + + stakeToken = result.stakeToken; + rewardToken = result.rewardToken; + farm = result.farm; + + defaultTokenAmount = TWO_TOKENS; + + await farm.farmDeposit( + defaultTokenAmount + ); + }); + + it("if tokens unlocked should reduce the balance of the wallet thats withrawing the stakeTokens", async () => { + + const withdrawAmount = ONE_TOKEN; + const withdrawAccount = owner; + + const supplyBefore = await farm.balanceOf( + withdrawAccount + ); + + await expectRevert( + farm.farmWithdraw( + withdrawAmount, + { + from: withdrawAccount + } + ), + "TimeLockFarmV2: UNLOCK_INSUFFICIENT" + ); + + await time.increase( + defaultUnlockTime + ); + + await farm.farmWithdraw( + withdrawAmount, + { + from: withdrawAccount + } + + ); + + const supplyAfter = await farm.balanceOf( + withdrawAccount + ); + + assert.equal( + supplyAfter, + supplyBefore - withdrawAmount + ); + }); + + it("should deduct the correct amount from the total supply", async () => { + + const withdrawAmount = ONE_TOKEN; + const withdrawAccount = owner; + + const supplyBefore = await farm.balanceOf( + withdrawAccount + ); + + await time.increase( + defaultUnlockTime + ); + + await farm.farmWithdraw( + withdrawAmount, + { + from: owner + } + + ); + + const totalSupply = await farm.totalSupply(); + + assert.equal( + totalSupply, + supplyBefore - withdrawAmount + ); + }); + + it("should not be able to withdraw as last farmer until rewards are still available", async () => { + + await farm.farmDeposit( + defaultTokenAmount + ); + + await farm.setRewardRate( + 10 + ); + + const withdrawAccount = owner; + + const possibleWithdraw = await farm.balanceOf( + withdrawAccount + ); + + await expectRevert( + farm.farmWithdraw( + possibleWithdraw, + { + from: owner + } + ), + "TimeLockFarmV2: STILL_EARNING" + ); + + await stakeToken.mint( + defaultTokenAmount, + { + from: bob + } + ); + + await stakeToken.approve( + farm.address, + defaultTokenAmount, + { + from: bob + } + ); + + await farm.farmDeposit( + defaultTokenAmount, + { + from: bob + } + ); + + await time.increase( + defaultUnlockTime + ); + + await farm.farmWithdraw( + possibleWithdraw, + { + from: owner + } + ); + }); + }); + + describe("Witharaw with timelock functionality", () => { + + beforeEach(async () => { + + const result = await setupScenario({ + approval: true + }); + + stakeToken = result.stakeToken; + rewardToken = result.rewardToken; + farm = result.farm; + + defaultDepositAmount = TWO_TOKENS; + + await farm.farmDeposit( + defaultDepositAmount + ); + }); + + it("should have correct stake count", async () => { + + const expectedAccount = owner; + const expectedCount = 1; + + const userStakeCount = await farm.stakeCount( + expectedAccount + ); + + assert.equal( + userStakeCount, + expectedCount + ); + }); + + it("should create stake object for account when stake created", async () => { + + const expectedAccount = owner; + const expectedDeposit = defaultDepositAmount; + + const timeLock = await farm.timeLock(); + const stampAfterDeposit = await rewardToken.timestamp(); + + const stakeCount = await farm.stakeCount( + expectedAccount + ); + + const latestStakeIndex = stakeCount - 1; + + const userStakeOne = await farm.stakes( + expectedAccount, + latestStakeIndex + ); + + assert.equal( + userStakeOne.amount.toString(), + expectedDeposit.toString() + ); + + assert.equal( + parseInt(userStakeOne.unlockTime), + parseInt(stampAfterDeposit) + parseInt(timeLock) + ); + }); + + it("checks that if tokens are locked then user cannot withdraw them", async () => { + + const withdrawAmount = defaultDepositAmount; + const withdrawAccount = owner; + + const unlockedBefore = await farm.unlockable( + withdrawAccount + ); + + assert.equal( + unlockedBefore, + "0" + ); + + await expectRevert( + farm.farmWithdraw( + withdrawAmount, + { + from: withdrawAccount + } + ), + "TimeLockFarmV2: UNLOCK_INSUFFICIENT" + ); + + await time.increase( + defaultUnlockTime + ); + + const unlockedAfter = await farm.unlockable( + withdrawAccount + ); + + assert.equal( + unlockedAfter, + defaultDepositAmount + ); + + await farm.farmWithdraw( + withdrawAmount, + { + from: withdrawAccount + } + + ); + + const transactionData = await getLastEvent( + "Withdrawn", + farm + ); + + assert.equal( + transactionData.user, + withdrawAccount + ); + + assert.equal( + transactionData.tokenAmount, + defaultDepositAmount + ); + }); + + it("should unlock stakes only once unlock time passed for each stake", async () => { + + const withdrawAccount = owner; + const withdrawAmountOne = defaultDepositAmount; + const withdrawAmountTwo = FIVE_TOKENS; + const halfTime = defaultUnlockTime / 2 + + assert.isAbove( + parseInt(withdrawAmountTwo), + parseInt(withdrawAmountOne) + ); + + await time.increase( + halfTime + ); + + await farm.farmDeposit( + withdrawAmountTwo + ); + + const userStakeCount = await farm.stakeCount( + withdrawAccount + ); + + assert.equal( + userStakeCount.toString(), + "2" + ); + + await time.increase( + halfTime + ); + + const unlockableFirstStake = await farm.unlockable( + withdrawAccount + ); + + assert.equal( + unlockableFirstStake, + withdrawAmountOne + ); + + await expectRevert( + farm.farmWithdraw( + withdrawAmountTwo, + { + from: withdrawAccount + } + ), + "TimeLockFarmV2: UNLOCK_INSUFFICIENT" + ); + + await farm.farmWithdraw( + withdrawAmountOne, + { + from: withdrawAccount + } + ); + + const userStakeCountAgain = await farm.stakeCount( + withdrawAccount + ); + + assert.equal( + userStakeCountAgain.toString(), + "1" + ); + + const unlockableSecondStake = await farm.unlockable( + withdrawAccount + ); + + assert.equal( + unlockableSecondStake.toString(), + "0" + ); + + await expectRevert( + farm.farmWithdraw( + withdrawAmountOne, + { + from: withdrawAccount + } + ), + "TimeLockFarmV2: UNLOCK_INSUFFICIENT" + ); + + await expectRevert( + farm.farmWithdraw( + withdrawAmountTwo, + { + from: withdrawAccount + } + ), + "TimeLockFarmV2: UNLOCK_INSUFFICIENT" + ); + + await time.increase( + halfTime + ); + + const unlockableSecondStakeAgain = await farm.unlockable( + withdrawAccount + ); + + assert.equal( + unlockableSecondStakeAgain.toString(), + withdrawAmountTwo.toString() + ); + + await farm.farmWithdraw( + withdrawAmountTwo, + { + from: withdrawAccount + } + ); + + const unlockableFinal = await farm.unlockable( + withdrawAccount + ); + + assert.equal( + unlockableFinal.toString(), + "0" + ); + + const finalStakeCount = await farm.stakeCount( + withdrawAccount + ); + + assert.equal( + finalStakeCount.toString(), + "0" + ); + }); + + it("should reduce stake amount when withdrawing if stoke is unlocked", async () => { + + const withdrawAccount = owner; + const withdrawAmount = tokens("2"); + const halfAmount = tokens("1"); + + const stakeCount = await farm.stakeCount( + withdrawAccount + ); + + const latestStakeIndex = stakeCount - 1; + const userStake = await farm.stakes( + withdrawAccount, + latestStakeIndex + ); + + assert.equal( + userStake.amount.toString(), + withdrawAmount.toString() + ); + + const unlockableInitial = await farm.unlockable( + withdrawAccount + ); + + assert.equal( + unlockableInitial.toString(), + "0" + ); + + await time.increase( + defaultUnlockTime + ); + + const unlockableFirstStake = await farm.unlockable( + withdrawAccount + ); + + assert.equal( + unlockableFirstStake, + withdrawAmount + ); + + await farm.farmWithdraw( + halfAmount, + { + from: withdrawAccount + } + ); + + const userStakeCountAgain = await farm.stakeCount( + withdrawAccount + ); + + assert.equal( + userStakeCountAgain.toString(), + "1" + ); + + const userStakeAgain = await farm.stakes( + withdrawAccount, + latestStakeIndex + ); + + assert.isBelow( + parseInt(userStakeAgain.amount), + parseInt(withdrawAmount) + ); + + assert.equal( + userStakeAgain.amount.toString(), + halfAmount.toString() + ); + + await expectRevert( + farm.farmWithdraw( + withdrawAmount, + { + from: withdrawAccount + } + ), + "TimeLockFarmV2: UNLOCK_INSUFFICIENT" + ); + + await farm.farmWithdraw( + halfAmount, + { + from: withdrawAccount + } + ); + + const unlockableFinal = await farm.unlockable( + withdrawAccount + ); + + assert.equal( + unlockableFinal.toString(), + "0" + ); + + const finalStakeCount = await farm.stakeCount( + withdrawAccount + ); + + assert.equal( + finalStakeCount.toString(), + "0" + ); + }); + + it("should unlock stake only once unlock time passed", async () => { + + const withdrawAccount = owner; + const withdrawAmount = defaultDepositAmount; + const halfTime = defaultUnlockTime / 2; + + const unlockableStepOne = await farm.unlockable( + withdrawAccount + ); + + assert.equal( + unlockableStepOne.toString(), + "0" + ); + + await time.increase( + halfTime + ); + + const unlockableStepTwo = await farm.unlockable( + withdrawAccount + ); + + assert.equal( + unlockableStepTwo.toString(), + "0" + ); + + await expectRevert( + farm.farmWithdraw( + withdrawAmount, + { + from: withdrawAccount + } + ), + "TimeLockFarmV2: UNLOCK_INSUFFICIENT" + ); + + await time.increase( + halfTime + ); + + const unlockableStepThree = await farm.unlockable( + withdrawAccount + ); + + assert.equal( + unlockableStepThree, + withdrawAmount + ); + + await farm.farmWithdraw( + withdrawAmount, + { + from: owner + } + ); + }); + + it("should not be able to withdraw as last farmer until rewards are still available", async () => { + + await farm.farmDeposit( + defaultTokenAmount + ); + + await farm.setRewardRate( + 10 + ); + + const withdrawAccount = owner; + + const possibleWithdraw = await farm.balanceOf( + withdrawAccount + ); + + await expectRevert( + farm.farmWithdraw( + possibleWithdraw, + { + from: owner + } + ), + "TimeLockFarmV2: STILL_EARNING" + ); + + await stakeToken.mint( + defaultTokenAmount, + { + from: bob + } + ); + + await stakeToken.approve( + farm.address, + defaultTokenAmount, + { + from: bob + } + ); + + await farm.farmDeposit( + defaultTokenAmount, + { + from: bob + } + ); + + await time.increase( + defaultUnlockTime + ); + + await farm.farmWithdraw( + possibleWithdraw, + { + from: owner + } + ); + }); + }); + + describe("Owner functionality", () => { + + beforeEach(async () => { + const result = await setupScenario(); + farm = result.farm; + }); + + it("should have correct owner address", async () => { + + const expectedAddress = owner; + const ownerAddress = await farm.ownerAddress(); + + assert.equal( + expectedAddress, + ownerAddress + ); + }); + + it("should have correct owner address based on deployment parameters", async () => { + + const expectedAddress = alice; + + const newFarm = await Farm.new( + stakeToken.address, + rewardToken.address, + expectedAddress, + expectedAddress, + defaultDurationInSeconds, + defaultUnlockTime, + { + from: owner + } + ); + + const ownerAddress = await newFarm.ownerAddress(); + + assert.equal( + expectedAddress, + ownerAddress + ); + }); + }); + + describe("Manager functionality", () => { + + beforeEach(async () => { + const result = await setupScenario(); + farm = result.farm; + }); + + it("should have correct manager address", async () => { + + const expectedAddress = owner; + const managerAddress = await farm.managerAddress(); + + assert.equal( + expectedAddress, + managerAddress + ); + }); + + it("should have correct manager address based on deployment wallet", async () => { + + const expectedManager = alice; + + const newFarm = await Farm.new( + stakeToken.address, + rewardToken.address, + owner, + expectedManager, + defaultDurationInSeconds, + defaultUnlockTime, + { + from: random + } + ); + + const managerAddress = await newFarm.managerAddress(); + + assert.equal( + expectedManager, + managerAddress + ); + }); + + it("should be able to change manager only by owner address", async () => { + + const expectedCurrentOwner = owner; + const expectedCurrentManager = owner; + const newManager = bob; + const wrongOwner = alice; + + const currentOwner = await farm.ownerAddress(); + const currentManager = await farm.managerAddress(); + + assert.equal( + currentOwner, + expectedCurrentOwner + ); + + assert.equal( + currentManager, + expectedCurrentManager + ); + + await expectRevert( + farm.changeManager( + newManager, + { + from: wrongOwner + } + ), + "TimeLockFarmV2: INVALID_OWNER" + ); + + await farm.changeManager( + newManager, + { + from: currentOwner + } + ); + + const newManagerAfterChange = await farm.managerAddress(); + + assert.notEqual( + currentManager, + newManagerAfterChange + ); + + assert.equal( + newManager, + newManagerAfterChange + ); + }); + + it("should revert if newManager is ZERO_ADDRESS", async () => { + + const wrongAddress = "0x0000000000000000000000000000000000000000"; + const rightAddress = "0x0000000000000000000000000000000000000001"; + + await expectRevert( + farm.changeManager( + wrongAddress, + { + from: owner + } + ), + "TimeLockFarmV2: WRONG_ADDRESS" + ); + + await farm.changeManager( + rightAddress, + { + from: owner + } + ); + + const managerAddress = await farm.managerAddress(); + + assert.equal( + rightAddress, + managerAddress + ); + }); + + it("should emit correct ManagerChanged event", async () => { + + const newManager = bob; + + await farm.changeManager( + newManager + ); + + const newManagerAfterChange = await farm.managerAddress(); + + assert.equal( + newManager, + newManagerAfterChange + ); + + const transactionData = await getLastEvent( + "ManagerChanged", + farm + ); + + assert.equal( + transactionData.newManager, + newManagerAfterChange + ); + }); + }); + + describe("Earn functionality", () => { + + beforeEach(async () => { + + const result = await setupScenario({ + approval: true + }); + + stakeToken = result.stakeToken; + rewardToken = result.rewardToken; + farm = result.farm; + + defaultTokenAmount = TWO_TOKENS; + defaultRewardRate = 10; + + await farm.farmDeposit( + defaultTokenAmount + ); + + await stakeToken.mint( + defaultTokenAmount, + { + from: bob + } + ); + + await stakeToken.approve( + farm.address, + defaultTokenAmount, + { + from: bob + } + ); + }); + + it("should earn rewards proportionally to stake time", async () => { + + await farm.setRewardRate( + defaultRewardRate + ); + + const stepTimeFrame = 1; + const expectedDefaultEarn = 0; + const rewardRate = await farm.rewardRate(); + const earnPerStep = stepTimeFrame * rewardRate; + + const earnedInital = await farm.earned( + owner + ); + + assert.equal( + parseInt(earnedInital), + parseInt(expectedDefaultEarn) + ); + + await time.increase( + stepTimeFrame + ); + + const earnedStep1 = await farm.earned( + owner + ); + + assert.isAtLeast( + parseInt(earnedStep1), + earnPerStep * 1 + ); + + await time.increase( + stepTimeFrame + ); + + const earnedStep2 = await farm.earned( + owner + ); + + assert.isAtLeast( + parseInt(earnedStep2), + earnPerStep * 2 + ); + }); + + it("should earn rewards proportionally to staked amount single", async () => { + + await farm.farmDeposit( + defaultTokenAmount, + { + from: bob + } + ); + + await farm.setRewardRate( + defaultRewardRate + ); + + const stepTimeFrame = 1; + const expectedDefaultEarn = 0; + + const depositedByOwner = await farm.balanceOf( + owner + ); + + const depositedByBob = await farm.balanceOf( + bob + ); + + assert.equal( + depositedByOwner.toString(), + depositedByBob.toString() + ); + + const earnedInitalOwner = await farm.earned( + owner + ); + + const earnedInitalBob = await farm.earned( + owner + ); + + assert.equal( + earnedInitalOwner.toString(), + earnedInitalBob.toString() + ); + + await time.increase( + stepTimeFrame + ); + + const earnedOwnerStep1 = await farm.earned( + owner + ); + + const earnedBobStep1 = await farm.earned( + bob + ); + + assert.equal( + earnedOwnerStep1.toString(), + earnedBobStep1.toString() + ); + + await time.increase( + stepTimeFrame + ); + + const earnedOwnerStep2 = await farm.earned( + owner + ); + + const earnedBobStep2 = await farm.earned( + bob + ); + + assert.equal( + earnedOwnerStep2.toString(), + earnedBobStep2.toString() + ); + + assert.isAbove( + parseInt(earnedOwnerStep2), + parseInt(earnedOwnerStep1) + ); + + assert.isAbove( + parseInt(earnedBobStep2), + parseInt(earnedBobStep1) + ); + }); + + it("should earn rewards proportionally to staked amount multiple", async () => { + + await farm.farmDeposit( + ONE_TOKEN, + { + from: bob + } + ); + + await farm.setRewardRate( + defaultRewardRate + ); + + const stepTimeFrame = 1; + const expectedDefaultEarn = 0; + const rewardRate = await farm.rewardRate(); + const earnPerStep = stepTimeFrame * rewardRate; + + const depositedByOwner = await farm.balanceOf( + owner + ); + + const depositedByBob = await farm.balanceOf( + bob + ); + + assert.isAbove( + parseInt(depositedByOwner), + parseInt(depositedByBob) + ); + + assert.equal( + depositedByOwner, + depositedByBob * 2 + ); + + const earnedInitalOwner = await farm.earned( + owner + ); + + const earnedInitalBob = await farm.earned( + owner + ); + + assert.equal( + earnedInitalOwner, + earnedInitalBob * 2 + ); + + await time.increase( + stepTimeFrame + ); + + const earnedOwnerStep1 = await farm.earned( + owner + ); + + const earnedBobStep1 = await farm.earned( + bob + ); + + assert.equal( + earnedOwnerStep1, + earnedBobStep1 * 2 + ); + }); + }); + + describe("Claiming functionality", () => { + + beforeEach(async () => { + + defaultDeposit = tokens("1"); + defaultRate = 10; + + const result = await setupScenario({ + approval: true, + deposit: defaultDeposit + // rate: defaultRate + }); + + stakeToken = result.stakeToken; + rewardToken = result.rewardToken; + farm = result.farm; + }); + + it("should reset userRewards mapping after claim to 0", async () => { + + const stakerAddess = owner; + const expectedValue = 0; + + const userRewardsBeforeClaim = await farm.userRewards( + stakerAddess + ); + + const earnedFromStart = await farm.earned( + stakerAddess + ); + + assert.equal( + parseInt(earnedFromStart), + expectedValue + ); + + assert.equal( + parseInt(userRewardsBeforeClaim), + expectedValue + ); + + await farm.setRewardRate( + defaultRate + ); + + const timeJumpStep = 1; + + await time.increase( + timeJumpStep + ); + + const earnedAfterStart = await farm.earned( + stakerAddess + ); + + assert.isAbove( + parseInt(earnedAfterStart), + expectedValue + ); + + await time.increase( + timeJumpStep + ); + + await farm.claimReward(); + + const userRewardsAfterClaim = await farm.userRewards( + stakerAddess + ); + + const earnAfterClaim = await farm.earned( + stakerAddess + ); + + assert.isBelow( + parseInt(earnAfterClaim), + parseInt(earnedAfterStart) + ); + + assert.equal( + parseInt(userRewardsAfterClaim), + expectedValue + ); + }); + + it("should revert if nothing to claim", async () => { + const stakerAddess = owner; + const nonStakerAddress = bob; + const timeJumpStep = 1; + + await farm.setRewardRate( + defaultRate, + { + from: stakerAddess + } + ); + + await time.increase( + timeJumpStep + ); + + await expectRevert( + farm.claimReward( + { + from: nonStakerAddress + } + ), + "TimeLockFarmV2: NOTHING_TO_CLAIM" + ); + }); + + it("should update lastUpdateTime value after claim", async () => { + + const stakerAddess = owner; + const expectedValue = 0; + + const userRewardsBeforeClaim = await farm.userRewards( + stakerAddess + ); + + const earnedFromStart = await farm.earned( + stakerAddess + ); + + assert.equal( + parseInt(earnedFromStart), + expectedValue + ); + + assert.equal( + parseInt(userRewardsBeforeClaim), + expectedValue + ); + + await farm.setRewardRate( + defaultRate + ); + + const timeJumpStep = 1; + + await time.increase( + timeJumpStep + ); + + const earnedAfterStart = await farm.earned( + stakerAddess + ); + + assert.isAbove( + parseInt(earnedAfterStart), + expectedValue + ); + + await time.increase( + timeJumpStep + ); + + const lastUpdateTime = await farm.lastUpdateTime(); + await farm.claimReward(); + const lastUpdateTimeAfter = await farm.lastUpdateTime(); + + assert.isAbove( + lastUpdateTimeAfter.toNumber(), + lastUpdateTime.toNumber() + ); + }); + }); + + describe("Exit functionality", () => { + + beforeEach(async () => { + + defaultTokenAmount = TWO_TOKENS; + defaultRate = 10; + + const result = await setupScenario({ + approval: true, + deposit: defaultTokenAmount, + rate: defaultRate + }); + + stakeToken = result.stakeToken; + rewardToken = result.rewardToken; + farm = result.farm; + }); + + it("if all tokens unlock should not be able to exit until rewards are still available", async () => { + + const withdrawAccount = owner; + + const possibleWithdraw = await farm.balanceOf( + withdrawAccount + ); + + await time.increase( + defaultUnlockTime + ); + + await expectRevert( + farm.exitFarm( + { + from: owner + } + ), + "TimeLockFarmV2: STILL_EARNING" + ); + + await time.increase( + defaultDurationInSeconds + 1 + ); + + await farm.exitFarm( + { + from: withdrawAccount + } + ); + }); + + it("if all tokens unlocked should not be able to exit as last farmer until rewards are still available", async () => { + + const withdrawAccount = owner; + + const possibleWithdraw = await farm.balanceOf( + withdrawAccount + ); + + await time.increase( + defaultUnlockTime + ); + + await expectRevert( + farm.exitFarm( + { + from: owner + } + ), + "TimeLockFarmV2: STILL_EARNING" + ); + + await stakeToken.mint( + defaultTokenAmount, + { + from: bob + } + ); + + await stakeToken.approve( + farm.address, + defaultTokenAmount, + { + from: bob + } + ); + + await farm.farmDeposit( + defaultTokenAmount, + { + from: bob + } + ); + + await time.increase( + 1 + ); + + await farm.exitFarm( + { + from: withdrawAccount + } + ); + }); + + it("should not be able to exit if nothing to claim, perform withdraw instead", async () => { + + const withdrawAccount = owner; + + const possibleWithdraw = await farm.balanceOf( + withdrawAccount + ); + + await time.increase( + defaultUnlockTime + ); + + await expectRevert( + farm.exitFarm( + { + from: owner + } + ), + "TimeLockFarmV2: STILL_EARNING" + ); + + await time.increase( + defaultDurationInSeconds + 1 + ); + + await farm.claimReward( + { + from: withdrawAccount + } + ); + + await expectRevert( + farm.exitFarm( + { + from: owner + } + ), + "TimeLockFarmV2: NOTHING_TO_CLAIM" + ); + + await farm.farmWithdraw( + possibleWithdraw, + { + from: withdrawAccount + } + ); + + await expectRevert.unspecified( + farm.farmWithdraw( + possibleWithdraw, + { + from: withdrawAccount + } + ) + ); + }); + }); + + describe("Recover token functionality", () => { + + beforeEach(async () => { + + const result = await setupScenario(); + + randomToken = await Token.new(); + stakeToken = result.stakeToken; + rewardToken = result.rewardToken; + farm = result.farm; + }); + + it("should be able to recover accidentally sent tokens from the contract", async () => { + + const transferAmount = ONE_TOKEN; + + await randomToken.transfer( + farm.address, + transferAmount + ); + + const balanceBefore = await randomToken.balanceOf( + farm.address + ); + + assert.equal( + balanceBefore, + transferAmount + ); + + await farm.recoverToken( + randomToken.address, + balanceBefore + ); + + const balanceAfter = await randomToken.balanceOf( + farm.address + ); + + assert.equal( + balanceAfter.toString(), + "0" + ); + }); + + it("should not be able to recover stakeTokens from the contract", async () => { + + const transferAmount = ONE_TOKEN; + + await rewardToken.transfer( + farm.address, + transferAmount + ); + + await expectRevert( + farm.recoverToken( + rewardToken.address, + transferAmount + ), + "TimeLockFarmV2: INVALID_TOKEN" + ); + }); + + it("should not be able to recover rewardTokens from the contract", async () => { + + const transferAmount = ONE_TOKEN; + + await stakeToken.transfer( + farm.address, + transferAmount + ); + + await expectRevert( + farm.recoverToken( + stakeToken.address, + transferAmount + ), + "TimeLockFarmV2: INVALID_TOKEN" + ); + }); + }); + + describe("Earn functionality with transfer", () => { + + beforeEach(async () => { + + const result = await setupScenario({ + approval: true + }); + + stakeToken = result.stakeToken; + rewardToken = result.rewardToken; + farm = result.farm; + + defaultTokenAmount = tokens("10000"); + defaultRewardRate = 100; + + await stakeToken.mint( + defaultTokenAmount, + { + from: alice + } + ); + + await stakeToken.mint( + defaultTokenAmount, + { + from: bob + } + ); + + await stakeToken.approve( + farm.address, + defaultTokenAmount, + { + from: alice + } + ); + + await stakeToken.approve( + farm.address, + defaultTokenAmount, + { + from: bob + } + ); + }); + + it("should issue tokens accordingly to staked balances even if transferred", async () => { + + const aliceDeposit = tokens("100"); + const bobDeposit = tokens("9900"); + + const SECONDS_IN_DAY = 86400; + const THREE_MONTHS = 90 * SECONDS_IN_DAY; + + await farm.farmDeposit( + aliceDeposit, + { + from: alice + } + ); + + await farm.farmDeposit( + bobDeposit, + { + from: bob + } + ); + + await farm.setRewardRate( + defaultRewardRate + ); + + const supplyInFarmInitially = await rewardToken.balanceOf( + farm.address + ); + + const depositedByAlice = await farm.balanceOf( + alice + ); + + const depositedByBob = await farm.balanceOf( + bob + ); + + assert.isAbove( + parseInt(depositedByBob), + parseInt(depositedByAlice) + ); + + await time.increase( + THREE_MONTHS + ); + + const earnedByBobBeforeTransfer = await farm.earned( + bob + ); + + const earnedByAliceBeforeTransfer = await farm.earned( + alice + ); + + assert.isAbove( + parseInt(earnedByBobBeforeTransfer), + parseInt(earnedByAliceBeforeTransfer) + ); + + await farm.transfer( + alice, + depositedByBob, + { + from: bob + } + ); + + const earnedByBobAfterTransfer = await farm.earned( + bob + ); + + const earnedByAliceAfterTransfer = await farm.earned( + alice + ); + + assert.isAbove( + parseInt(earnedByBobAfterTransfer), + parseInt(earnedByAliceAfterTransfer) + ); + + assert.equal( + parseInt(earnedByBobAfterTransfer), + parseInt(earnedByBobBeforeTransfer), + ); + + assert.equal( + parseInt(earnedByAliceBeforeTransfer), + parseInt(earnedByAliceAfterTransfer) + ); + + const depositedByAliceAfterTransfer = await farm.balanceOf( + alice + ); + + const depositedByBobAfterTransfer = await farm.balanceOf( + bob + ); + + assert.equal( + parseInt(depositedByBobAfterTransfer), + 0 + ); + + assert.equal( + parseInt(depositedByAliceAfterTransfer), + parseInt(depositedByAlice) + parseInt(depositedByBob) + ); + + const supplyInFarmBefore = await rewardToken.balanceOf( + farm.address + ); + + await farm.farmWithdraw( + tokens("10000"), + { + from: alice + } + ); + + await farm.claimReward( + { + from: alice + } + ); + + const alicesTransfer = await getLastEvent( + "Transfer", + rewardToken + ); + + await farm.claimReward( + { + from: bob + } + ); + + const bobsTransfer = await getLastEvent( + "Transfer", + rewardToken + ); + + const supplyAliceGot = await rewardToken.balanceOf( + alice + ); + + assert.equal( + supplyInFarmBefore.toString(), + supplyInFarmInitially.toString() + ); + + assert.equal( + alicesTransfer.from, + farm.address + ); + + assert.equal( + alicesTransfer.to, + alice + ); + + assert.equal( + alicesTransfer.value.toString(), + earnedByAliceBeforeTransfer.toString() + ); + + assert.equal( + alicesTransfer.value.toString(), + supplyAliceGot.toString() + ); + + assert.equal( + bobsTransfer.value.toString(), + earnedByBobBeforeTransfer.toString() + ); + + assert.equal( + bobsTransfer.value.toString(), + earnedByBobAfterTransfer.toString() + ); + }); + + it("should issue tokens accordingly to staked balances even if transferred", async () => { + + const aliceDeposit = tokens("100"); + const bobDeposit = tokens("9900"); + + const SECONDS_IN_DAY = 86400; + const THREE_MONTHS = 90 * SECONDS_IN_DAY; + + await farm.farmDeposit( + aliceDeposit, + { + from: alice + } + ); + + await farm.setRewardRate( + defaultRewardRate + ); + + const supplyInFarmInitially = await rewardToken.balanceOf( + farm.address + ); + + const depositedByAlice = await farm.balanceOf( + alice + ); + + await time.increase( + THREE_MONTHS + ); + + const earnedByAliceBeforeTransfer = await farm.earned( + alice + ); + + await farm.farmDeposit( + bobDeposit, + { + from: bob + } + ); + + const depositedByBob = await farm.balanceOf( + bob + ); + + const earnedByBobBeforeTransfer = await farm.earned( + bob + ); + + await time.increase( + defaultUnlockTime + ); + + await farm.transfer( + alice, + depositedByBob, + { + from: bob + } + ); + + await expectRevert( + farm.claimReward( + { + from: bob + } + ), + "TimeLockFarmV2: NOTHING_TO_CLAIM" + ); + + const earnedByBobAfterTransfer = await farm.earned( + bob + ); + + const earnedByAliceAfterTransfer = await farm.earned( + alice + ); + + assert.isAbove( + parseInt(earnedByAliceAfterTransfer), + parseInt(earnedByBobAfterTransfer) + ); + + assert.equal( + parseInt(earnedByBobAfterTransfer), + 0 + ); + + assert.equal( + parseInt(earnedByAliceAfterTransfer), + parseInt(earnedByAliceBeforeTransfer) + parseInt(earnedByBobBeforeTransfer) + ); + + const depositedByAliceAfterTransfer = await farm.balanceOf( + alice + ); + + const depositedByBobAfterTransfer = await farm.balanceOf( + bob + ); + + assert.equal( + parseInt(depositedByBobAfterTransfer), + 0 + ); + + assert.equal( + parseInt(depositedByAliceAfterTransfer), + parseInt(depositedByAlice) + parseInt(depositedByBob) + ); + + const supplyInFarmBefore = await rewardToken.balanceOf( + farm.address + ); + + await farm.farmWithdraw( + tokens("10000"), + { + from: alice + } + ); + + await farm.claimReward( + { + from: alice + } + ); + + await expectRevert( + farm.claimReward( + { + from: bob + } + ), + "TimeLockFarmV2: NOTHING_TO_CLAIM" + ); + + const supplyInFarmAfter = await rewardToken.balanceOf( + farm.address + ); + + const supplyAliceGot = await rewardToken.balanceOf( + alice + ); + + const { from, to, value } = await getLastEvent( + "Transfer", + rewardToken + ); + + assert.equal( + supplyInFarmBefore.toString(), + supplyInFarmInitially.toString() + ); + + assert.equal( + from, + farm.address + ); + + assert.equal( + to, + alice + ); + + assert.equal( + value.toString(), + supplyInFarmInitially.toString() + ); + }); + + it("should continue earning with higher/lower capacity after transfer", async () => { + + const aliceDeposit = tokens("5000"); + const bobDeposit = tokens("5000"); + const TIME_STEP = 100; + + await farm.farmDeposit( + aliceDeposit, + { + from: alice + } + ); + + await farm.farmDeposit( + bobDeposit, + { + from: bob + } + ); + + await farm.setRewardRate( + defaultRewardRate + ); + + const depositedByAlice = await farm.balanceOf( + alice + ); + + const depositedByBob = await farm.balanceOf( + bob + ); + + assert.equal( + parseInt(depositedByBob), + parseInt(depositedByAlice) + ); + + await time.increase( + defaultUnlockTime + ); + + const earnedByBobBeforeTransfer = await farm.earned( + bob + ); + + const earnedByAliceBeforeTransfer = await farm.earned( + alice + ); + + assert.equal( + parseInt(earnedByBobBeforeTransfer), + parseInt(earnedByAliceBeforeTransfer) + ); + + assert.isAbove( + parseInt(earnedByBobBeforeTransfer), + 0 + ); + + assert.isAbove( + parseInt(earnedByAliceBeforeTransfer), + 0 + ); + + await farm.transfer( + alice, + depositedByBob, + { + from: bob + } + ); + + await time.increase( + TIME_STEP + ); + + const earnedByBobAfterTransfer = await farm.earned( + bob + ); + + const earnedByAliceAfterTransfer = await farm.earned( + alice + ); + + assert.equal( + parseInt(earnedByBobBeforeTransfer), + parseInt(earnedByBobAfterTransfer) + ); + + assert.isAbove( + parseInt(earnedByAliceAfterTransfer), + parseInt(earnedByAliceBeforeTransfer) + ); + + const totalEarnedByAliceExpected = parseInt(earnedByBobBeforeTransfer) + + parseInt(earnedByAliceBeforeTransfer) + + parseInt(earnedByAliceBeforeTransfer); + + assert.equal( + parseInt(earnedByAliceAfterTransfer), + totalEarnedByAliceExpected + ); + + const earnedByAliceAfterTransferDelta = parseInt(earnedByAliceAfterTransfer) + - parseInt(earnedByAliceBeforeTransfer); + + assert.equal( + earnedByAliceAfterTransferDelta, + earnedByAliceBeforeTransfer * 2 + ); + }); + + it("should issue tokens accordingly to staked balances even if claimed and transferred", async () => { + + const aliceDeposit = tokens("100"); + const bobDeposit = tokens("9900"); + + const SECONDS_IN_DAY = 86400; + const THREE_MONTHS = 90 * SECONDS_IN_DAY; + + await farm.farmDeposit( + aliceDeposit, + { + from: alice + } + ); + + await farm.farmDeposit( + bobDeposit, + { + from: bob + } + ); + + await farm.setRewardRate( + defaultRewardRate + ); + + const supplyInFarmInitially = await rewardToken.balanceOf( + farm.address + ); + + const depositedByAlice = await farm.balanceOf( + alice + ); + + const depositedByBob = await farm.balanceOf( + bob + ); + + assert.isAbove( + parseInt(depositedByBob), + parseInt(depositedByAlice) + ); + + await time.increase( + THREE_MONTHS + ); + + const earnedByBobBeforeTransfer = await farm.earned( + bob + ); + + const earnedByAliceBeforeTransfer = await farm.earned( + alice + ); + + assert.isAbove( + parseInt(earnedByBobBeforeTransfer), + parseInt(earnedByAliceBeforeTransfer) + ); + + await farm.claimReward( + { + from: bob + } + ); + + const bobsClaim = await getLastEvent( + "Transfer", + rewardToken + ); + + assert.equal( + bobsClaim.from, + farm.address + ); + + assert.equal( + bobsClaim.to, + bob + ); + + assert.equal( + bobsClaim.value.toString(), + earnedByBobBeforeTransfer + ); + + await farm.transfer( + alice, + depositedByBob, + { + from: bob + } + ); + + const earnedByBobAfterTransfer = await farm.earned( + bob + ); + + const earnedByAliceAfterTransfer = await farm.earned( + alice + ); + + assert.isAbove( + parseInt(earnedByAliceAfterTransfer), + parseInt(earnedByBobAfterTransfer) + ); + + assert.equal( + parseInt(earnedByBobAfterTransfer), + 0 + ); + + assert.equal( + parseInt(earnedByAliceAfterTransfer), + parseInt(earnedByAliceBeforeTransfer) + ); + + const depositedByAliceAfterTransfer = await farm.balanceOf( + alice + ); + + const depositedByBobAfterTransfer = await farm.balanceOf( + bob + ); + + assert.equal( + parseInt(depositedByBobAfterTransfer), + 0 + ); + + assert.equal( + parseInt(depositedByAliceAfterTransfer), + parseInt(depositedByAlice) + parseInt(depositedByBob) + ); + + await farm.farmWithdraw( + tokens("10000"), + { + from: alice + } + ); + + await farm.claimReward( + { + from: alice + } + ); + + await expectRevert( + farm.claimReward( + { + from: bob + } + ), + "TimeLockFarmV2: NOTHING_TO_CLAIM" + ); + + const supplyInFarmAfter = await rewardToken.balanceOf( + farm.address + ); + + const supplyAliceGot = await rewardToken.balanceOf( + alice + ); + + const aliceTransfer = await getLastEvent( + "Transfer", + rewardToken + ); + + assert.equal( + aliceTransfer.from, + farm.address + ); + + assert.equal( + aliceTransfer.to, + alice + ); + + assert.equal( + aliceTransfer.value.toString(), + earnedByAliceBeforeTransfer + ); + + assert.equal( + aliceTransfer.value.toString(), + earnedByAliceAfterTransfer + ); + }); + }); +});