BlueGoldOne
Gold Token

Covered the UUPS-upgradeable ERC20 gold token: issuance/redemption workflow, transfer fee, and regulatory blacklisting.
report id
0741
category
Token & RWA
language
Solidity
final report
December 9, 2025
lines of code
161
Content

Download audit report

1

Executive Summary

This document presents the results of a security review conducted by Nethermind Security for BlueGoldOne's StandardGoldCoin Token contract.

Standard Gold Coin is a digitized commodity token designed to track the value of physical gold (1 gram per token). The system is a UUPS upgradeable ERC20 that implements: a unique issuance and redemption workflow to verify off-chain backing, a 0.02% transfer fee mechanism, regulatory blacklisting capabilities, emergency pause functionality, and EIP2612 Permit features.

The audit comprises 161 lines of the Solidity code. The audit was performed using (a) manual analysis of the codebase, and (b) automated analysis tools.

Audit assessment
Audit TypeSecurity Review
Initial ReportDecember 04, 2025
Final ReportDecember 09, 2025
Later edit to add deployment detailsJanuary 16, 2026
Initial Commit612f160
Final Commitbbd7923
Documentation AssessmentHigh
Test Suite AssessmentHigh
Total findings
4
Fixed
3
Acknowledged
0
Mitigated
1
Unresolved
0

Findings by severity

  • Critical0
  • High0
  • Medium1
  • Low0
  • Informational2
  • Best Practices1

2

Audited Files

#ContractLoCCommentsRatioBlankTotal
1src/StandardGoldCoin.sol161295183.2%63519
Total161295183.2%63519

4

System Overview

The Standard Gold Coin (SGC) protocol implements a digitized commodity system where each SGC token represents one gram of physical gold. The system is architected as a UUPS Upgradeable ERC20 token that integrates regulatory compliance features, a transaction fee mechanism, and a strict issuance model to maintain a 1:1 correlation with off-chain gold reserves.

The protocol consists of a single primary implementation contract, StandardGoldCoin, which utilizes OpenZeppelin's upgradeable contracts library for core standards including ERC20Permit, AccessControl, and Pausable.

4.1 Issuance and Redemption Logic

The system distinguishes itself from standard ERC20 tokens by enforcing a strict “Declared Backing” model. The total supply is managed through restricted roles to ensure on-chain tokens match off-chain physical assets.

  • Minting: The mintWithIssuance function allows the MINTER_ROLE to create tokens. Crucially, this operation requires a unique issuanceId. This ID links the on-chain minting event to a specific off-chain gold deposit, preventing duplicate processing of the same physical asset. The global totalDeclaredBacking counter is incremented upon success.
  • Redemption: Users wishing to redeem tokens for physical gold undergo a burning process via the burnForRedemption function (executed by the BURNER_ROLE). Similar to minting, this requires a unique redemptionId. This ensures the totalDeclaredBacking is decremented correctly and provides an immutable record of the redemption. Users may also burn their own tokens voluntarily via the public burn function.

4.2 Transfer and Fee Mechanism

The protocol overrides the standard _update function to inject custom logic into every token transfer.

  • Transaction Fees: A fee of 2 basis points (0.02%) is applied to standard transfers. This fee is deducted from the transfer amount and sent to a designated feeCollector.
  • Fee Exemptions: Mints and burns are inherently exempt from fees. Additionally, transfers where the sender or recipient is the feeCollector are processed without fees to prevent circular charging.
  • Collector Constraints: The protocol enforces a security constraint requiring the feeCollector to be an Externally Owned Account (EOA). The system explicitly checks code.length to prevent contract addresses from receiving fees.

4.3 Security and Compliance Controls

To adhere to regulatory requirements and ensure system safety, SGC implements centralized control mechanisms comparable to major stablecoins.

  • Blacklisting: A BLACKLIST_MANAGER_ROLE can freeze specific addresses via addBlackList and removeBlackList. Blacklisted addresses are strictly prohibited from sending or receiving tokens. The implementation follows the standard isBlackListed interface for compatibility with external compliance tools.
  • Emergency Pause: The PAUSER_ROLE can trigger a global pause, halting all token transfers, minting, and burning operations in the event of a security breach or system migration.
  • Access Control: The system utilizes granular role-based permissions. Distinct roles are assigned for upgrading the contract (UPGRADER_ROLE), managing fees (DEFAULT_ADMIN_ROLE), and operational tasks (Minting/Burning).

4.4 Deployment Details

