From abe190d63734efd191c8f23b27c77c0d0fa891fc Mon Sep 17 00:00:00 2001 From: Sebastian Lindner <33971232+salindne@users.noreply.github.com> Date: Thu, 28 May 2026 14:29:57 -0600 Subject: [PATCH] chore(config): switch DEMO/USDCx/PROMPT display addresses to synthetic placeholders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- config.e2e-local.yaml | 2 +- pkg/config/defaults/config.api-server.docker.yaml | 2 +- .../defaults/config.api-server.local-devnet.yaml | 2 +- pkg/config/defaults/config.api-server.mainnet.yaml | 11 ++++++++++- pkg/config/tests/env-substitution.api.yaml | 2 +- pkg/config/tests/invalid-database-url.api.yaml | 2 +- pkg/config/tests/minimal.api.yaml | 2 +- pkg/config/tests/missing-env.api.yaml | 2 +- tests/e2e/devstack/stack/types.go | 9 ++++++--- 9 files changed, 23 insertions(+), 11 deletions(-) diff --git a/config.e2e-local.yaml b/config.e2e-local.yaml index 28c724c..d135755 100644 --- a/config.e2e-local.yaml +++ b/config.e2e-local.yaml @@ -82,7 +82,7 @@ token: symbol: "DEMO" decimals: 18 instrument_id: "DEMO" - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": + "0xC1A0000000000000000000000000000000000001": name: "USD Coin" symbol: "USDCx" decimals: 6 diff --git a/pkg/config/defaults/config.api-server.docker.yaml b/pkg/config/defaults/config.api-server.docker.yaml index 434a0ab..125dc1b 100644 --- a/pkg/config/defaults/config.api-server.docker.yaml +++ b/pkg/config/defaults/config.api-server.docker.yaml @@ -86,7 +86,7 @@ token: symbol: "DEMO" decimals: 18 instrument_id: "DEMO" - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": + "0xC1A0000000000000000000000000000000000001": name: "USD Coin" symbol: "USDCx" decimals: 6 diff --git a/pkg/config/defaults/config.api-server.local-devnet.yaml b/pkg/config/defaults/config.api-server.local-devnet.yaml index 15b2f66..d871983 100644 --- a/pkg/config/defaults/config.api-server.local-devnet.yaml +++ b/pkg/config/defaults/config.api-server.local-devnet.yaml @@ -79,7 +79,7 @@ token: symbol: "DEMO" decimals: 18 instrument_id: "DEMO" - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": + "0xC1A0000000000000000000000000000000000001": name: "USD Coin" symbol: "USDCx" decimals: 6 diff --git a/pkg/config/defaults/config.api-server.mainnet.yaml b/pkg/config/defaults/config.api-server.mainnet.yaml index aaf9f48..d8ea5c4 100644 --- a/pkg/config/defaults/config.api-server.mainnet.yaml +++ b/pkg/config/defaults/config.api-server.mainnet.yaml @@ -48,12 +48,21 @@ canton: token: supported_tokens: + # Display-only synthetic addresses for MetaMask. The api-server's + # eth_call balanceOf facade keys balances by these addresses. They must + # NOT collide with well-known mainnet token contracts (e.g. real USDC, + # USDT, etc.) or MetaMask flags imports as suspected phishing. + "0x9907000000000000000000000000000000000001": + name: "PROMPT" + symbol: "PROMPT" + decimals: 18 + instrument_id: "PROMPT" "0xDE30000000000000000000000000000000000001": name: "Demo Token" symbol: "DEMO" decimals: 18 instrument_id: "DEMO" - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": + "0xC1A0000000000000000000000000000000000001": name: "USD Coin" symbol: "USDCx" decimals: 6 diff --git a/pkg/config/tests/env-substitution.api.yaml b/pkg/config/tests/env-substitution.api.yaml index ccc220f..b22ff59 100644 --- a/pkg/config/tests/env-substitution.api.yaml +++ b/pkg/config/tests/env-substitution.api.yaml @@ -31,7 +31,7 @@ token: symbol: "PROMPT" decimals: 18 instrument_id: "PROMPT" - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": + "0xC1A0000000000000000000000000000000000001": name: "USD Coin" symbol: "USDCx" decimals: 6 diff --git a/pkg/config/tests/invalid-database-url.api.yaml b/pkg/config/tests/invalid-database-url.api.yaml index 47f1040..6b55e8f 100644 --- a/pkg/config/tests/invalid-database-url.api.yaml +++ b/pkg/config/tests/invalid-database-url.api.yaml @@ -31,7 +31,7 @@ token: symbol: "PROMPT" decimals: 18 instrument_id: "PROMPT" - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": + "0xC1A0000000000000000000000000000000000001": name: "USD Coin" symbol: "USDCx" decimals: 6 diff --git a/pkg/config/tests/minimal.api.yaml b/pkg/config/tests/minimal.api.yaml index 17c043a..f7dd7ad 100644 --- a/pkg/config/tests/minimal.api.yaml +++ b/pkg/config/tests/minimal.api.yaml @@ -31,7 +31,7 @@ token: symbol: "PROMPT" decimals: 18 instrument_id: "PROMPT" - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": + "0xC1A0000000000000000000000000000000000001": name: "USD Coin" symbol: "USDCx" decimals: 6 diff --git a/pkg/config/tests/missing-env.api.yaml b/pkg/config/tests/missing-env.api.yaml index ee39fb6..52ad978 100644 --- a/pkg/config/tests/missing-env.api.yaml +++ b/pkg/config/tests/missing-env.api.yaml @@ -31,7 +31,7 @@ token: symbol: "PROMPT" decimals: 18 instrument_id: "PROMPT" - "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": + "0xC1A0000000000000000000000000000000000001": name: "USD Coin" symbol: "USDCx" decimals: 6 diff --git a/tests/e2e/devstack/stack/types.go b/tests/e2e/devstack/stack/types.go index 7e63f5c..195edb6 100644 --- a/tests/e2e/devstack/stack/types.go +++ b/tests/e2e/devstack/stack/types.go @@ -23,9 +23,12 @@ const ( DemoTokenVirtualAddr = "0xDE30000000000000000000000000000000000001" // USDCxTokenVirtualAddr is the well-known virtual EVM address mapped to the - // USDCx external token in the api-server configuration. - // #nosec G101 -- public deterministic EVM contract address, not a credential. - USDCxTokenVirtualAddr = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + // USDCx external token in the api-server configuration. Synthetic (no real + // on-chain meaning) so MetaMask's anti-phishing check — which compares + // imported token addresses against its known-mainnet-tokens registry — does + // not flag USDCx imports as a possible spoof of real-mainnet USDC. + // #nosec G101 -- synthetic placeholder EVM address, not a credential. + USDCxTokenVirtualAddr = "0xC1A0000000000000000000000000000000000001" ) // CantonHolding is a minimal view of a CIP56Holding contract used by E2E tests.