As of 3 Nov 2026, AMPL has 4 audit reports by 2 security firms on Trustblock; the latest is by CertiK, dated 12 Feb 2021. Those reports list no open critical findings.
Record last updated . It holds audits, findings and contracts up to Nov 2026, and incidents up to Oct 2026. Trustblock does not review code.
Newest first
| Audit | Security firm | Date | Scope | Critical findings | Report |
|---|---|---|---|---|---|
| Ampleforth's Token Geyser v2 | Security firm: CertiK | Date: | Scope: Files named in the report | No open critical findings | Open · skynet.certik.com |
| XCAmpleforth | Security firm: CertiK | Date: | Scope: Files named in the report | No open critical findings | Open · skynet.certik.com |
| Ampleforth | Security firm: CertiK | Date: | Scope: Not recorded (see the report) | No open critical findings | Open · skynet.certik.com |
| Ampleforth | Security firm: Quantstamp | Date: | Scope: Files named in the report | No open critical findings | Open · certificate.quantstamp.com |
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 1 |
| Medium | 0 | 0 | 4 |
| Low | 13 | 0 | 37 |
Certain tokens throw when a zero-value transfer is attempted, meaning that the unstakeAndClaim mechanism may break if all bonus tokens of such a token have been claimed.
Open the reportThe “externalCall” function returns a variable of type “bool” as stated in its function signature. Internally, an in-memory variable is declared called “result” of type “bool” which is assigned the result of the low-level “call” invocation and then explicitly returned as the last statement of the function body
Open the reportThis Exhibit relies on whether Exhibit 2 is applied on the codebase. If Exhibit 2 is applied, this Exhibit can be safely ignored. In the aforementioned line, whenever a new “Transaction” struct is constructed the hard-coded value of “true” is assigned to its “enabled” member. This will presently cause a 32-byte write operation to be conducted as the memory needs to be initialized to a non-zero value.
Open the reportThe loop included in the aforementioned lines iterates through an array of dynamic size that could potentially lead to the function being impossible to execute if many transactions are included or if the gas cost of the transactions collectively exceeds the block’s gas limit.
Open the reportThe “TransactionFailed” event contains a “uint” variable that represents the index of the transaction that failed. However, this variable may be misleading under certain circumstances as transaction ordering in Ethereum is up to the miners of the blocks. As an example, should a single block contain the following transaction ordering, the “index” variable will be misleading and lead to an out-of-bound access on both the previous and current block of the blockchain: 1. Inclusion of new transaction in transaction queue. This will increase the transaction queue length and add the final transaction to the end. 2. Execution of “rebase” and failed execution of the newly included transaction, leading to the “TransactionFailed” event being emitted with the “index” variable being the last element of the array. 3. The deletion of the last transaction in the transaction queue. This will decrease the transaction queue length and remove the final transaction that was previously executed but failed. The above sequence will lead to an “index” being emitted that is otherwise inaccessible. The above scenario, although unlikely, can occur should the owner of the contract accidentally include a transaction and attempt to remove it with users invoking “rebase” in the process.
Open the reportThe “Transaction” struct included on the Orchestrator contract can be optimized to occupy one less slot, significantly reducing the gas cost of all types of transactions relating to it such as read and write operations.
Open the reportWhenever the “length” of an array is reduced, Solidity internally calls the “delete” operator on the last element of the array and as such, it is unnecessary to explicitly call it.
Open the reportThe “externalCall” function contains a “transferValueWei” variable in its signature referring to the amount of wei that will be transferred in the external call. This function is labelled as “internal” and is only invoked in a single location, line 55, where the “transferValueWei” argument is hard-coded as zero.
Open the reportThe aforementioned line contains an assignment of the zero value casted to an “address” type to the “orchestrator” variable of the contract. This type of assignment is unnecessary as Solidity, akin to many other programming languages, assigns a default value to uninitialized variables which in the case of addresses is the zero address.
Open the reportThe “externalCall” function contains a “dataLength” variable in its signature referring to the length of the “bytes” dynamic array that will be transferred in the external call. This is unnecessary because, as mentioned in comment line 138, the length of the “bytes” is already included in the variable at the first location of the “bytes” pointer.
Open the reportThe function “transactionsLength” is meant to return, as its name implies, the “length” of the “transactions” storage array. It is generally considered ill-practise to declare a dot-accessor in camel-case format as the function name.
Open the reportProjects may rely on block timestamps for various purposes. However, it's important to realize that miners individually set the timestamp of a block, and attackers may be able to manipulate timestamps for their own purposes. If a smart contract relies on a timestamp, it must take this into account.
Open the reportThe functions transfer() and transferFrom() take value that signifies the number of tokens to transfer. Both functions compute the corresponding number of gons and use them to update the ledger. It is possible that the value of _gonsPerFragment becomes large enough (due to constantly increasing target rate) so that gonValue exceeds the account balance even if value equals 1. Such a transfer will fail on SafeMath.sub(). Consequently, the source account will have a non-zero gon balance that will be untransferable. Theoretically, a large number of gons can be dispersed among multiple accounts in too low quantities, so all those gons will become unspendable.
Open the reportThe reports name a repository or files. Open a report to see its scope.
Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.
Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.
<head><script src="https://widget.trustblock.run/project-widget.min.js" defer></script></head><body><divdata-tb-project-widgetdata-tb-project-slug="ampleforth"></div></body>
Paste the code where the label should appear. It uses no API credit and updates by itself.
Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.
Tell us