← Contracts

Tests · MIT license

MockPons.sol

A pons stand-in matching the live contracts' observed behaviour, used by the tests.

Download .sol
1// SPDX-License-Identifier: MIT
2pragma 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 on
8/// Robinhood Chain mainnet (see script/simulate-pons.sh): a 1B token minted to its
9/// curve, a 1.68 ETH virtual quote reserve, a 1% fee taken from the input on buys and
10/// 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 external
123 payable
124 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}