Implement ETH send and QR code receive
All checks were successful
check / check (push) Successful in 22s
All checks were successful
check / check (push) Successful in 22s
Send: stores mnemonic/private key with wallet data, derives signing key from mnemonic + address index via ethers HDNodeWallet, constructs transaction with parseEther, broadcasts via sendTransaction, waits for confirmation, shows block number and tx hash. ENS resolution in To field preserved. Receive: QR code rendered to canvas via qrcode library (1.5.4). Shows scannable QR above the full address text. README updated with qrcode dependency and TODO progress.
This commit is contained in:
@@ -5,8 +5,10 @@ const {
|
||||
Wallet,
|
||||
JsonRpcProvider,
|
||||
formatEther,
|
||||
parseEther,
|
||||
} = require("ethers");
|
||||
const { getTopTokenPrices } = require("../shared/tokens");
|
||||
const QRCode = require("qrcode");
|
||||
|
||||
const DEBUG = true;
|
||||
const DEBUG_MNEMONIC =
|
||||
@@ -145,6 +147,22 @@ function formatUsd(amount) {
|
||||
);
|
||||
}
|
||||
|
||||
// Get an ethers Wallet (signer) for the currently selected address
|
||||
function getSignerForCurrentAddress() {
|
||||
const wallet = state.wallets[state.selectedWallet];
|
||||
const addrIndex = state.selectedAddress;
|
||||
if (wallet.type === "hd") {
|
||||
const node = HDNodeWallet.fromPhrase(
|
||||
wallet.mnemonic,
|
||||
"",
|
||||
BIP44_ETH_BASE,
|
||||
);
|
||||
return node.deriveChild(addrIndex);
|
||||
} else {
|
||||
return new Wallet(wallet.privateKey);
|
||||
}
|
||||
}
|
||||
|
||||
// -- balance fetching --
|
||||
function getProvider() {
|
||||
return new JsonRpcProvider(state.rpcUrl);
|
||||
@@ -415,6 +433,7 @@ async function init() {
|
||||
type: "hd",
|
||||
name: "Wallet " + walletNum,
|
||||
xpub: xpub,
|
||||
mnemonic: mnemonic,
|
||||
nextIndex: 1,
|
||||
addresses: [
|
||||
{ address: firstAddress, balance: "0.0000", tokens: [] },
|
||||
@@ -444,6 +463,7 @@ async function init() {
|
||||
addWalletAndGoToMain({
|
||||
type: "key",
|
||||
name: "Wallet " + walletNum,
|
||||
privateKey: key,
|
||||
addresses: [{ address: addr, balance: "0.0000", tokens: [] }],
|
||||
});
|
||||
});
|
||||
@@ -485,7 +505,15 @@ async function init() {
|
||||
|
||||
$("btn-receive").addEventListener("click", () => {
|
||||
const addr = currentAddress();
|
||||
$("receive-address").textContent = addr ? addr.address : "";
|
||||
const address = addr ? addr.address : "";
|
||||
$("receive-address").textContent = address;
|
||||
if (address) {
|
||||
QRCode.toCanvas($("receive-qr"), address, {
|
||||
width: 200,
|
||||
margin: 2,
|
||||
color: { dark: "#000000", light: "#ffffff" },
|
||||
});
|
||||
}
|
||||
showView("receive");
|
||||
});
|
||||
|
||||
@@ -530,13 +558,29 @@ async function init() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// TODO: prompt for password, decrypt key, construct and send transaction
|
||||
const el = $("send-status");
|
||||
el.textContent =
|
||||
"Sending to " +
|
||||
resolvedTo +
|
||||
" (stub — password/signing not yet implemented)";
|
||||
el.classList.remove("hidden");
|
||||
const statusEl = $("send-status") || $("send-status");
|
||||
statusEl.textContent = "Sending...";
|
||||
statusEl.classList.remove("hidden");
|
||||
try {
|
||||
const signer = getSignerForCurrentAddress();
|
||||
const provider = getProvider();
|
||||
const connectedSigner = signer.connect(provider);
|
||||
const tx = await connectedSigner.sendTransaction({
|
||||
to: resolvedTo,
|
||||
value: parseEther(amount),
|
||||
});
|
||||
statusEl.textContent = "Sent. Waiting for confirmation...";
|
||||
const receipt = await tx.wait();
|
||||
statusEl.textContent =
|
||||
"Confirmed in block " +
|
||||
receipt.blockNumber +
|
||||
". Tx: " +
|
||||
receipt.hash;
|
||||
// Refresh balance after send
|
||||
refreshBalances().then(() => renderWalletList());
|
||||
} catch (e) {
|
||||
statusEl.textContent = "Failed: " + (e.shortMessage || e.message);
|
||||
}
|
||||
});
|
||||
|
||||
$("btn-send-back").addEventListener("click", () => {
|
||||
|
||||
Reference in New Issue
Block a user