Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

platform voting fix #38

Merged
merged 1 commit into from
Jul 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 53 additions & 2 deletions contracts/infrastructure/PlatformVoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ contract PlatformVoter is ControllableV3, IPlatformVoter {
// *************************************************************

/// @dev Version of this contract. Adjust manually on each code modification.
string public constant PLATFORM_VOTER_VERSION = "1.0.1";
string public constant PLATFORM_VOTER_VERSION = "1.0.2";
/// @dev Denominator for different ratios. It is default for the whole platform.
uint public constant RATIO_DENOMINATOR = 100_000;
/// @dev Delay between votes.
Expand Down Expand Up @@ -255,8 +255,14 @@ contract PlatformVoter is ControllableV3, IPlatformVoter {
if (found) {
require(v.timestamp + VOTE_DELAY < block.timestamp, "delay");
_removeVote(tokenId, v._type, v.target, v.weight, v.weightedValue);
// with descent loop we remove one by one last elements

if (i != length) {
_votes[i - 1] = _votes[length - 1];
}

_votes.pop();
length--;

emit VoteReset(
tokenId,
uint(v._type),
Expand Down Expand Up @@ -296,4 +302,49 @@ contract PlatformVoter is ControllableV3, IPlatformVoter {
}
}

///////////////////////////////////////////////////////////////
// EMERGENCY ACTIONS
// If something went wrong governance can fix weights.
///////////////////////////////////////////////////////////////

/// @dev In case if something went wrong with vote calculation governance can remove the vote manually for a user
/// If removeWeights is false then it will only remove vote from the list without changing weights.
/// This will lead to "staked" weights forever. Use `emergencyAdjustWeights()` to fix it.
function emergencyResetVote(uint tokenId, uint index, bool removeWeights) external {
require(msg.sender == IController(controller()).governance(), "!gov");
Vote[] storage _votes = votes[tokenId];

Vote memory v = _votes[index];
if (removeWeights) {
_removeVote(tokenId, v._type, v.target, v.weight, v.weightedValue);
}

_votes[index] = _votes[_votes.length - 1];
_votes.pop();

emit VoteReset(
tokenId,
uint(v._type),
v.target,
v.weight,
v.weightedValue,
v.timestamp
);
}

/// @dev Before calling this function need to calculate simulation where all votes removed for all user and check the remaining weights/values.
/// The difference should be counted for the new values and passed to this function.
/// Do not call this function without properly check that users will able to reset votes!
/// If any user has invalid votes need to call `emergencyResetVote()` firstly and simulate full reset for all users.
function emergencyAdjustWeights(AttributeType _type, address target, uint weights, uint values) external {
require(msg.sender == IController(controller()).governance(), "!gov");

attributeWeights[_type][target] = weights;
attributeValues[_type][target] = values;

uint newValue = weights == 0 ? 0 : values / weights;
require(newValue <= RATIO_DENOMINATOR, '!ratio');
_setAttribute(_type, newValue, target);
}

}
48 changes: 28 additions & 20 deletions scripts/gov/poke-platform-voter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,39 @@ import {ethers} from "hardhat";
import {Addresses} from "../addresses/addresses";
import {PlatformVoter__factory} from "../../typechain";
import {RunHelper} from "../utils/RunHelper";
import {txParams} from "../deploy/DeployContract";

// tslint:disable-next-line:no-var-requires
const {request, gql} = require('graphql-request')

// tslint:disable-next-line:no-var-requires
const hre = require("hardhat");

async function main() {
const [signer] = await ethers.getSigners();
const core = Addresses.getCore();

const voter = PlatformVoter__factory.connect(core.platformVoter, signer);

const data = await request('https://api.thegraph.com/subgraphs/name/tetu-io/tetu-v2', gql`
query {
platformVoterEntities {
votes(first: 1000) {
desiredValue
date
newValue
percent
target
voteType
veWeightedValue
vePower
veNFT {
veNFTId
}
}
}
}
`);
const data = await request('https://api.thegraph.com/subgraphs/name/tetu-io/tetu-v2', gql`
query {
platformVoterEntities {
votes(first: 1000) {
desiredValue
date
newValue
percent
target
voteType
veWeightedValue
vePower
veNFT {
veNFTId
}
}
}
}
`);

const votes = data.platformVoterEntities[0].votes;

Expand Down Expand Up @@ -58,7 +62,11 @@ async function main() {

for (const veId of vePokes) {
console.log('poke ve: ', veId);
// await RunHelper.runAndWait(() => voter.poke(veId));
if(veId === 14) {
continue;
}
const params = await txParams(hre, ethers.provider);
await RunHelper.runAndWait(() => voter.poke(veId, {...params}));
}

}
Expand Down
109 changes: 109 additions & 0 deletions test/infrastructure/PlatformVoterTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,108 @@ describe("Platform voter tests", function () {
expect(await forwarder.toInvestFundRatio()).eq(0);
});

it("reset multiple votes test", async function () {
await platformVoter.vote(1, 1, 100, Misc.ZERO_ADDRESS);
await platformVoter.vote(1, 2, 100, Misc.ZERO_ADDRESS);
await platformVoter.vote(1, 3, 100, platformVoter.address);
await platformVoter.vote(1, 3, 100, ve.address);

expect(await platformVoter.veVotesLength(1)).eq(4);

expect(await forwarder.toInvestFundRatio()).eq(100);
expect(await forwarder.toGaugesRatio()).eq(100);

const v0 = await platformVoter.votes(1, 0);
const v1 = await platformVoter.votes(1, 1);
const v2 = await platformVoter.votes(1, 2);
const v3 = await platformVoter.votes(1, 3);
expect(v0._type).eq(1);
expect(v1._type).eq(2);
expect(v2._type).eq(3);
expect(v3._type).eq(3);
expect(v2.target).eq(platformVoter.address);
expect(v3.target).eq(ve.address);

await TimeUtils.advanceBlocksOnTs(WEEK);

await platformVoter.reset(1, [2, 3], [Misc.ZERO_ADDRESS, platformVoter.address]);

expect(await platformVoter.veVotesLength(1)).eq(2);

const v0New = await platformVoter.votes(1, 0);
const v1New = await platformVoter.votes(1, 1);
expect(v0New._type).eq(1);
expect(v1New._type).eq(3);
expect(v1New.target).eq(ve.address);
});


it("emergency reset vote test", async function () {
await expect(platformVoter.connect(owner3).emergencyResetVote(1, 2, true)).revertedWith('!gov');

expect(await forwarder.toInvestFundRatio()).eq(0);
expect(await forwarder.toGaugesRatio()).eq(0);

await platformVoter.vote(1, 1, 100, Misc.ZERO_ADDRESS);
await platformVoter.vote(1, 2, 100, Misc.ZERO_ADDRESS);
await platformVoter.vote(1, 3, 100, platformVoter.address);
await platformVoter.vote(1, 3, 100, ve.address);

expect(await platformVoter.veVotesLength(1)).eq(4);

expect(await forwarder.toInvestFundRatio()).eq(100);
expect(await forwarder.toGaugesRatio()).eq(100);

const vv1 = [
await platformVoter.votes(1, 0),
await platformVoter.votes(1, 1),
await platformVoter.votes(1, 2),
await platformVoter.votes(1, 3)
];
expect(vv1[0]._type).eq(1);
expect(vv1[1]._type).eq(2);
expect(vv1[2]._type).eq(3);
expect(vv1[3]._type).eq(3);
expect(vv1[2].target).eq(platformVoter.address);
expect(vv1[3].target).eq(ve.address);

await platformVoter.emergencyResetVote(1, 2, true);

expect(await platformVoter.veVotesLength(1)).eq(3);

const vv2 = [
await platformVoter.votes(1, 0),
await platformVoter.votes(1, 1),
await platformVoter.votes(1, 2),
];
expect(vv2[0]._type).eq(1);
expect(vv2[1]._type).eq(2);
expect(vv2[2]._type).eq(3);
expect(vv2[2].target).eq(ve.address);

await platformVoter.emergencyResetVote(1, 1, false);

expect(await platformVoter.veVotesLength(1)).eq(2);

const vv3 = [
await platformVoter.votes(1, 0),
await platformVoter.votes(1, 1),
];
expect(vv3[0]._type).eq(1);
expect(vv3[1]._type).eq(3);
expect(vv3[1].target).eq(ve.address);

expect(await forwarder.toInvestFundRatio()).eq(100);
expect(await forwarder.toGaugesRatio()).eq(100);

});

it("emergency Adjust Weights test", async function () {
await platformVoter.emergencyAdjustWeights(1, Misc.ZERO_ADDRESS, 100, 100);
await expect(platformVoter.connect(owner3).emergencyAdjustWeights(1, Misc.ZERO_ADDRESS, 100, 1)).revertedWith('!gov');
await expect(platformVoter.emergencyAdjustWeights(1, Misc.ZERO_ADDRESS, 1, 1000_000)).revertedWith('!ratio');
});

it("reset vote with zero value test", async function () {
await platformVoter.vote(1, 1, 0, Misc.ZERO_ADDRESS);
await TimeUtils.advanceBlocksOnTs(WEEK);
Expand Down Expand Up @@ -228,8 +330,15 @@ describe("Platform voter tests", function () {

// vote for not strategy should not revert
await platformVoter.vote(1, 3, 50000, platformVoter.address);
expect(await platformVoter.veVotesLength(1)).eq(2);
await TimeUtils.advanceBlocksOnTs(WEEK * 8);
await platformVoter.poke(1);
expect(await platformVoter.veVotesLength(1)).eq(2);

// poke for ended ve should not revert
await TimeUtils.advanceBlocksOnTs(WEEK * 52);
await platformVoter.poke(1);
expect(await platformVoter.veVotesLength(1)).eq(0);
});

it("re vote test", async function () {
Expand Down
Loading