Sequence

QuantstampFiles named in the report

Quantstamp reviewed Sequence on 12 Jan 2024: 23 findings, 0 critical; 15 marked fixed, 7 acknowledged, 1 open.

No open critical findings
Open the reportOpen Sequence’s security record

Report hosted on certificate.quantstamp.com.

Trustblock does not review code.

Findings23

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

SeverityOpenAcknowledgedFixed
Critical000
High000
Medium002
Low1713
MediumPotential Signature Replayability Across ChainsFixed

The lack of chain ID integration in contract's message hashing could pose risks in scenarios involving multiple blockchain networks. 1. The `ERC1155BaseToken` contract inherits `ERC1155Meta` (out of scope) which includes functions `metaSafeTransferFrom()` and `metaSafeBatchTransferFrom()`. The functions enable assets to be transferred from the owner to a recipient, provided there is a valid signature from the asset owner authorizing the transfer. The transfer functions use the `hashEIP712Message()` for message hashing. However, this function does not include a chain ID in its implementation. The absence of a chain ID in the EIP-712 message structure could lead to a situation where a valid signature on one blockchain might be replayed on another blockchain. 2. Although the `Trust` contract checks the validity of the signed message in `isValidSignature()`, the hashed value excludes a chain ID, and, therefore, the signed message may be reused across different Ethereum chains. Typically, the inclusion of a chain ID in the signed message is a common security measure to prevent such replay attacks, ensuring that signatures are valid only on the intended blockchain.

MediumToken Sale Owners Can Front-Run Mints With Increased CostFixed

The `mint()` function in the contracts `ERC721Sale` and `ERC1155Sale`, is vulnerable to front running from the `MINT_ADMIN_ROLE`. If the `MINT_ADMIN_ROLE` finds a mint transaction in the mempool, and the mint caller has given sufficient approval, the `MINT_ADMIN_ROLE` can front-run the mint with a call to `setSaleDetails()` and increase the `cost`. Thus, the mint caller will pay more for the token than expected.

Low'Dead' CodeFixed

"Dead" code refers to code which is never executed and hence makes no impact on the final result of running a program. Dead code raises a concern, since either the code is unnecessary or the necessary code's results were ignored. 1. `ERC1155Sale._ERC20_TRANSFERFROM_SELECTOR` is never used in `ERC1155Sale`. 2. `ERC721Sale._ERC20_TRANSFERFROM_SELECTOR` is never used in `ERC721Sale`.

LowCollisions In `abi.encodePacked()`Fixed

Factory contracts call `abi.encodePacked()` to concatenate the parameters of the contract before hashing the result. This is the salt used by `CREATE2` to generate the new contract. However, `abi.encodePacked()` does not pad the dynamic types, potentially leading to hash collisions (e.g. `[token, $token]`, will have the same hash as `[token$t, oken]`).

LowCreate ERC-20 Offers in an Orderbook Designed for ERC-1155 and ERC-721Fixed

The orderbook, designed for handling ERC-1155 and ERC-721 tokens, is vulnerable to unintended listings of ERC-20 tokens due to the identical `transferFrom()` function signature shared between ERC-20 and ERC-721 standards. In both standards, the function signature is `transferFrom(address, address, uint256)`. However, in the context of ERC-20, the third parameter (`uint256`) represents the amount of tokens to be transferred, while in ERC-721, it denotes the unique `tokenId` of the NFT. This similarity in function structure allows for the possibility of ERC-20 tokens being listed in the orderbook as if they were ERC-721 tokens, with the `tokenId` inadvertently interpreted as the quantity of ERC-20 tokens. This misalignment can lead to transactional errors and confusion, as the orderbook is not designed to accommodate the fungible nature and transactional semantics of ERC-20 tokens. Although unlikely, if a user were to unintentionally accept what they believe is an ERC-721 order, and they have a pre-existing ERC-20 token allowance set for the orderbook, this could lead to an unintentional transfer of ERC-20 tokens to the creator of the spoofed ERC-721 order. Although there is an approval check in `_hasApprovedTokens` when creating the spoofed ERC-721 order, the ownership validation occurs only when the order is a listing.

LowDeprecated FunctionsFixed

Several initializers in the codebase call `_setupRole()` to assign privileged roles to certain addresses, instead of using `_grantRole()`. Both functions have the same effect, as `_setupRole()` just calls `_grantRole()`. `_setupRole()` will be deprecated in `v5.0.0` of OpenZeppelin contracts, and its use is not recommended in the current version used by the codebase (`v4.9.3`). See `_setupRole()` comment: ``` NOTE: This function is deprecated in favor of {_grantRole}. ```

LowGas Optimization: Cache VariablesFixed