The token has been deployed at the following proxy address 0x4e5A9fDb7F3473CDB86661AAd2b084B853D18B78 on Base Mainnet, with the following implementation address 0x80990084304cf47ed27159fd685992e9066a4584. Upon deployment the contract was initialized, granting the following roles DEFAULT_ADMIN_ROLE, PAUSER_ROLE, MINTER_ROLE, BURNER_ROLE, UPGRADER_ROLE, and BLACKLIST_MANAGER_ROLE to an address owned by the protocol 0x2F54Db274570b8222583Ef3eB8397e40EDf1B176 and setting the feeCollector at 0x2E27573b37127Ae773cd280B645f29298D1B55B2.

The token implements a fee-of-transfer mechanism. The contract is upgradable, meaning that the admin can change the logic of the token if necessary.

The bytecode of the deployed implementation can be verified to match the compiled code provided in the audited repository at this specific commit bbd7923e3a08bb23e8f85e5e27e158e3818d56fb by comparing a keccak hash of the locally compiled deployment bytecode against the deployment bytecode registered onchain:

  • Audited commit: keccak(deployed_code) == 0xcc73f7876c8c5817d65b21205207bee397f217bb515c125ea91175c82c4433b5
  • Deployed Onchain: keccak(deployed_code) == 0xcc73f7876c8c5817d65b21205207bee397f217bb515c125ea91175c82c4433b5

Given that both deployment binaries match when hashed, it is proven that the code provided in the respository is the same as the code deployed on-chain. Additionally, from the on-chain contract code, we can determine that the Solidity compiler version used was 0.8.24.

5

Risk Rating Methodology

The risk rating methodology used by Nethermind Security follows the principles established by the OWASP Foundation. The severity of each finding is determined by two factors: Likelihood and Impact.

Likelihood measures how likely the finding is to be uncovered and exploited by an attacker. This factor will be one of the following values:

  1. High: the issue is trivial to exploit and has no specific conditions that need to be met;
  2. Medium: the issue is moderately complex and may have some conditions that need to be met;
  3. Low: the issue is very complex and requires very specific conditions to be met.

When defining the likelihood of a finding, other factors are also considered. These can include but are not limited to motive, opportunity, exploit accessibility, ease of discovery, and ease of exploit.

Impact is a measure of the damage that may be caused if an attacker exploits the finding. This factor will be one of the following values:

  1. High: the issue can cause significant damage, such as loss of funds or the protocol entering an unrecoverable state;
  2. Medium: the issue can cause moderate damage, such as impacts that only affect a small group of users or only a particular part of the protocol;
  3. Low: the issue can cause little to no damage, such as bugs that are easily recoverable or cause unexpected interactions that cause minor inconveniences.

When defining the impact of a finding, other factors are also considered. These can include but are not limited to data and state integrity, loss of availability, financial loss, and reputation damage. After defining the likelihood and impact of an issue, the severity is determined according to the table below.

Impact / LikelihoodLowMediumHigh
HighMediumHighCritical
MediumLowMediumHigh
LowInfo / Best PracticesLowMedium
UndeterminedUndeterminedUndeterminedUndetermined

To address issues that do not fit a High, Medium or Low severity, Nethermind Security also uses three more finding severities: Informational, Best Practices, and Undetermined.

  1. Informational findings do not pose any risk to the application, but they carry some information that the audit team intends to pass to the client formally;
  2. Best Practice findings are used when some piece of code does not conform with smart contract development best practices;
  3. Undetermined findings are used when we cannot predict the impact or likelihood of the issue.

6

Issues

6.1 Blacklisted spenders can still execute transfers via transferFrom(...)

FileFix commitTypeStatus
src/StandardGoldCoin.sol—MediumFixed

The StandardGoldCoin contract implements a blacklist mechanism designed to freeze malicious accounts and prevent them from participating in transactions. This restriction is enforced by overriding the _update(...) function to check both the sender ( from) and the recipient ( to).

However, the contract inherits the standard ERC20 transferFrom(...) logic without overriding it or _spendAllowance(...) to validate the status of the spender.

In a transferFrom(...) operation, the msg.sender is the spender. Since _update(...) only verifies the token owner and the recipient, a blacklisted address acting as a spender can still move funds on behalf of other users. This bypasses the intent of the blacklist, which is to isolate the malicious account from the protocol.

// @audit The _spendAllowance function doesn't check if the spender is blacklisted or not
function _update(address from, address to, uint256 value) internal override whenNotPaused {
// Enforce blacklist (skip for mint/burn)
if (from != address(0)) require(!_blacklisted[from], "SGC: sender blacklisted");
if (to != address(0)) require(!_blacklisted[to], "SGC: recipient blacklisted");

// ...
}

