Skip to content

chore(config): switch DEMO/USDCx/PROMPT display addresses to synthetic placeholders#287

Merged
salindne merged 1 commit into
mainfrom
s3b/synthetic-token-placeholders
May 28, 2026
Merged

chore(config): switch DEMO/USDCx/PROMPT display addresses to synthetic placeholders#287
salindne merged 1 commit into
mainfrom
s3b/synthetic-token-placeholders

Conversation

@salindne
Copy link
Copy Markdown
Contributor

Summary

The api-server's token.supported_tokens map keys each Canton-supported token by an EVM display address — the value MetaMask sees when rendering the user's Canton-side balance. These are placeholders, not real on-chain contracts:

  • PROMPT lives at 0x28d38dF637dB75533bD3F71426F3410a82041544 on Ethereum mainnet, but that address is only load-bearing in ethereum.token_contract of the relayer config (used to watch mainnet for deposit events).
  • USDCx and DEMO are Canton-native and have no Ethereum ERC-20 at all — any address there is purely for MetaMask display.

The previous USDCx placeholder reused real mainnet USDC's address (0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48). MetaMask flags that as a phishing risk on import because its anti-phishing check compares any imported token address against the known-mainnet-tokens registry — chain-agnostic, so the warning fires even on our Canton-facade chain. Arun hit this on prod1 yesterday:

"While importing USDCx to metamask, I am getting following error: This address matches a known Ethereum Mainnet token address. Recheck the contract address and network for the token you are trying to add."

What changed

Token Old address New address
PROMPT (missing from mainnet template) 0x9907000000000000000000000000000000000001
DEMO 0xDE30000000000000000000000000000000000001 unchanged
USDCx 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 (real mainnet USDC) 0xC1A0000000000000000000000000000000000001

The PROMPT placeholder is also switched defensively, in case PROMPT is ever listed in MM's high-profile registry. The relayer's ethereum.token_contract keeps the real mainnet PROMPT address — that side actually watches the on-chain contract for deposit events.

What's intentionally unchanged

  • pkg/config/defaults/config.api-server.docker.yaml keeps 0x5FbDB2…aa3 for PROMPT — that's the anvil-deterministic first-deploy address used by E2E tests, a real ERC-20 deployment.
  • pkg/config/defaults/config.api-server.local-devnet.yaml keeps 0x90cb4f9e…48e for PROMPT — the deployed Sepolia bridge token used by Sepolia↔devnet flows, also a real ERC-20.
  • Relayer configs keep all real on-chain addresses (ethereum.token_contract, ethereum.bridge_contract).
  • scripts/setup/bootstrap-bridge.go, contracts/canton-erc20/daml/bridge-wayfinder/src/Wayfinder/Bridge.daml, docs/WAYFINDER_DEPLOYMENT_REQUIREMENTS.md, and the contracts/* CHANGELOG/DEPLOYMENT docs all keep the real PROMPT mainnet address — those reference it as the real address it is.

Files touched

  • pkg/config/defaults/config.api-server.mainnet.yaml — USDCx swap, added PROMPT row with synthetic placeholder
  • pkg/config/defaults/config.api-server.docker.yaml — USDCx swap
  • pkg/config/defaults/config.api-server.local-devnet.yaml — USDCx swap
  • config.e2e-local.yaml — USDCx swap
  • pkg/config/tests/{minimal,missing-env,invalid-database-url,env-substitution}.api.yaml — USDCx swap (test fixtures)
  • tests/e2e/devstack/stack/types.goUSDCxTokenVirtualAddr constant updated, doc comment expanded

Test plan

  • go build ./... — clean
  • go vet ./... — clean
  • go test ./pkg/... — all green (config tests use the updated fixtures)
  • go test -tags e2e -count=0 ./tests/e2e/tests/... — compiles cleanly (runtime fails only on the expected devstack-not-running discovery step)
  • All CLI scripts in scripts/testing/ that touched these addresses compile

Heads-up for testers

Anyone with an existing MetaMask import of PROMPT or USDCx on the Canton-facade chain will see "0 balance" after this rolls out, because the api-server's eth_call balanceOf lookup keys on the new address. Remove the old token entry in MM and re-import using the new addresses above. Fresh accounts unaffected.

PROMPT bridging on real Ethereum mainnet is unaffected — the relayer continues to use the real 0x28d38d…1544 contract.

…c placeholders

The api-server's token.supported_tokens map keys these tokens by their EVM
display address — the value MetaMask sees when rendering the user's Canton-side
balance. They are placeholders, not real on-chain contracts: PROMPT lives at
0x28d38d…1544 on Ethereum mainnet but that address is only load-bearing in the
relayer's ethereum.token_contract; USDCx and DEMO are Canton-native and have no
mainnet ERC-20 at all.

The previous USDCx placeholder reused real mainnet USDC's address
(0xA0b86991…eB48), which MetaMask flags as a phishing risk when users try to
import the token (its anti-phishing check compares addresses against the known-
mainnet-tokens registry, chain-agnostic, so the warning fires even on our
Canton-facade chainId). Use synthetic addresses instead:

  PROMPT  0x9907000000000000000000000000000000000001  (was missing from mainnet template)
  DEMO    0xDE30000000000000000000000000000000000001  (unchanged)
  USDCx   0xC1A0000000000000000000000000000000000001  (was 0xA0b86991…eB48)

PROMPT is also given a synthetic placeholder defensively, in case it's ever
listed in MetaMask's high-profile registry. The relayer's ethereum.token_contract
keeps the real mainnet PROMPT address — that side is load-bearing.

The docker and local-devnet configs keep their existing PROMPT addresses
(0x5FbDB2…aa3 / 0x90cb4f9e…48e) because on those test chains PROMPT is the
actual deployed ERC-20 used by E2E bridge flows, not a display placeholder.

Updated:
  - pkg/config/defaults/config.api-server.{mainnet,docker,local-devnet}.yaml
  - config.e2e-local.yaml
  - pkg/config/tests/*.api.yaml fixtures
  - tests/e2e/devstack/stack/types.go (USDCxTokenVirtualAddr constant)
@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@38ad918). Learn more about missing BASE report.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #287   +/-   ##
=======================================
  Coverage        ?   31.27%           
=======================================
  Files           ?      131           
  Lines           ?    10179           
  Branches        ?        0           
=======================================
  Hits            ?     3183           
  Misses          ?     6725           
  Partials        ?      271           
Flag Coverage Δ
unittests 31.27% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces the real Ethereum mainnet address for USDC with a synthetic address (0xC1A0000000000000000000000000000000000001) for the USDCx token across multiple configuration and test files. This prevents MetaMask from flagging the imported token as a phishing attempt. Additionally, a new synthetic token 'PROMPT' has been added to the mainnet configuration. No review comments were provided, and the changes look correct.

@salindne salindne merged commit 14e507f into main May 28, 2026
4 of 5 checks passed
@salindne salindne deleted the s3b/synthetic-token-placeholders branch May 28, 2026 21:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants