diff --git a/src/Avatar.sol b/src/Avatar.sol new file mode 100644 index 0000000..e4095f4 --- /dev/null +++ b/src/Avatar.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.12; + +import {OwnableUpgradeable} from "openzeppelin-contracts-upgradeable/access/OwnableUpgradeable.sol"; +import "./lib/GlobalAccessControlManaged.sol"; +import "./lib/Executor.sol"; + +/** + Avatar + Forwards calls from the owner + +*/ +contract Avatar is GlobalAccessControlManaged, OwnableUpgradeable, Executor { + function initialize(address _globalAccessControl, address _owner) + public + initializer + { + __GlobalAccessControlManaged_init(_globalAccessControl); + __Ownable_init_unchained(); + transferOwnership(_owner); + } + + /** + * @dev Make arbitrary Ethereum call + * @param to Address to call + * @param value ETH value + * @param data TX data + */ + function call( + address to, + uint256 value, + bytes memory data + ) external payable onlyOwner gacPausable returns (bool success) { + return execute(to, value, data, false, gasleft()); + } +} diff --git a/src/Funding.sol b/src/Funding.sol index 8d3de31..194dff4 100644 --- a/src/Funding.sol +++ b/src/Funding.sol @@ -160,6 +160,7 @@ contract Funding is GlobalAccessControlManaged, ReentrancyGuardUpgradeable { */ function deposit(uint256 _assetAmountIn, uint256 _minCitadelOut) external + virtual onlyWhenPriceNotFlagged gacPausable nonReentrant diff --git a/src/FundingWithEth.sol b/src/FundingWithEth.sol new file mode 100644 index 0000000..747178d --- /dev/null +++ b/src/FundingWithEth.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.12; + +import "./Funding.sol"; +/** + * @notice Sells a token at a predetermined price to whitelisted buyers. + * TODO: Better revert strings + */ +contract FundingWithEth is Funding { + + /// ========================== + /// ===== Public actions ===== + /// ========================== + + /** + * @notice Exchange `msg.value` of Ether for `citadel` + * @param _minCitadelOut Minimum amount of `citadel` to receive + * @return citadelAmount_ Amount of `xCitadel` bought + */ + function depositEth(uint256 _minCitadelOut) + external + payable + onlyWhenPriceNotFlagged + gacPausable + nonReentrant + returns (uint256 citadelAmount_) + { + uint256 _assetAmountIn = msg.value; + require(_assetAmountIn > 0, "_assetAmountIn must not be 0"); + require( + funding.assetCumulativeFunded + _assetAmountIn <= funding.assetCap, + "asset funding cap exceeded" + ); + funding.assetCumulativeFunded = + funding.assetCumulativeFunded + + _assetAmountIn; + // Take in asset from user + citadelAmount_ = getAmountOut(_assetAmountIn); + require(citadelAmount_ >= _minCitadelOut, "minCitadelOut"); + + payable(saleRecipient).transfer(_assetAmountIn); + + // Deposit xCitadel and send to user + // TODO: Check gas costs. How does this relate to market buying if you do want to deposit to xCTDL? + xCitadel.depositFor(msg.sender, citadelAmount_); + + emit Deposit(msg.sender, _assetAmountIn, citadelAmount_); + } + + function deposit(uint256 _assetAmountIn, uint256 _minCitadelOut) + external + override + onlyWhenPriceNotFlagged + gacPausable + nonReentrant + returns (uint256 citadelAmount_) + { + revert("FundingWithEth: use depositEth"); + } + +} diff --git a/src/KnightingRound.sol b/src/KnightingRound.sol index 2d2c77c..e5d5df8 100644 --- a/src/KnightingRound.sol +++ b/src/KnightingRound.sol @@ -168,7 +168,7 @@ contract KnightingRound is uint256 _tokenInAmount, uint8 _daoId, bytes32[] calldata _proof - ) public gacPausable returns (uint256 tokenOutAmount_) { + ) public virtual gacPausable returns (uint256 tokenOutAmount_) { require(saleStart <= block.timestamp, "KnightingRound: not started"); require( block.timestamp < saleStart + saleDuration, diff --git a/src/KnightingRoundRegistry.sol b/src/KnightingRoundRegistry.sol index f6fc264..16246bf 100644 --- a/src/KnightingRoundRegistry.sol +++ b/src/KnightingRoundRegistry.sol @@ -105,9 +105,13 @@ contract KnightingRoundRegistry is Initializable { function getRoundData(address _roundAddress) public view - returns (KnightingRoundData.RoundData memory ) + returns (KnightingRoundData.RoundData memory) { - return KnightingRoundData.getRoundData(_roundAddress, knightingRoundsWithEth); + return + KnightingRoundData.getRoundData( + _roundAddress, + knightingRoundsWithEth + ); } /// @notice using to get all rounds diff --git a/src/KnightingRoundWithEth.sol b/src/KnightingRoundWithEth.sol index 95db7af..1e393ce 100644 --- a/src/KnightingRoundWithEth.sol +++ b/src/KnightingRoundWithEth.sol @@ -22,9 +22,51 @@ contract KnightingRoundWithEth is KnightingRound { gacPausable returns (uint256 tokenOutAmount_) { - WETH weth = WETH(address(tokenIn)); - weth.deposit{value: msg.value}(); - IERC20(address(tokenIn)).safeTransfer(msg.sender, msg.value); - tokenOutAmount_ = super.buy(msg.value, _daoId, _proof); + uint256 _tokenInAmount = msg.value; + require(saleStart <= block.timestamp, "KnightingRound: not started"); + require( + block.timestamp < saleStart + saleDuration, + "KnightingRound: already ended" + ); + require(_tokenInAmount > 0, "_tokenInAmount should be > 0"); + require( + totalTokenIn + _tokenInAmount <= tokenInLimit, + "total amount exceeded" + ); + + if (address(guestlist) != address(0)) { + require(guestlist.authorized(msg.sender, _proof), "not authorized"); + } + + uint256 boughtAmountTillNow = boughtAmounts[msg.sender]; + + if (boughtAmountTillNow > 0) { + require( + _daoId == daoVotedFor[msg.sender], + "can't vote for multiple daos" + ); + } else { + daoVotedFor[msg.sender] = _daoId; + } + + tokenOutAmount_ = getAmountOut(_tokenInAmount); + + boughtAmounts[msg.sender] = boughtAmountTillNow + tokenOutAmount_; + daoCommitments[_daoId] = daoCommitments[_daoId] + tokenOutAmount_; + + totalTokenIn = totalTokenIn + _tokenInAmount; + totalTokenOutBought = totalTokenOutBought + tokenOutAmount_; + + payable(saleRecipient).transfer(_tokenInAmount); + + emit Sale(msg.sender, _daoId, _tokenInAmount, tokenOutAmount_); + } + + function buy( + uint256 _tokenInAmount, + uint8 _daoId, + bytes32[] calldata _proof + ) public override gacPausable returns (uint256 tokenOutAmount_) { + require(false, "use buyEth() function"); } }