Skip to content

Commit

Permalink
MOD: aime with swap in power contract
Browse files Browse the repository at this point in the history
  • Loading branch information
cctv2206 committed Mar 28, 2024
1 parent b13abc4 commit 6b41dc3
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 207 deletions.
27 changes: 11 additions & 16 deletions contracts/aime/AIMeFactoryV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,19 @@ contract AIMeFactoryV2 is Ownable {
) public payable {
require(msg.value >= protocolFee * 10, "Insufficient payment");
require(aimeAddresses[name_] == address(0), "AIME already exists");
// todo: pass in permit2 address
AIMeNFTV2 aime = new AIMeNFTV2(string(abi.encodePacked("AIME:", name_)), name_, avatar_, bio_, image_);
address payable aimeAddress = payable(address(aime));
address aimeAddress = address(aime);
aimeAddresses[name_] = aimeAddress;
aimeSigners[aimeAddress] = aimeSigner;
(bool success, ) = aimeAddress.call{value: msg.value}("");

address payable aimePower = payable(aime.aimePower());
(bool success, ) = aimePower.call{value: msg.value}("");
require(success, "Failed to send Ether");
emit AIMeCreated(msg.sender, address(aime));
}

function mintAIMeNFT(
address payable aimeAddress,
address aimeAddress,
string memory key,
string memory dataType,
string memory data,
Expand All @@ -101,7 +102,8 @@ contract AIMeFactoryV2 is Ownable {
AIMeNFTV2 aime = AIMeNFTV2(aimeAddress);
uint256 tokenId = aime.safeMint(msg.sender, key, dataType, data, image, amount);

(bool success, ) = aimeAddress.call{value: msg.value}("");
address payable aimePower = payable(aime.aimePower());
(bool success, ) = aimePower.call{value: msg.value}("");
require(success, "Failed to send Ether");

emit AIMeNFTMinted(
Expand All @@ -116,7 +118,7 @@ contract AIMeFactoryV2 is Ownable {
}

function updateAIMeNFT(
address payable aimeAddress,
address aimeAddress,
uint256 tokenId,
string memory data,
string memory image,
Expand All @@ -135,18 +137,11 @@ contract AIMeFactoryV2 is Ownable {
AIMeNFTV2 aime = AIMeNFTV2(aimeAddress);
aime.updateAIMeInfo(tokenId, msg.sender, data, image);

(bool success, ) = aimeAddress.call{value: msg.value}("");
address payable aimePower = payable(aime.aimePower());
(bool success, ) = aimePower.call{value: msg.value}("");
require(success, "Failed to send Ether");
emit AIMeNFTUpdated(msg.sender, aimeAddress, tokenId, data);
}

function withdrawFee() public onlyOwner {
uint amount = address(this).balance;
(bool success, ) = owner().call{value: amount}("");
require(success, "Failed to send Ether");
}

receive() external payable {
emit Received(msg.sender, msg.value);
}
receive() external payable {}
}
200 changes: 9 additions & 191 deletions contracts/aime/AIMeNFTV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,23 @@ import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./AIMePower.sol";
import "./AIMePowerV2.sol";

contract AIMeNFTV2 is ERC721, Ownable, ERC721Holder {
// The canonical permit2 contract.
IPermit2 public immutable PERMIT2;
AIMePower public immutable aimePower;
uint256 public constant AIME_POWER_TOTAL_AMOUNT = 1000000 * 1e18;
uint256 public constant AIME_POWER_SWAP_INIT_AMOUNT = 100000 * 1e18;
AIMePowerV2 public immutable aimePower;
uint256 public constant AIME_NFT_PRICE_FACTOR = 12;
uint256 public constant NFT_HOLDING_PERIOD = 30 days;
uint256 public aimePowerReserved;
uint256 public swapPowerBalance;
string public avatar;
address private _factory;
using Strings for uint256;
uint256 private _nextTokenId;
mapping(uint256 => AIMeInfo) public tokenContents;

error AIMeNFTUnauthorizedAccount(address account);
event Trade(
address trader,
bool isBuy,
uint256 powerAmount,
uint256 priceAfterFee,
uint256 fee,
uint256 supply
);

event TradeNFT(address from, address to, uint256 tokenId, uint256 price);

event Received(address sender, uint amount);

modifier onlyFactory() {
if (factory() != _msgSender()) {
revert AIMeNFTUnauthorizedAccount(_msgSender());
Expand All @@ -62,135 +47,20 @@ contract AIMeNFTV2 is ERC721, Ownable, ERC721Holder {
string memory bio_,
string memory image_
) ERC721(name_, symbol_) Ownable(msg.sender) {
// todo: pass in permit2 address
PERMIT2 = IPermit2(address(0x000000000022D473030F116dDEE9F6B43aC78BA3));
_factory = _msgSender();
aimePower = new AIMePower(name_, symbol_);
aimePower.mint(address(this), AIME_POWER_TOTAL_AMOUNT);

swapPowerBalance = AIME_POWER_SWAP_INIT_AMOUNT;
aimePowerReserved =
AIME_POWER_TOTAL_AMOUNT -
AIME_POWER_SWAP_INIT_AMOUNT;


aimePower = new AIMePowerV2(name_, symbol_);
aimePowerReserved = aimePower.balanceOf(address(this));
avatar = avatar_;

// mint initial nft
safeMint(address(this), "basic_prompt", "static", bio_, image_, 0);
}

function transferPowerFrom(
address from,
address to,
uint256 amount,
uint256 nonce,
uint256 deadline,
bytes calldata signature
) private {
PERMIT2.permitTransferFrom(
// The permit message.
IPermit2.PermitTransferFrom({
permitted: IPermit2.TokenPermissions({
token: aimePower,
amount: amount
}),
nonce: nonce,
deadline: deadline
}),
// The transfer recipient and amount.
IPermit2.SignatureTransferDetails({
to: to,
requestedAmount: amount
}),
// The owner of the tokens, which must also be
// the signer of the message, otherwise this call
// will fail.
from,
// The packed signature that was the result of signing
// the EIP712 hash of `permit`.
signature
);
}

function factory() public view virtual returns (address) {
return _factory;
}

function getAmountOut(
uint256 value,
bool _buy
) public view returns (uint256) {
uint256 ethBalance = address(this).balance;
if (_buy) {
return (swapPowerBalance * value) / (ethBalance + value);
} else {
return (ethBalance * value) / (swapPowerBalance + value);
}
}

function getAmountIn(
uint256 value,
bool _buy
) public view returns (uint256) {
uint256 ethBalance = address(this).balance;
if (_buy) {
return (ethBalance * value) / (swapPowerBalance - value);
} else {
return (swapPowerBalance * value) / (ethBalance - value);
}
}

function getBuyPrice(uint256 amount) public view returns (uint256) {
return getAmountIn(amount, true);
}

function getSellPrice(uint256 amount) public view returns (uint256) {
return getAmountOut(amount, false);
}

function buyPowers(uint256 amount) public payable {
require(amount < swapPowerBalance, "Insufficient power balance");
// eth amount
uint256 ethAmount = ((address(this).balance - msg.value) * amount) /
(swapPowerBalance - amount);
require(ethAmount > 0, "Amount too small");
require(msg.value == ethAmount, "Incorrect payment");

// transfer power to user
aimePower.transfer(msg.sender, amount);
swapPowerBalance -= amount;
emit Trade(msg.sender, true, amount, ethAmount, 0, 0);
}

function sellPowers(
uint256 amount,
uint256 nonce,
uint256 deadline,
bytes calldata signature
) public {
// eth amount
uint256 ethAmount = getAmountOut(amount, false);
require(ethAmount > 0, "Amount too small");
require(address(this).balance >= ethAmount, "Insufficient ETH balance");

// transfer power
transferPowerFrom(
msg.sender,
address(this),
amount,
nonce,
deadline,
signature
);
swapPowerBalance += amount;

// transfer eth to user
(bool success, ) = msg.sender.call{value: ethAmount}("");
require(success, "Unable to send funds");

emit Trade(msg.sender, false, amount, ethAmount, 0, 0);
}

function safeMint(
address to,
string memory key,
Expand Down Expand Up @@ -242,16 +112,12 @@ contract AIMeNFTV2 is ERC721, Ownable, ERC721Holder {
amount = tokenContents[tokenId].amount;
}

// AIMePower power = AIMePower(aimePowerAddress);
aimePower.transfer(msg.sender, amount);
emit TradeNFT(msg.sender, address(this), tokenId, amount);
}

function buyNFT(
uint256 tokenId,
uint256 nonce,
uint256 deadline,
bytes calldata signature
uint256 tokenId
) external {
require(tokenId != 0, "Cannot buy the first NFT");
address owner = _requireOwned(tokenId);
Expand All @@ -265,15 +131,9 @@ contract AIMeNFTV2 is ERC721, Ownable, ERC721Holder {
tokenContents[tokenId].currentAmount = amount;
}

// transfer power
transferPowerFrom(
msg.sender,
owner,
amount,
nonce,
deadline,
signature
);
require(aimePower.balanceOf(msg.sender) >= amount, "balance not enough");
require(aimePower.allowance(msg.sender, address(this)) >= amount, "allowance not enough");
aimePower.transferFrom(msg.sender, owner, amount);

_safeTransfer(owner, msg.sender, tokenId);
tokenContents[tokenId].timestamp = block.timestamp;
Expand Down Expand Up @@ -341,46 +201,4 @@ contract AIMeNFTV2 is ERC721, Ownable, ERC721Holder {

return output;
}

receive() external payable {
emit Received(msg.sender, msg.value);
}
}

// Minimal Permit2 interface, derived from
// https://github.com/Uniswap/permit2/blob/main/src/interfaces/ISignatureTransfer.sol
interface IPermit2 {
// Token and amount in a permit message.
struct TokenPermissions {
// Token to transfer.
IERC20 token;
// Amount to transfer.
uint256 amount;
}

// The permit2 message.
struct PermitTransferFrom {
// Permitted token and amount.
TokenPermissions permitted;
// Unique identifier for this permit.
uint256 nonce;
// Expiration for this permit.
uint256 deadline;
}

// Transfer details for permitTransferFrom().
struct SignatureTransferDetails {
// Recipient of tokens.
address to;
// Amount to transfer.
uint256 requestedAmount;
}

// Consume a permit2 message and transfer tokens.
function permitTransferFrom(
PermitTransferFrom calldata permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external;
}
Loading

0 comments on commit 6b41dc3

Please sign in to comment.