Skip to content

Commit

Permalink
Update founders forking test (#90)
Browse files Browse the repository at this point in the history
* wip

* add new tests and forking for founders update

* github run action file update

* update env name

* fix tests
  • Loading branch information
iainnash authored Dec 17, 2022
1 parent 7c16b04 commit 99afbe0
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 28 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ jobs:
build:
name: Test
runs-on: ubuntu-latest
environment: Test
steps:
- uses: actions/checkout@v2
with:
Expand All @@ -15,4 +16,4 @@ jobs:
- uses: onbjerg/foundry-toolchain@v1
with:
version: nightly
- run: npm run test
- run: ETH_RPC_MAINNET=${{secrets.ETH_RPC_MAINNET}} npm run test
24 changes: 14 additions & 10 deletions src/token/Token.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { ReentrancyGuard } from "../lib/utils/ReentrancyGuard.sol";
import { ERC721Votes } from "../lib/token/ERC721Votes.sol";
import { ERC721 } from "../lib/token/ERC721.sol";
import { Ownable } from "../lib/utils/Ownable.sol";

import { TokenStorageV1 } from "./storage/TokenStorageV1.sol";
import { IBaseMetadata } from "./metadata/interfaces/IBaseMetadata.sol";
import { IManager } from "../manager/IManager.sol";
Expand Down Expand Up @@ -92,15 +91,14 @@ contract Token is IToken, VersionedContract, UUPS, Ownable, ReentrancyGuard, ERC
/// @dev We do this by reserving an mapping of [0-100] token indices, such that if a new token mint ID % 100 is reserved, it's sent to the appropriate founder.
/// @param _founders The list of DAO founders
function _addFounders(IManager.FounderParams[] calldata _founders) internal {
// Cache the number of founders
uint256 numFounders = _founders.length;

// Used to store the total percent ownership among the founders
uint256 totalOwnership;

uint8 numFoundersAdded = 0;

unchecked {
// For each founder:
for (uint256 i; i < numFounders; ++i) {
for (uint256 i; i < _founders.length; ++i) {
// Cache the percent ownership
uint256 founderPct = _founders[i].ownershipPct;

Expand All @@ -118,7 +116,7 @@ contract Token is IToken, VersionedContract, UUPS, Ownable, ReentrancyGuard, ERC
}

// Compute the founder's id
uint256 founderId = settings.numFounders++;
uint256 founderId = numFoundersAdded++;

// Get the pointer to store the founder
Founder storage newFounder = founder[founderId];
Expand Down Expand Up @@ -152,7 +150,7 @@ contract Token is IToken, VersionedContract, UUPS, Ownable, ReentrancyGuard, ERC

// Store the founders' details
settings.totalOwnership = uint8(totalOwnership);
settings.numFounders = uint8(numFounders);
settings.numFounders = numFoundersAdded;
}
}

Expand Down Expand Up @@ -349,6 +347,15 @@ contract Token is IToken, VersionedContract, UUPS, Ownable, ReentrancyGuard, ERC
// copy the founder into memory
Founder memory cachedFounder = cachedFounders[i];

// Delete the founder from the stored mapping
delete founder[i];

// Some DAOs were initialized with 0 percentage ownership.
// This skips them to avoid a division by zero error.
if (cachedFounder.ownershipPct == 0) {
continue;
}

// using the ownership percentage, get reserved token percentages
uint256 schedule = 100 / cachedFounder.ownershipPct;

Expand All @@ -369,9 +376,6 @@ contract Token is IToken, VersionedContract, UUPS, Ownable, ReentrancyGuard, ERC
// Update the base token id
baseTokenId = (baseTokenId + schedule) % 100;
}

// Delete the founder from the stored mapping
delete founder[i];
}
}

Expand Down
89 changes: 72 additions & 17 deletions test/Token.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,16 @@ contract TokenTest is NounsBuilderTest, TokenTypesV1 {

deployWithCustomFounders(wallets, percents, vestExpirys);

assertEq(token.totalFounders(), 100);
// Last founder is omitted so total number of founders is 99
assertEq(token.totalFounders(), 99);
assertEq(token.totalFounderOwnership(), 99);

Founder memory founder;
Founder memory thisFounder;

for (uint256 i; i < 99; ++i) {
founder = token.getScheduledRecipient(i);
thisFounder = token.getScheduledRecipient(i);

assertEq(founder.wallet, otherUsers[i]);
assertEq(thisFounder.wallet, otherUsers[i]);
}
}

