├── .gitignore
├── LICENSE
├── README.md
├── foundry.toml
├── lib
└── forge-std
│ ├── LICENSE-APACHE
│ ├── LICENSE-MIT
│ ├── README.md
│ └── src
│ ├── Script.sol
│ ├── Test.sol
│ ├── Vm.sol
│ ├── console.sol
│ ├── console2.sol
│ └── test
│ ├── StdAssertions.t.sol
│ ├── StdCheats.t.sol
│ ├── StdError.t.sol
│ ├── StdMath.t.sol
│ └── StdStorage.t.sol
├── src
├── ArbitrageContract.sol
└── interfaces
│ ├── IERC20.sol
│ └── ISushi.sol
└── test
├── ArbitrageContract.t.sol
└── util
└── ERC20.sol
/.gitignore:
--------------------------------------------------------------------------------
1 | /out
2 | /cache
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU AFFERO GENERAL PUBLIC LICENSE
2 | Version 3, 19 November 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU Affero General Public License is a free, copyleft license for
11 | software and other kinds of works, specifically designed to ensure
12 | cooperation with the community in the case of network server software.
13 |
14 | The licenses for most software and other practical works are designed
15 | to take away your freedom to share and change the works. By contrast,
16 | our General Public Licenses are intended to guarantee your freedom to
17 | share and change all versions of a program--to make sure it remains free
18 | software for all its users.
19 |
20 | When we speak of free software, we are referring to freedom, not
21 | price. Our General Public Licenses are designed to make sure that you
22 | have the freedom to distribute copies of free software (and charge for
23 | them if you wish), that you receive source code or can get it if you
24 | want it, that you can change the software or use pieces of it in new
25 | free programs, and that you know you can do these things.
26 |
27 | Developers that use our General Public Licenses protect your rights
28 | with two steps: (1) assert copyright on the software, and (2) offer
29 | you this License which gives you legal permission to copy, distribute
30 | and/or modify the software.
31 |
32 | A secondary benefit of defending all users' freedom is that
33 | improvements made in alternate versions of the program, if they
34 | receive widespread use, become available for other developers to
35 | incorporate. Many developers of free software are heartened and
36 | encouraged by the resulting cooperation. However, in the case of
37 | software used on network servers, this result may fail to come about.
38 | The GNU General Public License permits making a modified version and
39 | letting the public access it on a server without ever releasing its
40 | source code to the public.
41 |
42 | The GNU Affero General Public License is designed specifically to
43 | ensure that, in such cases, the modified source code becomes available
44 | to the community. It requires the operator of a network server to
45 | provide the source code of the modified version running there to the
46 | users of that server. Therefore, public use of a modified version, on
47 | a publicly accessible server, gives the public access to the source
48 | code of the modified version.
49 |
50 | An older license, called the Affero General Public License and
51 | published by Affero, was designed to accomplish similar goals. This is
52 | a different license, not a version of the Affero GPL, but Affero has
53 | released a new version of the Affero GPL which permits relicensing under
54 | this license.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | TERMS AND CONDITIONS
60 |
61 | 0. Definitions.
62 |
63 | "This License" refers to version 3 of the GNU Affero General Public License.
64 |
65 | "Copyright" also means copyright-like laws that apply to other kinds of
66 | works, such as semiconductor masks.
67 |
68 | "The Program" refers to any copyrightable work licensed under this
69 | License. Each licensee is addressed as "you". "Licensees" and
70 | "recipients" may be individuals or organizations.
71 |
72 | To "modify" a work means to copy from or adapt all or part of the work
73 | in a fashion requiring copyright permission, other than the making of an
74 | exact copy. The resulting work is called a "modified version" of the
75 | earlier work or a work "based on" the earlier work.
76 |
77 | A "covered work" means either the unmodified Program or a work based
78 | on the Program.
79 |
80 | To "propagate" a work means to do anything with it that, without
81 | permission, would make you directly or secondarily liable for
82 | infringement under applicable copyright law, except executing it on a
83 | computer or modifying a private copy. Propagation includes copying,
84 | distribution (with or without modification), making available to the
85 | public, and in some countries other activities as well.
86 |
87 | To "convey" a work means any kind of propagation that enables other
88 | parties to make or receive copies. Mere interaction with a user through
89 | a computer network, with no transfer of a copy, is not conveying.
90 |
91 | An interactive user interface displays "Appropriate Legal Notices"
92 | to the extent that it includes a convenient and prominently visible
93 | feature that (1) displays an appropriate copyright notice, and (2)
94 | tells the user that there is no warranty for the work (except to the
95 | extent that warranties are provided), that licensees may convey the
96 | work under this License, and how to view a copy of this License. If
97 | the interface presents a list of user commands or options, such as a
98 | menu, a prominent item in the list meets this criterion.
99 |
100 | 1. Source Code.
101 |
102 | The "source code" for a work means the preferred form of the work
103 | for making modifications to it. "Object code" means any non-source
104 | form of a work.
105 |
106 | A "Standard Interface" means an interface that either is an official
107 | standard defined by a recognized standards body, or, in the case of
108 | interfaces specified for a particular programming language, one that
109 | is widely used among developers working in that language.
110 |
111 | The "System Libraries" of an executable work include anything, other
112 | than the work as a whole, that (a) is included in the normal form of
113 | packaging a Major Component, but which is not part of that Major
114 | Component, and (b) serves only to enable use of the work with that
115 | Major Component, or to implement a Standard Interface for which an
116 | implementation is available to the public in source code form. A
117 | "Major Component", in this context, means a major essential component
118 | (kernel, window system, and so on) of the specific operating system
119 | (if any) on which the executable work runs, or a compiler used to
120 | produce the work, or an object code interpreter used to run it.
121 |
122 | The "Corresponding Source" for a work in object code form means all
123 | the source code needed to generate, install, and (for an executable
124 | work) run the object code and to modify the work, including scripts to
125 | control those activities. However, it does not include the work's
126 | System Libraries, or general-purpose tools or generally available free
127 | programs which are used unmodified in performing those activities but
128 | which are not part of the work. For example, Corresponding Source
129 | includes interface definition files associated with source files for
130 | the work, and the source code for shared libraries and dynamically
131 | linked subprograms that the work is specifically designed to require,
132 | such as by intimate data communication or control flow between those
133 | subprograms and other parts of the work.
134 |
135 | The Corresponding Source need not include anything that users
136 | can regenerate automatically from other parts of the Corresponding
137 | Source.
138 |
139 | The Corresponding Source for a work in source code form is that
140 | same work.
141 |
142 | 2. Basic Permissions.
143 |
144 | All rights granted under this License are granted for the term of
145 | copyright on the Program, and are irrevocable provided the stated
146 | conditions are met. This License explicitly affirms your unlimited
147 | permission to run the unmodified Program. The output from running a
148 | covered work is covered by this License only if the output, given its
149 | content, constitutes a covered work. This License acknowledges your
150 | rights of fair use or other equivalent, as provided by copyright law.
151 |
152 | You may make, run and propagate covered works that you do not
153 | convey, without conditions so long as your license otherwise remains
154 | in force. You may convey covered works to others for the sole purpose
155 | of having them make modifications exclusively for you, or provide you
156 | with facilities for running those works, provided that you comply with
157 | the terms of this License in conveying all material for which you do
158 | not control copyright. Those thus making or running the covered works
159 | for you must do so exclusively on your behalf, under your direction
160 | and control, on terms that prohibit them from making any copies of
161 | your copyrighted material outside their relationship with you.
162 |
163 | Conveying under any other circumstances is permitted solely under
164 | the conditions stated below. Sublicensing is not allowed; section 10
165 | makes it unnecessary.
166 |
167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
168 |
169 | No covered work shall be deemed part of an effective technological
170 | measure under any applicable law fulfilling obligations under article
171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
172 | similar laws prohibiting or restricting circumvention of such
173 | measures.
174 |
175 | When you convey a covered work, you waive any legal power to forbid
176 | circumvention of technological measures to the extent such circumvention
177 | is effected by exercising rights under this License with respect to
178 | the covered work, and you disclaim any intention to limit operation or
179 | modification of the work as a means of enforcing, against the work's
180 | users, your or third parties' legal rights to forbid circumvention of
181 | technological measures.
182 |
183 | 4. Conveying Verbatim Copies.
184 |
185 | You may convey verbatim copies of the Program's source code as you
186 | receive it, in any medium, provided that you conspicuously and
187 | appropriately publish on each copy an appropriate copyright notice;
188 | keep intact all notices stating that this License and any
189 | non-permissive terms added in accord with section 7 apply to the code;
190 | keep intact all notices of the absence of any warranty; and give all
191 | recipients a copy of this License along with the Program.
192 |
193 | You may charge any price or no price for each copy that you convey,
194 | and you may offer support or warranty protection for a fee.
195 |
196 | 5. Conveying Modified Source Versions.
197 |
198 | You may convey a work based on the Program, or the modifications to
199 | produce it from the Program, in the form of source code under the
200 | terms of section 4, provided that you also meet all of these conditions:
201 |
202 | a) The work must carry prominent notices stating that you modified
203 | it, and giving a relevant date.
204 |
205 | b) The work must carry prominent notices stating that it is
206 | released under this License and any conditions added under section
207 | 7. This requirement modifies the requirement in section 4 to
208 | "keep intact all notices".
209 |
210 | c) You must license the entire work, as a whole, under this
211 | License to anyone who comes into possession of a copy. This
212 | License will therefore apply, along with any applicable section 7
213 | additional terms, to the whole of the work, and all its parts,
214 | regardless of how they are packaged. This License gives no
215 | permission to license the work in any other way, but it does not
216 | invalidate such permission if you have separately received it.
217 |
218 | d) If the work has interactive user interfaces, each must display
219 | Appropriate Legal Notices; however, if the Program has interactive
220 | interfaces that do not display Appropriate Legal Notices, your
221 | work need not make them do so.
222 |
223 | A compilation of a covered work with other separate and independent
224 | works, which are not by their nature extensions of the covered work,
225 | and which are not combined with it such as to form a larger program,
226 | in or on a volume of a storage or distribution medium, is called an
227 | "aggregate" if the compilation and its resulting copyright are not
228 | used to limit the access or legal rights of the compilation's users
229 | beyond what the individual works permit. Inclusion of a covered work
230 | in an aggregate does not cause this License to apply to the other
231 | parts of the aggregate.
232 |
233 | 6. Conveying Non-Source Forms.
234 |
235 | You may convey a covered work in object code form under the terms
236 | of sections 4 and 5, provided that you also convey the
237 | machine-readable Corresponding Source under the terms of this License,
238 | in one of these ways:
239 |
240 | a) Convey the object code in, or embodied in, a physical product
241 | (including a physical distribution medium), accompanied by the
242 | Corresponding Source fixed on a durable physical medium
243 | customarily used for software interchange.
244 |
245 | b) Convey the object code in, or embodied in, a physical product
246 | (including a physical distribution medium), accompanied by a
247 | written offer, valid for at least three years and valid for as
248 | long as you offer spare parts or customer support for that product
249 | model, to give anyone who possesses the object code either (1) a
250 | copy of the Corresponding Source for all the software in the
251 | product that is covered by this License, on a durable physical
252 | medium customarily used for software interchange, for a price no
253 | more than your reasonable cost of physically performing this
254 | conveying of source, or (2) access to copy the
255 | Corresponding Source from a network server at no charge.
256 |
257 | c) Convey individual copies of the object code with a copy of the
258 | written offer to provide the Corresponding Source. This
259 | alternative is allowed only occasionally and noncommercially, and
260 | only if you received the object code with such an offer, in accord
261 | with subsection 6b.
262 |
263 | d) Convey the object code by offering access from a designated
264 | place (gratis or for a charge), and offer equivalent access to the
265 | Corresponding Source in the same way through the same place at no
266 | further charge. You need not require recipients to copy the
267 | Corresponding Source along with the object code. If the place to
268 | copy the object code is a network server, the Corresponding Source
269 | may be on a different server (operated by you or a third party)
270 | that supports equivalent copying facilities, provided you maintain
271 | clear directions next to the object code saying where to find the
272 | Corresponding Source. Regardless of what server hosts the
273 | Corresponding Source, you remain obligated to ensure that it is
274 | available for as long as needed to satisfy these requirements.
275 |
276 | e) Convey the object code using peer-to-peer transmission, provided
277 | you inform other peers where the object code and Corresponding
278 | Source of the work are being offered to the general public at no
279 | charge under subsection 6d.
280 |
281 | A separable portion of the object code, whose source code is excluded
282 | from the Corresponding Source as a System Library, need not be
283 | included in conveying the object code work.
284 |
285 | A "User Product" is either (1) a "consumer product", which means any
286 | tangible personal property which is normally used for personal, family,
287 | or household purposes, or (2) anything designed or sold for incorporation
288 | into a dwelling. In determining whether a product is a consumer product,
289 | doubtful cases shall be resolved in favor of coverage. For a particular
290 | product received by a particular user, "normally used" refers to a
291 | typical or common use of that class of product, regardless of the status
292 | of the particular user or of the way in which the particular user
293 | actually uses, or expects or is expected to use, the product. A product
294 | is a consumer product regardless of whether the product has substantial
295 | commercial, industrial or non-consumer uses, unless such uses represent
296 | the only significant mode of use of the product.
297 |
298 | "Installation Information" for a User Product means any methods,
299 | procedures, authorization keys, or other information required to install
300 | and execute modified versions of a covered work in that User Product from
301 | a modified version of its Corresponding Source. The information must
302 | suffice to ensure that the continued functioning of the modified object
303 | code is in no case prevented or interfered with solely because
304 | modification has been made.
305 |
306 | If you convey an object code work under this section in, or with, or
307 | specifically for use in, a User Product, and the conveying occurs as
308 | part of a transaction in which the right of possession and use of the
309 | User Product is transferred to the recipient in perpetuity or for a
310 | fixed term (regardless of how the transaction is characterized), the
311 | Corresponding Source conveyed under this section must be accompanied
312 | by the Installation Information. But this requirement does not apply
313 | if neither you nor any third party retains the ability to install
314 | modified object code on the User Product (for example, the work has
315 | been installed in ROM).
316 |
317 | The requirement to provide Installation Information does not include a
318 | requirement to continue to provide support service, warranty, or updates
319 | for a work that has been modified or installed by the recipient, or for
320 | the User Product in which it has been modified or installed. Access to a
321 | network may be denied when the modification itself materially and
322 | adversely affects the operation of the network or violates the rules and
323 | protocols for communication across the network.
324 |
325 | Corresponding Source conveyed, and Installation Information provided,
326 | in accord with this section must be in a format that is publicly
327 | documented (and with an implementation available to the public in
328 | source code form), and must require no special password or key for
329 | unpacking, reading or copying.
330 |
331 | 7. Additional Terms.
332 |
333 | "Additional permissions" are terms that supplement the terms of this
334 | License by making exceptions from one or more of its conditions.
335 | Additional permissions that are applicable to the entire Program shall
336 | be treated as though they were included in this License, to the extent
337 | that they are valid under applicable law. If additional permissions
338 | apply only to part of the Program, that part may be used separately
339 | under those permissions, but the entire Program remains governed by
340 | this License without regard to the additional permissions.
341 |
342 | When you convey a copy of a covered work, you may at your option
343 | remove any additional permissions from that copy, or from any part of
344 | it. (Additional permissions may be written to require their own
345 | removal in certain cases when you modify the work.) You may place
346 | additional permissions on material, added by you to a covered work,
347 | for which you have or can give appropriate copyright permission.
348 |
349 | Notwithstanding any other provision of this License, for material you
350 | add to a covered work, you may (if authorized by the copyright holders of
351 | that material) supplement the terms of this License with terms:
352 |
353 | a) Disclaiming warranty or limiting liability differently from the
354 | terms of sections 15 and 16 of this License; or
355 |
356 | b) Requiring preservation of specified reasonable legal notices or
357 | author attributions in that material or in the Appropriate Legal
358 | Notices displayed by works containing it; or
359 |
360 | c) Prohibiting misrepresentation of the origin of that material, or
361 | requiring that modified versions of such material be marked in
362 | reasonable ways as different from the original version; or
363 |
364 | d) Limiting the use for publicity purposes of names of licensors or
365 | authors of the material; or
366 |
367 | e) Declining to grant rights under trademark law for use of some
368 | trade names, trademarks, or service marks; or
369 |
370 | f) Requiring indemnification of licensors and authors of that
371 | material by anyone who conveys the material (or modified versions of
372 | it) with contractual assumptions of liability to the recipient, for
373 | any liability that these contractual assumptions directly impose on
374 | those licensors and authors.
375 |
376 | All other non-permissive additional terms are considered "further
377 | restrictions" within the meaning of section 10. If the Program as you
378 | received it, or any part of it, contains a notice stating that it is
379 | governed by this License along with a term that is a further
380 | restriction, you may remove that term. If a license document contains
381 | a further restriction but permits relicensing or conveying under this
382 | License, you may add to a covered work material governed by the terms
383 | of that license document, provided that the further restriction does
384 | not survive such relicensing or conveying.
385 |
386 | If you add terms to a covered work in accord with this section, you
387 | must place, in the relevant source files, a statement of the
388 | additional terms that apply to those files, or a notice indicating
389 | where to find the applicable terms.
390 |
391 | Additional terms, permissive or non-permissive, may be stated in the
392 | form of a separately written license, or stated as exceptions;
393 | the above requirements apply either way.
394 |
395 | 8. Termination.
396 |
397 | You may not propagate or modify a covered work except as expressly
398 | provided under this License. Any attempt otherwise to propagate or
399 | modify it is void, and will automatically terminate your rights under
400 | this License (including any patent licenses granted under the third
401 | paragraph of section 11).
402 |
403 | However, if you cease all violation of this License, then your
404 | license from a particular copyright holder is reinstated (a)
405 | provisionally, unless and until the copyright holder explicitly and
406 | finally terminates your license, and (b) permanently, if the copyright
407 | holder fails to notify you of the violation by some reasonable means
408 | prior to 60 days after the cessation.
409 |
410 | Moreover, your license from a particular copyright holder is
411 | reinstated permanently if the copyright holder notifies you of the
412 | violation by some reasonable means, this is the first time you have
413 | received notice of violation of this License (for any work) from that
414 | copyright holder, and you cure the violation prior to 30 days after
415 | your receipt of the notice.
416 |
417 | Termination of your rights under this section does not terminate the
418 | licenses of parties who have received copies or rights from you under
419 | this License. If your rights have been terminated and not permanently
420 | reinstated, you do not qualify to receive new licenses for the same
421 | material under section 10.
422 |
423 | 9. Acceptance Not Required for Having Copies.
424 |
425 | You are not required to accept this License in order to receive or
426 | run a copy of the Program. Ancillary propagation of a covered work
427 | occurring solely as a consequence of using peer-to-peer transmission
428 | to receive a copy likewise does not require acceptance. However,
429 | nothing other than this License grants you permission to propagate or
430 | modify any covered work. These actions infringe copyright if you do
431 | not accept this License. Therefore, by modifying or propagating a
432 | covered work, you indicate your acceptance of this License to do so.
433 |
434 | 10. Automatic Licensing of Downstream Recipients.
435 |
436 | Each time you convey a covered work, the recipient automatically
437 | receives a license from the original licensors, to run, modify and
438 | propagate that work, subject to this License. You are not responsible
439 | for enforcing compliance by third parties with this License.
440 |
441 | An "entity transaction" is a transaction transferring control of an
442 | organization, or substantially all assets of one, or subdividing an
443 | organization, or merging organizations. If propagation of a covered
444 | work results from an entity transaction, each party to that
445 | transaction who receives a copy of the work also receives whatever
446 | licenses to the work the party's predecessor in interest had or could
447 | give under the previous paragraph, plus a right to possession of the
448 | Corresponding Source of the work from the predecessor in interest, if
449 | the predecessor has it or can get it with reasonable efforts.
450 |
451 | You may not impose any further restrictions on the exercise of the
452 | rights granted or affirmed under this License. For example, you may
453 | not impose a license fee, royalty, or other charge for exercise of
454 | rights granted under this License, and you may not initiate litigation
455 | (including a cross-claim or counterclaim in a lawsuit) alleging that
456 | any patent claim is infringed by making, using, selling, offering for
457 | sale, or importing the Program or any portion of it.
458 |
459 | 11. Patents.
460 |
461 | A "contributor" is a copyright holder who authorizes use under this
462 | License of the Program or a work on which the Program is based. The
463 | work thus licensed is called the contributor's "contributor version".
464 |
465 | A contributor's "essential patent claims" are all patent claims
466 | owned or controlled by the contributor, whether already acquired or
467 | hereafter acquired, that would be infringed by some manner, permitted
468 | by this License, of making, using, or selling its contributor version,
469 | but do not include claims that would be infringed only as a
470 | consequence of further modification of the contributor version. For
471 | purposes of this definition, "control" includes the right to grant
472 | patent sublicenses in a manner consistent with the requirements of
473 | this License.
474 |
475 | Each contributor grants you a non-exclusive, worldwide, royalty-free
476 | patent license under the contributor's essential patent claims, to
477 | make, use, sell, offer for sale, import and otherwise run, modify and
478 | propagate the contents of its contributor version.
479 |
480 | In the following three paragraphs, a "patent license" is any express
481 | agreement or commitment, however denominated, not to enforce a patent
482 | (such as an express permission to practice a patent or covenant not to
483 | sue for patent infringement). To "grant" such a patent license to a
484 | party means to make such an agreement or commitment not to enforce a
485 | patent against the party.
486 |
487 | If you convey a covered work, knowingly relying on a patent license,
488 | and the Corresponding Source of the work is not available for anyone
489 | to copy, free of charge and under the terms of this License, through a
490 | publicly available network server or other readily accessible means,
491 | then you must either (1) cause the Corresponding Source to be so
492 | available, or (2) arrange to deprive yourself of the benefit of the
493 | patent license for this particular work, or (3) arrange, in a manner
494 | consistent with the requirements of this License, to extend the patent
495 | license to downstream recipients. "Knowingly relying" means you have
496 | actual knowledge that, but for the patent license, your conveying the
497 | covered work in a country, or your recipient's use of the covered work
498 | in a country, would infringe one or more identifiable patents in that
499 | country that you have reason to believe are valid.
500 |
501 | If, pursuant to or in connection with a single transaction or
502 | arrangement, you convey, or propagate by procuring conveyance of, a
503 | covered work, and grant a patent license to some of the parties
504 | receiving the covered work authorizing them to use, propagate, modify
505 | or convey a specific copy of the covered work, then the patent license
506 | you grant is automatically extended to all recipients of the covered
507 | work and works based on it.
508 |
509 | A patent license is "discriminatory" if it does not include within
510 | the scope of its coverage, prohibits the exercise of, or is
511 | conditioned on the non-exercise of one or more of the rights that are
512 | specifically granted under this License. You may not convey a covered
513 | work if you are a party to an arrangement with a third party that is
514 | in the business of distributing software, under which you make payment
515 | to the third party based on the extent of your activity of conveying
516 | the work, and under which the third party grants, to any of the
517 | parties who would receive the covered work from you, a discriminatory
518 | patent license (a) in connection with copies of the covered work
519 | conveyed by you (or copies made from those copies), or (b) primarily
520 | for and in connection with specific products or compilations that
521 | contain the covered work, unless you entered into that arrangement,
522 | or that patent license was granted, prior to 28 March 2007.
523 |
524 | Nothing in this License shall be construed as excluding or limiting
525 | any implied license or other defenses to infringement that may
526 | otherwise be available to you under applicable patent law.
527 |
528 | 12. No Surrender of Others' Freedom.
529 |
530 | If conditions are imposed on you (whether by court order, agreement or
531 | otherwise) that contradict the conditions of this License, they do not
532 | excuse you from the conditions of this License. If you cannot convey a
533 | covered work so as to satisfy simultaneously your obligations under this
534 | License and any other pertinent obligations, then as a consequence you may
535 | not convey it at all. For example, if you agree to terms that obligate you
536 | to collect a royalty for further conveying from those to whom you convey
537 | the Program, the only way you could satisfy both those terms and this
538 | License would be to refrain entirely from conveying the Program.
539 |
540 | 13. Remote Network Interaction; Use with the GNU General Public License.
541 |
542 | Notwithstanding any other provision of this License, if you modify the
543 | Program, your modified version must prominently offer all users
544 | interacting with it remotely through a computer network (if your version
545 | supports such interaction) an opportunity to receive the Corresponding
546 | Source of your version by providing access to the Corresponding Source
547 | from a network server at no charge, through some standard or customary
548 | means of facilitating copying of software. This Corresponding Source
549 | shall include the Corresponding Source for any work covered by version 3
550 | of the GNU General Public License that is incorporated pursuant to the
551 | following paragraph.
552 |
553 | Notwithstanding any other provision of this License, you have
554 | permission to link or combine any covered work with a work licensed
555 | under version 3 of the GNU General Public License into a single
556 | combined work, and to convey the resulting work. The terms of this
557 | License will continue to apply to the part which is the covered work,
558 | but the work with which it is combined will remain governed by version
559 | 3 of the GNU General Public License.
560 |
561 | 14. Revised Versions of this License.
562 |
563 | The Free Software Foundation may publish revised and/or new versions of
564 | the GNU Affero General Public License from time to time. Such new versions
565 | will be similar in spirit to the present version, but may differ in detail to
566 | address new problems or concerns.
567 |
568 | Each version is given a distinguishing version number. If the
569 | Program specifies that a certain numbered version of the GNU Affero General
570 | Public License "or any later version" applies to it, you have the
571 | option of following the terms and conditions either of that numbered
572 | version or of any later version published by the Free Software
573 | Foundation. If the Program does not specify a version number of the
574 | GNU Affero General Public License, you may choose any version ever published
575 | by the Free Software Foundation.
576 |
577 | If the Program specifies that a proxy can decide which future
578 | versions of the GNU Affero General Public License can be used, that proxy's
579 | public statement of acceptance of a version permanently authorizes you
580 | to choose that version for the Program.
581 |
582 | Later license versions may give you additional or different
583 | permissions. However, no additional obligations are imposed on any
584 | author or copyright holder as a result of your choosing to follow a
585 | later version.
586 |
587 | 15. Disclaimer of Warranty.
588 |
589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
597 |
598 | 16. Limitation of Liability.
599 |
600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
608 | SUCH DAMAGES.
609 |
610 | 17. Interpretation of Sections 15 and 16.
611 |
612 | If the disclaimer of warranty and limitation of liability provided
613 | above cannot be given local legal effect according to their terms,
614 | reviewing courts shall apply local law that most closely approximates
615 | an absolute waiver of all civil liability in connection with the
616 | Program, unless a warranty or assumption of liability accompanies a
617 | copy of the Program in return for a fee.
618 |
619 | END OF TERMS AND CONDITIONS
620 |
621 | How to Apply These Terms to Your New Programs
622 |
623 | If you develop a new program, and you want it to be of the greatest
624 | possible use to the public, the best way to achieve this is to make it
625 | free software which everyone can redistribute and change under these terms.
626 |
627 | To do so, attach the following notices to the program. It is safest
628 | to attach them to the start of each source file to most effectively
629 | state the exclusion of warranty; and each file should have at least
630 | the "copyright" line and a pointer to where the full notice is found.
631 |
632 |
633 | Copyright (C)
634 |
635 | This program is free software: you can redistribute it and/or modify
636 | it under the terms of the GNU Affero General Public License as published
637 | by the Free Software Foundation, either version 3 of the License, or
638 | (at your option) any later version.
639 |
640 | This program is distributed in the hope that it will be useful,
641 | but WITHOUT ANY WARRANTY; without even the implied warranty of
642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643 | GNU Affero General Public License for more details.
644 |
645 | You should have received a copy of the GNU Affero General Public License
646 | along with this program. If not, see .
647 |
648 | Also add information on how to contact you by electronic and paper mail.
649 |
650 | If your software can interact with users remotely through a computer
651 | network, you should also make sure that it provides a way for users to
652 | get its source. For example, if your program is a web application, its
653 | interface could display a "Source" link that leads users to an archive
654 | of the code. There are many ways you could offer source, and different
655 | solutions will be better for different programs; see section 13 for the
656 | specific requirements.
657 |
658 | You should also get your employer (if you work as a programmer) or school,
659 | if any, to sign a "copyright disclaimer" for the program, if necessary.
660 | For more information on this, and how to apply and follow the GNU AGPL, see
661 | .
662 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Arbitrage-Example
2 |
3 | There were just no good up to date Uniswap V2 Arbitrage Examples so I made one
4 |
5 | Test via
6 |
7 | ```
8 | forge test --fork-url
9 | ```
10 |
11 | ## Notes on Effiency
12 |
13 | - Rewrite in Yul+ since the repayment math does need to be safe but solidity safemath is horrible in effiency
14 | - getPair can be derived inside the contract through a function like [this](https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol#L18) but including factory init code hash is confusing for people
15 |
--------------------------------------------------------------------------------
/foundry.toml:
--------------------------------------------------------------------------------
1 | [profile.default]
2 | src = 'src'
3 | out = 'out'
4 | libs = ['lib']
5 | solc = "0.8.16"
6 | optimizer = true
7 | optimizer_runs = 1000000
8 | via_ir = true
9 |
10 | # Turn on more compiler settings here, specically the stack optimizer for via_ir process
11 |
--------------------------------------------------------------------------------
/lib/forge-std/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2021 Brock Elmore
2 |
3 | Apache License
4 | Version 2.0, January 2004
5 | http://www.apache.org/licenses/
6 |
7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8 |
9 | 1. Definitions.
10 |
11 | "License" shall mean the terms and conditions for use, reproduction,
12 | and distribution as defined by Sections 1 through 9 of this document.
13 |
14 | "Licensor" shall mean the copyright owner or entity authorized by
15 | the copyright owner that is granting the License.
16 |
17 | "Legal Entity" shall mean the union of the acting entity and all
18 | other entities that control, are controlled by, or are under common
19 | control with that entity. For the purposes of this definition,
20 | "control" means (i) the power, direct or indirect, to cause the
21 | direction or management of such entity, whether by contract or
22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
23 | outstanding shares, or (iii) beneficial ownership of such entity.
24 |
25 | "You" (or "Your") shall mean an individual or Legal Entity
26 | exercising permissions granted by this License.
27 |
28 | "Source" form shall mean the preferred form for making modifications,
29 | including but not limited to software source code, documentation
30 | source, and configuration files.
31 |
32 | "Object" form shall mean any form resulting from mechanical
33 | transformation or translation of a Source form, including but
34 | not limited to compiled object code, generated documentation,
35 | and conversions to other media types.
36 |
37 | "Work" shall mean the work of authorship, whether in Source or
38 | Object form, made available under the License, as indicated by a
39 | copyright notice that is included in or attached to the work
40 | (an example is provided in the Appendix below).
41 |
42 | "Derivative Works" shall mean any work, whether in Source or Object
43 | form, that is based on (or derived from) the Work and for which the
44 | editorial revisions, annotations, elaborations, or other modifications
45 | represent, as a whole, an original work of authorship. For the purposes
46 | of this License, Derivative Works shall not include works that remain
47 | separable from, or merely link (or bind by name) to the interfaces of,
48 | the Work and Derivative Works thereof.
49 |
50 | "Contribution" shall mean any work of authorship, including
51 | the original version of the Work and any modifications or additions
52 | to that Work or Derivative Works thereof, that is intentionally
53 | submitted to Licensor for inclusion in the Work by the copyright owner
54 | or by an individual or Legal Entity authorized to submit on behalf of
55 | the copyright owner. For the purposes of this definition, "submitted"
56 | means any form of electronic, verbal, or written communication sent
57 | to the Licensor or its representatives, including but not limited to
58 | communication on electronic mailing lists, source code control systems,
59 | and issue tracking systems that are managed by, or on behalf of, the
60 | Licensor for the purpose of discussing and improving the Work, but
61 | excluding communication that is conspicuously marked or otherwise
62 | designated in writing by the copyright owner as "Not a Contribution."
63 |
64 | "Contributor" shall mean Licensor and any individual or Legal Entity
65 | on behalf of whom a Contribution has been received by Licensor and
66 | subsequently incorporated within the Work.
67 |
68 | 2. Grant of Copyright License. Subject to the terms and conditions of
69 | this License, each Contributor hereby grants to You a perpetual,
70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
71 | copyright license to reproduce, prepare Derivative Works of,
72 | publicly display, publicly perform, sublicense, and distribute the
73 | Work and such Derivative Works in Source or Object form.
74 |
75 | 3. Grant of Patent License. Subject to the terms and conditions of
76 | this License, each Contributor hereby grants to You a perpetual,
77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
78 | (except as stated in this section) patent license to make, have made,
79 | use, offer to sell, sell, import, and otherwise transfer the Work,
80 | where such license applies only to those patent claims licensable
81 | by such Contributor that are necessarily infringed by their
82 | Contribution(s) alone or by combination of their Contribution(s)
83 | with the Work to which such Contribution(s) was submitted. If You
84 | institute patent litigation against any entity (including a
85 | cross-claim or counterclaim in a lawsuit) alleging that the Work
86 | or a Contribution incorporated within the Work constitutes direct
87 | or contributory patent infringement, then any patent licenses
88 | granted to You under this License for that Work shall terminate
89 | as of the date such litigation is filed.
90 |
91 | 4. Redistribution. You may reproduce and distribute copies of the
92 | Work or Derivative Works thereof in any medium, with or without
93 | modifications, and in Source or Object form, provided that You
94 | meet the following conditions:
95 |
96 | (a) You must give any other recipients of the Work or
97 | Derivative Works a copy of this License; and
98 |
99 | (b) You must cause any modified files to carry prominent notices
100 | stating that You changed the files; and
101 |
102 | (c) You must retain, in the Source form of any Derivative Works
103 | that You distribute, all copyright, patent, trademark, and
104 | attribution notices from the Source form of the Work,
105 | excluding those notices that do not pertain to any part of
106 | the Derivative Works; and
107 |
108 | (d) If the Work includes a "NOTICE" text file as part of its
109 | distribution, then any Derivative Works that You distribute must
110 | include a readable copy of the attribution notices contained
111 | within such NOTICE file, excluding those notices that do not
112 | pertain to any part of the Derivative Works, in at least one
113 | of the following places: within a NOTICE text file distributed
114 | as part of the Derivative Works; within the Source form or
115 | documentation, if provided along with the Derivative Works; or,
116 | within a display generated by the Derivative Works, if and
117 | wherever such third-party notices normally appear. The contents
118 | of the NOTICE file are for informational purposes only and
119 | do not modify the License. You may add Your own attribution
120 | notices within Derivative Works that You distribute, alongside
121 | or as an addendum to the NOTICE text from the Work, provided
122 | that such additional attribution notices cannot be construed
123 | as modifying the License.
124 |
125 | You may add Your own copyright statement to Your modifications and
126 | may provide additional or different license terms and conditions
127 | for use, reproduction, or distribution of Your modifications, or
128 | for any such Derivative Works as a whole, provided Your use,
129 | reproduction, and distribution of the Work otherwise complies with
130 | the conditions stated in this License.
131 |
132 | 5. Submission of Contributions. Unless You explicitly state otherwise,
133 | any Contribution intentionally submitted for inclusion in the Work
134 | by You to the Licensor shall be under the terms and conditions of
135 | this License, without any additional terms or conditions.
136 | Notwithstanding the above, nothing herein shall supersede or modify
137 | the terms of any separate license agreement you may have executed
138 | with Licensor regarding such Contributions.
139 |
140 | 6. Trademarks. This License does not grant permission to use the trade
141 | names, trademarks, service marks, or product names of the Licensor,
142 | except as required for reasonable and customary use in describing the
143 | origin of the Work and reproducing the content of the NOTICE file.
144 |
145 | 7. Disclaimer of Warranty. Unless required by applicable law or
146 | agreed to in writing, Licensor provides the Work (and each
147 | Contributor provides its Contributions) on an "AS IS" BASIS,
148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
149 | implied, including, without limitation, any warranties or conditions
150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
151 | PARTICULAR PURPOSE. You are solely responsible for determining the
152 | appropriateness of using or redistributing the Work and assume any
153 | risks associated with Your exercise of permissions under this License.
154 |
155 | 8. Limitation of Liability. In no event and under no legal theory,
156 | whether in tort (including negligence), contract, or otherwise,
157 | unless required by applicable law (such as deliberate and grossly
158 | negligent acts) or agreed to in writing, shall any Contributor be
159 | liable to You for damages, including any direct, indirect, special,
160 | incidental, or consequential damages of any character arising as a
161 | result of this License or out of the use or inability to use the
162 | Work (including but not limited to damages for loss of goodwill,
163 | work stoppage, computer failure or malfunction, or any and all
164 | other commercial damages or losses), even if such Contributor
165 | has been advised of the possibility of such damages.
166 |
167 | 9. Accepting Warranty or Additional Liability. While redistributing
168 | the Work or Derivative Works thereof, You may choose to offer,
169 | and charge a fee for, acceptance of support, warranty, indemnity,
170 | or other liability obligations and/or rights consistent with this
171 | License. However, in accepting such obligations, You may act only
172 | on Your own behalf and on Your sole responsibility, not on behalf
173 | of any other Contributor, and only if You agree to indemnify,
174 | defend, and hold each Contributor harmless for any liability
175 | incurred by, or claims asserted against, such Contributor by reason
176 | of your accepting any such warranty or additional liability.
177 |
178 | END OF TERMS AND CONDITIONS
179 |
180 | APPENDIX: How to apply the Apache License to your work.
181 |
182 | To apply the Apache License to your work, attach the following
183 | boilerplate notice, with the fields enclosed by brackets "[]"
184 | replaced with your own identifying information. (Don't include
185 | the brackets!) The text should be enclosed in the appropriate
186 | comment syntax for the file format. We also recommend that a
187 | file or class name and description of purpose be included on the
188 | same "printed page" as the copyright notice for easier
189 | identification within third-party archives.
190 |
191 | Copyright [yyyy] [name of copyright owner]
192 |
193 | Licensed under the Apache License, Version 2.0 (the "License");
194 | you may not use this file except in compliance with the License.
195 | You may obtain a copy of the License at
196 |
197 | http://www.apache.org/licenses/LICENSE-2.0
198 |
199 | Unless required by applicable law or agreed to in writing, software
200 | distributed under the License is distributed on an "AS IS" BASIS,
201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
202 | See the License for the specific language governing permissions and
203 | limitations under the License.
204 |
--------------------------------------------------------------------------------
/lib/forge-std/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2021 Brock Elmore
2 |
3 | Permission is hereby granted, free of charge, to any
4 | person obtaining a copy of this software and associated
5 | documentation files (the "Software"), to deal in the
6 | Software without restriction, including without
7 | limitation the rights to use, copy, modify, merge,
8 | publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software
10 | is furnished to do so, subject to the following
11 | conditions:
12 |
13 | The above copyright notice and this permission notice
14 | shall be included in all copies or substantial portions
15 | of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24 | IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER
25 | DEALINGS IN THE SOFTWARE.R
26 |
--------------------------------------------------------------------------------
/lib/forge-std/README.md:
--------------------------------------------------------------------------------
1 | # Forge Standard Library • [](https://github.com/brockelmore/forge-std/actions/workflows/tests.yml)
2 |
3 | Forge Standard Library is a collection of helpful contracts for use with [`forge` and `foundry`](https://github.com/foundry-rs/foundry). It leverages `forge`'s cheatcodes to make writing tests easier and faster, while improving the UX of cheatcodes.
4 |
5 | **Learn how to use Forge Std with the [📖 Foundry Book (Forge Std Guide)](https://book.getfoundry.sh/forge/forge-std.html).**
6 |
7 | ## Install
8 |
9 | ```bash
10 | forge install foundry-rs/forge-std
11 | ```
12 |
13 | ## Contracts
14 | ### stdError
15 |
16 | This is a helper contract for errors and reverts. In `forge`, this contract is particularly helpful for the `expectRevert` cheatcode, as it provides all compiler builtin errors.
17 |
18 | See the contract itself for all error codes.
19 |
20 | #### Example usage
21 |
22 | ```solidity
23 |
24 | import "forge-std/Test.sol";
25 |
26 | contract TestContract is Test {
27 | ErrorsTest test;
28 |
29 | function setUp() public {
30 | test = new ErrorsTest();
31 | }
32 |
33 | function testExpectArithmetic() public {
34 | vm.expectRevert(stdError.arithmeticError);
35 | test.arithmeticError(10);
36 | }
37 | }
38 |
39 | contract ErrorsTest {
40 | function arithmeticError(uint256 a) public {
41 | uint256 a = a - 100;
42 | }
43 | }
44 | ```
45 |
46 | ### stdStorage
47 |
48 | This is a rather large contract due to all of the overloading to make the UX decent. Primarily, it is a wrapper around the `record` and `accesses` cheatcodes. It can *always* find and write the storage slot(s) associated with a particular variable without knowing the storage layout. The one _major_ caveat to this is while a slot can be found for packed storage variables, we can't write to that variable safely. If a user tries to write to a packed slot, the execution throws an error, unless it is uninitialized (`bytes32(0)`).
49 |
50 | This works by recording all `SLOAD`s and `SSTORE`s during a function call. If there is a single slot read or written to, it immediately returns the slot. Otherwise, behind the scenes, we iterate through and check each one (assuming the user passed in a `depth` parameter). If the variable is a struct, you can pass in a `depth` parameter which is basically the field depth.
51 |
52 | I.e.:
53 | ```solidity
54 | struct T {
55 | // depth 0
56 | uint256 a;
57 | // depth 1
58 | uint256 b;
59 | }
60 | ```
61 |
62 | #### Example usage
63 |
64 | ```solidity
65 | import "forge-std/Test.sol";
66 |
67 | contract TestContract is Test {
68 | using stdStorage for StdStorage;
69 |
70 | Storage test;
71 |
72 | function setUp() public {
73 | test = new Storage();
74 | }
75 |
76 | function testFindExists() public {
77 | // Lets say we want to find the slot for the public
78 | // variable `exists`. We just pass in the function selector
79 | // to the `find` command
80 | uint256 slot = stdstore.target(address(test)).sig("exists()").find();
81 | assertEq(slot, 0);
82 | }
83 |
84 | function testWriteExists() public {
85 | // Lets say we want to write to the slot for the public
86 | // variable `exists`. We just pass in the function selector
87 | // to the `checked_write` command
88 | stdstore.target(address(test)).sig("exists()").checked_write(100);
89 | assertEq(test.exists(), 100);
90 | }
91 |
92 | // It supports arbitrary storage layouts, like assembly based storage locations
93 | function testFindHidden() public {
94 | // `hidden` is a random hash of a bytes, iteration through slots would
95 | // not find it. Our mechanism does
96 | // Also, you can use the selector instead of a string
97 | uint256 slot = stdstore.target(address(test)).sig(test.hidden.selector).find();
98 | assertEq(slot, uint256(keccak256("my.random.var")));
99 | }
100 |
101 | // If targeting a mapping, you have to pass in the keys necessary to perform the find
102 | // i.e.:
103 | function testFindMapping() public {
104 | uint256 slot = stdstore
105 | .target(address(test))
106 | .sig(test.map_addr.selector)
107 | .with_key(address(this))
108 | .find();
109 | // in the `Storage` constructor, we wrote that this address' value was 1 in the map
110 | // so when we load the slot, we expect it to be 1
111 | assertEq(uint(vm.load(address(test), bytes32(slot))), 1);
112 | }
113 |
114 | // If the target is a struct, you can specify the field depth:
115 | function testFindStruct() public {
116 | // NOTE: see the depth parameter - 0 means 0th field, 1 means 1st field, etc.
117 | uint256 slot_for_a_field = stdstore
118 | .target(address(test))
119 | .sig(test.basicStruct.selector)
120 | .depth(0)
121 | .find();
122 |
123 | uint256 slot_for_b_field = stdstore
124 | .target(address(test))
125 | .sig(test.basicStruct.selector)
126 | .depth(1)
127 | .find();
128 |
129 | assertEq(uint(vm.load(address(test), bytes32(slot_for_a_field))), 1);
130 | assertEq(uint(vm.load(address(test), bytes32(slot_for_b_field))), 2);
131 | }
132 | }
133 |
134 | // A complex storage contract
135 | contract Storage {
136 | struct UnpackedStruct {
137 | uint256 a;
138 | uint256 b;
139 | }
140 |
141 | constructor() {
142 | map_addr[msg.sender] = 1;
143 | }
144 |
145 | uint256 public exists = 1;
146 | mapping(address => uint256) public map_addr;
147 | // mapping(address => Packed) public map_packed;
148 | mapping(address => UnpackedStruct) public map_struct;
149 | mapping(address => mapping(address => uint256)) public deep_map;
150 | mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct;
151 | UnpackedStruct public basicStruct = UnpackedStruct({
152 | a: 1,
153 | b: 2
154 | });
155 |
156 | function hidden() public view returns (bytes32 t) {
157 | // an extremely hidden storage slot
158 | bytes32 slot = keccak256("my.random.var");
159 | assembly {
160 | t := sload(slot)
161 | }
162 | }
163 | }
164 | ```
165 |
166 | ### stdCheats
167 |
168 | This is a wrapper over miscellaneous cheatcodes that need wrappers to be more dev friendly. Currently there are only functions related to `prank`. In general, users may expect ETH to be put into an address on `prank`, but this is not the case for safety reasons. Explicitly this `hoax` function should only be used for address that have expected balances as it will get overwritten. If an address already has ETH, you should just use `prank`. If you want to change that balance explicitly, just use `deal`. If you want to do both, `hoax` is also right for you.
169 |
170 |
171 | #### Example usage:
172 | ```solidity
173 |
174 | // SPDX-License-Identifier: Unlicense
175 | pragma solidity ^0.8.0;
176 |
177 | import "forge-std/Test.sol";
178 |
179 | // Inherit the stdCheats
180 | contract StdCheatsTest is Test {
181 | Bar test;
182 | function setUp() public {
183 | test = new Bar();
184 | }
185 |
186 | function testHoax() public {
187 | // we call `hoax`, which gives the target address
188 | // eth and then calls `prank`
189 | hoax(address(1337));
190 | test.bar{value: 100}(address(1337));
191 |
192 | // overloaded to allow you to specify how much eth to
193 | // initialize the address with
194 | hoax(address(1337), 1);
195 | test.bar{value: 1}(address(1337));
196 | }
197 |
198 | function testStartHoax() public {
199 | // we call `startHoax`, which gives the target address
200 | // eth and then calls `startPrank`
201 | //
202 | // it is also overloaded so that you can specify an eth amount
203 | startHoax(address(1337));
204 | test.bar{value: 100}(address(1337));
205 | test.bar{value: 100}(address(1337));
206 | vm.stopPrank();
207 | test.bar(address(this));
208 | }
209 | }
210 |
211 | contract Bar {
212 | function bar(address expectedSender) public payable {
213 | require(msg.sender == expectedSender, "!prank");
214 | }
215 | }
216 | ```
217 |
218 | ### Std Assertions
219 |
220 | Expand upon the assertion functions from the `DSTest` library.
221 |
222 | ### `console.log`
223 |
224 | Usage follows the same format as [Hardhat](https://hardhat.org/hardhat-network/reference/#console-log).
225 | It's recommended to use `console2.sol` as shown below, as this will show the decoded logs in Forge traces.
226 |
227 | ```solidity
228 | // import it indirectly via Test.sol
229 | import "forge-std/Test.sol";
230 | // or directly import it
231 | import "forge-std/console2.sol";
232 | ...
233 | console2.log(someValue);
234 | ```
235 |
236 | If you need compatibility with Hardhat, you must use the standard `console.sol` instead.
237 | Due to a bug in `console.sol`, logs that use `uint256` or `int256` types will not be properly decoded in Forge traces.
238 |
239 | ```solidity
240 | // import it indirectly via Test.sol
241 | import "forge-std/Test.sol";
242 | // or directly import it
243 | import "forge-std/console.sol";
244 | ...
245 | console.log(someValue);
246 | ```
247 |
--------------------------------------------------------------------------------
/lib/forge-std/src/Script.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Unlicense
2 | pragma solidity >=0.6.0 <0.9.0;
3 |
4 | import "./Vm.sol";
5 | import "./console.sol";
6 | import "./console2.sol";
7 |
8 | abstract contract Script {
9 | bool public IS_SCRIPT = true;
10 | address constant private VM_ADDRESS =
11 | address(bytes20(uint160(uint256(keccak256('hevm cheat code')))));
12 |
13 | Vm public constant vm = Vm(VM_ADDRESS);
14 | }
15 |
--------------------------------------------------------------------------------
/lib/forge-std/src/Test.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Unlicense
2 | pragma solidity >=0.6.0 <0.9.0;
3 |
4 | import "./Script.sol";
5 | import "ds-test/test.sol";
6 |
7 | // Wrappers around Cheatcodes to avoid footguns
8 | abstract contract Test is DSTest, Script {
9 | using stdStorage for StdStorage;
10 |
11 | uint256 private constant UINT256_MAX =
12 | 115792089237316195423570985008687907853269984665640564039457584007913129639935;
13 |
14 | StdStorage internal stdstore;
15 |
16 | /*//////////////////////////////////////////////////////////////////////////
17 | STD-LOGS
18 | //////////////////////////////////////////////////////////////////////////*/
19 |
20 | event log_array(uint256[] val);
21 | event log_array(int256[] val);
22 | event log_array(address[] val);
23 | event log_named_array(string key, uint256[] val);
24 | event log_named_array(string key, int256[] val);
25 | event log_named_array(string key, address[] val);
26 |
27 | /*//////////////////////////////////////////////////////////////////////////
28 | STD-CHEATS
29 | //////////////////////////////////////////////////////////////////////////*/
30 |
31 | // Skip forward or rewind time by the specified number of seconds
32 | function skip(uint256 time) public {
33 | vm.warp(block.timestamp + time);
34 | }
35 |
36 | function rewind(uint256 time) public {
37 | vm.warp(block.timestamp - time);
38 | }
39 |
40 | // Setup a prank from an address that has some ether
41 | function hoax(address who) public {
42 | vm.deal(who, 1 << 128);
43 | vm.prank(who);
44 | }
45 |
46 | function hoax(address who, uint256 give) public {
47 | vm.deal(who, give);
48 | vm.prank(who);
49 | }
50 |
51 | function hoax(address who, address origin) public {
52 | vm.deal(who, 1 << 128);
53 | vm.prank(who, origin);
54 | }
55 |
56 | function hoax(address who, address origin, uint256 give) public {
57 | vm.deal(who, give);
58 | vm.prank(who, origin);
59 | }
60 |
61 | // Start perpetual prank from an address that has some ether
62 | function startHoax(address who) public {
63 | vm.deal(who, 1 << 128);
64 | vm.startPrank(who);
65 | }
66 |
67 | function startHoax(address who, uint256 give) public {
68 | vm.deal(who, give);
69 | vm.startPrank(who);
70 | }
71 |
72 | // Start perpetual prank from an address that has some ether
73 | // tx.origin is set to the origin parameter
74 | function startHoax(address who, address origin) public {
75 | vm.deal(who, 1 << 128);
76 | vm.startPrank(who, origin);
77 | }
78 |
79 | function startHoax(address who, address origin, uint256 give) public {
80 | vm.deal(who, give);
81 | vm.startPrank(who, origin);
82 | }
83 |
84 | function changePrank(address who) internal {
85 | vm.stopPrank();
86 | vm.startPrank(who);
87 | }
88 |
89 | // DEPRECATED: Use `deal` instead
90 | function tip(address token, address to, uint256 give) public {
91 | emit log_named_string("WARNING", "Test tip(address,address,uint256): The `tip` stdcheat has been deprecated. Use `deal` instead.");
92 | stdstore
93 | .target(token)
94 | .sig(0x70a08231)
95 | .with_key(to)
96 | .checked_write(give);
97 | }
98 |
99 | // The same as Vm's `deal`
100 | // Use the alternative signature for ERC20 tokens
101 | function deal(address to, uint256 give) public {
102 | vm.deal(to, give);
103 | }
104 |
105 | // Set the balance of an account for any ERC20 token
106 | // Use the alternative signature to update `totalSupply`
107 | function deal(address token, address to, uint256 give) public {
108 | deal(token, to, give, false);
109 | }
110 |
111 | function deal(address token, address to, uint256 give, bool adjust) public {
112 | // get current balance
113 | (, bytes memory balData) = token.call(abi.encodeWithSelector(0x70a08231, to));
114 | uint256 prevBal = abi.decode(balData, (uint256));
115 |
116 | // update balance
117 | stdstore
118 | .target(token)
119 | .sig(0x70a08231)
120 | .with_key(to)
121 | .checked_write(give);
122 |
123 | // update total supply
124 | if(adjust){
125 | (, bytes memory totSupData) = token.call(abi.encodeWithSelector(0x18160ddd));
126 | uint256 totSup = abi.decode(totSupData, (uint256));
127 | if(give < prevBal) {
128 | totSup -= (prevBal - give);
129 | } else {
130 | totSup += (give - prevBal);
131 | }
132 | stdstore
133 | .target(token)
134 | .sig(0x18160ddd)
135 | .checked_write(totSup);
136 | }
137 | }
138 |
139 | function bound(uint256 x, uint256 min, uint256 max) internal virtual returns (uint256 result) {
140 | require(min <= max, "Test bound(uint256,uint256,uint256): Max is less than min.");
141 |
142 | uint256 size = max - min;
143 |
144 | if (size == 0)
145 | {
146 | result = min;
147 | }
148 | else if (size == UINT256_MAX)
149 | {
150 | result = x;
151 | }
152 | else
153 | {
154 | ++size; // make `max` inclusive
155 | uint256 mod = x % size;
156 | result = min + mod;
157 | }
158 |
159 | emit log_named_uint("Bound Result", result);
160 | }
161 |
162 | // Deploy a contract by fetching the contract bytecode from
163 | // the artifacts directory
164 | // e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))`
165 | function deployCode(string memory what, bytes memory args)
166 | public
167 | returns (address addr)
168 | {
169 | bytes memory bytecode = abi.encodePacked(vm.getCode(what), args);
170 | /// @solidity memory-safe-assembly
171 | assembly {
172 | addr := create(0, add(bytecode, 0x20), mload(bytecode))
173 | }
174 |
175 | require(
176 | addr != address(0),
177 | "Test deployCode(string,bytes): Deployment failed."
178 | );
179 | }
180 |
181 | function deployCode(string memory what)
182 | public
183 | returns (address addr)
184 | {
185 | bytes memory bytecode = vm.getCode(what);
186 | /// @solidity memory-safe-assembly
187 | assembly {
188 | addr := create(0, add(bytecode, 0x20), mload(bytecode))
189 | }
190 |
191 | require(
192 | addr != address(0),
193 | "Test deployCode(string): Deployment failed."
194 | );
195 | }
196 |
197 | /*//////////////////////////////////////////////////////////////////////////
198 | STD-ASSERTIONS
199 | //////////////////////////////////////////////////////////////////////////*/
200 |
201 | function fail(string memory err) internal virtual {
202 | emit log_named_string("Error", err);
203 | fail();
204 | }
205 |
206 | function assertFalse(bool data) internal virtual {
207 | assertTrue(!data);
208 | }
209 |
210 | function assertFalse(bool data, string memory err) internal virtual {
211 | assertTrue(!data, err);
212 | }
213 |
214 | function assertEq(bool a, bool b) internal {
215 | if (a != b) {
216 | emit log ("Error: a == b not satisfied [bool]");
217 | emit log_named_string (" Expected", b ? "true" : "false");
218 | emit log_named_string (" Actual", a ? "true" : "false");
219 | fail();
220 | }
221 | }
222 |
223 | function assertEq(bool a, bool b, string memory err) internal {
224 | if (a != b) {
225 | emit log_named_string("Error", err);
226 | assertEq(a, b);
227 | }
228 | }
229 |
230 | function assertEq(bytes memory a, bytes memory b) internal {
231 | assertEq0(a, b);
232 | }
233 |
234 | function assertEq(bytes memory a, bytes memory b, string memory err) internal {
235 | assertEq0(a, b, err);
236 | }
237 |
238 | function assertEq(uint256[] memory a, uint256[] memory b) internal {
239 | if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
240 | emit log("Error: a == b not satisfied [uint[]]");
241 | emit log_named_array(" Expected", b);
242 | emit log_named_array(" Actual", a);
243 | fail();
244 | }
245 | }
246 |
247 | function assertEq(int256[] memory a, int256[] memory b) internal {
248 | if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
249 | emit log("Error: a == b not satisfied [int[]]");
250 | emit log_named_array(" Expected", b);
251 | emit log_named_array(" Actual", a);
252 | fail();
253 | }
254 | }
255 |
256 | function assertEq(address[] memory a, address[] memory b) internal {
257 | if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
258 | emit log("Error: a == b not satisfied [address[]]");
259 | emit log_named_array(" Expected", b);
260 | emit log_named_array(" Actual", a);
261 | fail();
262 | }
263 | }
264 |
265 | function assertEq(uint256[] memory a, uint256[] memory b, string memory err) internal {
266 | if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
267 | emit log_named_string("Error", err);
268 | assertEq(a, b);
269 | }
270 | }
271 |
272 | function assertEq(int256[] memory a, int256[] memory b, string memory err) internal {
273 | if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
274 | emit log_named_string("Error", err);
275 | assertEq(a, b);
276 | }
277 | }
278 |
279 |
280 | function assertEq(address[] memory a, address[] memory b, string memory err) internal {
281 | if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
282 | emit log_named_string("Error", err);
283 | assertEq(a, b);
284 | }
285 | }
286 |
287 | function assertApproxEqAbs(
288 | uint256 a,
289 | uint256 b,
290 | uint256 maxDelta
291 | ) internal virtual {
292 | uint256 delta = stdMath.delta(a, b);
293 |
294 | if (delta > maxDelta) {
295 | emit log ("Error: a ~= b not satisfied [uint]");
296 | emit log_named_uint (" Expected", b);
297 | emit log_named_uint (" Actual", a);
298 | emit log_named_uint (" Max Delta", maxDelta);
299 | emit log_named_uint (" Delta", delta);
300 | fail();
301 | }
302 | }
303 |
304 | function assertApproxEqAbs(
305 | uint256 a,
306 | uint256 b,
307 | uint256 maxDelta,
308 | string memory err
309 | ) internal virtual {
310 | uint256 delta = stdMath.delta(a, b);
311 |
312 | if (delta > maxDelta) {
313 | emit log_named_string ("Error", err);
314 | assertApproxEqAbs(a, b, maxDelta);
315 | }
316 | }
317 |
318 | function assertApproxEqAbs(
319 | int256 a,
320 | int256 b,
321 | uint256 maxDelta
322 | ) internal virtual {
323 | uint256 delta = stdMath.delta(a, b);
324 |
325 | if (delta > maxDelta) {
326 | emit log ("Error: a ~= b not satisfied [int]");
327 | emit log_named_int (" Expected", b);
328 | emit log_named_int (" Actual", a);
329 | emit log_named_uint (" Max Delta", maxDelta);
330 | emit log_named_uint (" Delta", delta);
331 | fail();
332 | }
333 | }
334 |
335 | function assertApproxEqAbs(
336 | int256 a,
337 | int256 b,
338 | uint256 maxDelta,
339 | string memory err
340 | ) internal virtual {
341 | uint256 delta = stdMath.delta(a, b);
342 |
343 | if (delta > maxDelta) {
344 | emit log_named_string ("Error", err);
345 | assertApproxEqAbs(a, b, maxDelta);
346 | }
347 | }
348 |
349 | function assertApproxEqRel(
350 | uint256 a,
351 | uint256 b,
352 | uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100%
353 | ) internal virtual {
354 | if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too.
355 |
356 | uint256 percentDelta = stdMath.percentDelta(a, b);
357 |
358 | if (percentDelta > maxPercentDelta) {
359 | emit log ("Error: a ~= b not satisfied [uint]");
360 | emit log_named_uint (" Expected", b);
361 | emit log_named_uint (" Actual", a);
362 | emit log_named_decimal_uint (" Max % Delta", maxPercentDelta, 18);
363 | emit log_named_decimal_uint (" % Delta", percentDelta, 18);
364 | fail();
365 | }
366 | }
367 |
368 | function assertApproxEqRel(
369 | uint256 a,
370 | uint256 b,
371 | uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%
372 | string memory err
373 | ) internal virtual {
374 | if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too.
375 |
376 | uint256 percentDelta = stdMath.percentDelta(a, b);
377 |
378 | if (percentDelta > maxPercentDelta) {
379 | emit log_named_string ("Error", err);
380 | assertApproxEqRel(a, b, maxPercentDelta);
381 | }
382 | }
383 |
384 | function assertApproxEqRel(
385 | int256 a,
386 | int256 b,
387 | uint256 maxPercentDelta
388 | ) internal virtual {
389 | if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too.
390 |
391 | uint256 percentDelta = stdMath.percentDelta(a, b);
392 |
393 | if (percentDelta > maxPercentDelta) {
394 | emit log ("Error: a ~= b not satisfied [int]");
395 | emit log_named_int (" Expected", b);
396 | emit log_named_int (" Actual", a);
397 | emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18);
398 | emit log_named_decimal_uint(" % Delta", percentDelta, 18);
399 | fail();
400 | }
401 | }
402 |
403 | function assertApproxEqRel(
404 | int256 a,
405 | int256 b,
406 | uint256 maxPercentDelta,
407 | string memory err
408 | ) internal virtual {
409 | if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too.
410 |
411 | uint256 percentDelta = stdMath.percentDelta(a, b);
412 |
413 | if (percentDelta > maxPercentDelta) {
414 | emit log_named_string ("Error", err);
415 | assertApproxEqRel(a, b, maxPercentDelta);
416 | }
417 | }
418 | }
419 |
420 | /*//////////////////////////////////////////////////////////////////////////
421 | STD-ERRORS
422 | //////////////////////////////////////////////////////////////////////////*/
423 |
424 | library stdError {
425 | bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01);
426 | bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11);
427 | bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12);
428 | bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21);
429 | bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22);
430 | bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31);
431 | bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32);
432 | bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41);
433 | bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51);
434 | // DEPRECATED: Use Vm's `expectRevert` without any arguments instead
435 | bytes public constant lowLevelError = bytes(""); // `0x`
436 | }
437 |
438 | /*//////////////////////////////////////////////////////////////////////////
439 | STD-STORAGE
440 | //////////////////////////////////////////////////////////////////////////*/
441 |
442 | struct StdStorage {
443 | mapping (address => mapping(bytes4 => mapping(bytes32 => uint256))) slots;
444 | mapping (address => mapping(bytes4 => mapping(bytes32 => bool))) finds;
445 |
446 | bytes32[] _keys;
447 | bytes4 _sig;
448 | uint256 _depth;
449 | address _target;
450 | bytes32 _set;
451 | }
452 |
453 | library stdStorage {
454 | event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint slot);
455 | event WARNING_UninitedSlot(address who, uint slot);
456 |
457 | uint256 private constant UINT256_MAX = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
458 | int256 private constant INT256_MAX = 57896044618658097711785492504343953926634992332820282019728792003956564819967;
459 |
460 | Vm private constant vm_std_store = Vm(address(uint160(uint256(keccak256('hevm cheat code')))));
461 |
462 | function sigs(
463 | string memory sigStr
464 | )
465 | internal
466 | pure
467 | returns (bytes4)
468 | {
469 | return bytes4(keccak256(bytes(sigStr)));
470 | }
471 |
472 | /// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against
473 | // slot complexity:
474 | // if flat, will be bytes32(uint256(uint));
475 | // if map, will be keccak256(abi.encode(key, uint(slot)));
476 | // if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))));
477 | // if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth);
478 | function find(
479 | StdStorage storage self
480 | )
481 | internal
482 | returns (uint256)
483 | {
484 | address who = self._target;
485 | bytes4 fsig = self._sig;
486 | uint256 field_depth = self._depth;
487 | bytes32[] memory ins = self._keys;
488 |
489 | // calldata to test against
490 | if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) {
491 | return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
492 | }
493 | bytes memory cald = abi.encodePacked(fsig, flatten(ins));
494 | vm_std_store.record();
495 | bytes32 fdat;
496 | {
497 | (, bytes memory rdat) = who.staticcall(cald);
498 | fdat = bytesToBytes32(rdat, 32*field_depth);
499 | }
500 |
501 | (bytes32[] memory reads, ) = vm_std_store.accesses(address(who));
502 | if (reads.length == 1) {
503 | bytes32 curr = vm_std_store.load(who, reads[0]);
504 | if (curr == bytes32(0)) {
505 | emit WARNING_UninitedSlot(who, uint256(reads[0]));
506 | }
507 | if (fdat != curr) {
508 | require(false, "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported.");
509 | }
510 | emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0]));
511 | self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]);
512 | self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true;
513 | } else if (reads.length > 1) {
514 | for (uint256 i = 0; i < reads.length; i++) {
515 | bytes32 prev = vm_std_store.load(who, reads[i]);
516 | if (prev == bytes32(0)) {
517 | emit WARNING_UninitedSlot(who, uint256(reads[i]));
518 | }
519 | // store
520 | vm_std_store.store(who, reads[i], bytes32(hex"1337"));
521 | bool success;
522 | bytes memory rdat;
523 | {
524 | (success, rdat) = who.staticcall(cald);
525 | fdat = bytesToBytes32(rdat, 32*field_depth);
526 | }
527 |
528 | if (success && fdat == bytes32(hex"1337")) {
529 | // we found which of the slots is the actual one
530 | emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i]));
531 | self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]);
532 | self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true;
533 | vm_std_store.store(who, reads[i], prev);
534 | break;
535 | }
536 | vm_std_store.store(who, reads[i], prev);
537 | }
538 | } else {
539 | require(false, "stdStorage find(StdStorage): No storage use detected for target.");
540 | }
541 |
542 | require(self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))], "stdStorage find(StdStorage): Slot(s) not found.");
543 |
544 | delete self._target;
545 | delete self._sig;
546 | delete self._keys;
547 | delete self._depth;
548 |
549 | return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
550 | }
551 |
552 | function target(StdStorage storage self, address _target) internal returns (StdStorage storage) {
553 | self._target = _target;
554 | return self;
555 | }
556 |
557 | function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) {
558 | self._sig = _sig;
559 | return self;
560 | }
561 |
562 | function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) {
563 | self._sig = sigs(_sig);
564 | return self;
565 | }
566 |
567 | function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) {
568 | self._keys.push(bytes32(uint256(uint160(who))));
569 | return self;
570 | }
571 |
572 | function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) {
573 | self._keys.push(bytes32(amt));
574 | return self;
575 | }
576 | function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) {
577 | self._keys.push(key);
578 | return self;
579 | }
580 |
581 | function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) {
582 | self._depth = _depth;
583 | return self;
584 | }
585 |
586 | function checked_write(StdStorage storage self, address who) internal {
587 | checked_write(self, bytes32(uint256(uint160(who))));
588 | }
589 |
590 | function checked_write(StdStorage storage self, uint256 amt) internal {
591 | checked_write(self, bytes32(amt));
592 | }
593 |
594 | function checked_write(StdStorage storage self, bool write) internal {
595 | bytes32 t;
596 | /// @solidity memory-safe-assembly
597 | assembly {
598 | t := write
599 | }
600 | checked_write(self, t);
601 | }
602 |
603 | function checked_write(
604 | StdStorage storage self,
605 | bytes32 set
606 | ) internal {
607 | address who = self._target;
608 | bytes4 fsig = self._sig;
609 | uint256 field_depth = self._depth;
610 | bytes32[] memory ins = self._keys;
611 |
612 | bytes memory cald = abi.encodePacked(fsig, flatten(ins));
613 | if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) {
614 | find(self);
615 | }
616 | bytes32 slot = bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]);
617 |
618 | bytes32 fdat;
619 | {
620 | (, bytes memory rdat) = who.staticcall(cald);
621 | fdat = bytesToBytes32(rdat, 32*field_depth);
622 | }
623 | bytes32 curr = vm_std_store.load(who, slot);
624 |
625 | if (fdat != curr) {
626 | require(false, "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported.");
627 | }
628 | vm_std_store.store(who, slot, set);
629 | delete self._target;
630 | delete self._sig;
631 | delete self._keys;
632 | delete self._depth;
633 | }
634 |
635 | function read(StdStorage storage self) private returns (bytes memory) {
636 | address t = self._target;
637 | uint256 s = find(self);
638 | return abi.encode(vm_std_store.load(t, bytes32(s)));
639 | }
640 |
641 | function read_bytes32(StdStorage storage self) internal returns (bytes32) {
642 | return abi.decode(read(self), (bytes32));
643 | }
644 |
645 |
646 | function read_bool(StdStorage storage self) internal returns (bool) {
647 | int256 v = read_int(self);
648 | if (v == 0) return false;
649 | if (v == 1) return true;
650 | revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool.");
651 | }
652 |
653 | function read_address(StdStorage storage self) internal returns (address) {
654 | return abi.decode(read(self), (address));
655 | }
656 |
657 | function read_uint(StdStorage storage self) internal returns (uint256) {
658 | return abi.decode(read(self), (uint256));
659 | }
660 |
661 | function read_int(StdStorage storage self) internal returns (int256) {
662 | return abi.decode(read(self), (int256));
663 | }
664 |
665 | function bytesToBytes32(bytes memory b, uint offset) public pure returns (bytes32) {
666 | bytes32 out;
667 |
668 | uint256 max = b.length > 32 ? 32 : b.length;
669 | for (uint i = 0; i < max; i++) {
670 | out |= bytes32(b[offset + i] & 0xFF) >> (i * 8);
671 | }
672 | return out;
673 | }
674 |
675 | function flatten(bytes32[] memory b) private pure returns (bytes memory)
676 | {
677 | bytes memory result = new bytes(b.length * 32);
678 | for (uint256 i = 0; i < b.length; i++) {
679 | bytes32 k = b[i];
680 | /// @solidity memory-safe-assembly
681 | assembly {
682 | mstore(add(result, add(32, mul(32, i))), k)
683 | }
684 | }
685 |
686 | return result;
687 | }
688 | }
689 |
690 | /*//////////////////////////////////////////////////////////////////////////
691 | STD-MATH
692 | //////////////////////////////////////////////////////////////////////////*/
693 |
694 | library stdMath {
695 | int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968;
696 |
697 | function abs(int256 a) internal pure returns (uint256) {
698 | // Required or it will fail when `a = type(int256).min`
699 | if (a == INT256_MIN)
700 | return 57896044618658097711785492504343953926634992332820282019728792003956564819968;
701 |
702 | return uint256(a >= 0 ? a : -a);
703 | }
704 |
705 | function delta(uint256 a, uint256 b) internal pure returns (uint256) {
706 | return a > b
707 | ? a - b
708 | : b - a;
709 | }
710 |
711 | function delta(int256 a, int256 b) internal pure returns (uint256) {
712 | // a and b are of the same sign
713 | if (a >= 0 && b >= 0 || a < 0 && b < 0) {
714 | return delta(abs(a), abs(b));
715 | }
716 |
717 | // a and b are of opposite signs
718 | return abs(a) + abs(b);
719 | }
720 |
721 | function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) {
722 | uint256 absDelta = delta(a, b);
723 |
724 | return absDelta * 1e18 / b;
725 | }
726 |
727 | function percentDelta(int256 a, int256 b) internal pure returns (uint256) {
728 | uint256 absDelta = delta(a, b);
729 | uint256 absB = abs(b);
730 |
731 | return absDelta * 1e18 / absB;
732 | }
733 | }
734 |
--------------------------------------------------------------------------------
/lib/forge-std/src/Vm.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Unlicense
2 | pragma solidity >=0.6.0;
3 | pragma experimental ABIEncoderV2;
4 |
5 | interface Vm {
6 | // Sets block.timestamp (newTimestamp)
7 | function warp(uint256) external;
8 | // Sets block.height (newHeight)
9 | function roll(uint256) external;
10 | // Sets block.basefee (newBasefee)
11 | function fee(uint256) external;
12 | // Sets block.chainid
13 | function chainId(uint256) external;
14 | // Loads a storage slot from an address (who, slot)
15 | function load(address,bytes32) external returns (bytes32);
16 | // Stores a value to an address' storage slot, (who, slot, value)
17 | function store(address,bytes32,bytes32) external;
18 | // Signs data, (privateKey, digest) => (v, r, s)
19 | function sign(uint256,bytes32) external returns (uint8,bytes32,bytes32);
20 | // Gets the address for a given private key, (privateKey) => (address)
21 | function addr(uint256) external returns (address);
22 | // Gets the nonce of an account
23 | function getNonce(address) external returns (uint64);
24 | // Sets the nonce of an account; must be higher than the current nonce of the account
25 | function setNonce(address, uint64) external;
26 | // Performs a foreign function call via the terminal, (stringInputs) => (result)
27 | function ffi(string[] calldata) external returns (bytes memory);
28 | // Sets environment variables, (name, value)
29 | function setEnv(string calldata, string calldata) external;
30 | // Reads environment variables, (name) => (value)
31 | function envBool(string calldata) external returns (bool);
32 | function envUint(string calldata) external returns (uint256);
33 | function envInt(string calldata) external returns (int256);
34 | function envAddress(string calldata) external returns (address);
35 | function envBytes32(string calldata) external returns (bytes32);
36 | function envString(string calldata) external returns (string memory);
37 | function envBytes(string calldata) external returns (bytes memory);
38 | // Reads environment variables as arrays, (name, delim) => (value[])
39 | function envBool(string calldata, string calldata) external returns (bool[] memory);
40 | function envUint(string calldata, string calldata) external returns (uint256[] memory);
41 | function envInt(string calldata, string calldata) external returns (int256[] memory);
42 | function envAddress(string calldata, string calldata) external returns (address[] memory);
43 | function envBytes32(string calldata, string calldata) external returns (bytes32[] memory);
44 | function envString(string calldata, string calldata) external returns (string[] memory);
45 | function envBytes(string calldata, string calldata) external returns (bytes[] memory);
46 | // Sets the *next* call's msg.sender to be the input address
47 | function prank(address) external;
48 | // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called
49 | function startPrank(address) external;
50 | // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input
51 | function prank(address,address) external;
52 | // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input
53 | function startPrank(address,address) external;
54 | // Resets subsequent calls' msg.sender to be `address(this)`
55 | function stopPrank() external;
56 | // Sets an address' balance, (who, newBalance)
57 | function deal(address, uint256) external;
58 | // Sets an address' code, (who, newCode)
59 | function etch(address, bytes calldata) external;
60 | // Expects an error on next call
61 | function expectRevert(bytes calldata) external;
62 | function expectRevert(bytes4) external;
63 | function expectRevert() external;
64 | // Records all storage reads and writes
65 | function record() external;
66 | // Gets all accessed reads and write slot from a recording session, for a given address
67 | function accesses(address) external returns (bytes32[] memory reads, bytes32[] memory writes);
68 | // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData).
69 | // Call this function, then emit an event, then call a function. Internally after the call, we check if
70 | // logs were emitted in the expected order with the expected topics and data (as specified by the booleans)
71 | function expectEmit(bool,bool,bool,bool) external;
72 | function expectEmit(bool,bool,bool,bool,address) external;
73 | // Mocks a call to an address, returning specified data.
74 | // Calldata can either be strict or a partial match, e.g. if you only
75 | // pass a Solidity selector to the expected calldata, then the entire Solidity
76 | // function will be mocked.
77 | function mockCall(address,bytes calldata,bytes calldata) external;
78 | // Mocks a call to an address with a specific msg.value, returning specified data.
79 | // Calldata match takes precedence over msg.value in case of ambiguity.
80 | function mockCall(address,uint256,bytes calldata,bytes calldata) external;
81 | // Clears all mocked calls
82 | function clearMockedCalls() external;
83 | // Expects a call to an address with the specified calldata.
84 | // Calldata can either be a strict or a partial match
85 | function expectCall(address,bytes calldata) external;
86 | // Expects a call to an address with the specified msg.value and calldata
87 | function expectCall(address,uint256,bytes calldata) external;
88 | // Gets the code from an artifact file. Takes in the relative path to the json file
89 | function getCode(string calldata) external returns (bytes memory);
90 | // Labels an address in call traces
91 | function label(address, string calldata) external;
92 | // If the condition is false, discard this run's fuzz inputs and generate new ones
93 | function assume(bool) external;
94 | // Sets block.coinbase (who)
95 | function coinbase(address) external;
96 | // Using the address that calls the test contract, has the next call (at this call depth only) create a transaction that can later be signed and sent onchain
97 | function broadcast() external;
98 | // Has the next call (at this call depth only) create a transaction with the address provided as the sender that can later be signed and sent onchain
99 | function broadcast(address) external;
100 | // Using the address that calls the test contract, has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain
101 | function startBroadcast() external;
102 | // Has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain
103 | function startBroadcast(address) external;
104 | // Stops collecting onchain transactions
105 | function stopBroadcast() external;
106 | // Reads the entire content of file to string, (path) => (data)
107 | function readFile(string calldata) external returns (string memory);
108 | // Reads next line of file to string, (path) => (line)
109 | function readLine(string calldata) external returns (string memory);
110 | // Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does.
111 | // (path, data) => ()
112 | function writeFile(string calldata, string calldata) external;
113 | // Writes line to file, creating a file if it does not exist.
114 | // (path, data) => ()
115 | function writeLine(string calldata, string calldata) external;
116 | // Closes file for reading, resetting the offset and allowing to read it from beginning with readLine.
117 | // (path) => ()
118 | function closeFile(string calldata) external;
119 | // Removes file. This cheatcode will revert in the following situations, but is not limited to just these cases:
120 | // - Path points to a directory.
121 | // - The file doesn't exist.
122 | // - The user lacks permissions to remove the file.
123 | // (path) => ()
124 | function removeFile(string calldata) external;
125 | }
126 |
--------------------------------------------------------------------------------
/lib/forge-std/src/test/StdAssertions.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Unlicense
2 | pragma solidity >=0.7.0 <0.9.0;
3 |
4 | import "../Test.sol";
5 |
6 | contract StdAssertionsTest is Test
7 | {
8 | string constant CUSTOM_ERROR = "guh!";
9 |
10 | bool constant EXPECT_PASS = false;
11 | bool constant EXPECT_FAIL = true;
12 |
13 | TestTest t = new TestTest();
14 |
15 | /*//////////////////////////////////////////////////////////////////////////
16 | FAIL(STRING)
17 | //////////////////////////////////////////////////////////////////////////*/
18 |
19 | function testShouldFail() external {
20 | vm.expectEmit(false, false, false, true);
21 | emit log_named_string("Error", CUSTOM_ERROR);
22 | t._fail(CUSTOM_ERROR);
23 | }
24 |
25 | /*//////////////////////////////////////////////////////////////////////////
26 | ASSERT_FALSE
27 | //////////////////////////////////////////////////////////////////////////*/
28 |
29 | function testAssertFalse_Pass() external {
30 | t._assertFalse(false, EXPECT_PASS);
31 | }
32 |
33 | function testAssertFalse_Fail() external {
34 | vm.expectEmit(false, false, false, true);
35 | emit log("Error: Assertion Failed");
36 | t._assertFalse(true, EXPECT_FAIL);
37 | }
38 |
39 | function testAssertFalse_Err_Pass() external {
40 | t._assertFalse(false, CUSTOM_ERROR, EXPECT_PASS);
41 | }
42 |
43 | function testAssertFalse_Err_Fail() external {
44 | vm.expectEmit(false, false, false, true);
45 | emit log_named_string("Error", CUSTOM_ERROR);
46 | t._assertFalse(true, CUSTOM_ERROR, EXPECT_FAIL);
47 | }
48 |
49 | /*//////////////////////////////////////////////////////////////////////////
50 | ASSERT_EQ(BOOL)
51 | //////////////////////////////////////////////////////////////////////////*/
52 |
53 | function testAssertEq_Bool_Pass(bool a, bool b) external {
54 | vm.assume(a == b);
55 |
56 | t._assertEq(a, b, EXPECT_PASS);
57 | }
58 |
59 | function testAssertEq_Bool_Fail(bool a, bool b) external {
60 | vm.assume(a != b);
61 |
62 | vm.expectEmit(false, false, false, true);
63 | emit log("Error: a == b not satisfied [bool]");
64 | t._assertEq(a, b, EXPECT_FAIL);
65 | }
66 |
67 | function testAssertEq_BoolErr_Pass(bool a, bool b) external {
68 | vm.assume(a == b);
69 |
70 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_PASS);
71 | }
72 |
73 | function testAssertEq_BoolErr_Fail(bool a, bool b) external {
74 | vm.assume(a != b);
75 |
76 | vm.expectEmit(false, false, false, true);
77 | emit log_named_string("Error", CUSTOM_ERROR);
78 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL);
79 | }
80 |
81 | /*//////////////////////////////////////////////////////////////////////////
82 | ASSERT_EQ(BYTES)
83 | //////////////////////////////////////////////////////////////////////////*/
84 |
85 | function testAssertEq_Bytes_Pass(bytes calldata a, bytes calldata b) external {
86 | vm.assume(keccak256(a) == keccak256(b));
87 |
88 | t._assertEq(a, b, EXPECT_PASS);
89 | }
90 |
91 | function testAssertEq_Bytes_Fail(bytes calldata a, bytes calldata b) external {
92 | vm.assume(keccak256(a) != keccak256(b));
93 |
94 | vm.expectEmit(false, false, false, true);
95 | emit log("Error: a == b not satisfied [bytes]");
96 | t._assertEq(a, b, EXPECT_FAIL);
97 | }
98 |
99 | function testAssertEq_BytesErr_Pass(bytes calldata a, bytes calldata b) external {
100 | vm.assume(keccak256(a) == keccak256(b));
101 |
102 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_PASS);
103 | }
104 |
105 | function testAssertEq_BytesErr_Fail(bytes calldata a, bytes calldata b) external {
106 | vm.assume(keccak256(a) != keccak256(b));
107 |
108 | vm.expectEmit(false, false, false, true);
109 | emit log_named_string("Error", CUSTOM_ERROR);
110 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL);
111 | }
112 |
113 | /*//////////////////////////////////////////////////////////////////////////
114 | ASSERT_EQ(ARRAY)
115 | //////////////////////////////////////////////////////////////////////////*/
116 |
117 | function testAssertEq_UintArr_Pass(uint256 e0, uint256 e1, uint256 e2) public {
118 | uint256[] memory a = new uint256[](3);
119 | a[0] = e0;
120 | a[1] = e1;
121 | a[2] = e2;
122 | uint256[] memory b = new uint256[](3);
123 | b[0] = e0;
124 | b[1] = e1;
125 | b[2] = e2;
126 |
127 | t._assertEq(a, b, EXPECT_PASS);
128 | }
129 |
130 | function testAssertEq_IntArr_Pass(int256 e0, int256 e1, int256 e2) public {
131 | int256[] memory a = new int256[](3);
132 | a[0] = e0;
133 | a[1] = e1;
134 | a[2] = e2;
135 | int256[] memory b = new int256[](3);
136 | b[0] = e0;
137 | b[1] = e1;
138 | b[2] = e2;
139 |
140 | t._assertEq(a, b, EXPECT_PASS);
141 | }
142 |
143 | function testAssertEq_AddressArr_Pass(address e0, address e1, address e2) public {
144 | address[] memory a = new address[](3);
145 | a[0] = e0;
146 | a[1] = e1;
147 | a[2] = e2;
148 | address[] memory b = new address[](3);
149 | b[0] = e0;
150 | b[1] = e1;
151 | b[2] = e2;
152 |
153 | t._assertEq(a, b, EXPECT_PASS);
154 | }
155 |
156 | function testAssertEq_UintArr_FailEl(uint256 e1) public {
157 | vm.assume(e1 != 0);
158 | uint256[] memory a = new uint256[](3);
159 | uint256[] memory b = new uint256[](3);
160 | b[1] = e1;
161 |
162 | vm.expectEmit(false, false, false, true);
163 | emit log("Error: a == b not satisfied [uint[]]");
164 | t._assertEq(a, b, EXPECT_FAIL);
165 | }
166 |
167 | function testAssertEq_IntArr_FailEl(int256 e1) public {
168 | vm.assume(e1 != 0);
169 | int256[] memory a = new int256[](3);
170 | int256[] memory b = new int256[](3);
171 | b[1] = e1;
172 |
173 | vm.expectEmit(false, false, false, true);
174 | emit log("Error: a == b not satisfied [int[]]");
175 | t._assertEq(a, b, EXPECT_FAIL);
176 | }
177 |
178 |
179 | function testAssertEq_AddressArr_FailEl(address e1) public {
180 | vm.assume(e1 != address(0));
181 | address[] memory a = new address[](3);
182 | address[] memory b = new address[](3);
183 | b[1] = e1;
184 |
185 | vm.expectEmit(false, false, false, true);
186 | emit log("Error: a == b not satisfied [address[]]");
187 | t._assertEq(a, b, EXPECT_FAIL);
188 | }
189 |
190 | function testAssertEq_UintArrErr_FailEl(uint256 e1) public {
191 | vm.assume(e1 != 0);
192 | uint256[] memory a = new uint256[](3);
193 | uint256[] memory b = new uint256[](3);
194 | b[1] = e1;
195 |
196 | vm.expectEmit(false, false, false, true);
197 | emit log_named_string("Error", CUSTOM_ERROR);
198 | vm.expectEmit(false, false, false, true);
199 | emit log("Error: a == b not satisfied [uint[]]");
200 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL);
201 | }
202 |
203 | function testAssertEq_IntArrErr_FailEl(int256 e1) public {
204 | vm.assume(e1 != 0);
205 | int256[] memory a = new int256[](3);
206 | int256[] memory b = new int256[](3);
207 | b[1] = e1;
208 |
209 | vm.expectEmit(false, false, false, true);
210 | emit log_named_string("Error", CUSTOM_ERROR);
211 | vm.expectEmit(false, false, false, true);
212 | emit log("Error: a == b not satisfied [int[]]");
213 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL);
214 | }
215 |
216 |
217 | function testAssertEq_AddressArrErr_FailEl(address e1) public {
218 | vm.assume(e1 != address(0));
219 | address[] memory a = new address[](3);
220 | address[] memory b = new address[](3);
221 | b[1] = e1;
222 |
223 | vm.expectEmit(false, false, false, true);
224 | emit log_named_string("Error", CUSTOM_ERROR);
225 | vm.expectEmit(false, false, false, true);
226 | emit log("Error: a == b not satisfied [address[]]");
227 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL);
228 | }
229 |
230 | function testAssertEq_UintArr_FailLen(uint256 lenA, uint256 lenB) public {
231 | vm.assume(lenA != lenB);
232 | vm.assume(lenA <= 10000);
233 | vm.assume(lenB <= 10000);
234 | uint256[] memory a = new uint256[](lenA);
235 | uint256[] memory b = new uint256[](lenB);
236 |
237 | vm.expectEmit(false, false, false, true);
238 | emit log("Error: a == b not satisfied [uint[]]");
239 | t._assertEq(a, b, EXPECT_FAIL);
240 | }
241 |
242 | function testAssertEq_IntArr_FailLen(uint256 lenA, uint256 lenB) public {
243 | vm.assume(lenA != lenB);
244 | vm.assume(lenA <= 10000);
245 | vm.assume(lenB <= 10000);
246 | int256[] memory a = new int256[](lenA);
247 | int256[] memory b = new int256[](lenB);
248 |
249 | vm.expectEmit(false, false, false, true);
250 | emit log("Error: a == b not satisfied [int[]]");
251 | t._assertEq(a, b, EXPECT_FAIL);
252 | }
253 |
254 | function testAssertEq_AddressArr_FailLen(uint256 lenA, uint256 lenB) public {
255 | vm.assume(lenA != lenB);
256 | vm.assume(lenA <= 10000);
257 | vm.assume(lenB <= 10000);
258 | address[] memory a = new address[](lenA);
259 | address[] memory b = new address[](lenB);
260 |
261 | vm.expectEmit(false, false, false, true);
262 | emit log("Error: a == b not satisfied [address[]]");
263 | t._assertEq(a, b, EXPECT_FAIL);
264 | }
265 |
266 | function testAssertEq_UintArrErr_FailLen(uint256 lenA, uint256 lenB) public {
267 | vm.assume(lenA != lenB);
268 | vm.assume(lenA <= 10000);
269 | vm.assume(lenB <= 10000);
270 | uint256[] memory a = new uint256[](lenA);
271 | uint256[] memory b = new uint256[](lenB);
272 |
273 | vm.expectEmit(false, false, false, true);
274 | emit log_named_string("Error", CUSTOM_ERROR);
275 | vm.expectEmit(false, false, false, true);
276 | emit log("Error: a == b not satisfied [uint[]]");
277 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL);
278 | }
279 |
280 | function testAssertEq_IntArrErr_FailLen(uint256 lenA, uint256 lenB) public {
281 | vm.assume(lenA != lenB);
282 | vm.assume(lenA <= 10000);
283 | vm.assume(lenB <= 10000);
284 | int256[] memory a = new int256[](lenA);
285 | int256[] memory b = new int256[](lenB);
286 |
287 | vm.expectEmit(false, false, false, true);
288 | emit log_named_string("Error", CUSTOM_ERROR);
289 | vm.expectEmit(false, false, false, true);
290 | emit log("Error: a == b not satisfied [int[]]");
291 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL);
292 | }
293 |
294 | function testAssertEq_AddressArrErr_FailLen(uint256 lenA, uint256 lenB) public {
295 | vm.assume(lenA != lenB);
296 | vm.assume(lenA <= 10000);
297 | vm.assume(lenB <= 10000);
298 | address[] memory a = new address[](lenA);
299 | address[] memory b = new address[](lenB);
300 |
301 | vm.expectEmit(false, false, false, true);
302 | emit log_named_string("Error", CUSTOM_ERROR);
303 | vm.expectEmit(false, false, false, true);
304 | emit log("Error: a == b not satisfied [address[]]");
305 | t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL);
306 | }
307 |
308 | /*//////////////////////////////////////////////////////////////////////////
309 | APPROX_EQ_ABS(UINT)
310 | //////////////////////////////////////////////////////////////////////////*/
311 |
312 | function testAssertApproxEqAbs_Uint_Pass(uint256 a, uint256 b, uint256 maxDelta) external {
313 | vm.assume(stdMath.delta(a, b) <= maxDelta);
314 |
315 | t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS);
316 | }
317 |
318 | function testAssertApproxEqAbs_Uint_Fail(uint256 a, uint256 b, uint256 maxDelta) external {
319 | vm.assume(stdMath.delta(a, b) > maxDelta);
320 |
321 | vm.expectEmit(false, false, false, true);
322 | emit log("Error: a ~= b not satisfied [uint]");
323 | t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL);
324 | }
325 |
326 | function testAssertApproxEqAbs_UintErr_Pass(uint256 a, uint256 b, uint256 maxDelta) external {
327 | vm.assume(stdMath.delta(a, b) <= maxDelta);
328 |
329 | t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS);
330 | }
331 |
332 | function testAssertApproxEqAbs_UintErr_Fail(uint256 a, uint256 b, uint256 maxDelta) external {
333 | vm.assume(stdMath.delta(a, b) > maxDelta);
334 |
335 | vm.expectEmit(false, false, false, true);
336 | emit log_named_string("Error", CUSTOM_ERROR);
337 | t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL);
338 | }
339 |
340 | /*//////////////////////////////////////////////////////////////////////////
341 | APPROX_EQ_ABS(INT)
342 | //////////////////////////////////////////////////////////////////////////*/
343 |
344 | function testAssertApproxEqAbs_Int_Pass(int256 a, int256 b, uint256 maxDelta) external {
345 | vm.assume(stdMath.delta(a, b) <= maxDelta);
346 |
347 | t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS);
348 | }
349 |
350 | function testAssertApproxEqAbs_Int_Fail(int256 a, int256 b, uint256 maxDelta) external {
351 | vm.assume(stdMath.delta(a, b) > maxDelta);
352 |
353 | vm.expectEmit(false, false, false, true);
354 | emit log("Error: a ~= b not satisfied [int]");
355 | t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL);
356 | }
357 |
358 | function testAssertApproxEqAbs_IntErr_Pass(int256 a, int256 b, uint256 maxDelta) external {
359 | vm.assume(stdMath.delta(a, b) <= maxDelta);
360 |
361 | t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS);
362 | }
363 |
364 | function testAssertApproxEqAbs_IntErr_Fail(int256 a, int256 b, uint256 maxDelta) external {
365 | vm.assume(stdMath.delta(a, b) > maxDelta);
366 |
367 | vm.expectEmit(false, false, false, true);
368 | emit log_named_string("Error", CUSTOM_ERROR);
369 | t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL);
370 | }
371 |
372 | /*//////////////////////////////////////////////////////////////////////////
373 | APPROX_EQ_REL(UINT)
374 | //////////////////////////////////////////////////////////////////////////*/
375 |
376 | function testAssertApproxEqRel_Uint_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external {
377 | vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0);
378 | vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta);
379 |
380 | t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS);
381 | }
382 |
383 | function testAssertApproxEqRel_Uint_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external {
384 | vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0);
385 | vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta);
386 |
387 | vm.expectEmit(false, false, false, true);
388 | emit log("Error: a ~= b not satisfied [uint]");
389 | t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL);
390 | }
391 |
392 | function testAssertApproxEqRel_UintErr_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external {
393 | vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0);
394 | vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta);
395 |
396 | t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS);
397 | }
398 |
399 | function testAssertApproxEqRel_UintErr_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external {
400 | vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0);
401 | vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta);
402 |
403 | vm.expectEmit(false, false, false, true);
404 | emit log_named_string("Error", CUSTOM_ERROR);
405 | t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL);
406 | }
407 |
408 | /*//////////////////////////////////////////////////////////////////////////
409 | APPROX_EQ_REL(INT)
410 | //////////////////////////////////////////////////////////////////////////*/
411 |
412 | function testAssertApproxEqRel_Int_Pass(int128 a, int128 b, uint128 maxPercentDelta) external {
413 | vm.assume(b != 0);
414 | vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta);
415 |
416 | t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS);
417 | }
418 |
419 | function testAssertApproxEqRel_Int_Fail(int128 a, int128 b, uint128 maxPercentDelta) external {
420 | vm.assume(b != 0);
421 | vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta);
422 |
423 | vm.expectEmit(false, false, false, true);
424 | emit log("Error: a ~= b not satisfied [int]");
425 | t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL);
426 | }
427 |
428 | function testAssertApproxEqRel_IntErr_Pass(int128 a, int128 b, uint128 maxPercentDelta) external {
429 | vm.assume(b != 0);
430 | vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta);
431 |
432 | t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS);
433 | }
434 |
435 | function testAssertApproxEqRel_IntErr_Fail(int128 a, int128 b, uint128 maxPercentDelta) external {
436 | vm.assume(b != 0);
437 | vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta);
438 |
439 | vm.expectEmit(false, false, false, true);
440 | emit log_named_string("Error", CUSTOM_ERROR);
441 | t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL);
442 | }
443 | }
444 |
445 |
446 | contract TestTest is Test
447 | {
448 | modifier expectFailure(bool expectFail) {
449 | bool preState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00);
450 | _;
451 | bool postState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00);
452 |
453 | if (preState == true) {
454 | return;
455 | }
456 |
457 | if (expectFail) {
458 | require(postState == true, "expected failure not triggered");
459 |
460 | // unwind the expected failure
461 | vm.store(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x00)));
462 | } else {
463 | require(postState == false, "unexpected failure was triggered");
464 | }
465 | }
466 |
467 | function _fail(string memory err) external expectFailure(true) {
468 | fail(err);
469 | }
470 |
471 | function _assertFalse(bool data, bool expectFail) external expectFailure(expectFail) {
472 | assertFalse(data);
473 | }
474 |
475 | function _assertFalse(bool data, string memory err, bool expectFail) external expectFailure(expectFail) {
476 | assertFalse(data, err);
477 | }
478 |
479 | function _assertEq(bool a, bool b, bool expectFail) external expectFailure(expectFail) {
480 | assertEq(a, b);
481 | }
482 |
483 | function _assertEq(bool a, bool b, string memory err, bool expectFail) external expectFailure(expectFail) {
484 | assertEq(a, b, err);
485 | }
486 |
487 | function _assertEq(bytes memory a, bytes memory b, bool expectFail) external expectFailure(expectFail) {
488 | assertEq(a, b);
489 | }
490 |
491 | function _assertEq(bytes memory a,
492 | bytes memory b,
493 | string memory err,
494 | bool expectFail
495 | ) external expectFailure(expectFail) {
496 | assertEq(a, b, err);
497 | }
498 |
499 | function _assertEq(uint256[] memory a, uint256[] memory b, bool expectFail) external expectFailure(expectFail) {
500 | assertEq(a, b);
501 | }
502 |
503 | function _assertEq(int256[] memory a, int256[] memory b, bool expectFail) external expectFailure(expectFail) {
504 | assertEq(a, b);
505 | }
506 |
507 | function _assertEq(address[] memory a, address[] memory b, bool expectFail) external expectFailure(expectFail) {
508 | assertEq(a, b);
509 | }
510 |
511 | function _assertEq(uint256[] memory a, uint256[] memory b, string memory err, bool expectFail) external expectFailure(expectFail) {
512 | assertEq(a, b, err);
513 | }
514 |
515 | function _assertEq(int256[] memory a, int256[] memory b, string memory err, bool expectFail) external expectFailure(expectFail) {
516 | assertEq(a, b, err);
517 | }
518 |
519 | function _assertEq(address[] memory a, address[] memory b, string memory err, bool expectFail) external expectFailure(expectFail) {
520 | assertEq(a, b, err);
521 | }
522 |
523 |
524 | function _assertApproxEqAbs(
525 | uint256 a,
526 | uint256 b,
527 | uint256 maxDelta,
528 | bool expectFail
529 | ) external expectFailure(expectFail) {
530 | assertApproxEqAbs(a, b, maxDelta);
531 | }
532 |
533 | function _assertApproxEqAbs(
534 | uint256 a,
535 | uint256 b,
536 | uint256 maxDelta,
537 | string memory err,
538 | bool expectFail
539 | ) external expectFailure(expectFail) {
540 | assertApproxEqAbs(a, b, maxDelta, err);
541 | }
542 |
543 | function _assertApproxEqAbs(
544 | int256 a,
545 | int256 b,
546 | uint256 maxDelta,
547 | bool expectFail
548 | ) external expectFailure(expectFail) {
549 | assertApproxEqAbs(a, b, maxDelta);
550 | }
551 |
552 | function _assertApproxEqAbs(
553 | int256 a,
554 | int256 b,
555 | uint256 maxDelta,
556 | string memory err,
557 | bool expectFail
558 | ) external expectFailure(expectFail) {
559 | assertApproxEqAbs(a, b, maxDelta, err);
560 | }
561 |
562 | function _assertApproxEqRel(
563 | uint256 a,
564 | uint256 b,
565 | uint256 maxPercentDelta,
566 | bool expectFail
567 | ) external expectFailure(expectFail) {
568 | assertApproxEqRel(a, b, maxPercentDelta);
569 | }
570 |
571 | function _assertApproxEqRel(
572 | uint256 a,
573 | uint256 b,
574 | uint256 maxPercentDelta,
575 | string memory err,
576 | bool expectFail
577 | ) external expectFailure(expectFail) {
578 | assertApproxEqRel(a, b, maxPercentDelta, err);
579 | }
580 |
581 | function _assertApproxEqRel(
582 | int256 a,
583 | int256 b,
584 | uint256 maxPercentDelta,
585 | bool expectFail
586 | ) external expectFailure(expectFail) {
587 | assertApproxEqRel(a, b, maxPercentDelta);
588 | }
589 |
590 | function _assertApproxEqRel(
591 | int256 a,
592 | int256 b,
593 | uint256 maxPercentDelta,
594 | string memory err,
595 | bool expectFail
596 | ) external expectFailure(expectFail) {
597 | assertApproxEqRel(a, b, maxPercentDelta, err);
598 | }
599 | }
600 |
--------------------------------------------------------------------------------
/lib/forge-std/src/test/StdCheats.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Unlicense
2 | pragma solidity >=0.7.0 <0.9.0;
3 |
4 | import "../Test.sol";
5 |
6 | contract StdCheatsTest is Test {
7 | Bar test;
8 |
9 | function setUp() public {
10 | test = new Bar();
11 | }
12 |
13 | function testSkip() public {
14 | vm.warp(100);
15 | skip(25);
16 | assertEq(block.timestamp, 125);
17 | }
18 |
19 | function testRewind() public {
20 | vm.warp(100);
21 | rewind(25);
22 | assertEq(block.timestamp, 75);
23 | }
24 |
25 | function testHoax() public {
26 | hoax(address(1337));
27 | test.bar{value: 100}(address(1337));
28 | }
29 |
30 | function testHoaxOrigin() public {
31 | hoax(address(1337), address(1337));
32 | test.origin{value: 100}(address(1337));
33 | }
34 |
35 | function testHoaxDifferentAddresses() public {
36 | hoax(address(1337), address(7331));
37 | test.origin{value: 100}(address(1337), address(7331));
38 | }
39 |
40 | function testStartHoax() public {
41 | startHoax(address(1337));
42 | test.bar{value: 100}(address(1337));
43 | test.bar{value: 100}(address(1337));
44 | vm.stopPrank();
45 | test.bar(address(this));
46 | }
47 |
48 | function testStartHoaxOrigin() public {
49 | startHoax(address(1337), address(1337));
50 | test.origin{value: 100}(address(1337));
51 | test.origin{value: 100}(address(1337));
52 | vm.stopPrank();
53 | test.bar(address(this));
54 | }
55 |
56 | function testChangePrank() public {
57 | vm.startPrank(address(1337));
58 | test.bar(address(1337));
59 | changePrank(address(0xdead));
60 | test.bar(address(0xdead));
61 | changePrank(address(1337));
62 | test.bar(address(1337));
63 | vm.stopPrank();
64 | }
65 |
66 | function testDeal() public {
67 | deal(address(this), 1 ether);
68 | assertEq(address(this).balance, 1 ether);
69 | }
70 |
71 | function testDealToken() public {
72 | Bar barToken = new Bar();
73 | address bar = address(barToken);
74 | deal(bar, address(this), 10000e18);
75 | assertEq(barToken.balanceOf(address(this)), 10000e18);
76 | }
77 |
78 | function testDealTokenAdjustTS() public {
79 | Bar barToken = new Bar();
80 | address bar = address(barToken);
81 | deal(bar, address(this), 10000e18, true);
82 | assertEq(barToken.balanceOf(address(this)), 10000e18);
83 | assertEq(barToken.totalSupply(), 20000e18);
84 | deal(bar, address(this), 0, true);
85 | assertEq(barToken.balanceOf(address(this)), 0);
86 | assertEq(barToken.totalSupply(), 10000e18);
87 | }
88 |
89 | function testBound() public {
90 | assertEq(bound(5, 0, 4), 0);
91 | assertEq(bound(0, 69, 69), 69);
92 | assertEq(bound(0, 68, 69), 68);
93 | assertEq(bound(10, 150, 190), 160);
94 | assertEq(bound(300, 2800, 3200), 3100);
95 | assertEq(bound(9999, 1337, 6666), 6006);
96 | }
97 |
98 | function testCannotBoundMaxLessThanMin() public {
99 | vm.expectRevert(bytes("Test bound(uint256,uint256,uint256): Max is less than min."));
100 | bound(5, 100, 10);
101 | }
102 |
103 | function testBound(
104 | uint256 num,
105 | uint256 min,
106 | uint256 max
107 | ) public {
108 | if (min > max) (min, max) = (max, min);
109 |
110 | uint256 bounded = bound(num, min, max);
111 |
112 | assertGe(bounded, min);
113 | assertLe(bounded, max);
114 | }
115 |
116 | function testBoundUint256Max() public {
117 | assertEq(bound(0, type(uint256).max - 1, type(uint256).max), type(uint256).max - 1);
118 | assertEq(bound(1, type(uint256).max - 1, type(uint256).max), type(uint256).max);
119 | }
120 |
121 | function testCannotBoundMaxLessThanMin(
122 | uint256 num,
123 | uint256 min,
124 | uint256 max
125 | ) public {
126 | vm.assume(min > max);
127 | vm.expectRevert(bytes("Test bound(uint256,uint256,uint256): Max is less than min."));
128 | bound(num, min, max);
129 | }
130 |
131 | function testDeployCode() public {
132 | address deployed = deployCode("StdCheats.t.sol:StdCheatsTest", bytes(""));
133 | assertEq(string(getCode(deployed)), string(getCode(address(this))));
134 | }
135 |
136 | function testDeployCodeNoArgs() public {
137 | address deployed = deployCode("StdCheats.t.sol:StdCheatsTest");
138 | assertEq(string(getCode(deployed)), string(getCode(address(this))));
139 | }
140 |
141 | function testDeployCodeFail() public {
142 | vm.expectRevert(bytes("Test deployCode(string): Deployment failed."));
143 | this.deployCode("StdCheats.t.sol:RevertingContract");
144 | }
145 |
146 | function getCode(address who) internal view returns (bytes memory o_code) {
147 | /// @solidity memory-safe-assembly
148 | assembly {
149 | // retrieve the size of the code, this needs assembly
150 | let size := extcodesize(who)
151 | // allocate output byte array - this could also be done without assembly
152 | // by using o_code = new bytes(size)
153 | o_code := mload(0x40)
154 | // new "memory end" including padding
155 | mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
156 | // store length in memory
157 | mstore(o_code, size)
158 | // actually retrieve the code, this needs assembly
159 | extcodecopy(who, add(o_code, 0x20), 0, size)
160 | }
161 | }
162 | }
163 |
164 | contract Bar {
165 | constructor() {
166 | /// `DEAL` STDCHEAT
167 | totalSupply = 10000e18;
168 | balanceOf[address(this)] = totalSupply;
169 | }
170 |
171 | /// `HOAX` STDCHEATS
172 | function bar(address expectedSender) public payable {
173 | require(msg.sender == expectedSender, "!prank");
174 | }
175 | function origin(address expectedSender) public payable {
176 | require(msg.sender == expectedSender, "!prank");
177 | require(tx.origin == expectedSender, "!prank");
178 | }
179 | function origin(address expectedSender, address expectedOrigin) public payable {
180 | require(msg.sender == expectedSender, "!prank");
181 | require(tx.origin == expectedOrigin, "!prank");
182 | }
183 |
184 | /// `DEAL` STDCHEAT
185 | mapping (address => uint256) public balanceOf;
186 | uint256 public totalSupply;
187 | }
188 |
189 | contract RevertingContract {
190 | constructor() {
191 | revert();
192 | }
193 | }
--------------------------------------------------------------------------------
/lib/forge-std/src/test/StdError.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Unlicense
2 | pragma solidity >=0.8.10 <0.9.0;
3 |
4 | import "../Test.sol";
5 |
6 | contract StdErrorsTest is Test {
7 | ErrorsTest test;
8 |
9 | function setUp() public {
10 | test = new ErrorsTest();
11 | }
12 |
13 | function testExpectAssertion() public {
14 | vm.expectRevert(stdError.assertionError);
15 | test.assertionError();
16 | }
17 |
18 | function testExpectArithmetic() public {
19 | vm.expectRevert(stdError.arithmeticError);
20 | test.arithmeticError(10);
21 | }
22 |
23 | function testExpectDiv() public {
24 | vm.expectRevert(stdError.divisionError);
25 | test.divError(0);
26 | }
27 |
28 | function testExpectMod() public {
29 | vm.expectRevert(stdError.divisionError);
30 | test.modError(0);
31 | }
32 |
33 | function testExpectEnum() public {
34 | vm.expectRevert(stdError.enumConversionError);
35 | test.enumConversion(1);
36 | }
37 |
38 | function testExpectEncodeStg() public {
39 | vm.expectRevert(stdError.encodeStorageError);
40 | test.encodeStgError();
41 | }
42 |
43 | function testExpectPop() public {
44 | vm.expectRevert(stdError.popError);
45 | test.pop();
46 | }
47 |
48 | function testExpectOOB() public {
49 | vm.expectRevert(stdError.indexOOBError);
50 | test.indexOOBError(1);
51 | }
52 |
53 | function testExpectMem() public {
54 | vm.expectRevert(stdError.memOverflowError);
55 | test.mem();
56 | }
57 |
58 | function testExpectIntern() public {
59 | vm.expectRevert(stdError.zeroVarError);
60 | test.intern();
61 | }
62 |
63 | function testExpectLowLvl() public {
64 | vm.expectRevert(stdError.lowLevelError);
65 | test.someArr(0);
66 | }
67 | }
68 |
69 | contract ErrorsTest {
70 | enum T {
71 | T1
72 | }
73 |
74 | uint256[] public someArr;
75 | bytes someBytes;
76 |
77 | function assertionError() public pure {
78 | assert(false);
79 | }
80 |
81 | function arithmeticError(uint256 a) public pure {
82 | a -= 100;
83 | }
84 |
85 | function divError(uint256 a) public pure {
86 | 100 / a;
87 | }
88 |
89 | function modError(uint256 a) public pure {
90 | 100 % a;
91 | }
92 |
93 | function enumConversion(uint256 a) public pure {
94 | T(a);
95 | }
96 |
97 | function encodeStgError() public {
98 | /// @solidity memory-safe-assembly
99 | assembly {
100 | sstore(someBytes.slot, 1)
101 | }
102 | keccak256(someBytes);
103 | }
104 |
105 | function pop() public {
106 | someArr.pop();
107 | }
108 |
109 | function indexOOBError(uint256 a) public pure {
110 | uint256[] memory t = new uint256[](0);
111 | t[a];
112 | }
113 |
114 | function mem() public pure {
115 | uint256 l = 2**256 / 32;
116 | new uint256[](l);
117 | }
118 |
119 | function intern() public returns (uint256) {
120 | function(uint256) internal returns (uint256) x;
121 | x(2);
122 | return 7;
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/lib/forge-std/src/test/StdMath.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Unlicense
2 | pragma solidity >=0.8.0 <0.9.0;
3 |
4 | import "../Test.sol";
5 |
6 | contract StdMathTest is Test
7 | {
8 | function testGetAbs() external {
9 | assertEq(stdMath.abs(-50), 50);
10 | assertEq(stdMath.abs(50), 50);
11 | assertEq(stdMath.abs(-1337), 1337);
12 | assertEq(stdMath.abs(0), 0);
13 |
14 | assertEq(stdMath.abs(type(int256).min), (type(uint256).max >> 1) + 1);
15 | assertEq(stdMath.abs(type(int256).max), (type(uint256).max >> 1));
16 | }
17 |
18 | function testGetAbs_Fuzz(int256 a) external {
19 | uint256 manualAbs = getAbs(a);
20 |
21 | uint256 abs = stdMath.abs(a);
22 |
23 | assertEq(abs, manualAbs);
24 | }
25 |
26 | function testGetDelta_Uint() external {
27 | assertEq(stdMath.delta(uint256(0), uint256(0)), 0);
28 | assertEq(stdMath.delta(uint256(0), uint256(1337)), 1337);
29 | assertEq(stdMath.delta(uint256(0), type(uint64).max), type(uint64).max);
30 | assertEq(stdMath.delta(uint256(0), type(uint128).max), type(uint128).max);
31 | assertEq(stdMath.delta(uint256(0), type(uint256).max), type(uint256).max);
32 |
33 | assertEq(stdMath.delta(0, uint256(0)), 0);
34 | assertEq(stdMath.delta(1337, uint256(0)), 1337);
35 | assertEq(stdMath.delta(type(uint64).max, uint256(0)), type(uint64).max);
36 | assertEq(stdMath.delta(type(uint128).max, uint256(0)), type(uint128).max);
37 | assertEq(stdMath.delta(type(uint256).max, uint256(0)), type(uint256).max);
38 |
39 | assertEq(stdMath.delta(1337, uint256(1337)), 0);
40 | assertEq(stdMath.delta(type(uint256).max, type(uint256).max), 0);
41 | assertEq(stdMath.delta(5000, uint256(1250)), 3750);
42 | }
43 |
44 | function testGetDelta_Uint_Fuzz(uint256 a, uint256 b) external {
45 | uint256 manualDelta;
46 | if (a > b) {
47 | manualDelta = a - b;
48 | } else {
49 | manualDelta = b - a;
50 | }
51 |
52 | uint256 delta = stdMath.delta(a, b);
53 |
54 | assertEq(delta, manualDelta);
55 | }
56 |
57 | function testGetDelta_Int() external {
58 | assertEq(stdMath.delta(int256(0), int256(0)), 0);
59 | assertEq(stdMath.delta(int256(0), int256(1337)), 1337);
60 | assertEq(stdMath.delta(int256(0), type(int64).max), type(uint64).max >> 1);
61 | assertEq(stdMath.delta(int256(0), type(int128).max), type(uint128).max >> 1);
62 | assertEq(stdMath.delta(int256(0), type(int256).max), type(uint256).max >> 1);
63 |
64 | assertEq(stdMath.delta(0, int256(0)), 0);
65 | assertEq(stdMath.delta(1337, int256(0)), 1337);
66 | assertEq(stdMath.delta(type(int64).max, int256(0)), type(uint64).max >> 1);
67 | assertEq(stdMath.delta(type(int128).max, int256(0)), type(uint128).max >> 1);
68 | assertEq(stdMath.delta(type(int256).max, int256(0)), type(uint256).max >> 1);
69 |
70 | assertEq(stdMath.delta(-0, int256(0)), 0);
71 | assertEq(stdMath.delta(-1337, int256(0)), 1337);
72 | assertEq(stdMath.delta(type(int64).min, int256(0)), (type(uint64).max >> 1) + 1);
73 | assertEq(stdMath.delta(type(int128).min, int256(0)), (type(uint128).max >> 1) + 1);
74 | assertEq(stdMath.delta(type(int256).min, int256(0)), (type(uint256).max >> 1) + 1);
75 |
76 | assertEq(stdMath.delta(int256(0), -0), 0);
77 | assertEq(stdMath.delta(int256(0), -1337), 1337);
78 | assertEq(stdMath.delta(int256(0), type(int64).min), (type(uint64).max >> 1) + 1);
79 | assertEq(stdMath.delta(int256(0), type(int128).min), (type(uint128).max >> 1) + 1);
80 | assertEq(stdMath.delta(int256(0), type(int256).min), (type(uint256).max >> 1) + 1);
81 |
82 | assertEq(stdMath.delta(1337, int256(1337)), 0);
83 | assertEq(stdMath.delta(type(int256).max, type(int256).max), 0);
84 | assertEq(stdMath.delta(type(int256).min, type(int256).min), 0);
85 | assertEq(stdMath.delta(type(int256).min, type(int256).max), type(uint256).max);
86 | assertEq(stdMath.delta(5000, int256(1250)), 3750);
87 | }
88 |
89 | function testGetDelta_Int_Fuzz(int256 a, int256 b) external {
90 | uint256 absA = getAbs(a);
91 | uint256 absB = getAbs(b);
92 | uint256 absDelta = absA > absB
93 | ? absA - absB
94 | : absB - absA;
95 |
96 | uint256 manualDelta;
97 | if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) {
98 | manualDelta = absDelta;
99 | }
100 | // (a < 0 && b >= 0) || (a >= 0 && b < 0)
101 | else {
102 | manualDelta = absA + absB;
103 | }
104 |
105 | uint256 delta = stdMath.delta(a, b);
106 |
107 | assertEq(delta, manualDelta);
108 | }
109 |
110 | function testGetPercentDelta_Uint() external {
111 | assertEq(stdMath.percentDelta(uint256(0), uint256(1337)), 1e18);
112 | assertEq(stdMath.percentDelta(uint256(0), type(uint64).max), 1e18);
113 | assertEq(stdMath.percentDelta(uint256(0), type(uint128).max), 1e18);
114 | assertEq(stdMath.percentDelta(uint256(0), type(uint192).max), 1e18);
115 |
116 | assertEq(stdMath.percentDelta(1337, uint256(1337)), 0);
117 | assertEq(stdMath.percentDelta(type(uint192).max, type(uint192).max), 0);
118 | assertEq(stdMath.percentDelta(0, uint256(2500)), 1e18);
119 | assertEq(stdMath.percentDelta(2500, uint256(2500)), 0);
120 | assertEq(stdMath.percentDelta(5000, uint256(2500)), 1e18);
121 | assertEq(stdMath.percentDelta(7500, uint256(2500)), 2e18);
122 |
123 | vm.expectRevert(stdError.divisionError);
124 | stdMath.percentDelta(uint256(1), 0);
125 | }
126 |
127 | function testGetPercentDelta_Uint_Fuzz(uint192 a, uint192 b) external {
128 | vm.assume(b != 0);
129 | uint256 manualDelta;
130 | if (a > b) {
131 | manualDelta = a - b;
132 | } else {
133 | manualDelta = b - a;
134 | }
135 |
136 | uint256 manualPercentDelta = manualDelta * 1e18 / b;
137 | uint256 percentDelta = stdMath.percentDelta(a, b);
138 |
139 | assertEq(percentDelta, manualPercentDelta);
140 | }
141 |
142 | function testGetPercentDelta_Int() external {
143 | assertEq(stdMath.percentDelta(int256(0), int256(1337)), 1e18);
144 | assertEq(stdMath.percentDelta(int256(0), -1337), 1e18);
145 | assertEq(stdMath.percentDelta(int256(0), type(int64).min), 1e18);
146 | assertEq(stdMath.percentDelta(int256(0), type(int128).min), 1e18);
147 | assertEq(stdMath.percentDelta(int256(0), type(int192).min), 1e18);
148 | assertEq(stdMath.percentDelta(int256(0), type(int64).max), 1e18);
149 | assertEq(stdMath.percentDelta(int256(0), type(int128).max), 1e18);
150 | assertEq(stdMath.percentDelta(int256(0), type(int192).max), 1e18);
151 |
152 | assertEq(stdMath.percentDelta(1337, int256(1337)), 0);
153 | assertEq(stdMath.percentDelta(type(int192).max, type(int192).max), 0);
154 | assertEq(stdMath.percentDelta(type(int192).min, type(int192).min), 0);
155 |
156 | assertEq(stdMath.percentDelta(type(int192).min, type(int192).max), 2e18); // rounds the 1 wei diff down
157 | assertEq(stdMath.percentDelta(type(int192).max, type(int192).min), 2e18 - 1); // rounds the 1 wei diff down
158 | assertEq(stdMath.percentDelta(0, int256(2500)), 1e18);
159 | assertEq(stdMath.percentDelta(2500, int256(2500)), 0);
160 | assertEq(stdMath.percentDelta(5000, int256(2500)), 1e18);
161 | assertEq(stdMath.percentDelta(7500, int256(2500)), 2e18);
162 |
163 | vm.expectRevert(stdError.divisionError);
164 | stdMath.percentDelta(int256(1), 0);
165 | }
166 |
167 | function testGetPercentDelta_Int_Fuzz(int192 a, int192 b) external {
168 | vm.assume(b != 0);
169 | uint256 absA = getAbs(a);
170 | uint256 absB = getAbs(b);
171 | uint256 absDelta = absA > absB
172 | ? absA - absB
173 | : absB - absA;
174 |
175 | uint256 manualDelta;
176 | if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) {
177 | manualDelta = absDelta;
178 | }
179 | // (a < 0 && b >= 0) || (a >= 0 && b < 0)
180 | else {
181 | manualDelta = absA + absB;
182 | }
183 |
184 | uint256 manualPercentDelta = manualDelta * 1e18 / absB;
185 | uint256 percentDelta = stdMath.percentDelta(a, b);
186 |
187 | assertEq(percentDelta, manualPercentDelta);
188 | }
189 |
190 | /*//////////////////////////////////////////////////////////////////////////
191 | HELPERS
192 | //////////////////////////////////////////////////////////////////////////*/
193 |
194 | function getAbs(int256 a) private pure returns (uint256) {
195 | if (a < 0)
196 | return a == type(int256).min ? uint256(type(int256).max) + 1 : uint256(-a);
197 |
198 | return uint256(a);
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/lib/forge-std/src/test/StdStorage.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Unlicense
2 | pragma solidity >=0.7.0 <0.9.0;
3 |
4 | import "../Test.sol";
5 |
6 | contract StdStorageTest is Test {
7 | using stdStorage for StdStorage;
8 |
9 | StorageTest test;
10 |
11 | function setUp() public {
12 | test = new StorageTest();
13 | }
14 |
15 | function testStorageHidden() public {
16 | assertEq(uint256(keccak256("my.random.var")), stdstore.target(address(test)).sig("hidden()").find());
17 | }
18 |
19 | function testStorageObvious() public {
20 | assertEq(uint256(0), stdstore.target(address(test)).sig("exists()").find());
21 | }
22 |
23 | function testStorageCheckedWriteHidden() public {
24 | stdstore.target(address(test)).sig(test.hidden.selector).checked_write(100);
25 | assertEq(uint256(test.hidden()), 100);
26 | }
27 |
28 | function testStorageCheckedWriteObvious() public {
29 | stdstore.target(address(test)).sig(test.exists.selector).checked_write(100);
30 | assertEq(test.exists(), 100);
31 | }
32 |
33 | function testStorageMapStructA() public {
34 | uint256 slot = stdstore
35 | .target(address(test))
36 | .sig(test.map_struct.selector)
37 | .with_key(address(this))
38 | .depth(0)
39 | .find();
40 | assertEq(uint256(keccak256(abi.encode(address(this), 4))), slot);
41 | }
42 |
43 | function testStorageMapStructB() public {
44 | uint256 slot = stdstore
45 | .target(address(test))
46 | .sig(test.map_struct.selector)
47 | .with_key(address(this))
48 | .depth(1)
49 | .find();
50 | assertEq(uint256(keccak256(abi.encode(address(this), 4))) + 1, slot);
51 | }
52 |
53 | function testStorageDeepMap() public {
54 | uint256 slot = stdstore
55 | .target(address(test))
56 | .sig(test.deep_map.selector)
57 | .with_key(address(this))
58 | .with_key(address(this))
59 | .find();
60 | assertEq(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint(5)))))), slot);
61 | }
62 |
63 | function testStorageCheckedWriteDeepMap() public {
64 | stdstore
65 | .target(address(test))
66 | .sig(test.deep_map.selector)
67 | .with_key(address(this))
68 | .with_key(address(this))
69 | .checked_write(100);
70 | assertEq(100, test.deep_map(address(this), address(this)));
71 | }
72 |
73 | function testStorageDeepMapStructA() public {
74 | uint256 slot = stdstore
75 | .target(address(test))
76 | .sig(test.deep_map_struct.selector)
77 | .with_key(address(this))
78 | .with_key(address(this))
79 | .depth(0)
80 | .find();
81 | assertEq(bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint(6)))))) + 0), bytes32(slot));
82 | }
83 |
84 | function testStorageDeepMapStructB() public {
85 | uint256 slot = stdstore
86 | .target(address(test))
87 | .sig(test.deep_map_struct.selector)
88 | .with_key(address(this))
89 | .with_key(address(this))
90 | .depth(1)
91 | .find();
92 | assertEq(bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint(6)))))) + 1), bytes32(slot));
93 | }
94 |
95 | function testStorageCheckedWriteDeepMapStructA() public {
96 | stdstore
97 | .target(address(test))
98 | .sig(test.deep_map_struct.selector)
99 | .with_key(address(this))
100 | .with_key(address(this))
101 | .depth(0)
102 | .checked_write(100);
103 | (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this));
104 | assertEq(100, a);
105 | assertEq(0, b);
106 | }
107 |
108 | function testStorageCheckedWriteDeepMapStructB() public {
109 | stdstore
110 | .target(address(test))
111 | .sig(test.deep_map_struct.selector)
112 | .with_key(address(this))
113 | .with_key(address(this))
114 | .depth(1)
115 | .checked_write(100);
116 | (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this));
117 | assertEq(0, a);
118 | assertEq(100, b);
119 | }
120 |
121 | function testStorageCheckedWriteMapStructA() public {
122 | stdstore
123 | .target(address(test))
124 | .sig(test.map_struct.selector)
125 | .with_key(address(this))
126 | .depth(0)
127 | .checked_write(100);
128 | (uint256 a, uint256 b) = test.map_struct(address(this));
129 | assertEq(a, 100);
130 | assertEq(b, 0);
131 | }
132 |
133 | function testStorageCheckedWriteMapStructB() public {
134 | stdstore
135 | .target(address(test))
136 | .sig(test.map_struct.selector)
137 | .with_key(address(this))
138 | .depth(1)
139 | .checked_write(100);
140 | (uint256 a, uint256 b) = test.map_struct(address(this));
141 | assertEq(a, 0);
142 | assertEq(b, 100);
143 | }
144 |
145 | function testStorageStructA() public {
146 | uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(0).find();
147 | assertEq(uint256(7), slot);
148 | }
149 |
150 | function testStorageStructB() public {
151 | uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(1).find();
152 | assertEq(uint256(7) + 1, slot);
153 | }
154 |
155 | function testStorageCheckedWriteStructA() public {
156 | stdstore.target(address(test)).sig(test.basic.selector).depth(0).checked_write(100);
157 | (uint256 a, uint256 b) = test.basic();
158 | assertEq(a, 100);
159 | assertEq(b, 1337);
160 | }
161 |
162 | function testStorageCheckedWriteStructB() public {
163 | stdstore.target(address(test)).sig(test.basic.selector).depth(1).checked_write(100);
164 | (uint256 a, uint256 b) = test.basic();
165 | assertEq(a, 1337);
166 | assertEq(b, 100);
167 | }
168 |
169 | function testStorageMapAddrFound() public {
170 | uint256 slot = stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).find();
171 | assertEq(uint256(keccak256(abi.encode(address(this), uint(1)))), slot);
172 | }
173 |
174 | function testStorageMapUintFound() public {
175 | uint256 slot = stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).find();
176 | assertEq(uint256(keccak256(abi.encode(100, uint(2)))), slot);
177 | }
178 |
179 | function testStorageCheckedWriteMapUint() public {
180 | stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).checked_write(100);
181 | assertEq(100, test.map_uint(100));
182 | }
183 |
184 | function testStorageCheckedWriteMapAddr() public {
185 | stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).checked_write(100);
186 | assertEq(100, test.map_addr(address(this)));
187 | }
188 |
189 | function testStorageCheckedWriteMapBool() public {
190 | stdstore.target(address(test)).sig(test.map_bool.selector).with_key(address(this)).checked_write(true);
191 | assertTrue(test.map_bool(address(this)));
192 | }
193 |
194 | function testFailStorageCheckedWriteMapPacked() public {
195 | // expect PackedSlot error but not external call so cant expectRevert
196 | stdstore.target(address(test)).sig(test.read_struct_lower.selector).with_key(address(uint160(1337))).checked_write(100);
197 | }
198 |
199 | function testStorageCheckedWriteMapPackedSuccess() public {
200 | uint256 full = test.map_packed(address(1337));
201 | // keep upper 128, set lower 128 to 1337
202 | full = (full & (uint256((1 << 128) - 1) << 128)) | 1337;
203 | stdstore.target(address(test)).sig(test.map_packed.selector).with_key(address(uint160(1337))).checked_write(full);
204 | assertEq(1337, test.read_struct_lower(address(1337)));
205 | }
206 |
207 | function testFailStorageConst() public {
208 | // vm.expectRevert(abi.encodeWithSignature("NotStorage(bytes4)", bytes4(keccak256("const()"))));
209 | stdstore.target(address(test)).sig("const()").find();
210 | }
211 |
212 | function testFailStorageNativePack() public {
213 | stdstore.target(address(test)).sig(test.tA.selector).find();
214 | stdstore.target(address(test)).sig(test.tB.selector).find();
215 |
216 | // these both would fail
217 | stdstore.target(address(test)).sig(test.tC.selector).find();
218 | stdstore.target(address(test)).sig(test.tD.selector).find();
219 | }
220 |
221 | function testStorageReadBytes32() public {
222 | bytes32 val = stdstore.target(address(test)).sig(test.tE.selector).read_bytes32();
223 | assertEq(val, hex"1337");
224 | }
225 |
226 | function testStorageReadBool_False() public {
227 | bool val = stdstore.target(address(test)).sig(test.tB.selector).read_bool();
228 | assertEq(val, false);
229 | }
230 |
231 | function testStorageReadBool_True() public {
232 | bool val = stdstore.target(address(test)).sig(test.tH.selector).read_bool();
233 | assertEq(val, true);
234 | }
235 |
236 | function testStorageReadBool_Revert() public {
237 | vm.expectRevert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool.");
238 | this.readNonBoolValue();
239 | }
240 |
241 | function readNonBoolValue() public {
242 | stdstore.target(address(test)).sig(test.tE.selector).read_bool();
243 | }
244 |
245 | function testStorageReadAddress() public {
246 | address val = stdstore.target(address(test)).sig(test.tF.selector).read_address();
247 | assertEq(val, address(1337));
248 | }
249 |
250 | function testStorageReadUint() public {
251 | uint256 val = stdstore.target(address(test)).sig(test.exists.selector).read_uint();
252 | assertEq(val, 1);
253 | }
254 |
255 | function testStorageReadInt() public {
256 | int256 val = stdstore.target(address(test)).sig(test.tG.selector).read_int();
257 | assertEq(val, type(int256).min);
258 | }
259 | }
260 |
261 | contract StorageTest {
262 | uint256 public exists = 1;
263 | mapping(address => uint256) public map_addr;
264 | mapping(uint256 => uint256) public map_uint;
265 | mapping(address => uint256) public map_packed;
266 | mapping(address => UnpackedStruct) public map_struct;
267 | mapping(address => mapping(address => uint256)) public deep_map;
268 | mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct;
269 | UnpackedStruct public basic;
270 |
271 | uint248 public tA;
272 | bool public tB;
273 |
274 |
275 | bool public tC = false;
276 | uint248 public tD = 1;
277 |
278 |
279 | struct UnpackedStruct {
280 | uint256 a;
281 | uint256 b;
282 | }
283 |
284 | mapping(address => bool) public map_bool;
285 |
286 | bytes32 public tE = hex"1337";
287 | address public tF = address(1337);
288 | int256 public tG = type(int256).min;
289 | bool public tH = true;
290 |
291 | constructor() {
292 | basic = UnpackedStruct({
293 | a: 1337,
294 | b: 1337
295 | });
296 |
297 | uint256 two = (1<<128) | 1;
298 | map_packed[msg.sender] = two;
299 | map_packed[address(bytes20(uint160(1337)))] = 1<<128;
300 | }
301 |
302 | function read_struct_upper(address who) public view returns (uint256) {
303 | return map_packed[who] >> 128;
304 | }
305 |
306 | function read_struct_lower(address who) public view returns (uint256) {
307 | return map_packed[who] & ((1 << 128) - 1);
308 | }
309 |
310 | function hidden() public view returns (bytes32 t) {
311 | bytes32 slot = keccak256("my.random.var");
312 | /// @solidity memory-safe-assembly
313 | assembly {
314 | t := sload(slot)
315 | }
316 | }
317 |
318 | function const() public pure returns (bytes32 t) {
319 | t = bytes32(hex"1337");
320 | }
321 | }
322 |
--------------------------------------------------------------------------------
/src/ArbitrageContract.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.8.16;
2 |
3 | import "./interfaces/ISushi.sol";
4 | import "./interfaces/IERC20.sol";
5 |
6 | contract ArbitrageContract {
7 | /* Flashswap Arbitrage is a bit weird, but here is how it goes
8 |
9 | 1. Take in amountIn and OneToTwo, in addition to a target pool, and a true pool, which we will arb against
10 | 2. Flashloan amountIn from true pool, trading it into target pool
11 | 3. Repay amount from target pool minus profit to true LP
12 |
13 | */
14 |
15 | address immutable UNIFACTORY;
16 | address immutable SUSHIROUTER;
17 | uint256 constant MAX_UINT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
18 |
19 | constructor(address factory, address router) {
20 | UNIFACTORY = factory;
21 | SUSHIROUTER = router;
22 | }
23 |
24 | function arbitrageMarket(address true_pool, uint256 amountIn) external payable {
25 | bool OneToTwo;
26 | uint256 repay;
27 | assembly {
28 | mstore(0x69, 0x0902f1ac)
29 |
30 | pop(call(gas(), true_pool, 0, 0x85, 0x4, 0x69, 0x40))
31 |
32 | let reserve0 := mload(0x69)
33 | let reserve1 := mload(0x89)
34 |
35 | let k := mul(reserve0, reserve1)
36 |
37 | let new_r0 := 0
38 |
39 | // Instead of doing an overflow check at each operation
40 | // I just didn't so either use Yul+ where it is is safe, or do a specific check
41 |
42 | OneToTwo := callvalue()
43 |
44 | if OneToTwo { new_r0 := sub(reserve0, amountIn) }
45 | // pseudo - else
46 | if iszero(OneToTwo) { new_r0 := sub(reserve1, amountIn) }
47 |
48 | let new_r1 := div(k, new_r0)
49 |
50 | if OneToTwo { repay := div(mul(sub(new_r1, reserve1), 1000), 994) }
51 | // pseudo - else
52 | if iszero(OneToTwo) { repay := div(mul(sub(new_r1, reserve0), 1000), 994) }
53 | }
54 |
55 | bytes memory data = abi.encode(repay);
56 |
57 | if (OneToTwo) {
58 | // Flashloan A so we can repay in B
59 | SushiPair(true_pool).swap(amountIn, 0, address(this), data);
60 | } else {
61 | // Flashloan B so we can repay in A
62 | SushiPair(true_pool).swap(0, amountIn, address(this), data);
63 | }
64 | }
65 |
66 | function uniswapV2Call(address sender, uint256 amount0, uint256 amount1, bytes calldata data) external {
67 | // There are probably cheaper ways but in general not worth wasting security
68 | address token0 = SushiPair(msg.sender).token0(); // fetch the address of token0
69 | address token1 = SushiPair(msg.sender).token1(); // fetch the address of token1
70 |
71 | // You can calc this without the external call btw, it just involves hashing the factory init code and can be confusing to put in an example
72 | require(msg.sender == SushiFactory(UNIFACTORY).getPair(token0, token1)); // ensure that msg.sender is a V2 pair
73 | require(sender == address(this));
74 |
75 | (uint256 repay) = abi.decode(data, (uint256));
76 |
77 | // Maybe make this a router call?
78 | if (amount0 == 0) {
79 | // Trade A into B
80 | ERC20(token1).approve(SUSHIROUTER, MAX_UINT);
81 |
82 | address[] memory route = new address[](2);
83 |
84 | route[0] = token1;
85 | route[1] = token0;
86 |
87 | uint256[] memory tokensOut =
88 | SushiRouter(SUSHIROUTER).swapExactTokensForTokens(amount1, 0, route, address(this), MAX_UINT);
89 |
90 | require(tokensOut[1] - repay > 0); // ensure profit is there
91 |
92 | ERC20(token0).transfer(msg.sender, repay);
93 | } else {
94 | // Trade B into A
95 | ERC20(token0).approve(SUSHIROUTER, MAX_UINT);
96 |
97 | address[] memory route = new address[](2);
98 | route[0] = token0;
99 | route[1] = token1;
100 |
101 | uint256[] memory tokensOut =
102 | SushiRouter(SUSHIROUTER).swapExactTokensForTokens(amount0, 0, route, address(this), MAX_UINT);
103 |
104 | require(tokensOut[1] - repay > 0); // ensure profit is there
105 |
106 | ERC20(token1).transfer(msg.sender, repay);
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/interfaces/IERC20.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.8.16;
2 |
3 | /**
4 | * @dev Interface of the ERC20 standard as defined in the EIP.
5 | */
6 | interface ERC20 {
7 | /**
8 | * @dev Emitted when `value` tokens are moved from one account (`from`) to
9 | * another (`to`).
10 | *
11 | * Note that `value` may be zero.
12 | */
13 | event Transfer(address indexed from, address indexed to, uint256 value);
14 |
15 | /**
16 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by
17 | * a call to {approve}. `value` is the new allowance.
18 | */
19 | event Approval(address indexed owner, address indexed spender, uint256 value);
20 |
21 | /**
22 | * @dev Returns the amount of tokens in existence.
23 | */
24 | function totalSupply() external view returns (uint256);
25 |
26 | /**
27 | * @dev Returns the amount of tokens owned by `account`.
28 | */
29 | function balanceOf(address account) external view returns (uint256);
30 |
31 | /**
32 | * @dev Moves `amount` tokens from the caller's account to `to`.
33 | *
34 | * Returns a boolean value indicating whether the operation succeeded.
35 | *
36 | * Emits a {Transfer} event.
37 | */
38 | function transfer(address to, uint256 amount) external returns (bool);
39 |
40 | /**
41 | * @dev Returns the remaining number of tokens that `spender` will be
42 | * allowed to spend on behalf of `owner` through {transferFrom}. This is
43 | * zero by default.
44 | *
45 | * This value changes when {approve} or {transferFrom} are called.
46 | */
47 | function allowance(address owner, address spender) external view returns (uint256);
48 |
49 | /**
50 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
51 | *
52 | * Returns a boolean value indicating whether the operation succeeded.
53 | *
54 | * IMPORTANT: Beware that changing an allowance with this method brings the risk
55 | * that someone may use both the old and the new allowance by unfortunate
56 | * transaction ordering. One possible solution to mitigate this race
57 | * condition is to first reduce the spender's allowance to 0 and set the
58 | * desired value afterwards:
59 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
60 | *
61 | * Emits an {Approval} event.
62 | */
63 | function approve(address spender, uint256 amount) external returns (bool);
64 |
65 | /**
66 | * @dev Moves `amount` tokens from `from` to `to` using the
67 | * allowance mechanism. `amount` is then deducted from the caller's
68 | * allowance.
69 | *
70 | * Returns a boolean value indicating whether the operation succeeded.
71 | *
72 | * Emits a {Transfer} event.
73 | */
74 | function transferFrom(address from, address to, uint256 amount) external returns (bool);
75 | }
76 |
--------------------------------------------------------------------------------
/src/interfaces/ISushi.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.8.16;
2 |
3 | interface SushiPair {
4 | event Approval(address indexed owner, address indexed spender, uint256 value);
5 | event Transfer(address indexed from, address indexed to, uint256 value);
6 |
7 | function name() external pure returns (string memory);
8 |
9 | function symbol() external pure returns (string memory);
10 |
11 | function decimals() external pure returns (uint8);
12 |
13 | function totalSupply() external view returns (uint256);
14 |
15 | function balanceOf(address owner) external view returns (uint256);
16 |
17 | function allowance(address owner, address spender) external view returns (uint256);
18 |
19 | function approve(address spender, uint256 value) external returns (bool);
20 |
21 | function transfer(address to, uint256 value) external returns (bool);
22 |
23 | function transferFrom(address from, address to, uint256 value) external returns (bool);
24 |
25 | function DOMAIN_SEPARATOR() external view returns (bytes32);
26 |
27 | function PERMIT_TYPEHASH() external pure returns (bytes32);
28 |
29 | function nonces(address owner) external view returns (uint256);
30 |
31 | function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
32 | external;
33 |
34 | event Mint(address indexed sender, uint256 amount0, uint256 amount1);
35 | event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
36 | event Swap(
37 | address indexed sender,
38 | uint256 amount0In,
39 | uint256 amount1In,
40 | uint256 amount0Out,
41 | uint256 amount1Out,
42 | address indexed to
43 | );
44 | event Sync(uint112 reserve0, uint112 reserve1);
45 |
46 | function MINIMUM_LIQUIDITY() external pure returns (uint256);
47 |
48 | function factory() external view returns (address);
49 |
50 | function token0() external view returns (address);
51 |
52 | function token1() external view returns (address);
53 |
54 | function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
55 |
56 | function price0CumulativeLast() external view returns (uint256);
57 |
58 | function price1CumulativeLast() external view returns (uint256);
59 |
60 | function kLast() external view returns (uint256);
61 |
62 | function mint(address to) external returns (uint256 liquidity);
63 |
64 | function burn(address to) external returns (uint256 amount0, uint256 amount1);
65 |
66 | function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
67 |
68 | function skim(address to) external;
69 |
70 | function sync() external;
71 |
72 | function initialize(address, address) external;
73 | }
74 |
75 | interface SushiFactory {
76 | event PairCreated(address indexed token0, address indexed token1, address pair, uint256);
77 |
78 | function feeTo() external view returns (address);
79 |
80 | function feeToSetter() external view returns (address);
81 |
82 | function getPair(address tokenA, address tokenB) external view returns (address pair);
83 |
84 | function allPairs(uint256) external view returns (address pair);
85 |
86 | function allPairsLength() external view returns (uint256);
87 |
88 | function createPair(address tokenA, address tokenB) external returns (address pair);
89 |
90 | function setFeeTo(address) external;
91 |
92 | function setFeeToSetter(address) external;
93 | }
94 |
95 | interface SushiRouter {
96 | function getAmountsOut(uint256 amountIn, address[] memory path) external view returns (uint256[] memory amounts);
97 |
98 | function swapExactTokensForTokens(
99 | uint256 amountIn,
100 | uint256 amountOutMin,
101 | address[] calldata path,
102 | address to,
103 | uint256 deadline
104 | )
105 | external
106 | returns (uint256[] memory amounts);
107 |
108 | function swapExactTokensForETH(
109 | uint256 amountIn,
110 | uint256 amountOutMin,
111 | address[] calldata path,
112 | address to,
113 | uint256 deadline
114 | )
115 | external
116 | returns (uint256[] memory amounts);
117 |
118 | function swapExactETHForTokens(uint256 amountOutMin, address[] calldata path, address to, uint256 deadline)
119 | external
120 | payable
121 | returns (uint256[] memory amounts);
122 |
123 | function addLiquidity(
124 | address tokenA,
125 | address tokenB,
126 | uint256 amountADesired,
127 | uint256 amountBDesired,
128 | uint256 amountAMin,
129 | uint256 amountBMin,
130 | address to,
131 | uint256 deadline
132 | )
133 | external
134 | returns (uint256 amountA, uint256 amountB, uint256 liquidity);
135 |
136 | function removeLiquidity(
137 | address tokenA,
138 | address tokenB,
139 | uint256 liquidity,
140 | uint256 amountAMin,
141 | uint256 amountBMin,
142 | address to,
143 | uint256 deadline
144 | )
145 | external
146 | returns (uint256 amountA, uint256 amountB);
147 | }
148 |
--------------------------------------------------------------------------------
/test/ArbitrageContract.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: UNLICENSED
2 | pragma solidity ^0.8.16;
3 |
4 | import "../src/interfaces/ISushi.sol";
5 | import "../src/interfaces/IERC20.sol";
6 | import "../src/ArbitrageContract.sol";
7 | import "./util/ERC20.sol";
8 |
9 | contract ArbitrageContractTest {
10 | ArbitrageContract arb_contract;
11 | FakeERC20 tokenA;
12 | FakeERC20 tokenB;
13 |
14 | uint256 constant MAX_UINT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
15 |
16 | SushiFactory sushi_factory;
17 | SushiPair sushi_pair;
18 | SushiRouter sushi_router;
19 |
20 | SushiFactory uni_factory;
21 | SushiPair uni_pair;
22 | SushiRouter uni_router;
23 |
24 | function setUp() public {
25 | // Deploy contracts
26 | tokenA = new FakeERC20("tokenA", "A", 18);
27 | tokenB = new FakeERC20("tokenB", "B", 18);
28 |
29 | (tokenA, tokenB) = address(tokenA) < address(tokenB) ? (tokenA, tokenB) : (tokenB, tokenA);
30 |
31 | // Using Sushi Router and Factory
32 | arb_contract =
33 | new ArbitrageContract(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f, 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F);
34 |
35 | // Set up Sushi Pair
36 | sushi_factory = SushiFactory(0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac);
37 | sushi_router = SushiRouter(0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F);
38 | sushi_pair = SushiPair(sushi_factory.createPair(address(tokenA), address(tokenB)));
39 | tokenA._mint(address(this), 50 ether);
40 | tokenB._mint(address(this), 100 ether);
41 |
42 | tokenA.approve(address(sushi_router), MAX_UINT);
43 | tokenB.approve(address(sushi_router), MAX_UINT);
44 | sushi_router.addLiquidity(address(tokenA), address(tokenB), 50 ether, 100 ether, 0, 0, address(this), MAX_UINT);
45 |
46 | // Set up Uni Pair
47 | uni_factory = SushiFactory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);
48 | uni_router = SushiRouter(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
49 | uni_pair = SushiPair(uni_factory.createPair(address(tokenA), address(tokenB)));
50 | tokenA._mint(address(this), 100 ether);
51 | tokenB._mint(address(this), 50 ether);
52 |
53 | tokenA.approve(address(uni_router), MAX_UINT);
54 | tokenB.approve(address(uni_router), MAX_UINT);
55 | uni_router.addLiquidity(address(tokenA), address(tokenB), 100 ether, 50 ether, 0, 0, address(this), MAX_UINT);
56 | }
57 |
58 | function testArbitrage() public {
59 | uint256 start = tokenB.balanceOf(address(arb_contract));
60 | arb_contract.arbitrageMarket{value: 1}(address(uni_pair), 25 ether);
61 | uint256 end = tokenB.balanceOf(address(arb_contract));
62 | require(start < end, "No profit made");
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/test/util/ERC20.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: AGPL-3.0-only
2 | pragma solidity >=0.8.14;
3 |
4 | /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
5 | /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)
6 | /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
7 | /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it
8 | contract FakeERC20 {
9 | /*//////////////////////////////////////////////////////////////
10 | EVENTS
11 | //////////////////////////////////////////////////////////////*/
12 |
13 | event Transfer(address indexed from, address indexed to, uint256 amount);
14 |
15 | event Approval(address indexed owner, address indexed spender, uint256 amount);
16 |
17 | /*//////////////////////////////////////////////////////////////
18 | METADATA STORAGE
19 | //////////////////////////////////////////////////////////////*/
20 |
21 | string public name;
22 |
23 | string public symbol;
24 |
25 | uint8 public immutable decimals;
26 |
27 | /*//////////////////////////////////////////////////////////////
28 | ERC20 STORAGE
29 | //////////////////////////////////////////////////////////////*/
30 |
31 | uint256 public totalSupply;
32 |
33 | mapping(address => uint256) public balanceOf;
34 |
35 | mapping(address => mapping(address => uint256)) public allowance;
36 |
37 | /*//////////////////////////////////////////////////////////////
38 | EIP-2612 STORAGE
39 | //////////////////////////////////////////////////////////////*/
40 |
41 | uint256 internal immutable INITIAL_CHAIN_ID;
42 |
43 | bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
44 |
45 | mapping(address => uint256) public nonces;
46 |
47 | /*//////////////////////////////////////////////////////////////
48 | CONSTRUCTOR
49 | //////////////////////////////////////////////////////////////*/
50 |
51 | constructor(string memory _name, string memory _symbol, uint8 _decimals) {
52 | name = _name;
53 | symbol = _symbol;
54 | decimals = _decimals;
55 |
56 | INITIAL_CHAIN_ID = block.chainid;
57 | INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
58 | }
59 |
60 | /*//////////////////////////////////////////////////////////////
61 | ERC20 LOGIC
62 | //////////////////////////////////////////////////////////////*/
63 |
64 | function approve(address spender, uint256 amount) public virtual returns (bool) {
65 | allowance[msg.sender][spender] = amount;
66 |
67 | emit Approval(msg.sender, spender, amount);
68 |
69 | return true;
70 | }
71 |
72 | function transfer(address to, uint256 amount) public virtual returns (bool) {
73 | balanceOf[msg.sender] -= amount;
74 |
75 | // Cannot overflow because the sum of all user
76 | // balances can't exceed the max uint256 value.
77 | unchecked {
78 | balanceOf[to] += amount;
79 | }
80 |
81 | emit Transfer(msg.sender, to, amount);
82 |
83 | return true;
84 | }
85 |
86 | function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
87 | uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
88 |
89 | if (allowed != type(uint256).max) {
90 | allowance[from][msg.sender] = allowed - amount;
91 | }
92 |
93 | balanceOf[from] -= amount;
94 |
95 | // Cannot overflow because the sum of all user
96 | // balances can't exceed the max uint256 value.
97 | unchecked {
98 | balanceOf[to] += amount;
99 | }
100 |
101 | emit Transfer(from, to, amount);
102 |
103 | return true;
104 | }
105 |
106 | /*//////////////////////////////////////////////////////////////
107 | EIP-2612 LOGIC
108 | //////////////////////////////////////////////////////////////*/
109 |
110 | function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
111 | public
112 | virtual
113 | {
114 | require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
115 |
116 | // Unchecked because the only math done is incrementing
117 | // the owner's nonce which cannot realistically overflow.
118 | unchecked {
119 | address recoveredAddress = ecrecover(
120 | keccak256(
121 | abi.encodePacked(
122 | "\x19\x01",
123 | DOMAIN_SEPARATOR(),
124 | keccak256(
125 | abi.encode(
126 | keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"),
127 | owner,
128 | spender,
129 | value,
130 | nonces[owner]++,
131 | deadline
132 | )
133 | )
134 | )
135 | ),
136 | v,
137 | r,
138 | s
139 | );
140 |
141 | require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
142 |
143 | allowance[recoveredAddress][spender] = value;
144 | }
145 |
146 | emit Approval(owner, spender, value);
147 | }
148 |
149 | function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
150 | return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
151 | }
152 |
153 | function computeDomainSeparator() internal view virtual returns (bytes32) {
154 | return keccak256(
155 | abi.encode(
156 | keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
157 | keccak256(bytes(name)),
158 | keccak256("1"),
159 | block.chainid,
160 | address(this)
161 | )
162 | );
163 | }
164 |
165 | /*//////////////////////////////////////////////////////////////
166 | INTERNAL MINT/BURN LOGIC
167 | //////////////////////////////////////////////////////////////*/
168 |
169 | function _mint(address to, uint256 amount) external virtual {
170 | totalSupply += amount;
171 |
172 | // Cannot overflow because the sum of all user
173 | // balances can't exceed the max uint256 value.
174 | unchecked {
175 | balanceOf[to] += amount;
176 | }
177 |
178 | emit Transfer(address(0), to, amount);
179 | }
180 |
181 | function _burn(address from, uint256 amount) external virtual {
182 | balanceOf[from] -= amount;
183 |
184 | // Cannot underflow because a user's balance
185 | // will never be larger than the total supply.
186 | unchecked {
187 | totalSupply -= amount;
188 | }
189 |
190 | emit Transfer(from, address(0), amount);
191 | }
192 | }
193 |
--------------------------------------------------------------------------------