From 141211569aebc0f79d764d4b788ce0408445d81e Mon Sep 17 00:00:00 2001 From: gozzy Date: Sun, 9 Apr 2023 18:26:54 +0000 Subject: [PATCH] reimplement auction vesting --- src/RDA.sol | 62 +++++++++++++++------------------- src/interfaces/IGovernance.sol | 6 ++++ src/interfaces/IRDA.sol | 42 +++++++++++++++++++++++ test/Proposal.t.sol | 6 ++-- 4 files changed, 78 insertions(+), 38 deletions(-) diff --git a/src/RDA.sol b/src/RDA.sol index a238d02..4f6bcc1 100755 --- a/src/RDA.sol +++ b/src/RDA.sol @@ -1,6 +1,7 @@ pragma solidity 0.8.13; -import { IRDA } from "@root/interfaces/IRDA.sol"; +import { IRDA } from "@interfaces/IRDA.sol"; +import { IDelegatedVesting } from "@interfaces/IDelegatedVesting.sol"; import { ERC20 } from "@openzeppelin/token/ERC20/ERC20.sol"; import { SafeERC20 } from "@openzeppelin/token/ERC20/utils/SafeERC20.sol"; @@ -28,24 +29,7 @@ contract RDA is IRDA, ReentrancyGuard { /* @dev Auction mapping for the window index */ mapping(bytes => uint256) public _windows; - struct Auction { - uint256 windowDuration; /* @dev Unix time window duration */ - uint256 windowTimestamp; /* @dev Unix timestamp for window start */ - uint256 startTimestamp; /* @dev Unix auction start timestamp */ - uint256 endTimestamp; /* @dev Unix auction end timestamp */ - uint256 duration; /* @dev Unix time auction duration */ - uint256 proceeds; /* @dev Auction proceeds balance */ - uint256 reserves; /* @dev Auction reserves balance */ - uint256 price; /* @dev Auction origin price */ - } - - struct Window { - bytes bidId; /* @dev Bid identifier */ - uint256 expiry; /* @dev Unix timestamp window exipration */ - uint256 price; /* @dev Window price */ - uint256 volume; /* @dev Window volume */ - bool processed; /* @dev Window fuflfillment state */ - } + mapping(bytes => Vesting) public _vesting; /* * @dev Conditioner to ensure an auction is active @@ -137,6 +121,7 @@ contract RDA is IRDA, ReentrancyGuard { * @param w͟i͟n͟d͟o͟w͟D͟u͟r͟a͟t͟i͟o͟n͟ Uinx time window duration */ function createAuction( + address vestingAddress, address operatorAddress, address reserveToken, address purchaseToken, @@ -145,7 +130,8 @@ contract RDA is IRDA, ReentrancyGuard { uint256 startingOriginPrice, uint256 startTimestamp, uint256 endTimestamp, - uint256 windowDuration + uint256 windowDuration, + uint256 vestingDuration ) override external returns (bytes memory) { bytes memory auctionId = abi.encode( operatorAddress, @@ -155,13 +141,8 @@ contract RDA is IRDA, ReentrancyGuard { abi.encodePacked(reserveAmount, startingOriginPrice, startTimestamp, endTimestamp, windowDuration) ); - ERC20 tokenReserve = ERC20(reserveToken); - ERC20 tokenPurchase = ERC20(purchaseToken); - Auction storage state = _auctions[auctionId]; - - uint256 auctionDuration = endTimestamp - startTimestamp; - + if (state.price != 0) { revert AuctionExists(); } @@ -171,25 +152,32 @@ contract RDA is IRDA, ReentrancyGuard { if (startTimestamp < block.timestamp) { revert InvalidAuctionTimestamp(); } - if (tokenReserve.decimals() != tokenPurchase.decimals()){ + if (ERC20(reserveToken).decimals() != ERC20(purchaseToken).decimals()){ revert InvalidTokenDecimals(); } - if (auctionDuration < 1 days || windowDuration < 2 hours) { + if (endTimestamp - startTimestamp < 1 days || windowDuration < 2 hours) { revert InvalidAuctionDurations(); } - tokenReserve.safeTransferFrom(msg.sender, address(this), reserveAmount); + { + Vesting storage vesting = _vesting[auctionId]; - state.windowDuration = windowDuration; + vesting.period = vestingDuration; + vesting.instance = vestingAddress; + } + + state.duration = endTimestamp - startTimestamp; state.windowTimestamp = startTimestamp; state.startTimestamp = startTimestamp; + state.windowDuration = windowDuration; state.endTimestamp = endTimestamp; state.price = startingOriginPrice; - state.duration = auctionDuration; state.reserves = reserveAmount; emit NewAuction(auctionId, reserveToken, reserveAmount, startingOriginPrice, endTimestamp); + ERC20(reserveToken).safeTransferFrom(msg.sender, address(this), reserveAmount); + return auctionId; } @@ -451,20 +439,24 @@ contract RDA is IRDA, ReentrancyGuard { function redeem(address bidder, bytes calldata auctionId) inactiveAuction(auctionId) override external { - ERC20 tokenReserve = ERC20(reserveToken(auctionId)); + Vesting storage vesting = _vesting[auctionId]; + ERC20 tokenPurchase = ERC20(purchaseToken(auctionId)); + IDelegatedVesting vestingInstance = IDelegatedVesting(vesting.instance); + + uint256 vestingTimestamp = block.timestamp + vesting.period; bytes memory claimHash = _claims[bidder][auctionId]; - (uint256 refund, uint256 claim) = balancesOf(claimHash); - delete _claims[bidder][auctionId]; + (uint256 refund, uint256 claim) = balancesOf(claimHash); + if (refund > 0) { tokenPurchase.safeTransfer(bidder, refund); } if (claim > 0) { - tokenReserve.safeTransfer(bidder, claim); + vestingInstance.makeCommitment(bidder, claim, vestingTimestamp); } emit Claim(auctionId, claimHash); diff --git a/src/interfaces/IGovernance.sol b/src/interfaces/IGovernance.sol index 9963a50..e630a04 100755 --- a/src/interfaces/IGovernance.sol +++ b/src/interfaces/IGovernance.sol @@ -12,4 +12,10 @@ interface IGovernance { function Staking() external returns (address); + function propose(address target, string memory description) external returns (uint256); + + function castVote(uint256 proposalId, bool support) external; + + function execute(uint256 proposalId) external payable; + } diff --git a/src/interfaces/IRDA.sol b/src/interfaces/IRDA.sol index 138c022..bf4d1fb 100644 --- a/src/interfaces/IRDA.sol +++ b/src/interfaces/IRDA.sol @@ -2,14 +2,48 @@ pragma solidity 0.8.13; interface IRDA { + struct Auction { + uint256 windowDuration; /* @dev Unix time window duration */ + uint256 windowTimestamp; /* @dev Unix timestamp for window start */ + uint256 startTimestamp; /* @dev Unix auction start timestamp */ + uint256 endTimestamp; /* @dev Unix auction end timestamp */ + uint256 duration; /* @dev Unix time auction duration */ + uint256 proceeds; /* @dev Auction proceeds balance */ + uint256 reserves; /* @dev Auction reserves balance */ + uint256 price; /* @dev Auction origin price */ + } + + struct Window { + bytes bidId; /* @dev Bid identifier */ + uint256 expiry; /* @dev Unix timestamp window exipration */ + uint256 price; /* @dev Window price */ + uint256 volume; /* @dev Window volume */ + bool processed; /* @dev Window fuflfillment state */ + } + + struct Vesting { + address instance; + uint256 period; + } + error InvalidPurchaseVolume(); + error InvalidReserveVolume(); + error InvalidWindowVolume(); error InvalidWindowPrice(); error InsufficientReserves(); + error InvalidTokenDecimals(); + + error InvalidAuctionDurations(); + + error InvalidAuctionPrice(); + + error InvalidAuctionTimestamp(); + error InvalidScalarPrice(); error WindowUnexpired(); @@ -18,6 +52,10 @@ interface IRDA { error AuctionExists(); + error AuctionActive(); + + error AuctionInactive(); + function createAuction( address vestingAddress, address operatorAddress, @@ -31,6 +69,10 @@ interface IRDA { uint256 windowDuration, uint256 vestingDuration ) external returns (bytes memory); + + function commitBid(bytes memory auctionId, uint256 price, uint256 volume) external returns (bytes memory); + + function fulfillWindow(bytes memory auctionId, uint256 windowId) external; function withdraw(bytes memory auctionId) external; diff --git a/test/Proposal.t.sol b/test/Proposal.t.sol index 1362fa7..80cc0aa 100644 --- a/test/Proposal.t.sol +++ b/test/Proposal.t.sol @@ -1,8 +1,8 @@ pragma solidity ^0.8.1; -import "@interfaces/IRelayerRegistry.sol"; +import "@openzeppelin/token/ERC20/IERC20.sol"; import "@interfaces/IGovernance.sol"; -import "@interfaces/IERC20.sol"; +import "@interfaces/IRDA.sol"; import "@proprietary/Parameters.sol"; import "@proprietary/Mock.sol"; @@ -81,5 +81,5 @@ contract ProposalTest is Test, Parameters, Mock { function checkParameters() internal { } function checkResults() internal { } - + }