Repeatedly accessing certain variables can be gas-intensive. To optimize gas usage, values frequently accessed should be stored in memory variables. Consider storing the value in a memory variable and reference the memory variable for the following variables: 1. `requests.length` from `Orderbook.createOrderBatch()` 2. `ordersIds.length` from `Orderbook.acceptOrderBatch()` 3. `ordersIds.length` from `Orderbook.getOrderBatch()` 4. `ordersIds.length` from `Orderbook.isOrderValidBatch()`

LowGas Optimization: Use `calldata` Instead of `memory`Fixed

Solidity's `calldata` is a read-only byte-addressable space where function arguments reside. It is more cost-effective to employ `calldata` over `memory`. This is because `calldata` is not stored in memory but is directly accessed from the function call data, resulting in gas savings. It is recommended to change the `memory` to `calldata` in the mentioned functions: 1. `createOrder()` 2. `createOrderBatch()` 3. `_createOrder()` 4. `acceptOrder()` 5. `_acceptOrder()` 6. `acceptOrderBatch()` 7. `getOrderBatch()` 8. `cancelOrderBatch()` 9. `isOrderValidBatch()`

LowGreedy ContractsFixed

Sale contracts can be configured to accept payments in ERC-20 or native tokens. However, the functions are `payable`, so a user can send native tokens by mistake, locking them in the contract.

LowInconsistency in Order ID Retrieval for Partially Fulfilled NFT OrdersFixed

The `hashOrder()` function generates an order ID by hashing order data, including `uint256 quantity`. However, for orders that are partially fulfilled, the `quantity` within an order changes over time with each partial fulfillment. As a result, the `hashOrder()` function cannot consistently calculate the correct `orderId` based on the current `_orders` state variable since varying quantities lead to different hash outputs and, consequently, different IDs. In the protocol, operations such as accepting or cancelling orders use only the `orderId` to reference the order. This issue is specifically relevant for off-chain components or other protocols that use `hashOrder()` to reference or retrieve the order ID based on order data. These systems may end up with mismatched or incorrect order IDs due to the changing quantities in orders over time.

Show 5 more
LowInsufficient Allowance Check in NFT Order CreationsFixed

The NFT purchase process checks the buyer's token allowance based only on the token price and quantity, neglecting the additional royalty fees. This approach could result in situations where a buyer's approved allowance satisfies the token cost but falls short when royalty fees are included, leading to unsuccessful order fulfillment. `isOrderValid()` (for an order of "offer" type) verifies that the order creator gave enough allowance to cover the pay of the offer and also the royalties linked to the token. However, when a user creates an offer, `_createOrder()` verifies that enough allowance was provided to cover the new order, without taking royalties into account.

LowOutdated CommentsFixed

In several factory contracts, the following comment can be found: ``` @dev As `proxyOwner` owns the proxy, it will be unable to call the [...] functions. ``` However, the Sequence factories implement a modified Transparent Proxy pattern, where the administrator can also call the implementation, apart from the administration functions.

LowPotential EVM Compatibility Issue in Solidity Version `>=0.8.20`Fixed

According to the `foundry.toml` config file, the `Orderbook` contract is compiled in Solidity version `0.8.20` with an unspecified evm version. As a result, the contract bytecode may be compiled with the default evm version Shanghai and may include `PUSH0` opcodes, which are not supported on certain EVM chains, including BSC, [Arbitrum](https://docs.arbitrum.io/solidity-support), and [Optimism](https://community.optimism.io/docs/developers/build/differences/). The deployment or execution of the contract may fail due to the use of an invalid opcode.

LowPrivileged Users Limited to One ERC-1155 Token Mint When Only the Global Sale is EnabledFixed

The function `ERC1155Sale._payForActiveMint()`, called via `mint()`, collects the mint fees and checks if the caller is a valid leaf in the Merkle tree. If the caller is a valid leaf, the Merkle root is marked as used for the caller. However, since `_payForActiveMint()` allows for batch minting, and since the Merkle proof is verified for each minted token, minting will fail after one token per caller when only the global sale is enabled. This is not an issue when individual token sales are enabled and Merkle roots are unique for each token.

LowRisk of NFT Loss when Accepting OrderFixed

When accepting orders, the transferring ERC-721 tokens uses the `transferFrom()` function, which does not include safety checks to verify if the recipient is capable of handling ERC-721 tokens. This could lead to irreversible loss of NFTs if they are sent to contracts that do not implement the ERC-721 receiver interface.

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Repository and files the report names (4)

  • marketplace-contracts /contracts/*
  • wallet-contracts /contracts/TrustFactory.sol
  • wallet-contracts /contracts/Trust.sol
  • contracts-library /src/tokens/*

Part of Sequence’s security record

Sequence
Audits3 audits by 1 firmLast audit Dec 2025, by Quantstamp.
Critical findingsNo open critical findingsAcross 3 reports.
Open Sequence’s security record

Security firm

Quantstamp

236 projects reviewed · 332 reports · latest Oct 2026

See Quantstamp’s audits

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