AMPL security record

Avalanche, Base, BNB Chain, Ethereumampleforth.orgXGitHub

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.

Critical findings
No open critical findings
Across 4 reports.
Open the latest report
Your label, live
Get the label for your site

Record last updated . It holds audits and findings, contracts and incidents up to Nov 2026. Trustblock does not review code.

Audits4

Newest first

AuditSecurity firmDateScopeCritical findingsReport
Ampleforth's Token Geyser v2Security firm: CertiKDate: Scope: Files named in the reportNo open critical findingsOpen · skynet.certik.com
XCAmpleforthSecurity firm: CertiKDate: Scope: Files named in the reportNo open critical findingsOpen · skynet.certik.com
AmpleforthSecurity firm: CertiKDate: Scope: Not recorded (see the report)No open critical findingsOpen · skynet.certik.com
AmpleforthSecurity firm: QuantstampDate: Scope: Files named in the reportNo open critical findingsOpen · certificate.quantstamp.com

Findings55

Statuses are the security firm’s own, from each report.

SeverityOpenAcknowledgedFixed
Critical000
High001
Medium004
Low13037
HighInvalid Balance Sheet EvaluationAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The checkBalances function is meant to iterate over all locks existent on the vault and ensure that the locked balances do not exceed the amount of tokens held by the vault. The issue with the current implementation is that the loop iteration between L239 and L244 checks the balances of the locks sequentially whilst the same token can exist under two different lock IDs within the _lockSet set. For example, if two different Geyser s rely on the same vault, the same token will be "locked" under two different lock IDs, for the sake of this example let's consider that value to be 100 . If I were to maliciously call either externalCall or externalCallMulti , I would be able to withdraw 100 of the 200 units held by the vault as the two locks created above would each be 100 which would successfully pass the check imposed on L243.

Open the report
MediumFunction Comment InconsistencyAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The stake function comments denote that the totalStakeUnits should be adjusted when a stake occurs. However, the implementation of stake adjusts the units only before submitting the new stake and does not update the totalStakeUnits after, as unstakeAndClaim does.

Open the report
MediumSignature Validation Race ConditionAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The linked functions lock and unlock perform signature validation based on a globally incremented nonce on both functions regardless of the party that is providing the signature. This introduces a race condition whereby a validly signed lock can be invalidated by submitting another validly signed lock with a higher gas fee. This can render the system unusable in a realworld use case with high influx of activity as lock / unlock signature nonces will be overlapping between users.

Open the report
MediumPotential Loss of PrecisionXCAmpleforth · CertiK · 1 Feb 2021Fixed

The Ampleforth protocol follows a strict rebase policy whereby consequent rebases will never incur loss of precision in the underlying values used to transact with the currency as denoted by their `uFragments.sol` supply adjustment analysis. Multiple epoch rebases that can accumulate, however, do not guarantee the same constraints in the rebase operation of the cross-chain Ampleforth in comparison to the main-chain Ampleforth.

Open the report
MediumPotential Loss of PrecisionXCAmpleforth · CertiK · 1 Feb 2021Fixed

The Ampleforth protocol follows a strict rebase policy whereby consequent rebases will never incur loss of precision in the underlying values used to transact with the currency as denoted by their `uFragments.sol` supply adjustment analysis. Multiple epoch rebases that can accumulate, however, do not guarantee the same constraints in the rebase operation of the cross-chain Ampleforth in comparison to the main-chain Ampleforth.

Open the report
LowBytecode OptimizationAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The linked functions differ in the code they execute by a single variable which is passed as a literal in one implementation and as a variable in the other.

Open the report
LowConditional OptimizationAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The newStakeUnits calculated depend on whether time has passed between the timestamp and the lastUpdate of the _geyser , meaning that if those two are equal no change will occur.

Open the report
LowDenial-of-Service AttackAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

