Merge branch 'dev'
This commit is contained in:
commit
b7853beca1
|
|
@ -800,13 +800,29 @@ class FolkWalletViewer extends HTMLElement {
|
||||||
const incoming: any[] = [];
|
const incoming: any[] = [];
|
||||||
const outgoing: any[] = [];
|
const outgoing: any[] = [];
|
||||||
const results = data.results || [];
|
const results = data.results || [];
|
||||||
|
const addr = this.address.toLowerCase();
|
||||||
for (const tx of results) {
|
for (const tx of results) {
|
||||||
|
// Outgoing: Safe-initiated multisig transactions
|
||||||
if (tx.txType === "MULTISIG_TRANSACTION") {
|
if (tx.txType === "MULTISIG_TRANSACTION") {
|
||||||
outgoing.push(tx);
|
outgoing.push(tx);
|
||||||
}
|
}
|
||||||
|
// Incoming: external ETH/token transfers to Safe
|
||||||
|
if (tx.txType === "ETHEREUM_TRANSACTION") {
|
||||||
|
if (tx.from && tx.value && tx.value !== "0") {
|
||||||
|
incoming.push({
|
||||||
|
type: "ETHER_TRANSFER",
|
||||||
|
from: tx.from,
|
||||||
|
to: this.address,
|
||||||
|
value: tx.value,
|
||||||
|
executionDate: tx.executionDate,
|
||||||
|
blockTimestamp: tx.executionDate,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Embedded transfers (both tx types may have these)
|
||||||
if (tx.transfers) {
|
if (tx.transfers) {
|
||||||
for (const t of tx.transfers) {
|
for (const t of tx.transfers) {
|
||||||
if (t.to?.toLowerCase() === this.address.toLowerCase()) {
|
if (t.to?.toLowerCase() === addr && t.from?.toLowerCase() !== addr) {
|
||||||
incoming.push(t);
|
incoming.push(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2606,7 +2622,13 @@ class FolkWalletViewer extends HTMLElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
const sorted = allBals
|
const sorted = allBals
|
||||||
.filter(b => parseFloat(b.fiatBalance || "0") > 0.01 || BigInt(b.balance || "0") > 0n)
|
.filter(b => {
|
||||||
|
const fiat = parseFloat(b.fiatBalance || "0");
|
||||||
|
if (fiat > 0.01) return true;
|
||||||
|
if (b.chainId === "local" || b.tokenAddress?.startsWith("crdt:")) return true;
|
||||||
|
if (!b.tokenAddress && BigInt(b.balance || "0") > 0n) return true;
|
||||||
|
return false;
|
||||||
|
})
|
||||||
.sort((a, b) => parseFloat(b.fiatBalance || "0") - parseFloat(a.fiatBalance || "0"));
|
.sort((a, b) => parseFloat(b.fiatBalance || "0") - parseFloat(a.fiatBalance || "0"));
|
||||||
|
|
||||||
const totalUSD = sorted.reduce((sum, b) => sum + parseFloat(b.fiatBalance || "0"), 0);
|
const totalUSD = sorted.reduce((sum, b) => sum + parseFloat(b.fiatBalance || "0"), 0);
|
||||||
|
|
@ -2679,7 +2701,13 @@ class FolkWalletViewer extends HTMLElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
const sorted = allBals
|
const sorted = allBals
|
||||||
.filter(b => parseFloat(b.fiatBalance || "0") > 0.01 || BigInt(b.balance || "0") > 0n)
|
.filter(b => {
|
||||||
|
const fiat = parseFloat(b.fiatBalance || "0");
|
||||||
|
if (fiat > 0.01) return true;
|
||||||
|
if (b.chainId === "local" || b.tokenAddress?.startsWith("crdt:")) return true;
|
||||||
|
if (!b.tokenAddress && BigInt(b.balance || "0") > 0n) return true;
|
||||||
|
return false;
|
||||||
|
})
|
||||||
.sort((a, b) => parseFloat(b.fiatBalance || "0") - parseFloat(a.fiatBalance || "0"));
|
.sort((a, b) => parseFloat(b.fiatBalance || "0") - parseFloat(a.fiatBalance || "0"));
|
||||||
|
|
||||||
const totalUSD = sorted.reduce((sum, b) => sum + parseFloat(b.fiatBalance || "0"), 0);
|
const totalUSD = sorted.reduce((sum, b) => sum + parseFloat(b.fiatBalance || "0"), 0);
|
||||||
|
|
@ -2732,8 +2760,9 @@ class FolkWalletViewer extends HTMLElement {
|
||||||
for (const ch of chains) {
|
for (const ch of chains) {
|
||||||
totalChains.add(ch.chainId);
|
totalChains.add(ch.chainId);
|
||||||
for (const b of ch.balances) {
|
for (const b of ch.balances) {
|
||||||
if (parseFloat(b.fiatBalance || "0") > 0.01 || BigInt(b.balance || "0") > 0n) {
|
const fiat = parseFloat(b.fiatBalance || "0");
|
||||||
grandTotal += parseFloat(b.fiatBalance || "0");
|
if (fiat > 0.01 || (!b.tokenAddress && BigInt(b.balance || "0") > 0n)) {
|
||||||
|
grandTotal += fiat;
|
||||||
totalTokens++;
|
totalTokens++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3047,7 +3076,13 @@ class FolkWalletViewer extends HTMLElement {
|
||||||
if (unified.length === 0) return '<div class="empty">No token balances found.</div>';
|
if (unified.length === 0) return '<div class="empty">No token balances found.</div>';
|
||||||
|
|
||||||
const sorted = unified
|
const sorted = unified
|
||||||
.filter((b) => parseFloat(b.fiatBalance || "0") > 0.01 || BigInt(b.balance || "0") > 0n)
|
.filter((b) => {
|
||||||
|
const fiat = parseFloat(b.fiatBalance || "0");
|
||||||
|
if (fiat > 0.01) return true;
|
||||||
|
if (b.chainId === "local" || b.tokenAddress?.startsWith("crdt:")) return true;
|
||||||
|
if (!b.tokenAddress && BigInt(b.balance || "0") > 0n) return true;
|
||||||
|
return false;
|
||||||
|
})
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
const fiatDiff = parseFloat(b.fiatBalance || "0") - parseFloat(a.fiatBalance || "0");
|
const fiatDiff = parseFloat(b.fiatBalance || "0") - parseFloat(a.fiatBalance || "0");
|
||||||
if (fiatDiff !== 0) return fiatDiff;
|
if (fiatDiff !== 0) return fiatDiff;
|
||||||
|
|
@ -3253,7 +3288,13 @@ class FolkWalletViewer extends HTMLElement {
|
||||||
// Aggregate stats across ALL chains (ignoring filter)
|
// Aggregate stats across ALL chains (ignoring filter)
|
||||||
const allBalances = this.getUnifiedBalances(true);
|
const allBalances = this.getUnifiedBalances(true);
|
||||||
const totalUSD = allBalances.reduce((sum, b) => sum + parseFloat(b.fiatBalance || "0"), 0);
|
const totalUSD = allBalances.reduce((sum, b) => sum + parseFloat(b.fiatBalance || "0"), 0);
|
||||||
const totalTokens = allBalances.filter((b) => parseFloat(b.fiatBalance || "0") > 0 || BigInt(b.balance || "0") > 0n).length;
|
const totalTokens = allBalances.filter((b) => {
|
||||||
|
const fiat = parseFloat(b.fiatBalance || "0");
|
||||||
|
if (fiat > 0.01) return true;
|
||||||
|
if (b.chainId === "local" || b.tokenAddress?.startsWith("crdt:")) return true;
|
||||||
|
if (!b.tokenAddress && BigInt(b.balance || "0") > 0n) return true;
|
||||||
|
return false;
|
||||||
|
}).length;
|
||||||
|
|
||||||
// Build chain buttons with "All" filter
|
// Build chain buttons with "All" filter
|
||||||
const chainButtons = this.detectedChains.map((ch) => {
|
const chainButtons = this.detectedChains.map((ch) => {
|
||||||
|
|
@ -3305,8 +3346,6 @@ class FolkWalletViewer extends HTMLElement {
|
||||||
</div>
|
</div>
|
||||||
</div>` : ""}
|
</div>` : ""}
|
||||||
|
|
||||||
${this.renderViewTabs()}
|
|
||||||
|
|
||||||
${this.activeView === "balances"
|
${this.activeView === "balances"
|
||||||
? this.renderBalanceTable() + this.renderDefiPositions() + this.renderPaymentActions()
|
? this.renderBalanceTable() + this.renderDefiPositions() + this.renderPaymentActions()
|
||||||
: `<div class="viz-wrapper">
|
: `<div class="viz-wrapper">
|
||||||
|
|
@ -3500,13 +3539,7 @@ class FolkWalletViewer extends HTMLElement {
|
||||||
this.addToWatchlist(addr, chain, label);
|
this.addToWatchlist(addr, chain, label);
|
||||||
});
|
});
|
||||||
|
|
||||||
// View tab listeners (skip tour button which has no data-view)
|
// View tab listeners no longer needed — shell subnav handles navigation
|
||||||
this.shadow.querySelectorAll(".view-tab[data-view]").forEach((tab) => {
|
|
||||||
tab.addEventListener("click", () => {
|
|
||||||
const view = (tab as HTMLElement).dataset.view as ViewTab;
|
|
||||||
this.handleViewTabClick(view);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.shadow.querySelector("#btn-tour")?.addEventListener("click", () => this.startTour());
|
this.shadow.querySelector("#btn-tour")?.addEventListener("click", () => this.startTour());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,8 @@ routes.get("/api/safe/:chainId/:address/balances", async (c) => {
|
||||||
fiatBalance: item.fiatBalance || "0",
|
fiatBalance: item.fiatBalance || "0",
|
||||||
fiatConversion: item.fiatConversion || "0",
|
fiatConversion: item.fiatConversion || "0",
|
||||||
}));
|
}));
|
||||||
const enriched = await enrichWithPrices(data, chainId);
|
const enriched = (await enrichWithPrices(data, chainId))
|
||||||
|
.filter(b => BigInt(b.balance || "0") > 0n);
|
||||||
c.header("Cache-Control", "public, max-age=30");
|
c.header("Cache-Control", "public, max-age=30");
|
||||||
return c.json(enriched);
|
return c.json(enriched);
|
||||||
});
|
});
|
||||||
|
|
@ -1258,13 +1259,17 @@ function renderWallet(spaceSlug: string, initialView?: string) {
|
||||||
modules: getModuleInfoList(),
|
modules: getModuleInfoList(),
|
||||||
theme: "dark",
|
theme: "dark",
|
||||||
body: `<folk-wallet-viewer space="${spaceSlug}"${viewAttr}></folk-wallet-viewer>`,
|
body: `<folk-wallet-viewer space="${spaceSlug}"${viewAttr}></folk-wallet-viewer>`,
|
||||||
scripts: `<script type="module" src="/modules/rwallet/folk-wallet-viewer.js?v=19"></script>`,
|
scripts: `<script type="module" src="/modules/rwallet/folk-wallet-viewer.js?v=20"></script>`,
|
||||||
styles: `<link rel="stylesheet" href="/modules/rwallet/wallet.css">`,
|
styles: `<link rel="stylesheet" href="/modules/rwallet/wallet.css">`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
routes.get("/wallets", (c) => c.html(renderWallet(c.req.param("space") || "demo", "budget")));
|
routes.get("/budget", (c) => c.html(renderWallet(c.req.param("space") || "demo", "budget")));
|
||||||
routes.get("/tokens", (c) => c.html(renderWallet(c.req.param("space") || "demo", "balances")));
|
routes.get("/tokens", (c) => c.html(renderWallet(c.req.param("space") || "demo", "balances")));
|
||||||
|
routes.get("/flows", (c) => c.html(renderWallet(c.req.param("space") || "demo", "flows")));
|
||||||
|
|
||||||
|
// Legacy aliases
|
||||||
|
routes.get("/wallets", (c) => c.html(renderWallet(c.req.param("space") || "demo", "budget")));
|
||||||
routes.get("/transactions", (c) => c.html(renderWallet(c.req.param("space") || "demo", "budget")));
|
routes.get("/transactions", (c) => c.html(renderWallet(c.req.param("space") || "demo", "budget")));
|
||||||
|
|
||||||
routes.get("/", (c) => c.html(renderWallet(c.req.param("space") || "demo", "budget")));
|
routes.get("/", (c) => c.html(renderWallet(c.req.param("space") || "demo", "budget")));
|
||||||
|
|
@ -1294,8 +1299,8 @@ export const walletModule: RSpaceModule = {
|
||||||
],
|
],
|
||||||
acceptsFeeds: ["economic", "governance"],
|
acceptsFeeds: ["economic", "governance"],
|
||||||
outputPaths: [
|
outputPaths: [
|
||||||
{ path: "wallets", name: "Wallets", icon: "💳", description: "Connected Safe wallets and EOA accounts" },
|
{ path: "budget", name: "Budget", icon: "📊", description: "Budget visualization — balance river timeline" },
|
||||||
{ path: "tokens", name: "Token Balances", icon: "🪙", description: "Token balances across chains" },
|
{ path: "tokens", name: "Token Balances", icon: "🪙", description: "Token balances across chains" },
|
||||||
{ path: "transactions", name: "Transactions", icon: "📜", description: "Transaction history and transfers" },
|
{ path: "flows", name: "Flows", icon: "🔀", description: "Sankey flow diagram with transaction scrubber" },
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue