proposal & auction vesting
This commit is contained in:
parent
6e9bbaae8d
commit
71222d5759
@ -1,42 +0,0 @@
|
|||||||
import "@nomiclabs/hardhat-waffle"
|
|
||||||
import "@nomiclabs/hardhat-truffle5"
|
|
||||||
|
|
||||||
import * as dotenv from "dotenv"
|
|
||||||
|
|
||||||
import { HardhatUserConfig } from "hardhat/types"
|
|
||||||
import { solConfig } from './utils/constants'
|
|
||||||
import { task } from "hardhat/config"
|
|
||||||
|
|
||||||
dotenv.config({
|
|
||||||
path: `${__dirname}/.configuration.env`
|
|
||||||
})
|
|
||||||
|
|
||||||
let configuration: HardhatUserConfig = {
|
|
||||||
networks: {
|
|
||||||
hardhat: {
|
|
||||||
blockGasLimit: 9500000
|
|
||||||
}
|
|
||||||
},
|
|
||||||
solidity: {
|
|
||||||
compilers: [
|
|
||||||
{
|
|
||||||
version: "0.8.0",
|
|
||||||
settings: solConfig
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
mocha: {
|
|
||||||
timeout: 500000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(process.env.NETWORK){
|
|
||||||
configuration.networks[process.env.NETWORK] = {
|
|
||||||
url: `${process.env.RPC_ENDPOINT}`,
|
|
||||||
accounts: [
|
|
||||||
`0x${process.env.PRIVATE_KEY}`
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default configuration
|
|
@ -46,6 +46,7 @@ contract DelegatedInstance {
|
|||||||
bytes32 s
|
bytes32 s
|
||||||
) external isSpender {
|
) external isSpender {
|
||||||
IERC20(_tokenAddress).transferFrom(msg.sender, address(this), amount);
|
IERC20(_tokenAddress).transferFrom(msg.sender, address(this), amount);
|
||||||
|
IERC20(_tokenAddress).approve(_governanceAddress, amount);
|
||||||
IGovernance(_governanceAddress).lock(address(this), amount, deadline, v, r, s);
|
IGovernance(_governanceAddress).lock(address(this), amount, deadline, v, r, s);
|
||||||
IGovernance(_governanceAddress).delegate(to);
|
IGovernance(_governanceAddress).delegate(to);
|
||||||
}
|
}
|
||||||
@ -60,7 +61,6 @@ contract DelegatedInstance {
|
|||||||
|
|
||||||
IGovernance(_governanceAddress).unlock(stake);
|
IGovernance(_governanceAddress).unlock(stake);
|
||||||
IStaking(_stakingAddress).getReward();
|
IStaking(_stakingAddress).getReward();
|
||||||
|
|
||||||
IERC20(_tokenAddress).transfer(_spender, stake + reward);
|
IERC20(_tokenAddress).transfer(_spender, stake + reward);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,86 +68,85 @@ contract DelegatedInstance {
|
|||||||
|
|
||||||
contract DelegatedVesting {
|
contract DelegatedVesting {
|
||||||
|
|
||||||
uint256 public _period;
|
uint256 public _period;
|
||||||
address public _governanceAddress;
|
address public _governanceAddress;
|
||||||
address public _tokenAddress;
|
address public _tokenAddress;
|
||||||
|
|
||||||
mapping(address => uint256) _balances;
|
mapping(address => uint256) _balances;
|
||||||
mapping(address => address) _instances;
|
mapping(address => address) _instances;
|
||||||
mapping(address => uint256) _commitments;
|
mapping(address => uint256) _commitments;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
uint256 vestingDuration,
|
uint256 vestingDuration,
|
||||||
address governanceAddress,
|
address governanceAddress,
|
||||||
address tokenAddress
|
address tokenAddress
|
||||||
) {
|
) {
|
||||||
_period = vestingDuration;
|
_period = vestingDuration;
|
||||||
_tokenAddress = tokenAddress;
|
_tokenAddress = tokenAddress;
|
||||||
_operatorAddress = msg.sender;
|
_governanceAddress = governanceAddress;
|
||||||
_governanceAddress = governanceAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isActiveCommitment(address stakeholder) public view returns (bool) {
|
|
||||||
return _balances[stakeholder] > 0 && _commitments[stakeholder] > block.timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isDelegatedCommitment(address stakeholder) public view returns (bool) {
|
|
||||||
return isActiveCommitment(stakeholder) && _instances[stakeholder] != address(0x0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isFulfilledCommitment(address stakeholder) public view returns (bool) {
|
|
||||||
return _balances[stakeholder] > 0 && _commitments[stakeholder] < block.timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeCommitment(address stakeholder, uint256 amount) public {
|
|
||||||
require(IERC20(_tokenAddress).transferFrom(msg.sender, address(this), amount));
|
|
||||||
|
|
||||||
_commitments[stakeholder] = block.timestmap + _period;
|
|
||||||
_balances[stakeholder] += amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
function delegateCommitment(
|
|
||||||
address delegateAddress,
|
|
||||||
uint256 deadline,
|
|
||||||
uint8 v,
|
|
||||||
bytes32 r,
|
|
||||||
bytes32 s
|
|
||||||
) public {
|
|
||||||
require(isActiveCommitment(msg.sender), "INVALID COMMITMENT");
|
|
||||||
|
|
||||||
if(isDelegatedCommitment(msg.sender)) {
|
|
||||||
DelegatedInstance(_instance[msg.sender]).delegate(delegateAddress);
|
|
||||||
} else {
|
|
||||||
DelegatedInstance e = new DelegatedInstance(
|
|
||||||
msg.sender,
|
|
||||||
_governanceAddress,
|
|
||||||
_tokenAddress,
|
|
||||||
_balances[msg.sender],
|
|
||||||
deadline,
|
|
||||||
v, r, s
|
|
||||||
);
|
|
||||||
|
|
||||||
_instances[msg.sender] = address(e);
|
|
||||||
|
|
||||||
IERC20(_tokenAddress).approve(address(e), _balances[msg.sender]);
|
|
||||||
e.lockAndDelegate(delegateAddress, _balances[msg.sender], deadline, v, r, s);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function fulfillCommitment() public {
|
function isActiveCommitment(address stakeholder) public view returns (bool) {
|
||||||
require(isFulfilledCommitment(msg.sender), "INVALID FULFILLMENT");
|
return _balances[stakeholder] > 0 && _commitments[stakeholder] > block.timestamp;
|
||||||
|
}
|
||||||
uint256 stake = _balances[msg.sender];
|
|
||||||
address delegated = _instances[msg.sender];
|
function isDelegatedCommitment(address stakeholder) public view returns (bool) {
|
||||||
|
return isActiveCommitment(stakeholder) && _instances[stakeholder] != address(0x0);
|
||||||
delete _balances[msg.sender];
|
}
|
||||||
delete _instances[msg.sender];
|
|
||||||
|
function isFulfilledCommitment(address stakeholder) public view returns (bool) {
|
||||||
if(delegated != address(0x0)){
|
return _balances[stakeholder] > 0 && _commitments[stakeholder] < block.timestamp;
|
||||||
DelegatedInstance(delegated).unlockAndRedeem();
|
}
|
||||||
} else {
|
|
||||||
IERC20(_tokenAddress).transfer(msg.sender, stake);
|
function makeCommitment(address stakeholder, uint256 amount) public {
|
||||||
|
require(IERC20(_tokenAddress).transferFrom(msg.sender, address(this), amount));
|
||||||
|
|
||||||
|
_commitments[stakeholder] = block.timestmap + _period;
|
||||||
|
_balances[stakeholder] += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
function delegateCommitment(
|
||||||
|
address delegateAddress,
|
||||||
|
uint256 deadline,
|
||||||
|
uint8 v,
|
||||||
|
bytes32 r,
|
||||||
|
bytes32 s
|
||||||
|
) public {
|
||||||
|
require(isActiveCommitment(msg.sender), "INVALID COMMITMENT");
|
||||||
|
|
||||||
|
if(isDelegatedCommitment(msg.sender)) {
|
||||||
|
DelegatedInstance(_instance[msg.sender]).delegate(delegateAddress);
|
||||||
|
} else {
|
||||||
|
DelegatedInstance e = new DelegatedInstance(
|
||||||
|
msg.sender,
|
||||||
|
_governanceAddress,
|
||||||
|
_tokenAddress,
|
||||||
|
_balances[msg.sender],
|
||||||
|
deadline,
|
||||||
|
v, r, s
|
||||||
|
);
|
||||||
|
|
||||||
|
_instances[msg.sender] = address(e);
|
||||||
|
|
||||||
|
IERC20(_tokenAddress).approve(address(e), _balances[msg.sender]);
|
||||||
|
e.lockAndDelegate(delegateAddress, _balances[msg.sender], deadline, v, r, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fulfillCommitment() public {
|
||||||
|
require(isFulfilledCommitment(msg.sender), "INVALID FULFILLMENT");
|
||||||
|
|
||||||
|
uint256 stake = _balances[msg.sender];
|
||||||
|
address delegated = _instances[msg.sender];
|
||||||
|
|
||||||
|
delete _balances[msg.sender];
|
||||||
|
delete _instances[msg.sender];
|
||||||
|
|
||||||
|
if(delegated != address(0x0)){
|
||||||
|
DelegatedInstance(delegated).unlockAndRedeem();
|
||||||
|
} else {
|
||||||
|
IERC20(_tokenAddress).transfer(msg.sender, stake);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
36
src/Proposal.sol
Normal file
36
src/Proposal.sol
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
pragma solidity 0.8.0;
|
||||||
|
|
||||||
|
import "@root/interfaces/IERC20.sol";
|
||||||
|
import "@root/interfaces/IRollingDutchAuction.sol";
|
||||||
|
|
||||||
|
contract Proposal {
|
||||||
|
|
||||||
|
function executeProposal() external {
|
||||||
|
uint256 AUCTION_START_TS = block.timestamp;
|
||||||
|
uint256 AUCTION_END_TS = AUCTION_START_TS + 1 week;
|
||||||
|
uint256 AUCTION_ORIGIN_PRICE = 4172000 gwei;
|
||||||
|
uint256 AUCTION_RESERVE_AMOUNT = 100000 ether;
|
||||||
|
uint256 AUCTION_MINIMUM_AMOUNT = 1 ether;
|
||||||
|
uint256 AUCTION_WINDOW_LENGTH = 8 hours;
|
||||||
|
|
||||||
|
address wethAddress;
|
||||||
|
address tokenAddress;
|
||||||
|
address governanceAddress;
|
||||||
|
address auctionAddress;
|
||||||
|
address vestingAddress;
|
||||||
|
|
||||||
|
IRollingDutchAuction(auctionAddress).createAuction(
|
||||||
|
vestingAddress,
|
||||||
|
governanceAddress,
|
||||||
|
tokenAddress,
|
||||||
|
wethAddress,
|
||||||
|
AUCTION_RESERVE_AMOUNT,
|
||||||
|
AUCTION_MINIMUM_AMOUNT,
|
||||||
|
AUCTION_ORIGIN_PRICE,
|
||||||
|
AUCTION_START_TS,
|
||||||
|
AUCTION_END_TS,
|
||||||
|
AUCTION_WINDOW_LENGTH
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,6 +2,7 @@ pragma solidity 0.8.13;
|
|||||||
|
|
||||||
import { UD60x18 } from "@prb/math/UD60x18.sol";
|
import { UD60x18 } from "@prb/math/UD60x18.sol";
|
||||||
import { IERC20 } from "@root/interfaces/IERC20.sol";
|
import { IERC20 } from "@root/interfaces/IERC20.sol";
|
||||||
|
import { IVesting } from "@root/interfaces/IVesting.sol";
|
||||||
|
|
||||||
import { inv, add, sub, mul, exp, ln, wrap, unwrap, gte, mod, div } from "@prb/math/UD60x18.sol";
|
import { inv, add, sub, mul, exp, ln, wrap, unwrap, gte, mod, div } from "@prb/math/UD60x18.sol";
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ contract RollingDutchAuction {
|
|||||||
mapping(bytes => uint256) public _windows;
|
mapping(bytes => uint256) public _windows;
|
||||||
|
|
||||||
struct Auction {
|
struct Auction {
|
||||||
|
address vestingAddress;
|
||||||
uint256 windowDuration; /* @dev Unix time window duration */
|
uint256 windowDuration; /* @dev Unix time window duration */
|
||||||
uint256 windowTimestamp; /* @dev Unix timestamp for window start */
|
uint256 windowTimestamp; /* @dev Unix timestamp for window start */
|
||||||
uint256 startTimestamp; /* @dev Unix auction start timestamp */
|
uint256 startTimestamp; /* @dev Unix auction start timestamp */
|
||||||
@ -114,6 +116,7 @@ contract RollingDutchAuction {
|
|||||||
* @param w͟i͟n͟d͟o͟w͟D͟u͟r͟a͟t͟i͟o͟n͟ Uinx time window duration
|
* @param w͟i͟n͟d͟o͟w͟D͟u͟r͟a͟t͟i͟o͟n͟ Uinx time window duration
|
||||||
*/
|
*/
|
||||||
function createAuction(
|
function createAuction(
|
||||||
|
address vestingAddress,
|
||||||
address operatorAddress,
|
address operatorAddress,
|
||||||
address reserveToken,
|
address reserveToken,
|
||||||
address purchaseToken,
|
address purchaseToken,
|
||||||
@ -129,7 +132,7 @@ contract RollingDutchAuction {
|
|||||||
reserveToken,
|
reserveToken,
|
||||||
purchaseToken,
|
purchaseToken,
|
||||||
minimumPurchaseAmount,
|
minimumPurchaseAmount,
|
||||||
abi.encodePacked(reserveAmount, startingPrice, startTimestamp, endTimestamp, windowDuration)
|
abi.encodePacked(reserveAmount, startingOriginPrice, startTimestamp, endTimestamp, windowDuration)
|
||||||
);
|
);
|
||||||
|
|
||||||
Auction storage state = _auctions[auctionId];
|
Auction storage state = _auctions[auctionId];
|
||||||
@ -138,6 +141,7 @@ contract RollingDutchAuction {
|
|||||||
|
|
||||||
IERC20(reserveToken).transferFrom(msg.sender, address(this), reserveAmount);
|
IERC20(reserveToken).transferFrom(msg.sender, address(this), reserveAmount);
|
||||||
|
|
||||||
|
state.vestingAddress = vestingAddress;
|
||||||
state.duration = endTimestamp - startTimestamp;
|
state.duration = endTimestamp - startTimestamp;
|
||||||
state.windowDuration = windowDuration;
|
state.windowDuration = windowDuration;
|
||||||
state.windowTimestamp = startTimestamp;
|
state.windowTimestamp = startTimestamp;
|
||||||
@ -146,7 +150,7 @@ contract RollingDutchAuction {
|
|||||||
state.price = startingOriginPrice;
|
state.price = startingOriginPrice;
|
||||||
state.reserves = reserveAmount;
|
state.reserves = reserveAmount;
|
||||||
|
|
||||||
emit NewAuction(auctionId, reserveToken, reserveAmount, startingPrice, endTimestamp);
|
emit NewAuction(auctionId, reserveToken, reserveAmount, startingOriginPrice, endTimestamp);
|
||||||
|
|
||||||
return auctionId;
|
return auctionId;
|
||||||
}
|
}
|
||||||
@ -386,7 +390,7 @@ contract RollingDutchAuction {
|
|||||||
IERC20(purchaseToken(auctionId)).transfer(bidder, refund);
|
IERC20(purchaseToken(auctionId)).transfer(bidder, refund);
|
||||||
}
|
}
|
||||||
if (claim > 0) {
|
if (claim > 0) {
|
||||||
IERC20(reserveToken(auctionId)).transfer(bidder, claim);
|
IVesting(_auctions[auctionId].vestingAddress).makeCommitment(bidder, claim);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit Claim(auctionId, claimHash);
|
emit Claim(auctionId, claimHash);
|
||||||
|
22
src/interfaces/IRollingDutchAuction.sol
Normal file
22
src/interfaces/IRollingDutchAuction.sol
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
pragma solidity 0.8.0;
|
||||||
|
|
||||||
|
interface IRollingDutchAuction {
|
||||||
|
|
||||||
|
function createAuction(
|
||||||
|
address vestingAddress,
|
||||||
|
address operatorAddress,
|
||||||
|
address reserveToken,
|
||||||
|
address purchaseToken,
|
||||||
|
uint256 reserveAmount,
|
||||||
|
uint256 minimumPurchaseAmount,
|
||||||
|
uint256 startingOriginPrice,
|
||||||
|
uint256 startTimestamp,
|
||||||
|
uint256 endTimestamp,
|
||||||
|
uint256 windowDuration
|
||||||
|
) external returns (bytes memory);
|
||||||
|
|
||||||
|
function withdraw(bytes memory auctionId) external;
|
||||||
|
|
||||||
|
function redeem(address bidder, bytes memory auctionId external);
|
||||||
|
|
||||||
|
}
|
7
src/interfaces/IVesting.sol
Normal file
7
src/interfaces/IVesting.sol
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
pragma solidity 0.8.0;
|
||||||
|
|
||||||
|
interface IVesting {
|
||||||
|
|
||||||
|
function makeCommitment(address stakeholder, uint256 amount) external;
|
||||||
|
|
||||||
|
}
|
@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"files": ["./hardhat.config.ts"],
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es2018",
|
|
||||||
"module": "commonjs",
|
|
||||||
"noImplicitAny": false,
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"typeRoots": [
|
|
||||||
"node_modules/@types"
|
|
||||||
],
|
|
||||||
"lib": [
|
|
||||||
"es2018",
|
|
||||||
"dom"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"exclude": [
|
|
||||||
"node_modules/",
|
|
||||||
"contracts/",
|
|
||||||
],
|
|
||||||
"include": [
|
|
||||||
"types.d.ts",
|
|
||||||
"hre.d.ts",
|
|
||||||
"utils/",
|
|
||||||
"tests/"
|
|
||||||
],
|
|
||||||
"types": [
|
|
||||||
"jest",
|
|
||||||
"node"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
export const solConfig = {
|
|
||||||
optimizer: {
|
|
||||||
enabled: true,
|
|
||||||
runs: 200,
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user