Skip to content

Commit b12ab63

Browse files
authored
Fix/token addr zenith (#69)
* fix: issue #22 * fix: issue #23 * fix: issue #24 * fix: issue #26 * fix: issue #8 * fix issue #19 * fix issue #10 * fix issue #27 * fix issue #37 * fix issue #28 * fix issue #11 * fix issue 9 & 13 * updated deployment info * added salt to token creation * simplified onGenesisSuccess * add extra set function with salt * fixed contract size too big issue * revert * Optimized Genesis.sol contract size * updated FGenesis params validation * fix bonding_role upgrade and remove balance check in participate() * add Insufficient Agent Token balance check in onGenesisSuccess * update base-sepolia.json * fix unable to graduate multiple agents in the same block --------- Co-authored-by: Koo Huang <>
1 parent 0b3190f commit b12ab63

18 files changed

+1013
-633
lines changed

.openzeppelin/base-sepolia.json

Lines changed: 476 additions & 0 deletions
Large diffs are not rendered by default.

contracts/fun/Bonding.sol

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -193,24 +193,14 @@ contract Bonding is
193193
string memory img,
194194
string[4] memory urls,
195195
uint256 purchaseAmount
196-
) public nonReentrant returns (address, address, uint) {
197-
return launchFor(_name, _ticker, cores, desc, img, urls, purchaseAmount, msg.sender);
198-
}
199-
200-
function launchFor(
201-
string memory _name,
202-
string memory _ticker,
203-
uint8[] memory cores,
204-
string memory desc,
205-
string memory img,
206-
string[4] memory urls,
207-
uint256 purchaseAmount,
208-
address creator
209196
) public nonReentrant returns (address, address, uint) {
210197
require(
211198
purchaseAmount > fee,
212199
"Purchase amount must be greater than fee"
213200
);
201+
202+
require(cores.length > 0, "Cores must be provided");
203+
214204
address assetToken = router.assetToken();
215205
require(
216206
IERC20(assetToken).balanceOf(msg.sender) >= purchaseAmount,
@@ -224,7 +214,9 @@ contract Bonding is
224214
initialPurchase
225215
);
226216

227-
FERC20 token = new FERC20(string.concat("fun ", _name), _ticker, initialSupply, maxTx);
217+
FERC20 token = new FERC20{
218+
salt: keccak256(abi.encodePacked(msg.sender, block.timestamp))
219+
}(string.concat("fun ", _name), _ticker, initialSupply, maxTx);
228220
uint256 supply = token.totalSupply();
229221

230222
address _pair = factory.createPair(address(token), assetToken);
@@ -252,7 +244,7 @@ contract Bonding is
252244
lastUpdated: block.timestamp
253245
});
254246
Token memory tmpToken = Token({
255-
creator: creator,
247+
creator: msg.sender,
256248
token: address(token),
257249
agentToken: address(0),
258250
pair: _pair,
@@ -270,17 +262,17 @@ contract Bonding is
270262
tokenInfo[address(token)] = tmpToken;
271263
tokenInfos.push(address(token));
272264

273-
bool exists = _checkIfProfileExists(creator);
265+
bool exists = _checkIfProfileExists(msg.sender);
274266

275267
if (exists) {
276-
Profile storage _profile = profile[creator];
268+
Profile storage _profile = profile[msg.sender];
277269

278270
_profile.tokens.push(address(token));
279271
} else {
280-
bool created = _createUserProfile(creator);
272+
bool created = _createUserProfile(msg.sender);
281273

282274
if (created) {
283-
Profile storage _profile = profile[creator];
275+
Profile storage _profile = profile[msg.sender];
284276

285277
_profile.tokens.push(address(token));
286278
}
@@ -292,17 +284,26 @@ contract Bonding is
292284

293285
// Make initial purchase
294286
IERC20(assetToken).forceApprove(address(router), initialPurchase);
295-
router.buy(initialPurchase, address(token), address(this));
287+
_buy(
288+
address(this),
289+
initialPurchase,
290+
address(token),
291+
0,
292+
block.timestamp + 300
293+
);
296294
token.transfer(msg.sender, token.balanceOf(address(this)));
297295

298296
return (address(token), _pair, n);
299297
}
300298

301299
function sell(
302300
uint256 amountIn,
303-
address tokenAddress
301+
address tokenAddress,
302+
uint256 amountOutMin,
303+
uint256 deadline
304304
) public returns (bool) {
305305
require(tokenInfo[tokenAddress].trading, "Token not trading");
306+
require(block.timestamp <= deadline, "Deadline exceeded");
306307

307308
address pairAddress = factory.getPair(
308309
tokenAddress,
@@ -318,6 +319,7 @@ contract Bonding is
318319
tokenAddress,
319320
msg.sender
320321
);
322+
require(amount1Out >= amountOutMin, "Slippage too high");
321323

322324
uint256 newReserveA = reserveA + amount0In;
323325
uint256 newReserveB = reserveB - amount1Out;
@@ -351,12 +353,14 @@ contract Bonding is
351353
return true;
352354
}
353355

354-
function buy(
356+
function _buy(
357+
address buyer,
355358
uint256 amountIn,
356-
address tokenAddress
357-
) public payable returns (bool) {
358-
require(tokenInfo[tokenAddress].trading, "Token not trading");
359-
359+
address tokenAddress,
360+
uint256 amountOutMin,
361+
uint256 deadline
362+
) internal {
363+
require(block.timestamp <= deadline, "Deadline exceeded");
360364
address pairAddress = factory.getPair(
361365
tokenAddress,
362366
router.assetToken()
@@ -369,9 +373,11 @@ contract Bonding is
369373
(uint256 amount1In, uint256 amount0Out) = router.buy(
370374
amountIn,
371375
tokenAddress,
372-
msg.sender
376+
buyer
373377
);
374378

379+
require(amount0Out >= amountOutMin, "Slippage too high");
380+
375381
uint256 newReserveA = reserveA - amount0Out;
376382
uint256 newReserveB = reserveB + amount1In;
377383
uint256 duration = block.timestamp -
@@ -404,6 +410,17 @@ contract Bonding is
404410
if (newReserveA <= gradThreshold && tokenInfo[tokenAddress].trading) {
405411
_openTradingOnUniswap(tokenAddress);
406412
}
413+
}
414+
415+
function buy(
416+
uint256 amountIn,
417+
address tokenAddress,
418+
uint256 amountOutMin,
419+
uint256 deadline
420+
) public payable returns (bool) {
421+
require(tokenInfo[tokenAddress].trading, "Token not trading");
422+
423+
_buy(msg.sender, amountIn, tokenAddress, amountOutMin, deadline);
407424

408425
return true;
409426
}
@@ -448,11 +465,12 @@ contract Bonding is
448465
);
449466

450467
address agentToken = IAgentFactoryV3(agentFactory)
451-
.executeBondingCurveApplication(
468+
.executeBondingCurveApplicationSalt(
452469
id,
453470
_token.data.supply / (10 ** token_.decimals()),
454471
tokenBalance / (10 ** token_.decimals()),
455-
pairAddress
472+
pairAddress,
473+
keccak256(abi.encodePacked(msg.sender, block.timestamp, tokenAddress))
456474
);
457475
_token.agentToken = agentToken;
458476

contracts/fun/FERC20.sol

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,6 @@ contract FERC20 is Context, IERC20, Ownable {
121121
function _transfer(address from, address to, uint256 amount) private {
122122
require(from != address(0), "ERC20: transfer from the zero address");
123123
require(to != address(0), "ERC20: transfer to the zero address");
124-
require(amount > 0, "Transfer amount must be greater than zero");
125124

126125
if (!isExcludedFromMaxTx[from]) {
127126
require(amount <= _maxTxAmount, "Exceeds MaxTx");

contracts/genesis/FGenesis.sol

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@ import {Genesis} from "./Genesis.sol";
55
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
66
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
77
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
8-
import "../virtualPersona/AgentFactoryV3.sol";
98
import "./GenesisTypes.sol";
109
import "./GenesisLib.sol";
11-
import "../virtualPersona/AgentFactoryV3.sol";
1210

1311
contract FGenesis is Initializable, AccessControlUpgradeable {
1412
using GenesisLib for *;
@@ -38,6 +36,8 @@ contract FGenesis is Initializable, AccessControlUpgradeable {
3836

3937
event GenesisCreated(uint256 indexed id, address indexed addr);
4038

39+
bytes32 public constant BONDING_ROLE = keccak256("BONDING_ROLE");
40+
4141
/// @custom:oz-upgrades-unsafe-allow constructor
4242
constructor() {
4343
_disableInitializers();
@@ -50,9 +50,7 @@ contract FGenesis is Initializable, AccessControlUpgradeable {
5050
_setParams(p);
5151
}
5252

53-
function setParams(
54-
Params calldata p
55-
) external onlyRole(ADMIN_ROLE) {
53+
function setParams(Params calldata p) external onlyRole(ADMIN_ROLE) {
5654
_setParams(p);
5755
}
5856

@@ -66,15 +64,13 @@ contract FGenesis is Initializable, AccessControlUpgradeable {
6664
);
6765

6866
require(
69-
p.reserve > 0 &&
70-
p.maxContribution > 0 &&
71-
p.feeAmt > 0 &&
72-
p.duration > 0,
67+
p.reserve > 0 && p.maxContribution > 0 && p.feeAmt > 0,
7368
"Invalid amt"
7469
);
7570

7671
require(
77-
p.agentTokenTotalSupply > 0 &&
72+
p.duration > 0 &&
73+
p.agentTokenTotalSupply > 0 &&
7874
p.agentTokenLpSupply > 0 &&
7975
p.agentTokenTotalSupply >= p.agentTokenLpSupply,
8076
"Invalid amt"
@@ -96,7 +92,6 @@ contract FGenesis is Initializable, AccessControlUpgradeable {
9692
);
9793

9894
gParams.endTime = gParams.startTime + params.duration;
99-
10095
genesisID++;
10196
address addr = GenesisLib.validateAndDeploy(
10297
genesisID,
@@ -114,10 +109,7 @@ contract FGenesis is Initializable, AccessControlUpgradeable {
114109
params.agentTokenLpSupply
115110
);
116111

117-
// Grant BONDING_ROLE of ato the new Genesis contract
118-
bytes32 BONDING_ROLE = AgentFactoryV3(params.agentFactory)
119-
.BONDING_ROLE();
120-
AgentFactoryV3(params.agentFactory).grantRole(
112+
IAccessControl(params.agentFactory).grantRole(
121113
BONDING_ROLE,
122114
address(addr)
123115
);
@@ -147,6 +139,22 @@ contract FGenesis is Initializable, AccessControlUpgradeable {
147139
);
148140
}
149141

142+
function onGenesisSuccessSalt(
143+
uint256 id,
144+
SuccessParams calldata p,
145+
bytes32 salt
146+
) external onlyRole(OPERATION_ROLE) returns (address) {
147+
return
148+
_getGenesis(id).onGenesisSuccessSalt(
149+
p.refundAddresses,
150+
p.refundAmounts,
151+
p.distributeAddresses,
152+
p.distributeAmounts,
153+
p.creator,
154+
salt
155+
);
156+
}
157+
150158
function onGenesisFailed(
151159
uint256 id,
152160
uint256[] calldata participantIndexes

contracts/genesis/Genesis.sol

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -246,18 +246,6 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable {
246246
"Exceeds maximum virtuals per contribution"
247247
);
248248

249-
// Add balance check
250-
require(
251-
IERC20(virtualTokenAddress).balanceOf(msg.sender) >= virtualsAmt,
252-
"Insufficient Virtual Token balance"
253-
);
254-
// Add allowance check
255-
require(
256-
IERC20(virtualTokenAddress).allowance(msg.sender, address(this)) >=
257-
virtualsAmt,
258-
"Insufficient Virtual Token allowance"
259-
);
260-
261249
// Update participant list
262250
if (mapAddrToVirtuals[msg.sender] == 0) {
263251
participants.push(msg.sender);
@@ -286,24 +274,57 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable {
286274
onlyRole(FACTORY_ROLE)
287275
nonReentrant
288276
whenNotCancelled
289-
whenNotFailed
290277
whenEnded
291278
returns (address)
292279
{
280+
return
281+
_onGenesisSuccessSalt(
282+
refundVirtualsTokenUserAddresses,
283+
refundVirtualsTokenUserAmounts,
284+
distributeAgentTokenUserAddresses,
285+
distributeAgentTokenUserAmounts,
286+
creator,
287+
keccak256(abi.encodePacked(msg.sender, block.timestamp))
288+
);
289+
}
290+
291+
function onGenesisSuccessSalt(
292+
address[] calldata refundVirtualsTokenUserAddresses,
293+
uint256[] calldata refundVirtualsTokenUserAmounts,
294+
address[] calldata distributeAgentTokenUserAddresses,
295+
uint256[] calldata distributeAgentTokenUserAmounts,
296+
address creator,
297+
bytes32 salt
298+
)
299+
external
300+
onlyRole(FACTORY_ROLE)
301+
nonReentrant
302+
whenNotCancelled
303+
whenEnded
304+
returns (address)
305+
{
306+
return _onGenesisSuccessSalt(
307+
refundVirtualsTokenUserAddresses,
308+
refundVirtualsTokenUserAmounts,
309+
distributeAgentTokenUserAddresses,
310+
distributeAgentTokenUserAmounts,
311+
creator,
312+
salt
313+
);
314+
}
315+
316+
function _onGenesisSuccessSalt(
317+
address[] calldata refundVirtualsTokenUserAddresses,
318+
uint256[] calldata refundVirtualsTokenUserAmounts,
319+
address[] calldata distributeAgentTokenUserAddresses,
320+
uint256[] calldata distributeAgentTokenUserAmounts,
321+
address creator,
322+
bytes32 salt
323+
) internal returns (address) {
293324
require(
294325
refundUserCountForFailed == 0,
295326
"OnGenesisFailed already called"
296327
);
297-
require(
298-
refundVirtualsTokenUserAddresses.length ==
299-
refundVirtualsTokenUserAmounts.length,
300-
"Mismatched refund arrays"
301-
);
302-
require(
303-
distributeAgentTokenUserAddresses.length ==
304-
distributeAgentTokenUserAmounts.length,
305-
"Mismatched distribution arrays"
306-
);
307328

308329
// Calculate total refund amount
309330
uint256 totalRefundAmount = 0;
@@ -319,16 +340,6 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable {
319340

320341
// Check if launch has been called before
321342
bool isFirstLaunch = agentTokenAddress == address(0);
322-
// Calculate required balance based on whether this is first launch
323-
uint256 requiredVirtualsBalance = isFirstLaunch
324-
? totalRefundAmount + reserveAmount
325-
: totalRefundAmount;
326-
// Check if contract has enough virtuals balance
327-
require(
328-
IERC20(virtualTokenAddress).balanceOf(address(this)) >=
329-
requiredVirtualsBalance,
330-
"Insufficient Virtual Token balance"
331-
);
332343

333344
// Only do launch related operations if this is first launch
334345
if (isFirstLaunch) {
@@ -353,11 +364,12 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable {
353364
);
354365

355366
address agentToken = IAgentFactoryV3(agentFactoryAddress)
356-
.executeBondingCurveApplication(
367+
.executeBondingCurveApplicationSalt(
357368
id,
358369
agentTokenTotalSupply,
359370
agentTokenLpSupply,
360-
address(this) // vault
371+
address(this), // vault
372+
salt
361373
);
362374

363375
require(agentToken != address(0), "Agent token creation failed");

0 commit comments

Comments
 (0)