diff --git a/README.md b/README.md
index d1c7a78..8232742 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
# PolyNote · Polygon message pusher
-Send hex-encoded messages on Polygon mainnet using the Trust Wallet browser extension or in-app browser. The app builds a zero-value transaction with your message in the data field, so only gas is spent.
+Send hex-encoded messages on Polygon mainnet using the Trust Wallet or Phantom browser extensions. The app builds a zero-value transaction with your message in the data field, so only gas is spent.
## What it does
-- Connects to an injected EIP-1193 provider (Trust Wallet) and targets Polygon mainnet.
+- Connects to injected EIP-1193 providers (Trust Wallet or Phantom) and targets Polygon mainnet.
- Hex-encodes up to 280 characters and sends a 0 MATIC transaction carrying the payload.
- Internationalization (English, Spanish, French, German, Italian, Swedish) with a locale picker and auto language detection.
- Live feedback, copy-to-clipboard for the tx hash, Polygonscan deep links, and a session “recent messages” view.
diff --git a/app/globals.css b/app/globals.css
index 9fb056d..f00579d 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -593,6 +593,52 @@ button:hover:not(:disabled) {
font-size: 12px;
}
+.wallet-selector {
+ margin-top: 12px;
+ padding: 14px;
+ border: 1px solid var(--border);
+ border-radius: 14px;
+ background: var(--surface);
+}
+
+.wallet-selector-head {
+ display: flex;
+ align-items: baseline;
+ gap: 12px;
+ flex-wrap: wrap;
+ margin-bottom: 10px;
+}
+
+.wallet-toggle {
+ display: inline-flex;
+ gap: 10px;
+}
+
+.wallet-chip {
+ border: 1px solid var(--border);
+ background: var(--surface-soft);
+ color: var(--ink);
+ padding: 10px 14px;
+ border-radius: 12px;
+ font-weight: 700;
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.wallet-chip.active {
+ border-color: var(--accent);
+ background: rgba(14, 165, 233, 0.12);
+ color: var(--accent-strong);
+ box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.15);
+}
+
+.wallet-icon {
+ width: 18px;
+ height: 18px;
+ display: inline-block;
+}
+
.footer {
margin-top: 8px;
padding: 14px 18px;
diff --git a/app/locales/de.json b/app/locales/de.json
index 221e4c9..8e710fa 100644
--- a/app/locales/de.json
+++ b/app/locales/de.json
@@ -9,15 +9,16 @@
"light": "Heller Modus"
},
"hero": {
- "eyebrow": "Eingebettetes Trust Wallet • Polygon Mainnet",
- "title": "PolyNote · Trust Wallet zu Polygon",
- "lede": "Verbinde dich mit der Trust-Wallet-Erweiterung oder dem In-App-Browser. Wir kodieren deinen Text in Hex und senden eine Null-MATIC-Transaktion auf Polygon – nur Gasgebühren fallen an."
+ "eyebrow": "Trust Wallet oder Phantom • Polygon Mainnet",
+ "title": "PolyNote · Eingebettete Wallets zu Polygon",
+ "lede": "Verbinde dich mit den Erweiterungen von Trust Wallet oder Phantom. Wir kodieren deinen Text in Hex und senden eine 0-MATIC-Transaktion auf Polygon – nur Gasgebühren fallen an."
},
"connection": {
"title": "Verbindung",
- "subtitle": "Eingebettetes Trust Wallet (Browser-Erweiterung oder In-App dApp Browser).",
+ "subtitle": "Eingebettete Wallet (Trust Wallet- oder Phantom-Erweiterung).",
"pill": "Nur Polygon",
"connect": "Trust Wallet verbinden",
+ "connectWallet": "{wallet} verbinden",
"disconnect": "Trennen",
"account": "Konto",
"chain": "Netzwerk",
@@ -59,6 +60,12 @@
"footer": {
"repo": "Quellcode auf Gitea"
},
+ "wallet": {
+ "pick": "Wallet wählen",
+ "helper": "Nur injizierte Erweiterungen. Wähle Trust Wallet oder Phantom und verbinde dich.",
+ "trust": "Trust Wallet",
+ "phantom": "Phantom"
+ },
"status": {
"waiting": "Warten auf Verbindung…",
"preparingConnect": "Verbindung wird vorbereitet…",
@@ -78,7 +85,7 @@
"disconnected": "Getrennt."
},
"errors": {
- "noWallet": "Keine eingebettete Wallet gefunden. Verwende die Trust-Wallet-Erweiterung oder den In-App-Browser.",
+ "noWallet": "Keine injizierte {wallet} gefunden. Installiere die Erweiterung und versuche es erneut.",
"noAccounts": "Die Wallet hat keine Konten zurückgegeben.",
"sendFailed": "Nachrichten-Transaktion konnte nicht gesendet werden.",
"connectionFailed": "Verbindung fehlgeschlagen."
diff --git a/app/locales/en.json b/app/locales/en.json
index fafb1e1..d9310e1 100644
--- a/app/locales/en.json
+++ b/app/locales/en.json
@@ -9,15 +9,16 @@
"light": "Light mode"
},
"hero": {
- "eyebrow": "Injected Trust Wallet • Polygon mainnet",
- "title": "PolyNote · Trust Wallet to Polygon",
- "lede": "Connect with the Trust Wallet extension or the in-app browser. We hex-encode your text and submit a zero-value Polygon transaction that only costs gas."
+ "eyebrow": "Trust Wallet or Phantom • Polygon mainnet",
+ "title": "PolyNote · Injected wallets to Polygon",
+ "lede": "Connect with the Trust Wallet or Phantom browser extensions. We hex-encode your text and submit a zero-value Polygon transaction that only costs gas."
},
"connection": {
"title": "Connection",
- "subtitle": "Injected Trust Wallet (browser extension or in-app dApp browser).",
+ "subtitle": "Injected wallet (Trust Wallet or Phantom extension).",
"pill": "Polygon only",
"connect": "Connect Trust Wallet",
+ "connectWallet": "Connect {wallet}",
"disconnect": "Disconnect",
"account": "Account",
"chain": "Chain",
@@ -59,6 +60,12 @@
"footer": {
"repo": "Source on Gitea"
},
+ "wallet": {
+ "pick": "Choose a wallet",
+ "helper": "Injected extensions only. Pick Trust Wallet or Phantom, then connect.",
+ "trust": "Trust Wallet",
+ "phantom": "Phantom"
+ },
"status": {
"waiting": "Waiting to connect…",
"preparingConnect": "Preparing to connect…",
@@ -78,7 +85,7 @@
"disconnected": "Disconnected."
},
"errors": {
- "noWallet": "No injected wallet found. Try the Trust Wallet extension or app browser.",
+ "noWallet": "No injected {wallet} found. Install the extension and try again.",
"noAccounts": "No accounts returned from injected wallet.",
"sendFailed": "Failed to send message transaction.",
"connectionFailed": "Connection failed."
diff --git a/app/locales/es.json b/app/locales/es.json
index 36fc0db..e09cfd7 100644
--- a/app/locales/es.json
+++ b/app/locales/es.json
@@ -9,15 +9,16 @@
"light": "Modo claro"
},
"hero": {
- "eyebrow": "Trust Wallet inyectado • Polygon mainnet",
- "title": "PolyNote · Trust Wallet a Polygon",
- "lede": "Conecta con la extensión de Trust Wallet o el navegador dentro de la app. Codificamos tu texto en hex y enviamos una transacción de valor cero en Polygon; solo pagas gas."
+ "eyebrow": "Trust Wallet o Phantom • Polygon mainnet",
+ "title": "PolyNote · Wallets inyectadas a Polygon",
+ "lede": "Conecta con las extensiones de Trust Wallet o Phantom. Codificamos tu texto en hex y enviamos una transacción de valor cero en Polygon; solo pagas gas."
},
"connection": {
"title": "Conexión",
- "subtitle": "Trust Wallet inyectado (extensión o navegador dentro de la app).",
+ "subtitle": "Wallet inyectada (extensión Trust Wallet o Phantom).",
"pill": "Solo Polygon",
"connect": "Conectar Trust Wallet",
+ "connectWallet": "Conectar {wallet}",
"disconnect": "Desconectar",
"account": "Cuenta",
"chain": "Red",
@@ -59,6 +60,12 @@
"footer": {
"repo": "Código fuente en Gitea"
},
+ "wallet": {
+ "pick": "Elige una wallet",
+ "helper": "Solo extensiones inyectadas. Elige Trust Wallet o Phantom y conecta.",
+ "trust": "Trust Wallet",
+ "phantom": "Phantom"
+ },
"status": {
"waiting": "Esperando conexión…",
"preparingConnect": "Preparando conexión…",
@@ -78,7 +85,7 @@
"disconnected": "Desconectado."
},
"errors": {
- "noWallet": "No se encontró una wallet inyectada. Usa la extensión de Trust Wallet o el navegador de la app.",
+ "noWallet": "No se encontró una {wallet} inyectada. Instala la extensión e inténtalo de nuevo.",
"noAccounts": "La wallet no devolvió cuentas.",
"sendFailed": "No se pudo enviar la transacción con mensaje.",
"connectionFailed": "Fallo de conexión."
diff --git a/app/locales/fr.json b/app/locales/fr.json
index 6ea903d..5735217 100644
--- a/app/locales/fr.json
+++ b/app/locales/fr.json
@@ -9,15 +9,16 @@
"light": "Mode clair"
},
"hero": {
- "eyebrow": "Trust Wallet injecté • Polygon mainnet",
- "title": "PolyNote · Trust Wallet vers Polygon",
- "lede": "Connecte-toi avec l’extension Trust Wallet ou le navigateur intégré. Nous encodons ton texte en hex et envoyons une transaction à 0 MATIC sur Polygon ; seuls les frais de gas sont dus."
+ "eyebrow": "Trust Wallet ou Phantom • Polygon mainnet",
+ "title": "PolyNote · Wallets injectés vers Polygon",
+ "lede": "Connecte-toi avec les extensions Trust Wallet ou Phantom. Nous encodons ton texte en hex et envoyons une transaction à 0 MATIC sur Polygon ; seuls les frais de gas sont dus."
},
"connection": {
"title": "Connexion",
- "subtitle": "Trust Wallet injecté (extension navigateur ou navigateur dApp intégré).",
+ "subtitle": "Wallet injectée (extension Trust Wallet ou Phantom).",
"pill": "Polygon uniquement",
"connect": "Connecter Trust Wallet",
+ "connectWallet": "Connecter {wallet}",
"disconnect": "Déconnecter",
"account": "Compte",
"chain": "Réseau",
@@ -59,6 +60,12 @@
"footer": {
"repo": "Code source sur Gitea"
},
+ "wallet": {
+ "pick": "Choisis un wallet",
+ "helper": "Extensions injectées uniquement. Choisis Trust Wallet ou Phantom, puis connecte-toi.",
+ "trust": "Trust Wallet",
+ "phantom": "Phantom"
+ },
"status": {
"waiting": "En attente de connexion…",
"preparingConnect": "Préparation de la connexion…",
@@ -78,7 +85,7 @@
"disconnected": "Déconnecté."
},
"errors": {
- "noWallet": "Aucune wallet injectée trouvée. Utilise l’extension Trust Wallet ou le navigateur de l’app.",
+ "noWallet": "Aucun {wallet} injecté trouvé. Installe l’extension et réessaie.",
"noAccounts": "La wallet n’a renvoyé aucun compte.",
"sendFailed": "Impossible d’envoyer la transaction message.",
"connectionFailed": "Échec de connexion."
diff --git a/app/locales/it.json b/app/locales/it.json
index 870afc5..e197ff8 100644
--- a/app/locales/it.json
+++ b/app/locales/it.json
@@ -9,15 +9,16 @@
"light": "Modalità chiara"
},
"hero": {
- "eyebrow": "Trust Wallet iniettato • Polygon mainnet",
- "title": "PolyNote · Trust Wallet su Polygon",
- "lede": "Connetti con l’estensione di Trust Wallet o il browser integrato. Codifichiamo il testo in hex e inviamo una transazione a 0 MATIC su Polygon; paghi solo il gas."
+ "eyebrow": "Trust Wallet o Phantom • Polygon mainnet",
+ "title": "PolyNote · Wallet iniettate su Polygon",
+ "lede": "Connettiti con le estensioni di Trust Wallet o Phantom. Codifichiamo il testo in hex e inviamo una transazione a 0 MATIC su Polygon; paghi solo il gas."
},
"connection": {
"title": "Connessione",
- "subtitle": "Trust Wallet iniettato (estensione o browser dApp integrato).",
+ "subtitle": "Wallet iniettata (estensione Trust Wallet o Phantom).",
"pill": "Solo Polygon",
"connect": "Connetti Trust Wallet",
+ "connectWallet": "Connetti {wallet}",
"disconnect": "Disconnetti",
"account": "Account",
"chain": "Rete",
@@ -59,6 +60,12 @@
"footer": {
"repo": "Codice sorgente su Gitea"
},
+ "wallet": {
+ "pick": "Scegli un wallet",
+ "helper": "Solo estensioni iniettate. Scegli Trust Wallet o Phantom, poi connettiti.",
+ "trust": "Trust Wallet",
+ "phantom": "Phantom"
+ },
"status": {
"waiting": "In attesa di connessione…",
"preparingConnect": "Preparazione della connessione…",
@@ -78,7 +85,7 @@
"disconnected": "Disconnesso."
},
"errors": {
- "noWallet": "Nessun wallet iniettato trovato. Usa l’estensione Trust Wallet o il browser dell’app.",
+ "noWallet": "Nessuna {wallet} iniettata trovata. Installa l’estensione e riprova.",
"noAccounts": "Il wallet non ha restituito account.",
"sendFailed": "Impossibile inviare la transazione con messaggio.",
"connectionFailed": "Connessione fallita."
diff --git a/app/locales/sv.json b/app/locales/sv.json
index 446ee40..ff42459 100644
--- a/app/locales/sv.json
+++ b/app/locales/sv.json
@@ -9,15 +9,16 @@
"light": "Ljust läge"
},
"hero": {
- "eyebrow": "Injektad Trust Wallet • Polygon mainnet",
- "title": "PolyNote · Trust Wallet till Polygon",
- "lede": "Anslut via Trust Wallets tillägg eller den inbyggda webbläsaren. Vi kodar din text i hex och skickar en 0 MATIC-transaktion på Polygon; du betalar bara gas."
+ "eyebrow": "Trust Wallet eller Phantom • Polygon mainnet",
+ "title": "PolyNote · Injekterade wallets till Polygon",
+ "lede": "Anslut med Trust Wallet- eller Phantom-tilläggen. Vi kodar din text i hex och skickar en 0 MATIC-transaktion på Polygon; du betalar bara gas."
},
"connection": {
"title": "Anslutning",
- "subtitle": "Injekterad Trust Wallet (tillägg eller in-app dApp-webbläsare).",
+ "subtitle": "Injekterad wallet (Trust Wallet- eller Phantom-tillägg).",
"pill": "Endast Polygon",
"connect": "Anslut Trust Wallet",
+ "connectWallet": "Anslut {wallet}",
"disconnect": "Koppla från",
"account": "Konto",
"chain": "Nätverk",
@@ -59,6 +60,12 @@
"footer": {
"repo": "Källkod på Gitea"
},
+ "wallet": {
+ "pick": "Välj en wallet",
+ "helper": "Endast injekterade tillägg. Välj Trust Wallet eller Phantom och anslut.",
+ "trust": "Trust Wallet",
+ "phantom": "Phantom"
+ },
"status": {
"waiting": "Väntar på anslutning…",
"preparingConnect": "Förbereder anslutning…",
@@ -78,7 +85,7 @@
"disconnected": "Frånkopplad."
},
"errors": {
- "noWallet": "Ingen injekterad plånbok hittades. Använd Trust Wallet-tillägget eller appens webbläsare.",
+ "noWallet": "Ingen injekterad {wallet} hittades. Installera tillägget och försök igen.",
"noAccounts": "Plånboken returnerade inga konton.",
"sendFailed": "Det gick inte att skicka meddelande-transaktionen.",
"connectionFailed": "Anslutningen misslyckades."
diff --git a/app/page.tsx b/app/page.tsx
index 7a131b7..d612557 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -24,11 +24,13 @@ type Eip1193Provider = {
providers?: Eip1193Provider[];
isTrustWallet?: boolean;
isTrust?: boolean;
+ isPhantom?: boolean;
};
type EthereumWindow = Window & {
ethereum?: Eip1193Provider & { providers?: Eip1193Provider[] };
trustwallet?: Eip1193Provider;
+ phantom?: { ethereum?: Eip1193Provider };
};
const formatChain = (chainId: number | null) => {
@@ -45,6 +47,32 @@ type MessageEntry = {
createdAt: number;
};
+function TrustIcon() {
+ return (
+
+ );
+}
+
+function PhantomIcon() {
+ return (
+
+ );
+}
+
export default function HomePage() {
const { locale, setLocale, t, localeOptions } = useI18n("en");
const [account, setAccount] = useState("");
@@ -55,6 +83,7 @@ export default function HomePage() {
key: "status.waiting",
tone: "info",
});
+ const [walletChoice, setWalletChoice] = useState<"trust" | "phantom">("trust");
const [connecting, setConnecting] = useState(false);
const [sending, setSending] = useState(false);
const [connected, setConnected] = useState(false);
@@ -72,6 +101,7 @@ export default function HomePage() {
: status.tone === "error"
? "status-line status-error"
: "status-line";
+ const walletLabel = walletChoice === "trust" ? t("wallet.trust") : t("wallet.phantom");
const chainPillClass = onPolygon ? "pill pill-live" : "pill pill-quiet";
const chainPillText = onPolygon ? "Polygon" : chainLabel || t("live.chainRequired");
const disableSend = !connected || sending;
@@ -106,7 +136,7 @@ export default function HomePage() {
await disconnect(false);
try {
- await connectInjected();
+ await connectInjected(walletChoice);
} catch (err) {
console.error("Connection failed", err);
setStatusMessage(normalizeError(err, t("errors.connectionFailed"), t), "error");
@@ -116,10 +146,14 @@ export default function HomePage() {
}
}
- async function connectInjected() {
- const injected = pickInjectedProvider();
+ async function connectInjected(choice: "trust" | "phantom") {
+ const injected = pickInjectedProvider(choice);
if (!injected) {
- setStatusMessage(t("errors.noWallet"), "error", "errors.noWallet");
+ setStatusMessage(
+ t("errors.noWallet", { wallet: t(choice === "trust" ? "wallet.trust" : "wallet.phantom") }),
+ "error",
+ "errors.noWallet"
+ );
return;
}
@@ -174,6 +208,23 @@ export default function HomePage() {
setTxHash("—");
}
+ async function refreshSigner() {
+ if (!providerRef.current) return;
+ try {
+ const browserProvider = new ethers.BrowserProvider(
+ providerRef.current as unknown as ethers.Eip1193Provider
+ );
+ const signer = await browserProvider.getSigner();
+ signerRef.current = signer;
+ const address = await signer.getAddress();
+ const network = await browserProvider.getNetwork();
+ setAccount(address);
+ setChainId(Number(network.chainId));
+ } catch (err) {
+ console.warn("Failed to refresh signer after chain change", err);
+ }
+ }
+
function attachProviderEvents(provider: Eip1193Provider) {
if (!provider?.on) return;
provider.on("accountsChanged", handleAccountsChanged);
@@ -210,6 +261,7 @@ export default function HomePage() {
if (typeof newChainId !== "string" && typeof newChainId !== "number") return;
const parsed = parseChainId(newChainId);
setChainId(parsed);
+ void refreshSigner();
}
async function ensurePolygonChain() {
@@ -220,6 +272,7 @@ export default function HomePage() {
params: [{ chainId: "0x89" }],
});
setChainId(137);
+ await refreshSigner();
return true;
} catch (err) {
console.warn("Chain switch rejected", err);
@@ -393,6 +446,33 @@ export default function HomePage() {
{theme === "dark" ? t("theme.light") : t("theme.dark")}
+
+
+
+
{t("wallet.pick")}
+
{t("wallet.helper")}
+
+
+
+
+
+
@@ -413,7 +493,9 @@ export default function HomePage() {
onClick={connectWallet}
disabled={disableConnect}
>
- {connecting ? t("compose.sending") : t("connection.connect")}
+ {connecting
+ ? t("compose.sending")
+ : t("connection.connectWallet", { wallet: walletLabel })}