Recommendation

Consider overriding the _spendAllowance(...) function to explicitly require that msg.sender (the spender) is not blacklisted.

6.2 The EOA check in initialize(...) can be bypassed by contracts during construction

FileFix commitTypeStatus
/src/StandardGoldCoin.sol—InfoMitigated

The initialize(...) function attempts to distinguish whether the provided admin address is an Externally Owned Account (EOA) or a smart contract to correctly assign the feeCollector. The protocol explicitly intends for the feeCollector to be address(0) if the admin is a contract to avoid assigning a contract as a fee collector.

However, the logic relies on admin.code.length == 0 to verify EOA status. In Solidity, a smart contract returns a code size of 0 while it is being executed inside its own constructor.

This creates an edge case where a smart contract could call initialize(...) during its construction phase. The check would falsely identify it as an EOA, resulting in the contract address being assigned as the feeCollector, contrary to the protocol's intended design constraints.

function initialize(address admin) public initializer {
// ...
// @audit-issue Returns 0 if admin is a contract currently being constructed
if (admin.code.length == 0) {
feeCollector = admin;
emit FeeCollectorChanged(address(0), admin);
} else {
feeCollector = address(0);
emit FeeCollectorChanged(address(0), address(0));
}
}

Recommendation

Consider documenting this behavior to ensure operational teams are aware of it.

6.3 supportsInterface returns false for ERC20, Metadata, and Permit interfaces

FileFix commitTypeStatus
/src/StandardGoldCoin.sol—InfoFixed

The contract overrides supportsInterface to ensure compatibility with AccessControlUpgradeable. However, the implementation simply delegates to super.supportsInterface.

Since OpenZeppelin's ERC20Upgradeable and ERC20PermitUpgradeable do not implement ERC165 by default, the super call chain does not account for them. Consequently, the contract reports that it does not support the following standard interfaces, despite fully implementing them IERC20, IERC20Metadata, and IERC20Permit.

This creates a discrepancy where the contract functions as an ERC20/Permit token but denies supporting these interfaces.

// ...
function supportsInterface(bytes4 interfaceId) public view override(AccessControlUpgradeable) returns (bool) {
// @audit Returns false for IERC20, IERC20Metadata, and IERC20Permit
return super.supportsInterface(interfaceId);
}

Recommendation

Consider manually checking for these interface IDs to provide accurate contract information.

Update from Nethermind Security

You don't need to manually calculate interface ID. You can do something like:

return interfaceId == type(IERC20).interfaceId ||
interfaceId == type(IERC20Metadata).interfaceId ||
interfaceId == type(IERC20Permit).interfaceId ||
super.supportsInterface(interfaceId);

6.4 The implementation contract does not call _disableInitializers(...) in the constructor

FileFix commitTypeStatus
src/StandardGoldCoin.sol—Best PracticesFixed

The StandardGoldCoin contract is designed as an upgradeable contract that inherits from Initializable and UUPSUpgradeable. It relies on the initialize(...) function to set up the initial state, such as granting the DEFAULT_ADMIN_ROLE and other roles to the admin address.

However, the contract does not implement a constructor that calls _disableInitializers().

This means that the logic contract (the implementation) can be initialized by any third party after deployment. According to OpenZeppelin's best practices for upgradeable contracts, the implementation contract should be "locked" in the constructor to prevent it from being used or initialized directly. Leaving it open can allow an attacker to claim ownership of the implementation contract.

contract StandardGoldCoin is
Initializable,
ERC20Upgradeable,
ERC20PermitUpgradeable,
AccessControlUpgradeable,
PausableUpgradeable,
UUPSUpgradeable
{
// ...
// @audit-issue The contract lacks a constructor calling _disableInitializers().

//..
}

Recommendation

Consider adding a constructor to the contract that calls _disableInitializers(). This ensures that the implementation contract is locked upon deployment and cannot be initialized by an attacker later on.

7

Documentation Evaluation