Expand Down Expand Up @@ -183,16 +184,16 @@ contract TokenTest is NounsBuilderTest, TokenTypesV1 {
assertEq(token.totalFounders(), 50);
assertEq(token.totalFounderOwnership(), 99);

Founder memory founder;
Founder memory thisFounder;

for (uint256 i; i < 49; ++i) {
founder = token.getScheduledRecipient(i);
thisFounder = token.getScheduledRecipient(i);

assertEq(founder.wallet, otherUsers[i]);
assertEq(thisFounder.wallet, otherUsers[i]);

founder = token.getScheduledRecipient(i + 50);
thisFounder = token.getScheduledRecipient(i + 50);

assertEq(founder.wallet, otherUsers[i]);
assertEq(thisFounder.wallet, otherUsers[i]);
}
}

Expand All @@ -219,20 +220,20 @@ contract TokenTest is NounsBuilderTest, TokenTypesV1 {
assertEq(token.totalFounders(), 2);
assertEq(token.totalFounderOwnership(), 98);

Founder memory founder;
Founder memory thisFounder;

unchecked {
for (uint256 i; i < 500; ++i) {
founder = token.getScheduledRecipient(i);
thisFounder = token.getScheduledRecipient(i);

if (i % 100 >= 98) {
continue;
}

if (i % 2 == 0) {
assertEq(founder.wallet, otherUsers[0]);
assertEq(thisFounder.wallet, otherUsers[0]);
} else {
assertEq(founder.wallet, otherUsers[1]);
assertEq(thisFounder.wallet, otherUsers[1]);
}
}
}
Expand Down Expand Up @@ -423,16 +424,49 @@ contract TokenTest is NounsBuilderTest, TokenTypesV1 {
assertEq(token.totalFounders(), 2);
assertEq(token.totalFounderOwnership(), 99);

Founder memory founder;
Founder memory thisFounder;

unchecked {
for (uint256 i; i < 99; ++i) {
founder = token.getScheduledRecipient(i);
thisFounder = token.getScheduledRecipient(i);

if (i % 2 == 0) {
assertEq(founder.wallet, otherUsers[0]);
assertEq(thisFounder.wallet, otherUsers[0]);
} else {
assertEq(founder.wallet, otherUsers[1]);
assertEq(thisFounder.wallet, otherUsers[1]);
}
}
}

vm.prank(otherUsers[0]);
auction.unpause();
}

function testFoundersCreateZeroOwnershipOmitted() public {
createUsers(2, 1 ether);

address[] memory wallets = new address[](2);
uint256[] memory percents = new uint256[](2);
uint256[] memory vestExpirys = new uint256[](2);

uint256 end = 4 weeks;
wallets[0] = otherUsers[0];
vestExpirys[0] = end;
wallets[1] = otherUsers[1];
vestExpirys[1] = end;
percents[0] = 0;
percents[1] = 50;

deployWithCustomFounders(wallets, percents, vestExpirys);

assertEq(token.totalFounders(), 1);
assertEq(token.totalFounderOwnership(), 50);

unchecked {
for (uint256 i; i < 99; ++i) {
if (i % 2 == 0) {
Founder memory thisFounder = token.getScheduledRecipient(i);
assertEq(thisFounder.wallet, otherUsers[1]);
}
}
}
Expand Down Expand Up @@ -472,6 +506,27 @@ contract TokenTest is NounsBuilderTest, TokenTypesV1 {
token.updateFounders(foundersArr);
}

function test_UpdateFoundersZeroOwnership() public {
deployMock();

IManager.FounderParams[] memory newFoundersArr = new IManager.FounderParams[](2);
newFoundersArr[0] = IManager.FounderParams({
wallet: address(0x06B59d0b6AdCc6A5Dc63553782750dc0b41266a3),
ownershipPct: 0,
vestExpiry: 2556057600
});
newFoundersArr[1] = IManager.FounderParams({
wallet: address(0x06B59d0b6AdCc6A5Dc63553782750dc0b41266a3),
ownershipPct: 10,
vestExpiry: 2556057600
});

vm.prank(address(founder));
token.updateFounders(newFoundersArr);

assertEq(token.getFounders().length, 1);
}

function test_UpdateFounderShareAllocationFuzz(
uint256 f1Percentage,
uint256 f2Percentage,
Expand Down
82 changes: 82 additions & 0 deletions test/forking/TestUpdateOwners.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import { Test } from "forge-std/Test.sol";
import { Treasury } from "../../src/governance/treasury/Treasury.sol";
import { Auction } from "../../src/auction/Auction.sol";
import { Token } from "../../src/token/Token.sol";
import { Governor } from "../../src/governance/governor/Governor.sol";
import { IManager } from "../../src/manager/IManager.sol";
import { Manager } from "../../src/manager/Manager.sol";
import { UUPS } from "../../src/lib/proxy/UUPS.sol";

contract PurpleTests is Test {
Manager internal immutable manager = Manager(0xd310A3041dFcF14Def5ccBc508668974b5da7174);
Treasury internal immutable treasury = Treasury(payable(0xeB5977F7630035fe3b28f11F9Cb5be9F01A9557D));
Auction internal immutable auction = Auction(payable(0x658D3A1B6DaBcfbaa8b75cc182Bf33efefDC200d));
Token internal immutable token = Token(0xa45662638E9f3bbb7A6FeCb4B17853B7ba0F3a60);
Governor internal immutable governor = Governor(0xFB4A96541E1C70FC85Ee512420eB0B05C542df57);
address internal immutable fawkes = 0x617Cb4921071e73D0C41B5354F5246F12518745e;
address internal immutable upgradedTokenImplAddress = 0xb69dC36182Fe5dad045BD4B08Ffb042D10d0fB77;
address[] internal targets;
uint256[] internal values;
bytes[] internal calldatas;
string internal description;

function setUp() public {
uint256 mainnetFork = vm.createFork(vm.envString("ETH_RPC_MAINNET"));
vm.selectFork(mainnetFork);
vm.rollFork(16171761);

Token newTokenImpl = new Token(address(manager));

vm.prank(manager.owner());
manager.registerUpgrade(address(0x3E8c48b46C5752F40c6772520f03a4D8EDa49706), address(newTokenImpl));

IManager.FounderParams[] memory newFounderParams = new IManager.FounderParams[](3);
newFounderParams[0] = IManager.FounderParams({
wallet: address(0x06B59d0b6AdCc6A5Dc63553782750dc0b41266a3),
ownershipPct: 10,
vestExpiry:2556057600
});
newFounderParams[1] = IManager.FounderParams({
wallet: address(0x349993989b5AC27Fd033AcCb86a84920DEb91ABa),
ownershipPct: 10,
vestExpiry:2556057600
});
newFounderParams[2] = IManager.FounderParams({
wallet: address(0x0BC3807Ec262cB779b38D65b38158acC3bfedE10),
ownershipPct: 1,
vestExpiry: 2556057600
});

targets = new address[](2);
targets[0] = address(token);
targets[1] = address(token);
values = new uint256[](2);
values[0] = 0;
values[1] = 0;
calldatas = new bytes[](2);
calldatas[0] = abi.encodeWithSelector(UUPS.upgradeTo.selector, address(newTokenImpl));
calldatas[1] = abi.encodeWithSelector(Token.updateFounders.selector, newFounderParams);
}

function test_purpleUpgrade() public {
vm.prank(fawkes);
bytes32 proposalId = governor.propose(targets, values, calldatas, "");

vm.warp(block.timestamp + 3 days);
vm.prank(fawkes);
governor.castVote(proposalId, 1);
vm.prank(0x8700B87C2A053BDE8Cdc84d5078B4AE47c127FeB);
governor.castVote(proposalId, 1);

vm.warp(block.timestamp + 4 days);
governor.queue(proposalId);

vm.warp(block.timestamp + 3 days);
governor.execute(targets, values, calldatas, keccak256(""), fawkes);


}
}

0 comments on commit 99afbe0

Please sign in to comment.