Tests · MIT license
MockPons.sol
A pons stand-in matching the live contracts' observed behaviour, used by the tests.
1// SPDX-License-Identifier: MIT2pragma solidity ^0.8.28;3 4import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";5import {IPonsFactory} from "../../src/pons/IPons.sol";6 7/// Stand-ins for pons v2, matching what the live contracts were observed to do on8/// Robinhood Chain mainnet (see script/simulate-pons.sh): a 1B token minted to its9/// curve, a 1.68 ETH virtual quote reserve, a 1% fee taken from the input on buys and10/// from the output on sells, sells pulled with transferFrom, graduation at 4.2 ETH.11/// Used by the tests and by script/DeployLocalPons.s.sol for local UI work.12 13contract MockPonsToken is ERC20 {14 string public logo;15 string public description;16 IPonsFactory.Socials private _socials;17 18 constructor(IPonsFactory.TokenParams memory p, address curve) ERC20(p.name, p.symbol) {19 logo = p.logo;20 description = p.description;21 _socials = p.socials;22 _mint(curve, 1_000_000_000 ether);23 }24 25 function socials() external view returns (IPonsFactory.Socials memory) {26 return _socials;27 }28}29 30contract MockPonsCurve {31 event CurveBuy(address indexed buyer, address indexed recipient, uint256 quoteIn, uint256 tokensOut, uint256 fee, uint256 tax);32 event CurveSell(address indexed seller, address indexed recipient, uint256 tokensIn, uint256 quoteOut, uint256 fee, uint256 tax);33 34 MockPonsToken public token;35 uint256 public quoteReserve = 1.68 ether;36 uint256 public tokenReserve = 1_000_000_000 ether;37 uint256 public realQuoteReserve;38 uint256 public constant phantomQuote = 1.68 ether;39 uint256 public constant feeBps = 100;40 uint256 public constant graduationThreshold = 4.2 ether;41 uint256 public creatorTaxBps;42 /// Test knob: hand back this share of each buy (bps) to the caller, like a curve filling up.43 uint256 public refundBps;44 45 function init(MockPonsToken t, uint256 taxBps, uint256 refundBps_) external {46 token = t;47 creatorTaxBps = taxBps;48 refundBps = refundBps_;49 }50 51 function graduated() external view returns (bool) {52 return realQuoteReserve >= graduationThreshold;53 }54 55 function currentSnipeTaxBps(address) external pure returns (uint256) {56 return 0;57 }58 59 function buy(uint256 quoteIn, uint256 minTokensOut, address recipient) external payable returns (uint256 out) {60 require(msg.value == quoteIn, "value");61 uint256 refund = (quoteIn * refundBps) / 10_000;62 uint256 used = quoteIn - refund;63 uint256 fee = (used * feeBps) / 10_000;64 uint256 tax = (used * creatorTaxBps) / 10_000;65 uint256 net = used - fee - tax;66 out = (tokenReserve * net) / (quoteReserve + net);67 require(out >= minTokensOut, "slippage");68 quoteReserve += net;69 realQuoteReserve += net;70 tokenReserve -= out;71 token.transfer(recipient, out);72 emit CurveBuy(msg.sender, recipient, used, out, fee, tax);73 if (refund > 0) payable(msg.sender).transfer(refund);74 }75 76 function sell(uint256 tokensIn, uint256 minQuoteOut, address recipient) external returns (uint256 out) {77 token.transferFrom(msg.sender, address(this), tokensIn);78 uint256 gross = (quoteReserve * tokensIn) / (tokenReserve + tokensIn);79 uint256 fee = (gross * feeBps) / 10_000;80 uint256 tax = (gross * creatorTaxBps) / 10_000;81 out = gross - fee - tax;82 require(out >= minQuoteOut, "slippage");83 quoteReserve -= gross;84 realQuoteReserve -= gross;85 tokenReserve += tokensIn;86 emit CurveSell(msg.sender, recipient, tokensIn, out, fee, tax);87 payable(recipient).transfer(out);88 }89 90 receive() external payable {}91}92 93contract MockPonsFactory {94 uint256 public launchFee = 0.0005 ether;95 uint256 public constant maxCreatorTaxBps = 1000;96 bytes32 public constant ECON = keccak256("econ");97 IPonsFactory.TokenParams public last;98 address public lastLauncher;99 MockPonsCurve public lastCurve;100 address[] private _lastExemptions;101 mapping(bytes32 => bool) public saltUsed;102 /// Test knob: new curves refund this share of each buy.103 uint256 public nextRefundBps;104 105 function setNextRefundBps(uint256 bps) external {106 nextRefundBps = bps;107 }108 109 function lastExemptions() external view returns (address[] memory) {110 return _lastExemptions;111 }112 113 function canLaunch(address) external pure returns (bool) {114 return true;115 }116 117 function previewLaunchEconomics(uint256, address) external pure returns (bytes32) {118 return ECON;119 }120 121 function launchToken(IPonsFactory.TokenParams calldata p, uint256, address pairToken, address[] calldata exemptions)122 external123 payable124 returns (address token, address curve)125 {126 require(msg.value == launchFee, "fee");127 require(pairToken == address(0), "pair");128 require(p.expectedEconomics == ECON, "econ");129 require(p.creatorTaxBps <= maxCreatorTaxBps, "tax");130 bytes32 key = keccak256(abi.encode(msg.sender, p.salt));131 require(!saltUsed[key], "salt");132 saltUsed[key] = true;133 last = p;134 lastLauncher = msg.sender;135 _lastExemptions = exemptions;136 MockPonsCurve c = new MockPonsCurve();137 MockPonsToken t = new MockPonsToken(p, address(c));138 c.init(t, p.creatorTaxBps, nextRefundBps);139 lastCurve = c;140 return (address(t), address(c));141 }142}