Skip to content

Commit

Permalink
tests pass
Browse files Browse the repository at this point in the history
  • Loading branch information
polymorpher committed Oct 20, 2024
1 parent be5d8ed commit 6b16d67
Show file tree
Hide file tree
Showing 6 changed files with 319 additions and 29 deletions.
14 changes: 9 additions & 5 deletions contracts/FoodMeme.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ contract FoodMeme is MemeMetadata, OFT, AccessControl {
error AlreadyInitialized();
error NotInitialized();
error NotMasterChain();
error NotMintChain();
error NotMintChain(uint256 chainId);
error MintDisabled();

event EarlyUnlock(uint256 previousUnlockTime);
Expand Down Expand Up @@ -88,14 +88,14 @@ contract FoodMeme is MemeMetadata, OFT, AccessControl {
}
}
if (!isMintChain) {
revert NotMintChain();
revert NotMintChain(block.chainid);
}
_;
}

constructor(string memory _name, string memory _symbol, address _lzEndpoint, address _delegate)
OFT(_name, _symbol, _lzEndpoint, _delegate)
Ownable(_delegate)
OFT(_name, _symbol, _lzEndpoint, _delegate)
Ownable(_delegate)
{
_grantRole(DEFAULT_ADMIN_ROLE, _delegate);
_grantRole(ROLE_FACTORY, msg.sender);
Expand Down Expand Up @@ -177,7 +177,7 @@ contract FoodMeme is MemeMetadata, OFT, AccessControl {
if (quantity > maxPerMint) {
revert PerMintAmountExceeded();
}
uint256 price = Utils.computeUnitPrice(priceSettings, quantity, totalSupply());
uint256 price = mintPrice(quantity);
if (!(msg.value >= price * quantity)) {
revert InsufficientPayment();
}
Expand All @@ -186,6 +186,10 @@ contract FoodMeme is MemeMetadata, OFT, AccessControl {
// TODO: also note the total supply should be propagated to all chains, if we still want to have supply control - and very important to do that, in the case which the bounding curve (unit price) is linear or quadratic,
}

function mintPrice(uint256 quantity) public view mintChainOnly returns (uint256) {
return Utils.computeUnitPrice(priceSettings, quantity, totalSupply(), maxSupply);
}

function hasReviewed(address user) public view masterChainOnly returns (bool) {
return uint256(reviews[user].hash) == 0 && reviews[user].rating == 0;
}
Expand Down
31 changes: 18 additions & 13 deletions contracts/FoodMemeFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ contract FoodMemeFactory is Ownable {
}

function launch(Utils.MemeParams memory params, address maker, Utils.InitParams memory initParams)
external
payable
external
payable
returns (FoodMeme)
{
if (msg.value < launchFee) {
revert InsufficientLaunchFee();
Expand All @@ -72,19 +73,23 @@ contract FoodMemeFactory is Ownable {
address instance = Create2.deploy(0, salt, abi.encodePacked(helper.code(args)));
emit MemeLaunched(params.name, params.symbol, instance, msg.sender);
FoodMeme f = FoodMeme(instance);
if (bytes(initParams.baseUri).length == 0) {
initParams.baseUri = baseUrl;
}
f.initialize(maker, initParams);
return f;
}

// called after contracts are deployed in local chain and in all remote chains
function setupLz(FoodMeme f, Utils.LzParams memory params) internal {
function setupLz(FoodMeme f, Utils.LzParams memory params) external {
require(msg.sender == owner() || f.hasRole(f.ROLE_MAKER(), msg.sender), "Unauthorized");
require(params.endPointIds.length == params.remoteContractAddresses.length, "Bad lz params");
require(params.endPointIds.length == params.receiveLibraries.length, "Bad lz params");
require(params.endPointIds.length == params.sendLibraries.length, "Bad lz params");
require(params.endPointIds.length == params.sendConfigParams.length, "Bad lz params");
require(params.endPointIds.length == params.receiveConfigParams.length, "Bad lz params");
require(params.endPointIds.length == params.enforceConfigParams.length, "Bad lz params");
require(params.endPointIds.length == params.minGasEnforceConfig.length, "Bad lz params");
// require(params.endPointIds.length == params.receiveLibraries.length, "Bad lz params");
// require(params.endPointIds.length == params.sendLibraries.length, "Bad lz params");
// require(params.endPointIds.length == params.sendConfigParams.length, "Bad lz params");
// require(params.endPointIds.length == params.receiveConfigParams.length, "Bad lz params");
// require(params.endPointIds.length == params.enforceConfigParams.length, "Bad lz params");
// require(params.endPointIds.length == params.minGasEnforceConfig.length, "Bad lz params");

for (uint256 i = 0; i < params.endPointIds.length; i++) {
f.setPeer(params.endPointIds[i], params.remoteContractAddresses[i]);
Expand All @@ -96,13 +101,13 @@ contract FoodMemeFactory is Ownable {
if (params.sendLibraries.length > i) {
f.endpoint().setSendLibrary(address(f), params.endPointIds[i], params.sendLibraries[i]);
}
if (params.sendConfigParams[i].config.length > 0) {
if (params.sendConfigParams.length > i && params.sendConfigParams[i].config.length > 0) {
f.endpoint().setConfig(address(f), params.sendLibraries[i], params.sendConfigParams[i].config);
}
if (params.receiveConfigParams[i].config.length > 0) {
if (params.receiveConfigParams.length > i && params.receiveConfigParams[i].config.length > 0) {
f.endpoint().setConfig(address(f), params.receiveLibraries[i], params.receiveConfigParams[i].config);
}
if (params.minGasEnforceConfig[i] > 0) {
if (params.minGasEnforceConfig.length > i && params.minGasEnforceConfig[i] > 0) {
EnforcedOptionParam memory p = EnforcedOptionParam({
eid: params.endPointIds[i],
msgType: 1, // OFTCore.SEND,
Expand All @@ -112,7 +117,7 @@ contract FoodMemeFactory is Ownable {
pp[0] = p;
f.setEnforcedOptions(pp);
}
if (params.enforceConfigParams[i].config.length > 0) {
if (params.enforceConfigParams.length > i && params.enforceConfigParams[i].config.length > 0) {
f.setEnforcedOptions(params.enforceConfigParams[i].config);
}
}
Expand Down
12 changes: 6 additions & 6 deletions contracts/Utils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,18 @@ library Utils {
}

// TODO: check for risk of arithmetic error here. Probably switch to Q64 or Q96
function computeUnitPrice(PriceSettings memory s, uint256 quantity, uint256 supply)
internal
pure
returns (uint256)
function computeUnitPrice(PriceSettings memory s, uint256 quantity, uint256 supply, uint256 maxSupply)
internal
pure
returns (uint256)
{
if (s.mode == PriceMode.ConstantPrice) {
return s.c;
} else if (s.mode == PriceMode.LinearPrice) {
return s.b * (quantity + supply) + s.c;
return s.b * (quantity + supply) / maxSupply / DECIMALS + s.c / DECIMALS;
}
uint256 newSupply = quantity + supply;
return s.a * s.a * newSupply + s.b * newSupply + s.c;
return s.a * s.a * newSupply / DECIMALS / maxSupply / DECIMALS + s.b * newSupply / maxSupply / DECIMALS + s.c / DECIMALS;
}

struct Review {
Expand Down
4 changes: 3 additions & 1 deletion remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ layerzero-v2/=lib/layerzero-v2/
openzeppelin-contracts/=lib/openzeppelin-contracts/
solidity-bytes-utils/=lib/solidity-bytes-utils/

@layerzerolabs/lz-evm-messagelib-v2/=lib/layerzero-v2/packages/layerzero-v2/evm/messagelib/
@layerzerolabs/lz-evm-messagelib-v2/=lib/layerzero-v2/packages/layerzero-v2/evm/messagelib/
@layerzerolabs/test-devtools-evm-foundry=lib/devtools/packages/test-devtools-evm-foundry/
@layerzerolabs/lz-evm-v1-0.7/contracts/interfaces/=test/mock/
203 changes: 199 additions & 4 deletions test/FoodMemeFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,207 @@
pragma solidity ^0.8.26;

import {Test} from "forge-std/Test.sol";
import "forge-std/console.sol";
import {FoodMemeFactory} from "contracts/FoodMemeFactory.sol";
import {FoodMemeFactoryHelper} from "contracts/FoodMemeFactoryHelper.sol";
import {FoodMeme} from "contracts/FoodMeme.sol";
import {Utils} from "contracts/Utils.sol";

contract FoodMemeFactoryTest is Test {
// FoodMemeFactory public factory;
// OApp imports
import {OptionsBuilder} from "@layerzerolabs/oapp-evm/libs/OptionsBuilder.sol";

function setUp() public {}
// OFT imports
import {IOFT, SendParam, OFTReceipt} from "@layerzerolabs/oft-evm/interfaces/IOFT.sol";
import {MessagingFee, MessagingReceipt} from "@layerzerolabs/oft-evm/OFTCore.sol";
import {OFTMsgCodec} from "@layerzerolabs/oft-evm/libs/OFTMsgCodec.sol";
import {OFTComposeMsgCodec} from "@layerzerolabs/oft-evm/libs/OFTComposeMsgCodec.sol";
// DevTools imports
import {TestHelperOz5} from "@layerzerolabs/test-devtools-evm-foundry/contracts/TestHelperOz5.sol";

function test_Increment() public {}

contract FoodMemeFactoryTest is TestHelperOz5 {
uint256 DEPLOYER_PRIVATE_KEY = vm.envUint("DEPLOYER_PRIVATE_KEY");
address deployer = vm.addr(DEPLOYER_PRIVATE_KEY);
using OptionsBuilder for bytes;

uint32 private aEid = 1;
uint32 private bEid = 2;

FoodMeme private aOFT;
FoodMeme private bOFT;

address private userA = address(0x1);
address private userB = address(0x2);
uint256 private initialBalance = 1 ether;
FoodMemeFactoryHelper helper = new FoodMemeFactoryHelper();

FoodMemeFactory factory1;
FoodMemeFactory factory2;

function setUp() public virtual override {
vm.deal(userA, 1000 ether);
vm.deal(userB, 1000 ether);

super.setUp();
setUpEndpoints(2, LibraryType.UltraLightNode);

vm.startPrank(deployer);
vm.chainId(31337);
factory1 = new FoodMemeFactory(helper, "1");
vm.chainId(31338);
factory2 = new FoodMemeFactory(helper, "2");

vm.chainId(31337);
uint256[] memory mintChains = new uint256[](1);
mintChains[0] = block.chainid;
console.log("Current chain: %s", block.chainid);
aOFT = factory1.launch(
Utils.MemeParams({name: "a", symbol: "A", endpoint: address(endpoints[aEid])}),
userA,
Utils.InitParams({
mintable: true,
imageHash: bytes32(0),
recipeHash: bytes32(0),
mintChains: mintChains,
masterChain: block.chainid,
maxSupply: 0,
maxPerMint: 0,
minReviewThreshold: 0,
priceSettings: Utils.PriceSettings({mode: Utils.PriceMode.LinearPrice, a: 0, b: 2, c: 1}),
baseUri: ""
})
);
vm.chainId(31338);
console.log("Switched to chain: %s", block.chainid);
bOFT = factory2.launch(
Utils.MemeParams({name: "b", symbol: "B", endpoint: address(endpoints[aEid])}),
userB,
Utils.InitParams({
mintable: true,
imageHash: bytes32(0),
recipeHash: bytes32(0),
mintChains: mintChains,
masterChain: block.chainid,
maxSupply: 0,
maxPerMint: 0,
minReviewThreshold: 0,
priceSettings: Utils.PriceSettings({mode: Utils.PriceMode.LinearPrice, a: 0, b: 2, c: 2}),
baseUri: ""
})
);
console.log("aOFT delegate: %s", aOFT.owner());
console.log("factory1 : %s", address(factory1));
console.log("bOFT delegate: %s", bOFT.owner());
console.log("factory2 : %s", address(factory2));
{
vm.chainId(31337);
uint32[] memory endPointIds = new uint32[](1);
endPointIds[0] = bEid;
bytes32[] memory remoteContractAddresses = new bytes32[](1);
remoteContractAddresses[0] = bytes32(uint256(uint160(address(bOFT))));
address[] memory sendLibraries = new address[](0);
address[] memory receiveLibraries = new address[](0);
uint256[] memory gracePeriods = new uint256[](0);
uint128[] memory minGasEnforceConfig = new uint128[](1);
minGasEnforceConfig[0] = 100000;
Utils.LzSetConfigParam[] memory sendConfigParams = new Utils.LzSetConfigParam[](0);
Utils.LzSetConfigParam[] memory receiveConfigParams = new Utils.LzSetConfigParam[](0);
Utils.LzEnforcedOptionParam[] memory enforceConfigParams = new Utils.LzEnforcedOptionParam[](0);

Utils.LzParams memory lzParams = Utils.LzParams({
endPointIds: endPointIds,
remoteContractAddresses: remoteContractAddresses,
sendLibraries: sendLibraries,
receiveLibraries: receiveLibraries,
gracePeriods: gracePeriods,
minGasEnforceConfig: minGasEnforceConfig,
sendConfigParams: sendConfigParams,
receiveConfigParams: receiveConfigParams,
enforceConfigParams: enforceConfigParams
});
factory1.setupLz(aOFT, lzParams);
}
{
vm.chainId(31338);
uint32[] memory endPointIds = new uint32[](1);
endPointIds[0] = aEid;
bytes32[] memory remoteContractAddresses = new bytes32[](1);
remoteContractAddresses[0] = bytes32(uint256(uint160(address(aOFT))));
address[] memory sendLibraries = new address[](0);
address[] memory receiveLibraries = new address[](0);
uint256[] memory gracePeriods = new uint256[](0);
uint128[] memory minGasEnforceConfig = new uint128[](1);
minGasEnforceConfig[0] = 100000;
Utils.LzSetConfigParam[] memory sendConfigParams = new Utils.LzSetConfigParam[](0);
Utils.LzSetConfigParam[] memory receiveConfigParams = new Utils.LzSetConfigParam[](0);
Utils.LzEnforcedOptionParam[] memory enforceConfigParams = new Utils.LzEnforcedOptionParam[](0);

Utils.LzParams memory lzParams = Utils.LzParams({
endPointIds: endPointIds,
remoteContractAddresses: remoteContractAddresses,
sendLibraries: sendLibraries,
receiveLibraries: receiveLibraries,
gracePeriods: gracePeriods,
minGasEnforceConfig: minGasEnforceConfig,
sendConfigParams: sendConfigParams,
receiveConfigParams: receiveConfigParams,
enforceConfigParams: enforceConfigParams
});
factory2.setupLz(bOFT, lzParams);
}

vm.chainId(31337);
uint256 aPrice = aOFT.mintPrice(initialBalance);
console.log("aPrice %s", aPrice);
vm.chainId(31337);
aOFT.mint{value: aPrice * initialBalance}(initialBalance, userA);
console.log("a minted %s", aOFT.balanceOf(userA));
vm.chainId(31337);
uint256 bPrice = bOFT.mintPrice(initialBalance);
console.log("bPrice %s", bPrice);
vm.chainId(31338);
vm.expectRevert();
bOFT.mint{value: bPrice * initialBalance}(initialBalance, userB);
vm.chainId(31337);
bOFT.mint{value: bPrice * initialBalance}(initialBalance, userB);
console.log("aOFT owner after setup: %s", aOFT.owner());
console.log("bOFT after setup: %s", bOFT.owner());
vm.stopPrank();
}

function test_constructor() public {
assertEq(aOFT.owner(), deployer);
assertEq(bOFT.owner(), deployer);

assertEq(aOFT.balanceOf(userA), initialBalance);
assertEq(bOFT.balanceOf(userB), initialBalance);

assertEq(aOFT.token(), address(aOFT));
assertEq(bOFT.token(), address(bOFT));
}
//
// function test_send_oft() public {
// uint256 tokensToSend = 1 ether;
// bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200000, 0);
// SendParam memory sendParam = SendParam(
// bEid,
// addressToBytes32(userB),
// tokensToSend,
// tokensToSend,
// options,
// "",
// ""
// );
// MessagingFee memory fee = aOFT.quoteSend(sendParam, false);
//
// assertEq(aOFT.balanceOf(userA), initialBalance);
// assertEq(bOFT.balanceOf(userB), initialBalance);
//
// vm.prank(userA);
// aOFT.send{value: fee.nativeFee}(sendParam, fee, payable(address(this)));
// verifyPackets(bEid, addressToBytes32(address(bOFT)));
//
// assertEq(aOFT.balanceOf(userA), initialBalance - tokensToSend);
// assertEq(bOFT.balanceOf(userB), initialBalance + tokensToSend);
// }
}
Loading

0 comments on commit 6b16d67

Please sign in to comment.