Software documentation refers to the written or visual information that describes the functionality, architecture, design, and implementation of software. It provides a comprehensive overview of the software system and helps users, developers, and stakeholders understand how the software works, how to use it, and how to maintain it. Software documentation can take different forms, such as user manuals, system manuals, technical specifications, requirements documents, design documents, and code comments. Software documentation is critical in software development, enabling effective communication between developers, testers, users, and other stakeholders. It helps to ensure that everyone involved in the development process has a shared understanding of the software system and its functionality. Moreover, software documentation can improve software maintenance by providing a clear and complete understanding of the software system, making it easier for developers to maintain, modify, and update the software over time. Smart contracts can use various types of software documentation. Some of the most common types include:

  • Technical whitepaper: A technical whitepaper is a comprehensive document describing the smart contract’s design and technical details. It includes information about the purpose of the contract, its architecture, its components, and how they interact with each other;
  • User manual: A user manual is a document that provides information about how to use the smart contract. It includes step-by-step instructions on how to perform various tasks and explains the different features and functionalities of the contract;
  • Code documentation: Code documentation is a document that provides details about the code of the smart contract. It includes information about the functions, variables, and classes used in the code, as well as explanations of how they work;
  • API documentation: API documentation is a document that provides information about the API (Application Programming Interface) of the smart contract. It includes details about the methods, parameters, and responses that can be used to interact with the contract;
  • Testing documentation: Testing documentation is a document that provides information about how the smart contract was tested. It includes details about the test cases that were used, the results of the tests, and any issues that were identified during testing;
  • Audit documentation: Audit documentation includes reports, notes, and other materials related to the security audit of the smart contract. This type of documentation is critical in ensuring that the smart contract is secure and free from vulnerabilities.

These types of documentation are essential for smart contract development and maintenance. They help ensure that the contract is properly designed, implemented, and tested, and they provide a reference for developers who need to modify or maintain the contract in the future.

8

Remarks & Test Suite

The documentation for the BlueGoldOne protocol was provided through Natspec. Moreover, the team addressed all questions and concerns raised by the Nethermind Security team, providing valuable insights and a comprehensive understanding of the project's technical aspects.

The AuditAgent is an AI-powered smart contract auditing tool that analyses code, detects vulnerabilities, and provides actionable fixes. It accelerates the security analysis process, complementing human expertise with advanced AI models to deliver efficient and comprehensive smart contract audits. Available at https://app.auditagent.nethermind.io.

Test suite
20Tests passed0Failed

The complete test output is in the full report.

As auditors, we recommend that any changes or updates made to the audited codebase undergo a re-audit or security review to address potential vulnerabilities or risks introduced by the modifications. By conducting a re-audit or security review of the modified codebase, you can significantly enhance the overall security of your system and reduce the likelihood of exploitation. However, we do not possess the authority or right to impose obligations or restrictions on our clients regarding codebase updates, modifications, or subsequent audits. Accordingly, the decision to seek a re-audit or security review lies solely with you.

This report is based on the scope of materials and documentation provided by you to Nethermind in order that Nethermind could conduct the security review outlined in 1. Executive Summary and 2. Audited Files. The results set out in this report may not be complete nor inclusive of all vulnerabilities. Nethermind has provided the review and this report on an as-is, where-is, and as-available basis. You agree that your access and/or use, including but not limited to any associated services, products, protocols, platforms, content, and materials, will be at your sole risk. Blockchain technology remains under development and is subject to unknown risks and flaws. The review does not extend to the compiler layer, or any other areas beyond the programming language, or other programming aspects that could present security risks. This report does not indicate the endorsement of any particular project or team, nor guarantee its security. No third party should rely on this report in any way, including for the purpose of making any decisions to buy or sell a product, service or any other asset. To the fullest extent permitted by law, Nethermind disclaims any liability in connection with this report, its content, and any related services and products and your use thereof, including, without limitation, the implied warranties of merchantability, fitness for a particular purpose, and non-infringement. Nethermind does not warrant, endorse, guarantee, or assume responsibility for any product or service advertised or offered by a third party through the product, any open source or third-party software, code, libraries, materials, or information linked to, called by, referenced by or accessible through the report, its content, and the related services and products, any hyperlinked websites, any websites or mobile applications appearing on any advertising, and Nethermind will not be a party to or in any way be responsible for monitoring any transaction between you and any third-party providers of products or services. As with the purchase or use of a product or service through any medium or in any environment, you should use your best judgment and exercise caution where appropriate. FOR AVOIDANCE OF DOUBT, THE REPORT, ITS CONTENT, ACCESS, AND/OR USAGE THEREOF, INCLUDING ANY ASSOCIATED SERVICES OR MATERIALS, SHALL NOT BE CONSIDERED OR RELIED UPON AS ANY FORM OF FINANCIAL, INVESTMENT, TAX, LEGAL, REGULATORY, OR OTHER ADVICE.