Skip to content

Commit

Permalink
Merge pull request #110 from dvilelaf/post-external-audit
Browse files Browse the repository at this point in the history
refactor and test: addressing external audit
  • Loading branch information
DavidMinarsch authored Dec 28, 2024
2 parents 9cc65f5 + e88a45e commit fab1753
Show file tree
Hide file tree
Showing 15 changed files with 78 additions and 65 deletions.
12 changes: 10 additions & 2 deletions contracts/MemeArbitrum.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,22 @@ interface IWETH {

// @title MemeArbitrum - a smart contract factory for Meme Token creation on Arbitrum.
contract MemeArbitrum is MemeFactory {
// Base UniswapV3 pool cardinality that corresponds to 240 seconds window (240 / 1 seconds per block)
uint16 public constant POOL_CARDINALITY = 240;

/// @dev MemeArbitrum constructor
constructor(
address _olas,
address _nativeToken,
address _uniV3PositionManager,
address _buyBackBurner,
uint256 _minNativeTokenValue
) MemeFactory(_olas, _nativeToken, _uniV3PositionManager, _buyBackBurner, _minNativeTokenValue) {}
) MemeFactory(_nativeToken, _uniV3PositionManager, _buyBackBurner, _minNativeTokenValue) {}

/// @dev Gets required UniswapV3 pool cardinality.
/// @return Pool cardinality.
function _observationCardinalityNext() internal virtual override pure returns (uint16) {
return POOL_CARDINALITY;
}

/// @dev Allows diverting first x collected funds to a launch campaign.
/// @notice MemeArbitrum has no launch campaign, hence x = 0.
Expand Down
13 changes: 10 additions & 3 deletions contracts/MemeBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,21 @@ contract MemeBase is MemeFactory {
uint256 public constant LIQUIDITY_AGNT = 127412857890000000000;
// Block time of original summon:
uint256 public constant SUMMON_AGNT = 22902993;
// Base UniswapV3 pool cardinality that corresponds to 240 seconds window (240 / 2 seconds per block)
uint16 public constant POOL_CARDINALITY = 120;

// Launch campaign nonce
uint256 public immutable launchCampaignNonce;

/// @dev MemeBase constructor
constructor(
address _olas,
address _nativeToken,
address _uniV3PositionManager,
address _buyBackBurner,
uint256 _minNativeTokenValue,
address[] memory accounts,
uint256[] memory amounts
) MemeFactory(_olas, _nativeToken, _uniV3PositionManager, _buyBackBurner, _minNativeTokenValue) {
) MemeFactory(_nativeToken, _uniV3PositionManager, _buyBackBurner, _minNativeTokenValue) {
if (accounts.length > 0) {
launchCampaignNonce = _nonce;
_launchCampaignSetup(accounts, amounts);
Expand All @@ -39,6 +40,12 @@ contract MemeBase is MemeFactory {
}
}

/// @dev Gets required UniswapV3 pool cardinality.
/// @return Pool cardinality.
function _observationCardinalityNext() internal virtual override pure returns (uint16) {
return POOL_CARDINALITY;
}

/// @dev Launch campaign initialization function.
/// @param accounts Original accounts.
/// @param amounts Corresponding original amounts (without subtraction for burn).
Expand All @@ -57,7 +64,7 @@ contract MemeBase is MemeFactory {
uint256 totalAmount;
for (uint256 i = 0; i < accounts.length; ++i) {
totalAmount += amounts[i];
memeHearters[launchCampaignNonce][accounts[i]] = amounts[i];
memeHearters[launchCampaignNonce][accounts[i]] += amounts[i];
// to match original hearter events
emit Hearted(accounts[i], launchCampaignNonce, amounts[i]);
}
Expand Down
12 changes: 10 additions & 2 deletions contracts/MemeCelo.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,22 @@ import {MemeFactory} from "./MemeFactory.sol";

/// @title MemeCelo - a smart contract factory for Meme Token creation on Celo.
contract MemeCelo is MemeFactory {
// Base UniswapV3 pool cardinality that corresponds to 300 seconds window (300 / 5 seconds per block)
uint16 public constant POOL_CARDINALITY = 60;

/// @dev MemeCelo constructor
constructor(
address _olas,
address _nativeToken,
address _uniV3PositionManager,
address _buyBackBurner,
uint256 _minNativeTokenValue
) MemeFactory(_olas, _nativeToken, _uniV3PositionManager, _buyBackBurner, _minNativeTokenValue) {}
) MemeFactory(_nativeToken, _uniV3PositionManager, _buyBackBurner, _minNativeTokenValue) {}

/// @dev Gets required UniswapV3 pool cardinality.
/// @return Pool cardinality.
function _observationCardinalityNext() internal virtual override pure returns (uint16) {
return POOL_CARDINALITY;
}

/// @dev Allows diverting first x collected funds to a launch campaign.
/// @notice MemeCelo has no launch campaign, hence x = 0.
Expand Down
12 changes: 10 additions & 2 deletions contracts/MemeEthereum.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,22 @@ interface IWETH {

/// @title MemeEthereum - a smart contract factory for Meme Token creation on Ethereum.
contract MemeEthereum is MemeFactory {
// Base UniswapV3 pool cardinality that corresponds to 720 seconds window (720 / 12 seconds per block)
uint16 public constant POOL_CARDINALITY = 60;

/// @dev MemeEthereum constructor
constructor(
address _olas,
address _nativeToken,
address _uniV3PositionManager,
address _buyBackBurner,
uint256 _minNativeTokenValue
) MemeFactory(_olas, _nativeToken, _uniV3PositionManager, _buyBackBurner, _minNativeTokenValue) {}
) MemeFactory(_nativeToken, _uniV3PositionManager, _buyBackBurner, _minNativeTokenValue) {}

/// @dev Gets required UniswapV3 pool cardinality.
/// @return Pool cardinality.
function _observationCardinalityNext() internal virtual override pure returns (uint16) {
return POOL_CARDINALITY;
}

/// @dev Allows diverting first x collected funds to a launch campaign.
/// @notice MemeEthereum has no launch campaign, hence x = 0.
Expand Down
49 changes: 19 additions & 30 deletions contracts/MemeFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -115,17 +115,13 @@ abstract contract MemeFactory {

// Minimum value of native token deposit
uint256 public immutable minNativeTokenValue;
// OLAS token address
address public immutable olas;
// Native token address (ERC-20 equivalent)
address public immutable nativeToken;
// Uniswap V3 position manager address
address public immutable uniV3PositionManager;
// BuyBackBurner address
address public immutable buyBackBurner;

// Number of meme tokens
uint256 public numTokens;
// Native token (ERC-20) scheduled to be converted to OLAS for Ascendance
uint256 public scheduledForAscendance;
// Nonce
Expand All @@ -148,13 +144,11 @@ abstract contract MemeFactory {

/// @dev MemeFactory constructor
constructor(
address _olas,
address _nativeToken,
address _uniV3PositionManager,
address _buyBackBurner,
uint256 _minNativeTokenValue
) {
olas = _olas;
nativeToken = _nativeToken;
uniV3PositionManager = _uniV3PositionManager;
buyBackBurner = _buyBackBurner;
Expand Down Expand Up @@ -183,10 +177,10 @@ abstract contract MemeFactory {
: (memeToken, nativeToken, memeTokenAmount, nativeTokenAmount);

// Calculate the price ratio (amount1 / amount0) scaled by 1e18 to avoid floating point issues
uint256 priceX96 = (amount1 * 1e18) / amount0;
uint256 price = FixedPointMathLib.divWadDown(amount1, amount0);

// Calculate the square root of the price ratio in X96 format
uint160 sqrtPriceX96 = uint160((FixedPointMathLib.sqrt(priceX96) * (1 << 96)) / 1e9);
uint160 sqrtPriceX96 = uint160((FixedPointMathLib.sqrt(price) * (1 << 96)) / 1e9);

// Get factory address
address factory = IUniswapV3(uniV3PositionManager).factory();
Expand Down Expand Up @@ -220,13 +214,13 @@ abstract contract MemeFactory {

// Schedule for ascendance leftovers from native token
// Note that meme token leftovers will be purged via purgeThisMeme
uint256 nativeLeftovers = isNativeFirst ? (nativeTokenAmount - amount0) : (nativeTokenAmount - amount1);
uint256 nativeLeftovers = nativeTokenAmount - (isNativeFirst ? amount0 : amount1);
if (nativeLeftovers > 0) {
scheduledForAscendance += nativeLeftovers;
}

// Increase observation cardinality
IUniswapV3(pool).increaseObservationCardinalityNext(60);
IUniswapV3(pool).increaseObservationCardinalityNext(_observationCardinalityNext());
}

/// @dev Collects fees from LP position, burns the meme token part and schedules for ascendance the native token part.
Expand All @@ -250,16 +244,8 @@ abstract contract MemeFactory {
(uint256 amount0, uint256 amount1) = IUniswapV3(uniV3PositionManager).collect(params);
require(amount0 > 0 || amount1 > 0, "Zero fees available");

uint256 nativeAmountForOLASBurn;
uint256 memeAmountToBurn;

if (isNativeFirst) {
nativeAmountForOLASBurn = amount0;
memeAmountToBurn = amount1;
} else {
memeAmountToBurn = amount0;
nativeAmountForOLASBurn = amount1;
}
(uint256 nativeAmountForOLASBurn, uint256 memeAmountToBurn) = isNativeFirst ? (amount0, amount1) :
(amount1, amount0);

// Burn meme tokens
IERC20(memeToken).burn(memeAmountToBurn);
Expand Down Expand Up @@ -312,16 +298,16 @@ abstract contract MemeFactory {
) internal returns (address memeToken) {
bytes32 randomNonce = keccak256(abi.encodePacked(block.timestamp, msg.sender, memeNonce));
randomNonce = keccak256(abi.encodePacked(randomNonce));
bytes memory payload = abi.encodePacked(type(Meme).creationCode, abi.encode(name, symbol, DECIMALS, totalSupply));
// solhint-disable-next-line no-inline-assembly
assembly {
memeToken := create2(0x0, add(0x20, payload), mload(payload), randomNonce)
}
memeToken = address(new Meme{salt: randomNonce}(name, symbol, DECIMALS, totalSupply));

// Check for non-zero token address
require(memeToken != address(0), "Token creation failed");
}

/// @dev Gets required UniswapV3 pool cardinality.
/// @return Pool cardinality.
function _observationCardinalityNext() internal virtual pure returns (uint16);

/// @dev Allows diverting first x collected funds to a launch campaign.
/// @return adjustedAmount Adjusted amount of native token to convert to OLAS and burn.
function _launchCampaign() internal virtual returns (uint256 adjustedAmount);
Expand Down Expand Up @@ -364,7 +350,6 @@ abstract contract MemeFactory {

// Push token into the global list of tokens
memeTokens.push(memeToken);
numTokens = memeTokens.length;

// Allocate to the token hearter unleashing the meme
uint256 hearterContribution = memeHearters[memeNonce][msg.sender];
Expand Down Expand Up @@ -436,9 +421,7 @@ abstract contract MemeFactory {
require(memeSummon.unleashTime == 0, "Meme already unleashed");

// Update meme token map values
uint256 totalNativeTokenCommitted = memeSummon.nativeTokenContributed;
totalNativeTokenCommitted += msg.value;
memeSummon.nativeTokenContributed = totalNativeTokenCommitted;
memeSummon.nativeTokenContributed += msg.value;
memeHearters[memeNonce][msg.sender] += msg.value;

// Record msg.sender activity
Expand Down Expand Up @@ -581,7 +564,7 @@ abstract contract MemeFactory {

/// @dev Collects all accumulated LP fees.
/// @param tokens List of tokens to be iterated over.
function collectFees(address[] memory tokens) public {
function collectFees(address[] memory tokens) external {
require(_locked == 1, "Reentrancy guard");
_locked = 2;

Expand All @@ -600,4 +583,10 @@ abstract contract MemeFactory {

_locked = 1;
}

/// @dev Gets global number of unleashed meme tokens.
/// @return Number of unleashed meme tokens.
function numTokens() external view returns (uint256) {
return memeTokens.length;
}
}
4 changes: 2 additions & 2 deletions scripts/deployment/deploy_03_meme_base.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ async function main() {
const gasPrice = ethers.utils.parseUnits(gasPriceInGwei, "gwei");
const MemeBase = await ethers.getContractFactory("MemeBase");
console.log("You are signing the following transaction: MemeBase.connect(EOA).deploy()");
const memeBase = await MemeBase.connect(EOA).deploy(parsedData.olasAddress, parsedData.wethAddress,
parsedData.uniV3positionManagerAddress, parsedData.buyBackBurnerProxyAddress, parsedData.minNativeTokenValue,
const memeBase = await MemeBase.connect(EOA).deploy(parsedData.wethAddress, parsedData.uniV3positionManagerAddress,
parsedData.buyBackBurnerProxyAddress, parsedData.minNativeTokenValue,
accounts, amounts, { gasPrice, gasLimit: 11000000});
const result = await memeBase.deployed();

Expand Down
4 changes: 2 additions & 2 deletions scripts/deployment/deploy_04_meme_celo.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ async function main() {
const gasPrice = ethers.utils.parseUnits(gasPriceInGwei, "gwei");
const MemeCelo = await ethers.getContractFactory("MemeCelo");
console.log("You are signing the following transaction: MemeCelo.connect(EOA).deploy()");
const memeCelo = await MemeCelo.connect(EOA).deploy(parsedData.olasAddress, parsedData.celoAddress,
parsedData.uniV3positionManagerAddress, parsedData.buyBackBurnerProxyAddress, parsedData.minNativeTokenValue, { gasPrice });
const memeCelo = await MemeCelo.connect(EOA).deploy(parsedData.celoAddress, parsedData.uniV3positionManagerAddress,
parsedData.buyBackBurnerProxyAddress, parsedData.minNativeTokenValue, { gasPrice });
const result = await memeCelo.deployed();

// Transaction details
Expand Down
2 changes: 1 addition & 1 deletion scripts/deployment/deploy_05_meme_arbitrum.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ async function main() {
const gasPrice = ethers.utils.parseUnits(gasPriceInGwei, "gwei");
const MemeArbitrum = await ethers.getContractFactory("MemeArbitrum");
console.log("You are signing the following transaction: MemeArbitrum.connect(EOA).deploy()");
const memeArbitrum = await MemeArbitrum.connect(EOA).deploy(parsedData.olasAddress, parsedData.wethAddress,
const memeArbitrum = await MemeArbitrum.connect(EOA).deploy(parsedData.wethAddress,
parsedData.uniV3positionManagerAddress, buyBackBurner.address, parsedData.minNativeTokenValue, { gasPrice });
const result = await memeArbitrum.deployed();

Expand Down
1 change: 0 additions & 1 deletion scripts/deployment/verify_03_meme_base.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ for (let i = 0; i < redemptionsData.length; i++) {
}

module.exports = [
parsedData.olasAddress,
parsedData.wethAddress,
parsedData.uniV3positionManagerAddress,
parsedData.buyBackBurnerProxyAddress,
Expand Down
1 change: 0 additions & 1 deletion scripts/deployment/verify_04_meme_celo.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const dataFromJSON = fs.readFileSync(globalsFile, "utf8");
const parsedData = JSON.parse(dataFromJSON);

module.exports = [
parsedData.olasAddress,
parsedData.celoAddress,
parsedData.uniV3positionManagerAddress,
parsedData.buyBackBurnerProxyAddress,
Expand Down
1 change: 0 additions & 1 deletion scripts/deployment/verify_05_meme_arbitrum.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const dataFromJSON = fs.readFileSync(globalsFile, "utf8");
const parsedData = JSON.parse(dataFromJSON);

module.exports = [
parsedData.olasAddress,
parsedData.wethAddress,
parsedData.uniV3positionManagerAddress,
parsedData.buyBackBurnerProxyAddress,
Expand Down
4 changes: 2 additions & 2 deletions test/MemeBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ const main = async () => {

// MemeBase
const MemeBase = await ethers.getContractFactory("MemeBase");
const memeBase = await MemeBase.deploy(parsedData.olasAddress, parsedData.wethAddress,
parsedData.uniV3positionManagerAddress, buyBackBurner.address, parsedData.minNativeTokenValue, [], []);
const memeBase = await MemeBase.deploy(parsedData.wethAddress, parsedData.uniV3positionManagerAddress,
buyBackBurner.address, parsedData.minNativeTokenValue, [], []);
await memeBase.deployed();

// Summon a new meme token
Expand Down
20 changes: 8 additions & 12 deletions test/MemeBaseLaunchCampaign.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,8 @@ const main = async () => {
expect(deployer.address).to.equal(await buyBackBurner.owner());

const MemeBase = await ethers.getContractFactory("MemeBase");
const memeBase = await MemeBase.deploy(parsedData.olasAddress, parsedData.wethAddress,
parsedData.uniV3positionManagerAddress, buyBackBurner.address, parsedData.minNativeTokenValue,
accounts, amounts);
const memeBase = await MemeBase.deploy(parsedData.wethAddress, parsedData.uniV3positionManagerAddress,
buyBackBurner.address, parsedData.minNativeTokenValue, accounts, amounts);
await memeBase.deployed();

// Try to deploy oracle with incorrect values
Expand Down Expand Up @@ -110,21 +109,18 @@ const main = async () => {
// Try to deploy meme base with incorrect campaign params
// Incorrect array sizes
await expect(
MemeBase.deploy(parsedData.olasAddress, parsedData.wethAddress,
parsedData.uniV3positionManagerAddress, buyBackBurner.address, parsedData.minNativeTokenValue,
accounts, [])
MemeBase.deploy(parsedData.wethAddress, parsedData.uniV3positionManagerAddress, buyBackBurner.address,
parsedData.minNativeTokenValue, accounts, [])
).to.be.revertedWith("Array lengths are not equal");
await expect(
MemeBase.deploy(parsedData.olasAddress, parsedData.wethAddress,
parsedData.uniV3positionManagerAddress, buyBackBurner.address, parsedData.minNativeTokenValue,
accounts, [amounts[0]])
MemeBase.deploy(parsedData.wethAddress, parsedData.uniV3positionManagerAddress, buyBackBurner.address,
parsedData.minNativeTokenValue, accounts, [amounts[0]])
).to.be.revertedWith("Array lengths are not equal");

// Incorrect accumulated CONTRIBUTION_AGNT amount
await expect(
MemeBase.deploy(parsedData.olasAddress, parsedData.wethAddress,
parsedData.uniV3positionManagerAddress, buyBackBurner.address, parsedData.minNativeTokenValue,
[accounts[0]], [amounts[0]])
MemeBase.deploy(parsedData.wethAddress, parsedData.uniV3positionManagerAddress, buyBackBurner.address,
parsedData.minNativeTokenValue,[accounts[0]], [amounts[0]])
).to.be.revertedWith("Total amount must match original contribution amount");

const wethABI = fs.readFileSync("abis/uniswap/weth.json", "utf8");
Expand Down
4 changes: 2 additions & 2 deletions test/MemeCelo.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ const main = async () => {
const buyBackBurner = await ethers.getContractAt("BuyBackBurnerUniswap", buyBackBurnerProxy.address);

const MemeCelo = await ethers.getContractFactory("MemeCelo");
const memeCelo = await MemeCelo.deploy(parsedData.olasAddress, parsedData.celoAddress,
parsedData.uniV3positionManagerAddress, buyBackBurner.address, parsedData.minNativeTokenValue);
const memeCelo = await MemeCelo.deploy(parsedData.celoAddress, parsedData.uniV3positionManagerAddress,
buyBackBurner.address, parsedData.minNativeTokenValue);
await memeCelo.deployed();

// Summon a new meme token
Expand Down
4 changes: 2 additions & 2 deletions test/MemeEthereum.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ const main = async () => {
const buyBackBurner = await ethers.getContractAt("BuyBackBurnerUniswap", buyBackBurnerProxy.address);

const MemeEthereum = await ethers.getContractFactory("MemeEthereum");
const memeEthereum = await MemeEthereum.deploy(parsedData.olasAddress, parsedData.wethAddress,
parsedData.uniV3positionManagerAddress, buyBackBurner.address, parsedData.minNativeTokenValue);
const memeEthereum = await MemeEthereum.deploy(parsedData.wethAddress, parsedData.uniV3positionManagerAddress,
buyBackBurner.address, parsedData.minNativeTokenValue);
await memeEthereum.deployed();

const wethABI = fs.readFileSync("abis/uniswap/weth.json", "utf8");
Expand Down

0 comments on commit fab1753

Please sign in to comment.