Profit Calculation is done based on share amount but not on how long it has been invested. So Early membership buyers are at disadvantage.
Lets say, Alice buys total 112 shares (some membership tokens) after the creation of a DAO. And the DAO makes profit available after certain time period. As the time period is not documented by OWP, lets assume it can be 1 day to few years.
Bob buys the same amount of 112 share(membership tokens) just a day or hour before when the profit is available not necessarily by front running.
Both of them would get the same profit which is not desirable.
Lets take another simplistic scenario, A DAO which can take at most 365 members. If everyday a new member join the DAO by purchasing same share of membership tokens, and the profit is available after 365 days. They would all get the same profit. Then who would be at disadvantage and who would gain more.
Add this foundrty test file in the test folder. Should install forge-std dependencies.
pragma solidity ^0.8.22;
import "forge-std/Test.sol";
import "../contracts/dao/CurrencyManager.sol";
import "../contracts/dao/MembershipFactory.sol";
import "../contracts/dao/libraries/MembershipDAOStructs.sol";
import "../contracts/dao/tokens/MembershipERC1155.sol";
import { OWPERC20 } from "../contracts/shared/testERC20.sol";
contract MembershipFactoryTest is Test {
CurrencyManager public currencyManager;
MembershipERC1155 public membershipImplementation;
MembershipFactory public membershipFactory;
address public daoMembershipAddress;
OWPERC20 public testERC20;
address public owner = makeAddr("owner");
address public DAOCreator = makeAddr("DAOCreator");
address public profitProvider = makeAddr("profit provider");
address public alice = makeAddr("alice");
address public bob = makeAddr("bob");
DAOInputConfig public daoConfig;
TierConfig[] public tierConfig;
function setUp() public {
vm.startBroadcast(owner);
currencyManager = new CurrencyManager();
membershipImplementation = new MembershipERC1155();
testERC20 = new OWPERC20("OWP", "OWP");
currencyManager.addCurrency(address(testERC20));
testERC20.mint(alice, 10000000000000000000);
testERC20.mint(bob, 10000000000000000000);
testERC20.mint(profitProvider, 10000000000000000000);
membershipFactory = new MembershipFactory(
address(currencyManager),
address(owner),
"https://baseuri.com/",
address(membershipImplementation)
);
vm.stopBroadcast();
}
function testProfitSharingMechanism() public {
vm.startBroadcast(owner);
daoConfig = DAOInputConfig({
ensname: "testdao.eth",
daoType: DAOType.PUBLIC,
currency: address(testERC20),
maxMembers: 100,
noOfTiers: 3
});
tierConfig.push(
TierConfig({ price: 300, amount: 10, minted: 0, power: 12 })
);
tierConfig.push(
TierConfig({ price: 200, amount: 10, minted: 0, power: 6 })
);
tierConfig.push(
TierConfig({ price: 100, amount: 10, minted: 0, power: 3 })
);
daoMembershipAddress = membershipFactory.createNewDAOMembership(
daoConfig,
tierConfig
);
vm.stopBroadcast();
vm.startBroadcast(alice);
testERC20.approve(address(membershipFactory), 1000000000);
membershipFactory.joinDAO(daoMembershipAddress, 0);
membershipFactory.joinDAO(daoMembershipAddress, 1);
membershipFactory.joinDAO(daoMembershipAddress, 2);
vm.stopBroadcast();
vm.startBroadcast(bob);
testERC20.approve(address(membershipFactory), 1000000000);
membershipFactory.joinDAO(daoMembershipAddress, 0);
membershipFactory.joinDAO(daoMembershipAddress, 1);
membershipFactory.joinDAO(daoMembershipAddress, 2);
vm.stopBroadcast();
vm.startBroadcast(profitProvider);
testERC20.approve(daoMembershipAddress, 5000);
MembershipERC1155(daoMembershipAddress).sendProfit(5000);
vm.stopBroadcast();
console.log(
"Share of Alice: ",
MembershipERC1155(daoMembershipAddress).shareOf(alice)
);
console.log(
"Share of Bob: ",
MembershipERC1155(daoMembershipAddress).shareOf(bob)
);
vm.startBroadcast(alice);
console.log("Alice Claimed Profit.");
console.log(MembershipERC1155(daoMembershipAddress).claimProfit());
vm.stopBroadcast();
vm.startBroadcast(bob);
console.log("Bob Claimed Profit.");
console.log(MembershipERC1155(daoMembershipAddress).claimProfit());
vm.stopBroadcast();
}
}
Impact is also Medium. Concept of investment is always time bound which is defied in this profit sharing mechanism discouraging early investment (funding)
Manual Review.
There's two ways to solve this issue.
1) Include the time weight while calculating profit. or,
2) Must impose or restrict certain time limit to join in the DAO (which not beneficial from the economic perspective)