Skip to content

Commit cda0246

Browse files
authored
feedback/audit (#34)
1 parent 8226454 commit cda0246

File tree

6 files changed

+56
-64
lines changed

6 files changed

+56
-64
lines changed

.solhint.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"const-name-snakecase": "off",
99
"func-name-mixedcase": "off",
1010
"func-visibility": ["error", { "ignoreConstructors": true }],
11-
"max-line-length": ["error", 123],
11+
"max-line-length": ["warn", 123],
1212
"named-parameters-mapping": "warn",
1313
"no-empty-blocks": "off",
1414
"not-rely-on-time": "off",

contracts/core/SharesFactoryV1.sol

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pragma solidity 0.8.25;
44

55
import "@openzeppelin/contracts/access/Ownable2Step.sol";
66
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
7+
import { SafeCastLib } from "solady/utils/SafeCastLib.sol";
78
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
89
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
910
import { IShare } from "../interface/IShare.sol";
@@ -34,7 +35,7 @@ contract SharesFactoryV1 is Ownable2Step, ReentrancyGuard {
3435

3536
uint256 public shareIndex;
3637
uint256 public depositedETHAmount;
37-
uint256 public referralFeePercent = 5 * 1e16;
38+
uint256 public referralFeePercent = 2 * 1e16;
3839
uint256 public creatorFeePercent = 5 * 1e16;
3940
uint256 public migrationDeadline;
4041

@@ -43,7 +44,7 @@ contract SharesFactoryV1 is Ownable2Step, ReentrancyGuard {
4344
address public blankAggregator;
4445

4546
event QueueMigrateYield(address indexed newAggregator, uint256 deadline);
46-
event MigrateYield(address indexed newAggregator, uint256 timestamp);
47+
event MigrateYield(address indexed newAggregator);
4748
event ClaimYield(uint256 amount, address indexed to);
4849
event SetCurve(uint8 indexed curveType);
4950
event SetFee(uint256 indexed feePercent, string feeType);
@@ -63,9 +64,9 @@ contract SharesFactoryV1 is Ownable2Step, ReentrancyGuard {
6364

6465
// Set default curve params
6566
curvesMap[0] = Curve({
66-
basePrice: _basePrice, // 5000000000000000;
67-
inflectionPoint: _inflectionPoint, // 1500;
68-
inflectionPrice: _inflectionPrice, // 102500000000000000;
67+
basePrice: _basePrice, // 0.001 ether;
68+
inflectionPoint: _inflectionPoint, // 1000;
69+
inflectionPrice: _inflectionPrice, // 0.1 ether;
6970
linearPriceSlope: _linearPriceSlope, // 0;
7071
exists: true
7172
});
@@ -84,17 +85,12 @@ contract SharesFactoryV1 is Ownable2Step, ReentrancyGuard {
8485
function getCurve(uint8 curveType) public view returns (uint96, uint32, uint128, uint128, bool) {
8586
require(curvesMap[curveType].exists, "Invalid curveType");
8687
Curve memory curve = curvesMap[curveType];
87-
uint96 basePrice = curve.basePrice;
88-
uint32 g = curve.inflectionPoint;
89-
uint128 h = curve.inflectionPrice;
90-
uint128 m = curve.linearPriceSlope;
91-
bool exists = curve.exists;
92-
return (basePrice, g, h, m, exists);
88+
return (curve.basePrice, curve.inflectionPoint, curve.inflectionPrice, curve.linearPriceSlope, curve.exists);
9389
}
9490

9591
function getSubTotal(uint32 fromSupply, uint32 quantity, uint8 curveType) public view returns (uint256) {
96-
(uint96 basePrice, uint32 g, uint128 h, uint128 m,) = getCurve(curveType);
97-
return _subTotal(fromSupply, quantity, basePrice, g, h, m);
92+
(uint96 basePrice, uint32 inflectionPoint, uint128 inflectionPrice, uint128 linearPriceSlope,) = getCurve(curveType);
93+
return _subTotal(fromSupply, quantity, basePrice, inflectionPoint, inflectionPrice, linearPriceSlope);
9894
}
9995

10096
function setReferralFeePercent(uint256 _feePercent) external onlyOwner {
@@ -313,8 +309,9 @@ contract SharesFactoryV1 is Ownable2Step, ReentrancyGuard {
313309
(, uint8 curveType) = getShare(shareId);
314310
uint256 fromSupply = IShare(ERC1155).shareFromSupply(shareId);
315311
uint256 actualReferralFeePercent = referral != address(0) ? referralFeePercent : 0;
312+
require(fromSupply + uint256(quantity) <= type(uint32).max, "Exceeds max supply");
316313

317-
buyPrice = getSubTotal(uint32(fromSupply), quantity, curveType);
314+
buyPrice = getSubTotal(SafeCastLib.toUint32(fromSupply), quantity, curveType);
318315
referralFee = (buyPrice * actualReferralFeePercent) / 1 ether;
319316
creatorFee = (buyPrice * creatorFeePercent) / 1 ether;
320317
buyPriceAfterFee = buyPrice + referralFee + creatorFee;
@@ -346,7 +343,7 @@ contract SharesFactoryV1 is Ownable2Step, ReentrancyGuard {
346343
uint256 actualReferralFeePercent = referral != address(0) ? referralFeePercent : 0;
347344
require(fromSupply >= quantity, "Exceeds supply");
348345

349-
sellPrice = getSubTotal(uint32(fromSupply) - quantity, quantity, curveType);
346+
sellPrice = getSubTotal(SafeCastLib.toUint32(fromSupply) - quantity, quantity, curveType);
350347
referralFee = (sellPrice * actualReferralFeePercent) / 1 ether;
351348
creatorFee = (sellPrice * creatorFeePercent) / 1 ether;
352349
sellPriceAfterFee = sellPrice - referralFee - creatorFee;
@@ -381,7 +378,7 @@ contract SharesFactoryV1 is Ownable2Step, ReentrancyGuard {
381378
// Step 4: Deposit all ETH into the new yieldAggregator as yieldToken.
382379
_depositAllETHToYieldToken();
383380

384-
emit MigrateYield(address(_yieldAggregator), block.timestamp);
381+
emit MigrateYield(address(_yieldAggregator));
385382
}
386383

387384
/**
@@ -414,7 +411,7 @@ contract SharesFactoryV1 is Ownable2Step, ReentrancyGuard {
414411
uint32 inflectionPoint,
415412
uint128 inflectionPrice,
416413
uint128 linearPriceSlope
417-
) public pure returns (uint256 subTotal) {
414+
) internal pure returns (uint256 subTotal) {
418415
unchecked {
419416
subTotal = basePrice * quantity;
420417
subTotal += BondingCurveLib.linearSum(linearPriceSlope, fromSupply, quantity);

contracts/core/aggregator/AaveYieldAggregator.sol

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@ contract AaveYieldAggregator is Ownable, IYieldAggregator {
2222
IAaveGateway public immutable AAVE_WETH_GATEWAY;
2323
IERC20 public aWETH;
2424

25-
uint256 internal constant ACTIVE_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFF;
26-
uint256 internal constant FROZEN_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFF;
27-
uint256 internal constant PAUSED_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFF;
28-
2925
constructor(address _factory, address _weth, address _aavePool, address _aaveGateway) {
3026
FACTORY = _factory;
3127
WETH = _weth;
@@ -59,7 +55,6 @@ contract AaveYieldAggregator is Ownable, IYieldAggregator {
5955
* Only callable by the factory contract.
6056
*/
6157
function yieldDeposit() external onlyFactory {
62-
require(_checkAavePoolState(), "Aave paused");
6358
uint256 ethAmount = address(this).balance;
6459
if (ethAmount > 0) {
6560
AAVE_WETH_GATEWAY.depositETH{ value: ethAmount }(address(AAVE_POOL), FACTORY, 0);
@@ -71,7 +66,6 @@ contract AaveYieldAggregator is Ownable, IYieldAggregator {
7166
* Only callable by the factory contract.
7267
*/
7368
function yieldWithdraw(uint256 amount) external onlyFactory {
74-
require(_checkAavePoolState(), "Aave paused");
7569
if (amount > 0) {
7670
aWETH.safeTransferFrom(FACTORY, address(this), amount);
7771
AAVE_WETH_GATEWAY.withdrawETH(address(AAVE_POOL), amount, FACTORY);
@@ -98,30 +92,4 @@ contract AaveYieldAggregator is Ownable, IYieldAggregator {
9892
return withdrawableETHAmount - depositedETHAmount - yieldBuffer;
9993
}
10094
}
101-
102-
/**
103-
* @notice Check Aave pool state
104-
* @return bool true if Aave pool is active, false otherwise
105-
* @dev For more information, see:
106-
* https://github.com/aave/aave-v3-core/blob/master/contracts/protocol/libraries/configuration/ReserveConfiguration.sol
107-
*/
108-
function _checkAavePoolState() internal view returns (bool) {
109-
uint256 configData = AAVE_POOL.getReserveData(WETH).configuration.data;
110-
if (!(_getActive(configData) && !_getFrozen(configData) && !_getPaused(configData))) {
111-
return false;
112-
}
113-
return true;
114-
}
115-
116-
function _getActive(uint256 configData) internal pure returns (bool) {
117-
return configData & ~ACTIVE_MASK != 0;
118-
}
119-
120-
function _getFrozen(uint256 configData) internal pure returns (bool) {
121-
return configData & ~FROZEN_MASK != 0;
122-
}
123-
124-
function _getPaused(uint256 configData) internal pure returns (bool) {
125-
return configData & ~PAUSED_MASK != 0;
126-
}
12795
}

scripts/Base.s.sol

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ contract BaseScript is Script {
2020
mapping(uint chainid => address aave_weth_gateway) public AAVE_WETH_GATEWAY;
2121

2222
constructor() {
23+
// After the factory contract has been deployed,
24+
// set the factory address here so that the yieldAggregator can be deployed.
25+
2326
// Optimism Sepolia
2427
SHARES_FACTORY[OPTIMISM_TESTNET] = 0x9F94C75341D23EAb48793b2879F6062a400132e3;
2528
WETH[OPTIMISM_TESTNET] = 0x4200000000000000000000000000000000000006;

scripts/Deploy.s.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ contract DeployScript is BaseScript {
1313
BlankYieldAggregator public blankYieldAggregator;
1414

1515
string public constant BASE_URI = "https://vv.meme/shares/uri/";
16-
uint96 public constant BASE_PRICE = 0.005 ether;
17-
uint32 public constant INFLECTION_POINT = 1500;
18-
uint128 public constant INFLECTION_PRICE = 0.1025 ether;
16+
uint96 public constant BASE_PRICE = 0.001 ether;
17+
uint32 public constant INFLECTION_POINT = 1000;
18+
uint128 public constant INFLECTION_PRICE = 0.1 ether;
1919
uint128 public constant LINEAR_PRICE_SLOPE = 0;
2020

2121
function run() public virtual broadcast() {

test/unit/SharesFactory.t.sol

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
pragma solidity 0.8.25;
33

44
import { console } from "forge-std/console.sol";
5+
import { SafeCastLib } from "solady/utils/SafeCastLib.sol";
56
import { SharesFactoryV1 } from "contracts/core/SharesFactoryV1.sol";
67
import { IYieldAggregator } from "contracts/interface/IYieldAggregator.sol";
78
import { BaseTest } from "../BaseTest.t.sol";
@@ -68,21 +69,25 @@ contract SharesFactoryTests is BaseTest {
6869
uint256 aliceBalBefore = addrAlice.balance;
6970
uint256 bobBalBefore = addrBob.balance;
7071
uint256 referrerBalBefore = referralReceiver.balance;
71-
// uint256 factoryBalBefore = aWETH.balanceOf(address(sharesFactory));
7272
uint256 depositedETHAmountBefore = sharesFactory.depositedETHAmount();
7373

74+
(
75+
uint256 buyPriceAfterFee,
76+
uint256 buyPrice,
77+
uint256 referralFee,
78+
uint256 creatorFee
79+
) = sharesFactory.getBuyPriceAfterFee(0, 1, referralReceiver);
7480
_buyShare(addrBob, 0, 1, referralReceiver);
81+
console.log(buyPriceAfterFee, buyPrice, referralFee, creatorFee);
7582

7683
uint256 aliceBalAfter = addrAlice.balance;
7784
uint256 bobBalAfter = addrBob.balance;
7885
uint256 referrerBalAfter = referralReceiver.balance;
79-
// uint256 factoryBalAfter = aWETH.balanceOf(address(sharesFactory));
8086
uint256 depositedETHAmountAfter = sharesFactory.depositedETHAmount();
8187

82-
assertEq(bobBalBefore - bobBalAfter, 5500450999999993); // Bob buy 1 share
88+
assertEq(bobBalBefore - bobBalAfter, 5350438699999993); // Bob buy 1 share
8389
assertEq(aliceBalAfter - aliceBalBefore, 250020499999999); // Alice receive creator fee
84-
assertEq(referrerBalAfter - referrerBalBefore, 250020499999999); // referral receive fee
85-
// assertEq(factoryBalAfter - factoryBalBefore, 5000409999999995); // Factory aWETH balance with rounding error
90+
assertEq(referrerBalAfter - referrerBalBefore, 100008199999999); // referral receive fee
8691
assertEq(depositedETHAmountAfter - depositedETHAmountBefore, 5000409999999995); // Factory records ETH Amount
8792

8893
uint256 bobShareBal = sharesNFT.balanceOf(addrBob, 0);
@@ -93,21 +98,25 @@ contract SharesFactoryTests is BaseTest {
9398
uint256 aliceBalBefore = addrAlice.balance;
9499
uint256 bobBalBefore = addrBob.balance;
95100
uint256 referrerBalBefore = referralReceiver.balance;
96-
// uint256 factoryBalBefore = aWETH.balanceOf(address(sharesFactory));
97101
uint256 depositedETHAmountBefore = sharesFactory.depositedETHAmount();
98102

103+
(
104+
uint256 sellPriceAfterFee,
105+
uint256 sellPrice,
106+
uint256 referralFee,
107+
uint256 creatorFee
108+
) = sharesFactory.getSellPriceAfterFee(1, 1, referralReceiver);
99109
_sellShare(addrAlice, 1, 1, referralReceiver);
110+
console.log(sellPriceAfterFee, sellPrice, referralFee, creatorFee);
100111

101112
uint256 aliceBalAfter = addrAlice.balance;
102113
uint256 bobBalAfter = addrBob.balance;
103114
uint256 referrerBalAfter = referralReceiver.balance;
104-
// uint256 factoryBalAfter = aWETH.balanceOf(address(sharesFactory));
105115
uint256 depositedETHAmountAfter = sharesFactory.depositedETHAmount();
106116

107-
assertEq(aliceBalAfter - aliceBalBefore, 4500163999999998); // Alice sell 1 share
117+
assertEq(aliceBalAfter - aliceBalBefore, 4650169466666665); // Alice sell 1 share
108118
assertEq(bobBalAfter - bobBalBefore, 250009111111111); // Bob receive creator fee
109-
assertEq(referrerBalAfter - referrerBalBefore, 250009111111111); // Referral receive fee
110-
// assertEq(factoryBalBefore - factoryBalAfter, 5000182222222220); // Factory aWETH balance with rounding error
119+
assertEq(referrerBalAfter - referrerBalBefore, 100003644444444); // Referral receive fee
111120
assertEq(depositedETHAmountBefore - depositedETHAmountAfter, 5000182222222220); // Factory records ETH Amount
112121

113122
uint256 aliceShareBal = sharesNFT.balanceOf(addrAlice, 1);
@@ -374,6 +383,22 @@ contract SharesFactoryTests is BaseTest {
374383
}
375384

376385
function test_getBuyPriceAfterFeeFailed() public {
386+
// When the quantity is 5_000 that reach th
387+
uint256 gasBefore = gasleft();
388+
sharesFactory.getBuyPriceAfterFee(0, 5_000, referralReceiver);
389+
uint256 gasAfter = gasleft();
390+
console.log("gas usage", gasBefore - gasAfter);
391+
392+
vm.expectRevert(bytes("Exceeds max supply"));
393+
sharesFactory.getBuyPriceAfterFee(0, type(uint32).max, referralReceiver);
394+
395+
// Expect revert if supply is over `2**32 -1` (uint32)
396+
vm.expectRevert();
397+
sharesFactory.getSubTotal(SafeCastLib.toUint32(2**32), 1, 0);
398+
399+
// Expect success if supply is lower than `2**32` (uint32)
400+
sharesFactory.getSubTotal(SafeCastLib.toUint32(2**32 - 1), 1, 0);
401+
377402
vm.expectRevert(bytes("Invalid shareId"));
378403
sharesFactory.getBuyPriceAfterFee(999, 0, referralReceiver);
379404

@@ -514,7 +539,6 @@ contract SharesFactoryTests is BaseTest {
514539

515540
function _buyShare(address sender, uint256 shareId, uint32 quantity, address referral) internal {
516541
(uint256 buyPriceAfterFee,,,) = sharesFactory.getBuyPriceAfterFee(shareId, quantity, referral);
517-
// console.log("buyPriceAfterFee", buyPriceAfterFee, shareId, quantity, referral);
518542
vm.prank(address(sender));
519543
sharesFactory.buyShare{ value: buyPriceAfterFee }(shareId, quantity, referral);
520544
}

0 commit comments

Comments
 (0)