Although this particular attack vector requires escalated privileges, it is possible to freeze any unstakeAndClaim invocations by introducing numerous bonus tokens to the _bonusTokenSet thus causing the loop iteration of L998-L1014 to run out-of-gas.

Open the report
LowDynamic Evaluation of Loop LengthAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The linked for loops iterate from 0 until a specified length that is the result of a function invocation on the _lockSet . As the conditional statement is evaluated on each iteration, it is more optimal to store the length evaluation in-memory prior to the loop to optimize the conditional evaluation

Open the report
LowDynamically Computed Static ValueAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The linked lines compute the keccak256 value of string literals.

Open the report
Show 10 more
LowFunction Visibility OptimizationAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The linked function is declared as public , contains array function arguments and is not invoked in any of the contract's contained within the project's scope.

Open the report
LowFunction Visibility OptimizationAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The linked function is declared as public , contains array function arguments and is not invoked in any of the contract's contained within the project's scope.

Open the report
LowInput SanitizationAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The constructor of the PowerSwitch contract transfers ownership of itself to the address provided as input to it. However, no check exists that ensures the owner is non-zero in either the PowerSwitch implementation or parent contracts, such as Geyser , that create instances of it.

Open the report
LowInput SanitizationAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The constructor of the VaultFactory contract accepts a single address argument that remains immutable beyond its assignment and is used as the underlying implementation of spawned instances. However, no check is imposed in the constructor to ensure that it is not accidentally set to the 0x0 address.

Open the report
LowInsufficient Prevention of AllowanceAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The _externalCall implementation is meant to perform a function call that conducts an arbitrary action except from approving another address of an allowance, presumably to ensure that funds aren't exited from the vault after the checkBalances evaluation successfully passes. This check, however, is insufficient as a lot of contracts, including the Ampleforth token itself (AMPL), derive from OpenZeppelin and support the increaseAllowance and decreaseAllowance functions, thus circumventing the check.

Open the report
LowInversion of if ClauseAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The linked if clauses perform a conditional check whereby within the value literal 0 is assigned to the variable declared before the if block. As uint variables are initialized at 0 by default in Solidity, it is possible to invert the if clause and drop the else leg entirely.

Open the report
LowModifier require To Function CallAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

In Solidity, modifier s work by essentially wrapping the function they are utilized in with the corresponding code of the modifier , either appending or prepending statements. As require calls with an error message significantly increase the bytecode size and gas cost, it is more optimal to instead have the modifier implementations perform a function call, leading to the require checks not being duplicated and instead being existent on a single location.

Open the report
LowMutability Specifiers MissingAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The linked variables are assigned to only once, either during their contract-level declaration or during the constructor 's execution.

Open the report
LowMutability Specifiers MissingAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The linked variables are assigned to only once, either during their contract-level declaration or during the constructor 's execution.

Open the report
LowPotential Misbehaviour of the SystemAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The externalCallsMulti function iterates and executes all calls provided to it before evaluationg that the balance sheet of the vault is correct and finalizing the function's execution. This allows one to actually withdraw tokens and utilize them prior to returning them in the sequence of external calls performed by the contract which may be an undesired capability of the system.

Open the report
Show 10 more
LowPotentially Misutilized ImplementationAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The _truncateStakesArray implementation is meant to remove a number of StakeData members from the input array by initializing a new one in-memory, assigning to it in a sequential fashion and returning the new array copy. However, the function is solely utilized in L617 to remove the last stake of the array.

Open the report
LowRedundant CodeAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The implemented function _unregister is meant to remove an instance from the _instanceSet and emit a corresponding event, however, it remains unutilized throughout the project.

Open the report
LowUnnecessarily Convoluted LogicAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The linked code segment executes the calculateRewardFromStakes function which truncates the stakes consumed to produce the reward and returns the truncated array. In the code segment linked, the truncated array is not utilized directly and only the last remaining element is used along with the array's length .

Open the report
LowVariable ShadowingAmpleforth's Token Geyser v2 · CertiK · 12 Feb 2021Fixed

