Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
476 changes: 476 additions & 0 deletions .openzeppelin/base-sepolia.json

Large diffs are not rendered by default.

76 changes: 47 additions & 29 deletions contracts/fun/Bonding.sol
Original file line number Diff line number Diff line change
Expand Up @@ -193,24 +193,14 @@ contract Bonding is
string memory img,
string[4] memory urls,
uint256 purchaseAmount
) public nonReentrant returns (address, address, uint) {
return launchFor(_name, _ticker, cores, desc, img, urls, purchaseAmount, msg.sender);
}

function launchFor(
string memory _name,
string memory _ticker,
uint8[] memory cores,
string memory desc,
string memory img,
string[4] memory urls,
uint256 purchaseAmount,
address creator
) public nonReentrant returns (address, address, uint) {
require(
purchaseAmount > fee,
"Purchase amount must be greater than fee"
);

require(cores.length > 0, "Cores must be provided");

address assetToken = router.assetToken();
require(
IERC20(assetToken).balanceOf(msg.sender) >= purchaseAmount,
Expand All @@ -224,7 +214,9 @@ contract Bonding is
initialPurchase
);

FERC20 token = new FERC20(string.concat("fun ", _name), _ticker, initialSupply, maxTx);
FERC20 token = new FERC20{
salt: keccak256(abi.encodePacked(msg.sender, block.timestamp))
}(string.concat("fun ", _name), _ticker, initialSupply, maxTx);
uint256 supply = token.totalSupply();

address _pair = factory.createPair(address(token), assetToken);
Expand Down Expand Up @@ -252,7 +244,7 @@ contract Bonding is
lastUpdated: block.timestamp
});
Token memory tmpToken = Token({
creator: creator,
creator: msg.sender,
token: address(token),
agentToken: address(0),
pair: _pair,
Expand All @@ -270,17 +262,17 @@ contract Bonding is
tokenInfo[address(token)] = tmpToken;
tokenInfos.push(address(token));

bool exists = _checkIfProfileExists(creator);
bool exists = _checkIfProfileExists(msg.sender);

if (exists) {
Profile storage _profile = profile[creator];
Profile storage _profile = profile[msg.sender];

_profile.tokens.push(address(token));
} else {
bool created = _createUserProfile(creator);
bool created = _createUserProfile(msg.sender);

if (created) {
Profile storage _profile = profile[creator];
Profile storage _profile = profile[msg.sender];

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

// Make initial purchase
IERC20(assetToken).forceApprove(address(router), initialPurchase);
router.buy(initialPurchase, address(token), address(this));
_buy(
address(this),
initialPurchase,
address(token),
0,
block.timestamp + 300
);
token.transfer(msg.sender, token.balanceOf(address(this)));

return (address(token), _pair, n);
}

function sell(
uint256 amountIn,
address tokenAddress
address tokenAddress,
uint256 amountOutMin,
uint256 deadline
) public returns (bool) {
require(tokenInfo[tokenAddress].trading, "Token not trading");
require(block.timestamp <= deadline, "Deadline exceeded");

address pairAddress = factory.getPair(
tokenAddress,
Expand All @@ -318,6 +319,7 @@ contract Bonding is
tokenAddress,
msg.sender
);
require(amount1Out >= amountOutMin, "Slippage too high");

uint256 newReserveA = reserveA + amount0In;
uint256 newReserveB = reserveB - amount1Out;
Expand Down Expand Up @@ -351,12 +353,14 @@ contract Bonding is
return true;
}

function buy(
function _buy(
address buyer,
uint256 amountIn,
address tokenAddress
) public payable returns (bool) {
require(tokenInfo[tokenAddress].trading, "Token not trading");

address tokenAddress,
uint256 amountOutMin,
uint256 deadline
) internal {
require(block.timestamp <= deadline, "Deadline exceeded");
address pairAddress = factory.getPair(
tokenAddress,
router.assetToken()
Expand All @@ -369,9 +373,11 @@ contract Bonding is
(uint256 amount1In, uint256 amount0Out) = router.buy(
amountIn,
tokenAddress,
msg.sender
buyer
);

require(amount0Out >= amountOutMin, "Slippage too high");

uint256 newReserveA = reserveA - amount0Out;
uint256 newReserveB = reserveB + amount1In;
uint256 duration = block.timestamp -
Expand Down Expand Up @@ -404,6 +410,17 @@ contract Bonding is
if (newReserveA <= gradThreshold && tokenInfo[tokenAddress].trading) {
_openTradingOnUniswap(tokenAddress);
}
}

function buy(
uint256 amountIn,
address tokenAddress,
uint256 amountOutMin,
uint256 deadline
) public payable returns (bool) {
require(tokenInfo[tokenAddress].trading, "Token not trading");

_buy(msg.sender, amountIn, tokenAddress, amountOutMin, deadline);

return true;
}
Expand Down Expand Up @@ -448,11 +465,12 @@ contract Bonding is
);

address agentToken = IAgentFactoryV3(agentFactory)
.executeBondingCurveApplication(
.executeBondingCurveApplicationSalt(
id,
_token.data.supply / (10 ** token_.decimals()),
tokenBalance / (10 ** token_.decimals()),
pairAddress
pairAddress,
keccak256(abi.encodePacked(msg.sender, block.timestamp, tokenAddress))
);
_token.agentToken = agentToken;

Expand Down
1 change: 0 additions & 1 deletion contracts/fun/FERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ contract FERC20 is Context, IERC20, Ownable {
function _transfer(address from, address to, uint256 amount) private {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
require(amount > 0, "Transfer amount must be greater than zero");

if (!isExcludedFromMaxTx[from]) {
require(amount <= _maxTxAmount, "Exceeds MaxTx");
Expand Down
38 changes: 23 additions & 15 deletions contracts/genesis/FGenesis.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ import {Genesis} from "./Genesis.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../virtualPersona/AgentFactoryV3.sol";
import "./GenesisTypes.sol";
import "./GenesisLib.sol";
import "../virtualPersona/AgentFactoryV3.sol";

contract FGenesis is Initializable, AccessControlUpgradeable {
using GenesisLib for *;
Expand Down Expand Up @@ -38,6 +36,8 @@ contract FGenesis is Initializable, AccessControlUpgradeable {

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

bytes32 public constant BONDING_ROLE = keccak256("BONDING_ROLE");

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
Expand All @@ -50,9 +50,7 @@ contract FGenesis is Initializable, AccessControlUpgradeable {
_setParams(p);
}

function setParams(
Params calldata p
) external onlyRole(ADMIN_ROLE) {
function setParams(Params calldata p) external onlyRole(ADMIN_ROLE) {
_setParams(p);
}

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

require(
p.reserve > 0 &&
p.maxContribution > 0 &&
p.feeAmt > 0 &&
p.duration > 0,
p.reserve > 0 && p.maxContribution > 0 && p.feeAmt > 0,
"Invalid amt"
);

require(
p.agentTokenTotalSupply > 0 &&
p.duration > 0 &&
p.agentTokenTotalSupply > 0 &&
p.agentTokenLpSupply > 0 &&
p.agentTokenTotalSupply >= p.agentTokenLpSupply,
"Invalid amt"
Expand All @@ -96,7 +92,6 @@ contract FGenesis is Initializable, AccessControlUpgradeable {
);

gParams.endTime = gParams.startTime + params.duration;

genesisID++;
address addr = GenesisLib.validateAndDeploy(
genesisID,
Expand All @@ -114,10 +109,7 @@ contract FGenesis is Initializable, AccessControlUpgradeable {
params.agentTokenLpSupply
);

// Grant BONDING_ROLE of ato the new Genesis contract
bytes32 BONDING_ROLE = AgentFactoryV3(params.agentFactory)
.BONDING_ROLE();
AgentFactoryV3(params.agentFactory).grantRole(
IAccessControl(params.agentFactory).grantRole(
BONDING_ROLE,
address(addr)
);
Expand Down Expand Up @@ -147,6 +139,22 @@ contract FGenesis is Initializable, AccessControlUpgradeable {
);
}

function onGenesisSuccessSalt(
uint256 id,
SuccessParams calldata p,
bytes32 salt
) external onlyRole(OPERATION_ROLE) returns (address) {
return
_getGenesis(id).onGenesisSuccessSalt(
p.refundAddresses,
p.refundAmounts,
p.distributeAddresses,
p.distributeAmounts,
p.creator,
salt
);
}

function onGenesisFailed(
uint256 id,
uint256[] calldata participantIndexes
Expand Down
82 changes: 47 additions & 35 deletions contracts/genesis/Genesis.sol
Original file line number Diff line number Diff line change
Expand Up @@ -246,18 +246,6 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable {
"Exceeds maximum virtuals per contribution"
);

// Add balance check
require(
IERC20(virtualTokenAddress).balanceOf(msg.sender) >= virtualsAmt,
"Insufficient Virtual Token balance"
);
// Add allowance check
require(
IERC20(virtualTokenAddress).allowance(msg.sender, address(this)) >=
virtualsAmt,
"Insufficient Virtual Token allowance"
);

// Update participant list
if (mapAddrToVirtuals[msg.sender] == 0) {
participants.push(msg.sender);
Expand Down Expand Up @@ -286,24 +274,57 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable {
onlyRole(FACTORY_ROLE)
nonReentrant
whenNotCancelled
whenNotFailed
whenEnded
returns (address)
{
return
_onGenesisSuccessSalt(
refundVirtualsTokenUserAddresses,
refundVirtualsTokenUserAmounts,
distributeAgentTokenUserAddresses,
distributeAgentTokenUserAmounts,
creator,
keccak256(abi.encodePacked(msg.sender, block.timestamp))
);
}

function onGenesisSuccessSalt(
address[] calldata refundVirtualsTokenUserAddresses,
uint256[] calldata refundVirtualsTokenUserAmounts,
address[] calldata distributeAgentTokenUserAddresses,
uint256[] calldata distributeAgentTokenUserAmounts,
address creator,
bytes32 salt
)
external
onlyRole(FACTORY_ROLE)
nonReentrant
whenNotCancelled
whenEnded
returns (address)
{
return _onGenesisSuccessSalt(
refundVirtualsTokenUserAddresses,
refundVirtualsTokenUserAmounts,
distributeAgentTokenUserAddresses,
distributeAgentTokenUserAmounts,
creator,
salt
);
}

function _onGenesisSuccessSalt(
address[] calldata refundVirtualsTokenUserAddresses,
uint256[] calldata refundVirtualsTokenUserAmounts,
address[] calldata distributeAgentTokenUserAddresses,
uint256[] calldata distributeAgentTokenUserAmounts,
address creator,
bytes32 salt
) internal returns (address) {
require(
refundUserCountForFailed == 0,
"OnGenesisFailed already called"
);
require(
refundVirtualsTokenUserAddresses.length ==
refundVirtualsTokenUserAmounts.length,
"Mismatched refund arrays"
);
require(
distributeAgentTokenUserAddresses.length ==
distributeAgentTokenUserAmounts.length,
"Mismatched distribution arrays"
);

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

// Check if launch has been called before
bool isFirstLaunch = agentTokenAddress == address(0);
// Calculate required balance based on whether this is first launch
uint256 requiredVirtualsBalance = isFirstLaunch
? totalRefundAmount + reserveAmount
: totalRefundAmount;
// Check if contract has enough virtuals balance
require(
IERC20(virtualTokenAddress).balanceOf(address(this)) >=
requiredVirtualsBalance,
"Insufficient Virtual Token balance"
);

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

address agentToken = IAgentFactoryV3(agentFactoryAddress)
.executeBondingCurveApplication(
.executeBondingCurveApplicationSalt(
id,
agentTokenTotalSupply,
agentTokenLpSupply,
address(this) // vault
address(this), // vault
salt
);

require(agentToken != address(0), "Agent token creation failed");
Expand Down
Loading