When the amount is too high and price is too low, people will join in the lower tier and mint a lot of token then upgrade tier
when necessary. The DAO creator can market this tier as an onboarding tier so that new users mint at the lowest tier only. This bennefits both the user and the creator because all the funds sent by the users when joining DAO will be sent to the daoMembershipAddress address and users can join cheaply.
The protocol will not get a single fee because of truncation of digits in solidity in line 144-
When the tierPrice is 4 (satoshi/wei) or less, the platform fees will be 0.
pragma solidity ^0.8.20;
import {Test, console} from "../lib/forge-std/src/Test.sol";
import {MembershipERC1155} from "../contracts/dao/tokens/MembershipERC1155.sol";
import {MembershipFactory} from "../contracts/dao/MembershipFactory.sol";
import {CurrencyManager} from "../contracts/dao/CurrencyManager.sol";
import {DAOInputConfig, DAOType, TierConfig} from "../contracts/dao/libraries/MembershipDAOStructs.sol";
import {OWPERC20} from "../contracts/shared/testERC20.sol";
import {IMembershipERC1155} from "../contracts/dao/interfaces/IERC1155Mintable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
contract PoC is Test {
MembershipERC1155 public membershipERC1155;
MembershipFactory public membershipFactory;
CurrencyManager public currencyManager;
OWPERC20 public currency;
address opWallet;
address deployer;
address daoCreator;
address user;
bytes32 public constant OWP_FACTORY_ROLE = keccak256("OWP_FACTORY_ROLE");
bytes32 public constant DAO_CREATOR = keccak256("DAO_CREATOR");
function setUp() public {
opWallet = makeAddr("opWallet");
deployer = makeAddr("deployer");
daoCreator = makeAddr("daoCreator");
user = makeAddr("user");
vm.startPrank(deployer);
membershipERC1155 = new MembershipERC1155();
currencyManager = new CurrencyManager();
currency = new OWPERC20("Currency", "CUR");
membershipFactory = new MembershipFactory(address(currencyManager), opWallet, "baseUri", address(membershipERC1155));
currencyManager.addCurrency(address(currency));
vm.stopPrank();
}
function testLowFunds() public {
DAOInputConfig memory daoInputConfig = DAOInputConfig({
ensname: "One",
daoType: DAOType.PUBLIC,
currency: address(currency),
maxMembers: 200,
noOfTiers: 3
});
TierConfig[] memory tierConfigs = new TierConfig[]();
tierConfigs[0] = TierConfig({
amount: 40,
price: 64,
power: 40,
minted: 0
});
tierConfigs[1] = TierConfig({
amount: 40,
price: 16,
power: 20,
minted: 0
});
tierConfigs[2] = TierConfig({
amount: 40,
price: 4,
power: 10,
minted: 0
});
vm.prank(daoCreator);
address proxy = membershipFactory.createNewDAOMembership(daoInputConfig, tierConfigs);
currency.mint(user, 1e20);
vm.startPrank(user);
currency.approve(address(membershipFactory), 1e20);
for(uint i=0; i<10; i++) {
membershipFactory.joinDAO(proxy, 2);
}
vm.stopPrank();
uint256 balanceOfMembership = currency.balanceOf(proxy);
assertEq(balanceOfMembership, 4*10);
}
}
function joinDAO(address daoMembershipAddress, uint256 tierIndex) external {
require(daos[daoMembershipAddress].noOfTiers > tierIndex, "Invalid tier.");
require(daos[daoMembershipAddress].tiers[tierIndex].amount > daos[daoMembershipAddress].tiers[tierIndex].minted, "Tier full.");
uint256 tierPrice = daos[daoMembershipAddress].tiers[tierIndex].price;
uint256 platformFees = (20 * tierPrice) / 100;
+ if(platformFees == 0) {
+ platformFees = 1;
+ }
daos[daoMembershipAddress].tiers[tierIndex].minted += 1;
IERC20(daos[daoMembershipAddress].currency).transferFrom(_msgSender(), owpWallet, platformFees);
IERC20(daos[daoMembershipAddress].currency).transferFrom(_msgSender(), daoMembershipAddress, tierPrice - platformFees);
IMembershipERC1155(daoMembershipAddress).mint(_msgSender(), tierIndex, 1);
emit UserJoinedDAO(_msgSender(), daoMembershipAddress, tierIndex);
}