The linked variable shadows an existing declaration in a parent contract, OwnableUpgradeable , of the owner function that retrieves the owner of the contract.

Open the report
LowApproval Amount DesyncXCAmpleforth · CertiK · 1 Feb 2021Fixed

As the Ampleforth is unique in the sense that it is a rebasing token, a set amount of permitted tokens to be transmitted via an approval can have a different underlying gon value due to supply rebases.

Open the report
LowFunction SimplificationXCAmpleforth · CertiK · 1 Feb 2021Fixed

The linked functions toggle the `bool` state of the `whitelistedBridgeGateways` mapping to adjust whether a particular bridge is whitelisted to burn and mint tokens in the satellite chain.

Open the report
LowFunction SimplificationXCAmpleforth · CertiK · 1 Feb 2021Fixed

The linked functions toggle the `bool` state of the `whitelistedBridgeGateways` mapping to adjust whether a particular bridge is whitelisted to withdraw and deposit tokens to the vault.

Open the report
LowIncorrect Utilization of `chainid`XCAmpleforth · CertiK · 1 Feb 2021Fixed

The linked code relates to the utilization of the `chainid` variable which is meant to represent the current chain's ID for usage in the EIP-712 and EIP-2612 standards. As noted in the EIPs, by computing the `chainid` once the standards' functions are susceptible to cross-chain attacks in case of a fork.

Open the report
LowInexistent Error MessageXCAmpleforth · CertiK · 1 Feb 2021Fixed

Error messages should always accompany a `require` invocation to aid in both explaining what the imposed check is meant to achieve as well as aid in debugging processes.

Open the report
LowInexistent Error MessageXCAmpleforth · CertiK · 1 Feb 2021Fixed

Error messages should always accompany a `require` invocation to aid in both explaining what the imposed check is meant to achieve as well as aid in debugging processes.

Open the report
Show 10 more
LowMutability Specifiers MissingXCAmpleforth · CertiK · 1 Feb 2021Fixed

The linked variables are assigned to only once, either during their contract-level declaration or during the `constructor`'s execution.

Open the report
LowMutability Specifiers MissingXCAmpleforth · CertiK · 1 Feb 2021Fixed

The linked variables are assigned to only once, either during their contract-level declaration or during the `constructor`'s execution.

Open the report
LowPotential Incompatibility w/ Underlying TokenXCAmpleforth · CertiK · 1 Feb 2021Fixed

The vault is meant to be utilized with the Ampleforth main-chain currency on Ethereum which currently conforms to the ERC-20 standard properly, however, this may not always be the case.

Open the report
LowUsage of Deprecated RepresentationXCAmpleforth · CertiK · 1 Feb 2021Fixed

The maximum value of `int256` is currently represented by the contract using bitwise shifts and negations whereas the current standard utilizes the special type keyword to wrap the type and access the max member i.e. `type(int256).max` , as introduced in Solidity 0.6.8.

Open the report
LowUsage of Deprecated RepresentationXCAmpleforth · CertiK · 1 Feb 2021Fixed

The maximum value of `uint256` and `uint128` is currently represented by the contract using bitwise negations whereas the current standard utilizes the special type keyword to wrap the type and access the max member i.e. `type(uint256).max` , as introduced in Solidity 0.6.8.

Open the report
LowUsage of memory Variable Over storageXCAmpleforth · CertiK · 1 Feb 2021Fixed

The linked line performs a `return` statement on the `globalAMPLSupply` stored in `storage` after performing a successful equality check of this value with the in-memory `newGlobalAMPLSupply` variable.

Open the report
LowAllowance Double-Spend ExploitAmpleforth · Quantstamp · 13 Jun 2019Fixed

