Beginner FriendlyDeFiFoundry
100 EXP
View results
Submission Details
Severity: high
Invalid

USDC deployment address is incorrect, preventing accounts from making any deposits

Summary

The network configuration that is used to deploy the system, uses an incorrect address for the USDC token contract. This makes the protocol unusable for accounts that want to make a deposit, as all function calls to the address will fail.

Vulnerability Details

The mafia take down project uses the Foundry devtools which provide deployment capabilities via deployment scripts. The Deployer script in Deployer.s.sol is such a deployment script and makes use of a HelperConfig to determine the network configuration for the deployment.

A NetworkConfig currently only comes with a single setting - the address for the USDC token on the deploy chain:

struct NetworkConfig {
address usdc;
}

This NetworkConfig is created for various chains, allowing for different configuration values on different networks:

constructor() {
networkConfigs[ETH_MAINNET_CHAIN_ID] = getEthMainnetConfig();
networkConfigs[ETH_SEPOLIA_CHAIN_ID] = getZkSyncSepoliaConfig();
networkConfigs[ZKSYNC_MAINNET_CHAIN_ID] = getZkSyncConfig();
networkConfigs[ZKSYNC_SEPOLIA_CHAIN_ID] = getZkSyncSepoliaConfig();
networkConfigs[POLYGON_MAINNET_CHAIN_ID] = getPolygonMainnetConfig();
networkConfigs[POLYGON_MUMBAI_CHAIN_ID] = getPolygonMumbaiConfig();
}

To determine the network configuration, Deployer calls HelperConfig::getActiveNetworkConfig, which looks up the desired configuration given a chain id. If it can't find a network config for the given chain id, it assumes the local anvil chain and deploys a MockUSDC contract as a placeholder token.

This is the reason why the mentioned bug hasn't become an issue in tests. For local testing, a placeholder token contract is deployed resulting always in a valid address for NetworkConfig::usdc.

However, all production (and test) network configurations use incorrect addresses, as we can see in the dedicated functions for each network.

function getEthMainnetConfig() public pure returns (NetworkConfig memory) {
@> return NetworkConfig({ usdc: address(1) });
}
function getZkSyncConfig() public pure returns (NetworkConfig memory) {
@> return NetworkConfig({ usdc: address(1) });
}
function getZkSyncSepoliaConfig() public pure returns (NetworkConfig memory) {
@> return NetworkConfig({ usdc: address(1) });
}
function getPolygonMainnetConfig() public pure returns (NetworkConfig memory) {
@> return NetworkConfig({ usdc: address(1) });
}
function getPolygonMumbaiConfig() public pure returns (NetworkConfig memory) {
@> return NetworkConfig({ usdc: address(1) });
}

When the system is deployed on any of the supported test or production networks, it will point to address(1) when making any calls to its USDC token reference.

USDC is not deployed on address(1) on any of the supported chains, so all of these calls will fail.

Impact

Since all expected function calls will fail, this means no account will be able to deposit any USDC token into the system, making it unusable for its intended purpose.

Unless the deployment script configuration will be changed, the likelyhood of this becoming an issue is high.

Tools Used

  • Manual review

  • Foundry

Recommended Mitigation

Ensure all HelperConfig::networkConfigs have correct addresses for USDC tokens.

Note: These are taken from circle.com/en/usdc/developer, please double check for correctness.

function getEthMainnetConfig() public pure returns (NetworkConfig memory) {
- return NetworkConfig({ usdc: address(1) });
+ return NetworkConfig({ usdc: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 });
}
function getZkSyncConfig() public pure returns (NetworkConfig memory) {
- return NetworkConfig({ usdc: address(1) });
+ return NetworkConfig({ usdc: 0x1d17CBcF0D6D143135aE902365D2E5e2A16538D4 });
}
function getZkSyncSepoliaConfig() public pure returns (NetworkConfig memory) {
- return NetworkConfig({ usdc: address(1) });
+ return NetworkConfig({ usdc: 0xAe045DE5638162fa134807Cb558E15A3F5A7F853 });
}
function getPolygonMainnetConfig() public pure returns (NetworkConfig memory) {
- return NetworkConfig({ usdc: address(1) });
+ return NetworkConfig({ usdc: 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 });
}

Proof of Concept

To proof that this is an issue, all we have to do is have NetworkConfig::usdc point to address(1) on the local test chain as well. We will then see that things like ERC20(usdc).transfer() and ERC20(usdc).transferFrom() will revert:

function getOrCreateAnvilEthConfig() public returns (NetworkConfig memory) {
if (localNetworkConfig.usdc != address(0)) {
return localNetworkConfig;
}
console2.log(unicode"⚠️ You have deployed a mock conract!");
console2.log("Make sure this was intentional");
vm.prank(Deployer(msg.sender).godFather());
address mockUsdc = _deployMocks();
- localNetworkConfig = NetworkConfig({ usdc: mockUsdc });
+ localNetworkConfig = NetworkConfig({ usdc: address(1) });
return localNetworkConfig;
}

Then, running the tests:

❯ forge test -v
[⠊] Compiling...
No files changed, compilation skipped
Ran 1 test for test/Deploy.t.sol:DeployTest
[PASS] test_deploy() (gas: 19780)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 9.86ms (248.33µs CPU time)
Ran 1 test for test/EmergencyMigration.t.sol:EmergencyMigrationTest
[PASS] test_migrate() (gas: 1233371)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 10.00ms (517.38µs CPU time)
Ran 3 tests for test/Laundrette.t.sol:LaundretteTest
[FAIL. Reason: EvmError: Revert] test_depositAndWithdrawUSDC() (gas: 10645)
[PASS] test_depositAndWithdrawWeapon() (gas: 139020)
[PASS] test_joinAndQuitGang() (gas: 97768)
Suite result: FAILED. 2 passed; 1 failed; 0 skipped; finished in 10.02ms (991.04µs CPU time)
Ran 3 test suites in 471.72ms (29.87ms CPU time): 4 tests passed, 1 failed, 0 skipped (5 total tests)
Failing tests:
Encountered 1 failing test in test/Laundrette.t.sol:LaundretteTest
[FAIL. Reason: EvmError: Revert] test_depositAndWithdrawUSDC() (gas: 10645)
Encountered a total of 1 failing tests, 4 tests succeeded
Updates

Lead Judging Commences

n0kto Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.