-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from 1inch/feature/vested-voting-power
[SC-773] add VestedVotingPower contract
- Loading branch information
Showing
17 changed files
with
2,896 additions
and
1,196 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
name: Setup | ||
|
||
runs: | ||
using: composite | ||
steps: | ||
- uses: actions/setup-node@v3 | ||
with: | ||
node-version: 16 | ||
|
||
- run: npm install -g yarn | ||
shell: bash | ||
|
||
- id: yarn-cache | ||
run: echo "::set-output name=dir::$(yarn cache dir)" | ||
shell: bash | ||
|
||
- uses: actions/cache@v3 | ||
with: | ||
path: ${{ steps.yarn-cache.outputs.dir }} | ||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} | ||
restore-keys: | | ||
${{ runner.os }}-yarn- | ||
- run: yarn | ||
shell: bash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,93 +4,38 @@ on: | |
push: | ||
branches: [ master ] | ||
pull_request: | ||
branches: [ master ] | ||
|
||
jobs: | ||
lint: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- uses: actions/setup-node@v2 | ||
with: | ||
node-version: '14.x' | ||
|
||
- run: npm install -g yarn | ||
|
||
- id: yarn-cache | ||
run: echo "::set-output name=dir::$(yarn cache dir)" | ||
|
||
- uses: actions/cache@v2 | ||
with: | ||
path: ${{ steps.yarn-cache.outputs.dir }} | ||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} | ||
restore-keys: | | ||
${{ runner.os }}-yarn- | ||
- run: yarn | ||
- uses: actions/checkout@v3 | ||
- uses: ./.github/actions/setup | ||
- run: yarn lint | ||
|
||
test: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- uses: actions/setup-node@v2 | ||
with: | ||
node-version: '14.x' | ||
|
||
- run: npm install -g yarn | ||
|
||
- id: yarn-cache | ||
run: echo "::set-output name=dir::$(yarn cache dir)" | ||
|
||
- uses: actions/cache@v2 | ||
with: | ||
path: ${{ steps.yarn-cache.outputs.dir }} | ||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} | ||
restore-keys: | | ||
${{ runner.os }}-yarn- | ||
- uses: actions/checkout@v3 | ||
- uses: ./.github/actions/setup | ||
- name: Create env file | ||
run: | | ||
touch .env | ||
echo MAINNET_RPC_URL=${{ secrets.MAINNET_RPC_URL }} >> .env | ||
- run: yarn | ||
- run: yarn test | ||
|
||
coverage: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- uses: actions/setup-node@v2 | ||
with: | ||
node-version: 14.x | ||
|
||
- run: npm install -g yarn | ||
|
||
- id: yarn-cache | ||
run: echo "::set-output name=dir::$(yarn cache dir)" | ||
|
||
- uses: actions/cache@v2 | ||
with: | ||
path: ${{ steps.yarn-cache.outputs.dir }} | ||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} | ||
restore-keys: | | ||
${{ runner.os }}-yarn- | ||
- uses: actions/checkout@v3 | ||
- uses: ./.github/actions/setup | ||
- name: Create env file | ||
run: | | ||
touch .env | ||
echo MAINNET_RPC_URL=${{ secrets.MAINNET_RPC_URL }} >> .env | ||
- run: yarn | ||
- run: yarn coverage | ||
|
||
- name: Coveralls | ||
uses: coverallsapp/[email protected] | ||
- uses: codecov/codecov-action@v3 | ||
with: | ||
github-token: ${{ secrets.GITHUB_TOKEN }} | ||
token: ${{ secrets.CODECOV_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,26 @@ | ||
module.exports = { | ||
skipFiles: [ | ||
'mocks' | ||
] | ||
configureYulOptimizer: true, | ||
solcOptimizerDetails: { | ||
yul: true, | ||
yulDetails: { | ||
optimizerSteps: | ||
"dhfoDgvlfnTUtnIf" + // None of these can make stack problems worse | ||
"[" + | ||
"xa[r]EscLM" + // Turn into SSA and simplify | ||
"cCTUtTOntnfDIl" + // Perform structural simplification | ||
"Lcl" + // Simplify again | ||
"Vcl [j]" + // Reverse SSA | ||
|
||
// should have good "compilability" property here. | ||
|
||
"Tpel" + // Run functional expression inliner | ||
"xa[rl]" + // Prune a bit more in SSA | ||
"xa[r]cL" + // Turn into SSA again and simplify | ||
"gvf" + // Run full inliner | ||
"CTUca[r]LSsTFOtfDnca[r]Ilc" + // SSA plus simplify | ||
"]" + | ||
"jml[jl] VcTOcl jml", | ||
}, | ||
}, | ||
skipFiles: ['interfaces'], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity 0.8.19; | ||
|
||
import "@openzeppelin/contracts/access/Ownable.sol"; | ||
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; | ||
import "./interfaces/IStepVesting.sol"; | ||
import "./interfaces/ISt1inch.sol"; | ||
import "./interfaces/IVestedToken.sol"; | ||
import "./VotingPowerCalculator.sol"; | ||
|
||
contract VestedVotingPower is Ownable, VotingPowerCalculator { | ||
using EnumerableSet for EnumerableSet.AddressSet; | ||
|
||
IVestedToken public immutable vestedToken; | ||
mapping (address => EnumerableSet.AddressSet) private _vestingsByReceiver; | ||
|
||
uint256 private constant _VOTING_POWER_DIVIDER = 20; | ||
|
||
constructor(IVestedToken _vestedToken, ISt1inch st1inch) VotingPowerCalculator(st1inch.expBase(), st1inch.origin()) { | ||
vestedToken = _vestedToken; | ||
} | ||
|
||
function vestedTokenTransferOwnership(address newOwner) external onlyOwner { | ||
vestedToken.transferOwnership(newOwner); | ||
} | ||
|
||
function vestingsByReceiver(address receiver) external view returns (address[] memory) { | ||
return _vestingsByReceiver[receiver].values(); | ||
} | ||
|
||
function votingPowerOf(address account) external view returns (uint256 votingPower) { | ||
EnumerableSet.AddressSet storage vestings = _vestingsByReceiver[account]; | ||
uint256 len = vestings.length(); | ||
unchecked { | ||
for (uint256 i = 0; i < len; i++) { | ||
IStepVesting vesting = IStepVesting(vestings.at(i)); | ||
uint256 started = vesting.started(); | ||
uint256 cliffDuration = vesting.cliffDuration(); | ||
uint256 stepDuration = vesting.stepDuration(); | ||
if (block.timestamp < started + cliffDuration) { | ||
votingPower += _votingPowerAt(_balanceAt(vesting.cliffAmount() / _VOTING_POWER_DIVIDER, started + cliffDuration), block.timestamp); | ||
} | ||
uint256 numOfSteps = vesting.numOfSteps(); | ||
for (uint256 j = 0; j < numOfSteps; j++) { | ||
uint256 stepUnlockTimestamp = started + cliffDuration + stepDuration * (j + 1); | ||
if (block.timestamp < stepUnlockTimestamp) { | ||
votingPower += _votingPowerAt(_balanceAt(vesting.stepAmount() / _VOTING_POWER_DIVIDER, stepUnlockTimestamp), block.timestamp); | ||
} | ||
} | ||
} | ||
} | ||
return votingPower; | ||
} | ||
|
||
function registerVestings(address[] calldata vestings) external onlyOwner { | ||
if (vestedToken.owner() == address(this)) { | ||
vestedToken.registerVestings(vestings); | ||
} | ||
uint256 len = vestings.length; | ||
unchecked { | ||
for (uint256 i = 0; i < len; i++) { | ||
address vesting = vestings[i]; | ||
address receiver = IStepVesting(vesting).receiver(); | ||
require(_vestingsByReceiver[receiver].add(vesting), "Vesting is already registered"); | ||
} | ||
} | ||
} | ||
|
||
function deregisterVestings(address[] calldata vestings) external onlyOwner { | ||
if (vestedToken.owner() == address(this)) { | ||
vestedToken.deregisterVestings(vestings); | ||
} | ||
uint256 len = vestings.length; | ||
unchecked { | ||
for (uint256 i = 0; i < len; i++) { | ||
address vesting = vestings[i]; | ||
address receiver = IStepVesting(vesting).receiver(); | ||
EnumerableSet.AddressSet storage receiverVestings = _vestingsByReceiver[receiver]; | ||
require(receiverVestings.remove(vesting), "Vesting is not registered"); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.