22
33pragma solidity ^ 0.8.27 ;
44
5- import { IAuthority } from "@openzeppelin/contracts/access/manager/IAuthority.sol " ;
6- import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol " ;
7- import { IERC20Metadata } from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol " ;
8- import { ERC2771Context } from "@openzeppelin/contracts/metatx/ERC2771Context.sol " ;
9- import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol " ;
10- import { Hashes } from "@openzeppelin/contracts/utils/cryptography/Hashes.sol " ;
11- import { Math } from "@openzeppelin/contracts/utils/math/Math.sol " ;
12- import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol " ;
13- import { SignedMath } from "@openzeppelin/contracts/utils/math/SignedMath.sol " ;
14- import { Context } from "@openzeppelin/contracts/utils/Context.sol " ;
15- import { Multicall } from "@openzeppelin/contracts/utils/Multicall.sol " ;
16- import { Oracle } from "../oracle/Oracle.sol " ;
5+ import { IAuthority } from "@openzeppelin/contracts/access/manager/IAuthority.sol " ;
6+ import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol " ;
7+ import { IERC20Metadata } from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol " ;
8+ import { ERC2771Context } from "@openzeppelin/contracts/metatx/ERC2771Context.sol " ;
9+ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol " ;
10+ import { Hashes } from "@openzeppelin/contracts/utils/cryptography/Hashes.sol " ;
11+ import { Math } from "@openzeppelin/contracts/utils/math/Math.sol " ;
12+ import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol " ;
13+ import { SignedMath } from "@openzeppelin/contracts/utils/math/SignedMath.sol " ;
14+ import { Context } from "@openzeppelin/contracts/utils/Context.sol " ;
15+ import { Multicall } from "@openzeppelin/contracts/utils/Multicall.sol " ;
16+ import { Oracle } from "../oracle/Oracle.sol " ;
1717import { PermissionManaged } from "../permissions/PermissionManaged.sol " ;
1818
19- contract MultiATM is ERC2771Context , PermissionManaged , Multicall {
20- using Math for * ;
19+ contract MultiATM is ERC2771Context , PermissionManaged , Multicall
20+ {
21+ using Math for * ;
2122 using SafeCast for * ;
2223
2324 uint256 private constant _BASIS_POINT_SCALE = 1e4 ;
@@ -53,21 +54,8 @@ contract MultiATM is ERC2771Context, PermissionManaged, Multicall {
5354 mapping (bytes32 id = > Pair) private _pairs;
5455 uint256 public feeBasisPoints;
5556
56- event SwapExact (
57- IERC20 indexed input ,
58- IERC20 indexed output ,
59- uint256 inputAmount ,
60- uint256 outputAmount ,
61- address from ,
62- address to
63- );
64- event PairUpdated (
65- bytes32 indexed id ,
66- IERC20 indexed token1 ,
67- IERC20 indexed token2 ,
68- Oracle oracle ,
69- uint256 oracleTTL
70- );
57+ event SwapExact (IERC20 indexed input , IERC20 indexed output , uint256 inputAmount , uint256 outputAmount , address from , address to );
58+ event PairUpdated (bytes32 indexed id , IERC20 indexed token1 , IERC20 indexed token2 , Oracle oracle , uint256 oracleTTL );
7159 event PairRemoved (bytes32 indexed id );
7260 event FeeUpdated (uint256 newFeeBasisPoints );
7361 error OutputAmountTooLow (uint256 outputAmount , uint256 minOutputAmount );
@@ -77,207 +65,153 @@ contract MultiATM is ERC2771Context, PermissionManaged, Multicall {
7765 error InvalidFee (uint256 feeBasisPoints );
7866
7967 /// @custom:oz-upgrades-unsafe-allow constructor
80- constructor (
81- IAuthority _authority ,
82- address _trustedForwarder
83- ) PermissionManaged (_authority) ERC2771Context (_trustedForwarder) {}
68+ constructor (IAuthority _authority , address _trustedForwarder )
69+ PermissionManaged ( _authority)
70+ ERC2771Context ( _trustedForwarder)
71+ {}
8472
8573 /****************************************************************************************************************
8674 * Getters *
8775 ****************************************************************************************************************/
88- function viewPairDetails (
89- IERC20 input ,
90- IERC20 output
91- )
92- public
93- view
94- virtual
95- returns (
96- bytes32 id ,
97- IERC20 token1 ,
98- IERC20 token2 ,
99- Oracle oracle ,
100- uint256 oracleTTL ,
101- uint256 numerator ,
102- uint256 denominator
103- )
104- {
76+ function viewPairDetails (IERC20 input , IERC20 output ) public view virtual returns (
77+ bytes32 id ,
78+ IERC20 token1 ,
79+ IERC20 token2 ,
80+ Oracle oracle ,
81+ uint256 oracleTTL ,
82+ uint256 numerator ,
83+ uint256 denominator
84+ ) {
10585 id = hashPair (input, output);
10686 Pair storage pair = _pairs[id];
10787
108- return (id, pair.token1, pair.token2, pair.oracle, pair.oracleTTL, pair.numerator, pair.denominator);
88+ return (
89+ id,
90+ pair.token1,
91+ pair.token2,
92+ pair.oracle,
93+ pair.oracleTTL,
94+ pair.numerator,
95+ pair.denominator
96+ );
10997 }
11098
11199 function hashPair (IERC20 input , IERC20 output ) public view virtual returns (bytes32 ) {
112- return
113- Hashes.commutativeKeccak256 (
114- bytes32 (uint256 (uint160 (address (input)))),
115- bytes32 (uint256 (uint160 (address (output))))
116- );
100+ return Hashes.commutativeKeccak256 (
101+ bytes32 (uint256 (uint160 (address (input)))),
102+ bytes32 (uint256 (uint160 (address (output))))
103+ );
117104 }
118105
119106 /****************************************************************************************************************
120107 * Core - preview swaps *
121108 ****************************************************************************************************************/
122- function previewExactInput (
123- IERC20 [] memory path ,
124- uint256 inputAmount
125- ) public view virtual returns (uint256 /*outputAmount*/ ) {
109+ function previewExactInput (IERC20 [] memory path , uint256 inputAmount ) public view virtual returns (uint256 /*outputAmount*/ ) {
126110 uint256 outputAmount = inputAmount;
127111 for (uint256 i = 0 ; i < path.length - 1 ; ++ i) {
128- outputAmount = _exactInput (path[i], path[i + 1 ], outputAmount);
112+ outputAmount = _exactInput (path[i], path[i+ 1 ], outputAmount);
129113 }
130114 return outputAmount.mulDiv (_BASIS_POINT_SCALE - feeBasisPoints, _BASIS_POINT_SCALE, Math.Rounding.Floor);
131115 }
132116
133- function previewExactOutput (
134- IERC20 [] memory path ,
135- uint256 outputAmount
136- ) public view virtual returns (uint256 /*inputAmount*/ ) {
117+ function previewExactOutput (IERC20 [] memory path , uint256 outputAmount ) public view virtual returns (uint256 /*inputAmount*/ ) {
137118 uint256 inputAmount = outputAmount;
138119 for (uint256 i = path.length - 1 ; i > 0 ; -- i) {
139- inputAmount = _exactOutput (path[i - 1 ], path[i], inputAmount);
120+ inputAmount = _exactOutput (path[i- 1 ], path[i], inputAmount);
140121 }
141122 return inputAmount.mulDiv (_BASIS_POINT_SCALE, _BASIS_POINT_SCALE - feeBasisPoints, Math.Rounding.Ceil);
142123 }
143124
144- function previewExactInputSingle (
145- IERC20 input ,
146- IERC20 output ,
147- uint256 inputAmount
148- ) public view virtual returns (uint256 /*outputAmount*/ ) {
149- return
150- _exactInput (input, output, inputAmount).mulDiv (
151- _BASIS_POINT_SCALE - feeBasisPoints,
152- _BASIS_POINT_SCALE,
153- Math.Rounding.Floor
154- );
125+ function previewExactInputSingle (IERC20 input , IERC20 output , uint256 inputAmount ) public view virtual returns (uint256 /*outputAmount*/ ) {
126+ return _exactInput (input, output, inputAmount).mulDiv (_BASIS_POINT_SCALE - feeBasisPoints, _BASIS_POINT_SCALE, Math.Rounding.Floor);
155127 }
156128
157- function previewExactOutputSingle (
158- IERC20 input ,
159- IERC20 output ,
160- uint256 outputAmount
161- ) public view virtual returns (uint256 /*inputAmount*/ ) {
162- return
163- _exactOutput (input, output, outputAmount).mulDiv (
164- _BASIS_POINT_SCALE,
165- _BASIS_POINT_SCALE - feeBasisPoints,
166- Math.Rounding.Ceil
167- );
129+ function previewExactOutputSingle (IERC20 input , IERC20 output , uint256 outputAmount ) public view virtual returns (uint256 /*inputAmount*/ ) {
130+ return _exactOutput (input, output, outputAmount).mulDiv (_BASIS_POINT_SCALE, _BASIS_POINT_SCALE - feeBasisPoints, Math.Rounding.Ceil);
168131 }
169132
170- function _exactInput (
171- IERC20 input ,
172- IERC20 output ,
173- uint256 inputAmount
174- ) internal view virtual returns (uint256 /*outputAmount*/ ) {
175- (, IERC20 token1 , , Oracle oracle , uint256 oracleTTL , uint256 numerator , uint256 denominator ) = viewPairDetails (
176- input,
177- output
178- );
133+ function _exactInput (IERC20 input , IERC20 output , uint256 inputAmount ) internal view virtual returns (uint256 /*outputAmount*/ ) {
134+ (
135+ ,
136+ IERC20 token1 ,
137+ ,
138+ Oracle oracle ,
139+ uint256 oracleTTL ,
140+ uint256 numerator ,
141+ uint256 denominator
142+ ) = viewPairDetails (input, output);
179143
180144 require (address (oracle) != address (0 ), UnknownPair (input, output));
181145
182146 (int256 minPrice , int256 maxPrice ) = _getPrices (oracle, oracleTTL);
183- return
184- inputAmount.mulDiv (
185- Math.ternary (input == token1, numerator * minPrice.toUint256 (), denominator),
186- Math.ternary (input == token1, denominator, numerator * maxPrice.toUint256 ()),
187- Math.Rounding.Floor
188- );
147+ return inputAmount.mulDiv (
148+ Math.ternary (input == token1, numerator * minPrice.toUint256 (), denominator),
149+ Math.ternary (input == token1, denominator, numerator * maxPrice.toUint256 ()),
150+ Math.Rounding.Floor
151+ );
189152 }
190153
191- function _exactOutput (
192- IERC20 input ,
193- IERC20 output ,
194- uint256 outputAmount
195- ) internal view virtual returns (uint256 /*inputAmount*/ ) {
196- (, IERC20 token1 , , Oracle oracle , uint256 oracleTTL , uint256 numerator , uint256 denominator ) = viewPairDetails (
197- input,
198- output
199- );
154+ function _exactOutput (IERC20 input , IERC20 output , uint256 outputAmount ) internal view virtual returns (uint256 /*inputAmount*/ ) {
155+ (
156+ ,
157+ IERC20 token1 ,
158+ ,
159+ Oracle oracle ,
160+ uint256 oracleTTL ,
161+ uint256 numerator ,
162+ uint256 denominator
163+ ) = viewPairDetails (input, output);
200164
201165 require (address (oracle) != address (0 ), UnknownPair (input, output));
202166
203167 (int256 minPrice , int256 maxPrice ) = _getPrices (oracle, oracleTTL);
204- return
205- outputAmount.mulDiv (
206- Math.ternary (input == token1, denominator, numerator * maxPrice.toUint256 ()),
207- Math.ternary (input == token1, numerator * minPrice.toUint256 (), denominator),
208- Math.Rounding.Ceil
209- );
168+ return outputAmount.mulDiv (
169+ Math.ternary (input == token1, denominator, numerator * maxPrice.toUint256 ()),
170+ Math.ternary (input == token1, numerator * minPrice.toUint256 (), denominator),
171+ Math.Rounding.Ceil
172+ );
210173 }
211174
212175 /****************************************************************************************************************
213176 * Core - execute swaps *
214177 ****************************************************************************************************************/
215- function swapExactInput (
216- IERC20 [] memory path ,
217- uint256 inputAmount ,
218- address recipient ,
219- uint256 minOutputAmount
220- ) public virtual restricted returns (uint256 /*outputAmount*/ ) {
178+ function swapExactInput (IERC20 [] memory path , uint256 inputAmount , address recipient , uint256 minOutputAmount ) public virtual restricted () returns (uint256 /*outputAmount*/ ) {
221179 uint256 outputAmount = previewExactInput (path, inputAmount);
222180 require (outputAmount >= minOutputAmount, OutputAmountTooLow (outputAmount, minOutputAmount));
223181 _swapExact (path[0 ], path[path.length - 1 ], inputAmount, outputAmount, _msgSender (), recipient);
224182 return outputAmount;
225183 }
226184
227- function swapExactInputSingle (
228- IERC20 input ,
229- IERC20 output ,
230- uint256 inputAmount ,
231- address recipient ,
232- uint256 minOutputAmount
233- ) public virtual restricted returns (uint256 /*outputAmount*/ ) {
185+ function swapExactInputSingle (IERC20 input , IERC20 output , uint256 inputAmount , address recipient , uint256 minOutputAmount ) public virtual restricted () returns (uint256 /*outputAmount*/ ) {
234186 uint256 outputAmount = previewExactInputSingle (input, output, inputAmount);
235187 require (outputAmount >= minOutputAmount, OutputAmountTooLow (outputAmount, minOutputAmount));
236188 _swapExact (input, output, inputAmount, outputAmount, _msgSender (), recipient);
237189 return outputAmount;
238190 }
239191
240- function swapExactOutput (
241- IERC20 [] memory path ,
242- uint256 outputAmount ,
243- address recipient ,
244- uint256 maxInputAmount
245- ) public virtual restricted returns (uint256 /*inputAmount*/ ) {
192+ function swapExactOutput (IERC20 [] memory path , uint256 outputAmount , address recipient , uint256 maxInputAmount ) public virtual restricted () returns (uint256 /*inputAmount*/ ) {
246193 uint256 inputAmount = previewExactOutput (path, outputAmount);
247194 require (inputAmount <= maxInputAmount, InputAmountTooHigh (inputAmount, maxInputAmount));
248195 _swapExact (path[0 ], path[path.length - 1 ], inputAmount, outputAmount, _msgSender (), recipient);
249196 return inputAmount;
250197 }
251198
252- function swapExactOutputSingle (
253- IERC20 input ,
254- IERC20 output ,
255- uint256 outputAmount ,
256- address recipient ,
257- uint256 maxInputAmount
258- ) public virtual restricted returns (uint256 /*inputAmount*/ ) {
199+ function swapExactOutputSingle (IERC20 input , IERC20 output , uint256 outputAmount , address recipient , uint256 maxInputAmount ) public virtual restricted () returns (uint256 /*inputAmount*/ ) {
259200 uint256 inputAmount = previewExactOutputSingle (input, output, outputAmount);
260201 require (inputAmount <= maxInputAmount, InputAmountTooHigh (inputAmount, maxInputAmount));
261202 _swapExact (input, output, inputAmount, outputAmount, _msgSender (), recipient);
262203 return inputAmount;
263204 }
264205
265- function _swapExact (
266- IERC20 input ,
267- IERC20 output ,
268- uint256 inputAmount ,
269- uint256 outputAmount ,
270- address from ,
271- address to
272- ) private {
206+ function _swapExact (IERC20 input , IERC20 output , uint256 inputAmount , uint256 outputAmount , address from , address to ) private {
273207 SafeERC20.safeTransferFrom (input, from, address (this ), inputAmount);
274208 SafeERC20.safeTransfer (output, to, outputAmount);
275209 emit SwapExact (input, output, inputAmount, outputAmount, from, to);
276210 }
277211
278212 function _getPrices (Oracle oracle , uint256 oracleTTL ) internal view virtual returns (int256 min , int256 max ) {
279- (uint80 roundId , int256 latest , , , ) = oracle.latestRoundData ();
280- (, int256 previous , , uint256 updatedAt , ) = oracle.getRoundData (roundId - 1 );
213+ (uint80 roundId , int256 latest ,,, ) = oracle.latestRoundData ();
214+ (, int256 previous ,, uint256 updatedAt ,) = oracle.getRoundData (roundId - 1 );
281215 require (block .timestamp < updatedAt + oracleTTL, OracleValueTooOld (oracle));
282216 min = SignedMath.min (latest, previous);
283217 max = SignedMath.max (latest, previous);
@@ -286,12 +220,7 @@ contract MultiATM is ERC2771Context, PermissionManaged, Multicall {
286220 /****************************************************************************************************************
287221 * Admin actions *
288222 ****************************************************************************************************************/
289- function setPair (
290- IERC20Metadata token1 ,
291- IERC20Metadata token2 ,
292- Oracle oracle ,
293- uint256 oracleTTL
294- ) public virtual restricted {
223+ function setPair (IERC20Metadata token1 , IERC20Metadata token2 , Oracle oracle , uint256 oracleTTL ) public virtual restricted () {
295224 bytes32 id = hashPair (token1, token2);
296225 _pairs[id] = Pair ({
297226 token1: token1,
@@ -305,21 +234,27 @@ contract MultiATM is ERC2771Context, PermissionManaged, Multicall {
305234 emit PairUpdated (id, token1, token2, oracle, oracleTTL);
306235 }
307236
308- function removePair (IERC20 token1 , IERC20 token2 ) public virtual restricted {
237+ function removePair (IERC20 token1 , IERC20 token2 ) public virtual restricted () {
309238 bytes32 id = hashPair (token1, token2);
310239 delete _pairs[id];
311240
312241 emit PairRemoved (id);
313242 }
314243
315- function setFee (uint256 newFeeBasisPoints ) public virtual restricted {
244+ function setFee (uint256 newFeeBasisPoints ) public virtual restricted () {
316245 require (newFeeBasisPoints <= 50 , InvalidFee (newFeeBasisPoints)); // Max 0.5%
317246 feeBasisPoints = newFeeBasisPoints;
318247 emit FeeUpdated (newFeeBasisPoints);
319248 }
320249
321- function withdraw (IERC20 _token , address _to , uint256 _amount ) public virtual restricted {
322- SafeERC20.safeTransfer (_token, _to, _amount == type (uint256 ).max ? _token.balanceOf (address (this )) : _amount);
250+ function withdraw (IERC20 _token , address _to , uint256 _amount ) public virtual restricted () {
251+ SafeERC20.safeTransfer (
252+ _token,
253+ _to,
254+ _amount == type (uint256 ).max
255+ ? _token.balanceOf (address (this ))
256+ : _amount
257+ );
323258 }
324259
325260 /****************************************************************************************************************
@@ -336,4 +271,4 @@ contract MultiATM is ERC2771Context, PermissionManaged, Multicall {
336271 function _contextSuffixLength () internal view override (Context, ERC2771Context ) returns (uint256 ) {
337272 return super ._contextSuffixLength ();
338273 }
339- }
274+ }
0 commit comments