As it presently is constructed, the contract is vulnerable to the allowance double-spend exploit, as with other ERC20 tokens. Exploit Scenario: 1. Alice allows Bob to transfer N amount of Alice's tokens (N>0) by calling the approve() method on smart contract (passing Bob's address and N as method arguments) 2. After some time, Alice decides to change from N to M (M>0) the number of Alice's tokens Bob is allowed to transfer, so she calls the approve()method again, this time passing Bob's address and M as method arguments 3. Bob notices Alice's second transaction before it was mined and quickly sends another transaction that calls the transferFrom() method to transfer N Alice's tokens somewhere 4. If Bob's transaction will be executed before Alice's transaction, then Bob will successfully transfer N Alice's tokens and will gain an ability to transfer another M tokens 5. Before Alice notices any irregularities, Bob calls transferFrom() method again, this time to transfer M Alice's tokens.

Open the report
LowCentralization of PowerAmpleforth · Quantstamp · 13 Jun 2019Fixed

Smart contracts will often have owner variables to designate the person with special privileges to make modifications to the smart contract. The owner of UFragments may (un)pause rebasing and transfers. The owner of UFragmentsPolicy may set oracles and policy parameters. The owner of MedianOracle may arbitrarily whitelist data providers.

Open the report
LowGas Usage / for Loop ConcernsAmpleforth · Quantstamp · 13 Jun 2019Fixed

Gas usage is a main concern for smart contract developers and users, since high gas costs may prevent users from wanting to use the smart contract. Even worse, some gas usage issues may prevent the contract from providing services entirely. For example, if a for loop requires too much gas to finish, then it may prevent the contract from functioning correctly entirely. Specifically, the gas usage in for loops depends on the number of providers and reports.

Open the report
LowMalicious providers may perform DoS by making Select.computeMedian() revertAmpleforth · Quantstamp · 13 Jun 2019Fixed

getData() (used by rebase()) uses the function computeMedian() to compuute median of reported values from providers. In case of an even number of providers, it adds two middle values from the array. Malicious providers could collude and provide values that cause an overflow and, consequently, revert rebase().

Open the report
Show 2 more
LowRace Conditions / Front-RunningAmpleforth · Quantstamp · 13 Jun 2019Fixed

A block is an ordered collection of transactions from all around the network. It's possible for the ordering of these transactions to manipulate the end result of a block. A miner can take advantage of this by generating and moving transactions in a way that benefits themselves. In UFragmentsPolicy, there is a transaction ordering dependency between the functions setDeviationThreshold() (which sets the deviation threshold) and rebase() (which adjusts the token supply). In UFragments, there is a transaction ordering dependency between the functions transfer() (which sets the deviation threshold) and rebase() (which adjusts). A miner could take advantage of the ordering of transactions to sell their tokens at a higher rate than others. Exploit Scenario: 1. User calls UFragmentsPolicy.rebase() to adjust the supply and, indirectly, _gonsPerFragment so that its value increases. 2. Miner notices the transaction and realizes that due to increased _gonsPerFragment, they'll have less tokens. 3. The miner submits transfer() (e.g., as a part of an atomic swap with another token) to sell tokens, and orders it so that it gets executed before rebase().

Open the report
LowToken may fail to converge to the target rate if rebase() keeps failingAmpleforth · Quantstamp · 13 Jun 2019Fixed

The function getData() iterates over all reports from the providers and counts the number of valid reports (i.e., not too old and not too recent). rebase() uses the return value from getData() and reverts if there are no valid reports. In case of a revert, no information is logged by getData() and the token fails to apply the previously computed dampening factor. If rebase() keeps failing over the course of rebaseLag (days), then the price will never reach the previously computed target rate.

Open the report

Contracts

No deployed address is recorded for these audits.

The reports name a repository or files. Open a report to see its scope.

The repositories and files the reports name

Show this on your site

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.

Content

Facts

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.

Fixed as
Language

Style

Layout
Theme
Accent
Corners

Format

Size
Date
Embed as
HTML
<head>
<script src="https://widget.trustblock.run/project-widget.min.js" defer></script>
</head>
<body>
<div
data-tb-project-widget
data-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