Skip to content

Commit

Permalink
check overlock
Browse files Browse the repository at this point in the history
  • Loading branch information
todesstille committed Mar 8, 2024
1 parent e8043bf commit d3872ed
Show file tree
Hide file tree
Showing 2 changed files with 231 additions and 0 deletions.
15 changes: 15 additions & 0 deletions contracts/interfaces/gov/proposals/ITokenSaleProposal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,14 @@ interface ITokenSaleProposal {
/// @param tiers parameters of tiers
function createTiers(TierInitParams[] calldata tiers) external;

/// @notice This function is used for changing participation settings of the tier
/// @param tierId id of the tier to modify
/// @param newSettings list of participation parameters to set
function changeParticipationDetails(
uint256 tierId,
ParticipationInfoView calldata newSettings
) external;

/// @notice This function is used to add users to the whitelist of tier
/// @param requests requests for adding users to the whitelist
function addToWhitelist(WhitelistingRequest[] calldata requests) external;
Expand Down Expand Up @@ -397,6 +405,13 @@ interface ITokenSaleProposal {
uint256 limit
) external view returns (TierView[] memory tierViews);

/// @notice This function is used to get participation settings of a tier
/// @param tierId the tier id
/// @return tierParticipationDetails the list of tier participation settings
function getParticipationDetails(
uint256 tierId
) external view returns (ParticipationInfoView memory tierParticipationDetails);

/// @notice This function is used to get user's infos from tiers
/// @param user the address of the user whose infos are required
/// @param tierIds the list of tier ids to get infos from
Expand Down
216 changes: 216 additions & 0 deletions test/gov/proposals/TokenSaleProposal.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const {
getBytesApprove,
} = require("../../utils/gov-pool-utils");
const { getCurrentBlockTime, setTime } = require("../../helpers/block-helper");
const { impersonate } = require("../../helpers/impersonator");
const { StandardMerkleTree } = require("@openzeppelin/merkle-tree");

const ContractsRegistry = artifacts.require("ContractsRegistry");
Expand Down Expand Up @@ -218,6 +219,8 @@ describe("TokenSaleProposal", () => {
govPool = await GovPool.new();
tsp = await TokenSaleProposal.new();

await impersonate(govPool.address);

await settings.__GovSettings_init(
govPool.address,
validators.address,
Expand Down Expand Up @@ -1756,6 +1759,219 @@ describe("TokenSaleProposal", () => {
});
});

describe("modify tiers", () => {
function getDefaultDetailsInfo() {
const newDetails = [];
newDetails.isWhitelisted = false;
newDetails.isBABTed = false;
(newDetails.requiredDaoVotes = "0"), (newDetails.requiredTokenAddresses = []);
newDetails.requiredTokenAmounts = [];
newDetails.requiredNftAddresses = [];
newDetails.requiredNftAmounts = [];
newDetails.merkleRoot = "0x0000000000000000000000000000000000000000000000000000000000000000";
newDetails.merkleUri = "";

return newDetails;
}

function detailsInfoSimplify(details) {
const simpleDetails = [];
for (d in details) {
simpleDetails.push(details[d]);
}

return simpleDetails;
}

function tiersToParticipationDetails() {
const participationDetails = tiers.map((e) => {
let details = getDefaultDetailsInfo();

for (d of e.participationDetails) {
let decoded;
switch (d.participationType) {
case ParticipationType.MerkleWhitelist:
decoded = web3.eth.abi.decodeParameters(["bytes32", "string"], d.data);
details.merkleRoot = decoded[0];
details.merkleUri = decoded[1];
break;
case ParticipationType.Whitelist:
details.isWhitelisted = true;
break;
case ParticipationType.BABT:
details.isBABTed = true;
break;
case ParticipationType.DAOVotes:
decoded = web3.eth.abi.decodeParameters(["uint256"], d.data);
details.requiredDaoVotes = decoded[0].toString();
break;
case ParticipationType.TokenLock:
decoded = web3.eth.abi.decodeParameters(["address", "uint256"], d.data);
details.requiredTokenAddresses.push(decoded[0]);
details.requiredTokenAmounts.push(decoded[1]);
break;
case ParticipationType.NftLock:
decoded = web3.eth.abi.decodeParameters(["address", "uint256"], d.data);
details.requiredNftAddresses.push(decoded[0]);
details.requiredNftAmounts.push(decoded[1]);
break;
}
}
return details;
});

return participationDetails;
}

it("should return correct participation parameters", async () => {
const expectedParticipationInfos = tiersToParticipationDetails();

for (let i = 1; i <= 8; i++) {
let participationInfo = await tsp.getParticipationDetails(i);
assert.deepEqual(participationInfo.slice(9, 18), expectedParticipationInfos[i - 1]);
}
});

it("should be called from GovPool", async () => {
let details = getDefaultDetailsInfo();
details = detailsInfoSimplify(details);

await truffleAssert.reverts(tsp.changeParticipationDetails(0, details), "TSP: not a Gov contract");
});

it("cant change parameters after the end of tokensale", async () => {
await setTime(+tiers[0].saleEndTime);

let details = getDefaultDetailsInfo();
details = detailsInfoSimplify(details);

await truffleAssert.reverts(
tsp.changeParticipationDetails(1, details, { from: govPool.address }),
"TSP: token sale is over"
);
});

it("addresses and values length should match", async () => {
let details = getDefaultDetailsInfo();
details.requiredTokenAddresses = [SECOND];
details = detailsInfoSimplify(details);

await truffleAssert.reverts(
tsp.changeParticipationDetails(1, details, { from: govPool.address }),
"TSP: Tokens and amounts numbers does not match"
);

details = getDefaultDetailsInfo();
details.requiredNftAddresses = [SECOND];
details = detailsInfoSimplify(details);

await truffleAssert.reverts(
tsp.changeParticipationDetails(1, details, { from: govPool.address }),
"TSP: Nfts and amounts numbers does not match"
);
});

it("addresses should not repeat", async () => {
let details = getDefaultDetailsInfo();
details.requiredTokenAddresses = [SECOND, SECOND];
details.requiredTokenAmounts = [wei("2"), wei("3")];
details = detailsInfoSimplify(details);

await truffleAssert.reverts(
tsp.changeParticipationDetails(1, details, { from: govPool.address }),
"TSP: Duplicated address"
);
});

it("could modify settings", async () => {
const newDetails = [];
newDetails.isWhitelisted = false;
newDetails.isBABTed = true;
(newDetails.requiredDaoVotes = wei("1")), (newDetails.requiredTokenAddresses = [SECOND, THIRD]);
newDetails.requiredTokenAmounts = [wei("2"), wei("3")];
newDetails.requiredNftAddresses = [THIRD];
newDetails.requiredNftAmounts = ["3"];
newDetails.merkleRoot = merkleTree.root;
newDetails.merkleUri = "white_list";

let detailsToSend = detailsInfoSimplify(newDetails);
await tsp.changeParticipationDetails(1, detailsToSend, { from: govPool.address });

let returnedDetails = await tsp.getParticipationDetails(1);
assert.deepEqual(newDetails, returnedDetails.slice(9, 18));

newDetails.requiredTokenAddresses = [THIRD];
newDetails.requiredTokenAmounts = [wei("3")];
newDetails.requiredNftAddresses = [SECOND, THIRD];
newDetails.requiredNftAmounts = ["2", "3"];

detailsToSend = detailsInfoSimplify(newDetails);
await tsp.changeParticipationDetails(1, detailsToSend, { from: govPool.address });

returnedDetails = await tsp.getParticipationDetails(1);
assert.deepEqual(newDetails, returnedDetails.slice(9, 18));
});

it("could unlock overlocked tokens", async () => {
await setTime(+tiers[0].saleStartTime);

let details = getDefaultDetailsInfo();
details.requiredTokenAddresses = [participationToken.address];
details.requiredTokenAmounts = [wei("2")];
let simpleDetails = detailsInfoSimplify(details);

await tsp.changeParticipationDetails(1, simpleDetails, { from: govPool.address });

await participationToken.mint(OWNER, wei("2"));
await participationToken.approve(tsp.address, wei("2"));

await tsp.lockParticipationTokens(1, participationToken.address, wei("2"));

details.requiredTokenAmounts = [wei("1")];
simpleDetails = detailsInfoSimplify(details);
await tsp.changeParticipationDetails(1, simpleDetails, { from: govPool.address });

await truffleAssert.reverts(
tsp.unlockParticipationTokens(1, participationToken.address, wei("2")),
"TSP: unlock unavailable"
);

assert.equal(await participationToken.balanceOf(OWNER), 0);
await tsp.unlockParticipationTokens(1, participationToken.address, wei("1"));
assert.equal(await participationToken.balanceOf(OWNER), wei("1"));
});

it("could unlock overlocked nfts", async () => {
await setTime(+tiers[0].saleStartTime);

let details = getDefaultDetailsInfo();
details.requiredNftAddresses = [participationNft.address];
details.requiredNftAmounts = ["2"];
let simpleDetails = detailsInfoSimplify(details);

await tsp.changeParticipationDetails(1, simpleDetails, { from: govPool.address });

await participationNft.mint(OWNER, 1);
await participationNft.mint(OWNER, 2);
await participationNft.setApprovalForAll(tsp.address, true);

await tsp.lockParticipationNft(1, participationNft.address, [1, 2]);

details.requiredNftAmounts = ["1"];
simpleDetails = detailsInfoSimplify(details);
await tsp.changeParticipationDetails(1, simpleDetails, { from: govPool.address });

await truffleAssert.reverts(
tsp.unlockParticipationNft(1, participationNft.address, [1, 2]),
"TSP: unlock unavailable"
);

assert.equal(await participationNft.balanceOf(OWNER), 0);
await tsp.unlockParticipationNft(1, participationNft.address, [1]);
assert.equal(await participationNft.balanceOf(OWNER), 1);
});
});

describe("buy", () => {
it("should not buy if tier does not exist", async () => {
await truffleAssert.reverts(tsp.buy(10, purchaseToken1.address, wei(100), []), "TSP: tier does not exist");
Expand Down

0 comments on commit d3872ed

Please sign in to comment.