From 7436eb203c909c53440e51db0c3f538ce9e15622 Mon Sep 17 00:00:00 2001
From: Dev
Date: Sun, 30 Aug 2026 14:45:08 +0100
Subject: [PATCH] fix: resolve issues 292 293 294 295
---
.github/dependabot.yml | 20 +++++
.github/workflows/web.yml | 2 +-
.../issuer/panels/DistributionPanel.tsx | 83 ++++++++++++++++++-
components/issuer/panels/TokenPanel.tsx | 10 +++
lib/contracts.ts | 16 ++++
5 files changed, 129 insertions(+), 2 deletions(-)
create mode 100644 .github/dependabot.yml
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..86b868e
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,20 @@
+version: 2
+updates:
+ - package-ecosystem: npm
+ directory: "/"
+ schedule:
+ interval: weekly
+ day: monday
+ open-pull-requests-limit: 10
+ labels:
+ - dependencies
+ groups:
+ stellar:
+ patterns:
+ - "@stellar/*"
+ testing:
+ patterns:
+ - "jest*"
+ - "@types/jest"
+ - "@testing-library/*"
+ - "ts-jest"
diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml
index cf23031..b8a1395 100644
--- a/.github/workflows/web.yml
+++ b/.github/workflows/web.yml
@@ -28,7 +28,7 @@ jobs:
run: npm run typecheck
- name: Test
- run: npm test
+ run: npm run test:ci
- name: Lint
run: npm run lint
diff --git a/components/issuer/panels/DistributionPanel.tsx b/components/issuer/panels/DistributionPanel.tsx
index 4d3f2cf..5565803 100644
--- a/components/issuer/panels/DistributionPanel.tsx
+++ b/components/issuer/panels/DistributionPanel.tsx
@@ -3,8 +3,10 @@
import { useState } from "react";
import { StrKey } from "@stellar/stellar-sdk";
import type { AssetDetail } from "@/types";
-import { dividend } from "@/lib/contracts";
+import { assetToken, contractIds, dividend } from "@/lib/contracts";
import { useTx } from "@/hooks/useTx";
+import { useAsync } from "@/hooks/useAsync";
+import { useWallet } from "@/hooks/useWallet";
import { useDividends } from "@/hooks/useDividends";
import { parseTokenAmount, formatTokenAmount, truncateAddress } from "@/lib/format";
import { PAYMENT_TOKEN_DECIMALS } from "@/components/dividend/ClaimButton";
@@ -43,10 +45,44 @@ function CreateDistributionCard({
onCreated?: () => void;
}) {
const tx = useTx();
+ const { address, network } = useWallet();
const [paymentToken, setPaymentToken] = useState("");
const [totalAmount, setTotalAmount] = useState("");
const [formError, setFormError] = useState(null);
+ // Only fetch when the input looks like a valid contract address.
+ const isValidPt =
+ paymentToken.trim().length > 0 &&
+ (StrKey.isValidContract(paymentToken.trim()) ||
+ StrKey.isValidEd25519PublicKey(paymentToken.trim()));
+
+ // #293: Show the issuer's balance in the payment token before they submit.
+ const { data: balance, loading: balanceLoading } = useAsync(
+ () => assetToken.balance(network, paymentToken.trim(), address!),
+ [network, paymentToken, address],
+ isValidPt && !!address,
+ );
+
+ // #293: Show how much the dividend contract is already approved to pull.
+ // Issuers need to approve at least totalAmount before the distribution can be funded.
+ const dividendContractId = contractIds(network).dividend;
+ const { data: allowance, loading: allowanceLoading } = useAsync(
+ () => assetToken.allowance(network, paymentToken.trim(), address!, dividendContractId),
+ [network, paymentToken, address, dividendContractId],
+ isValidPt && !!address,
+ );
+
+ // Parse the requested amount for comparison (best-effort; errors handled on submit).
+ let requestedRaw: bigint | null = null;
+ try {
+ if (totalAmount.trim()) requestedRaw = parseTokenAmount(totalAmount, PAYMENT_TOKEN_DECIMALS);
+ } catch {
+ // handled at submit time
+ }
+
+ const insufficientBalance = balance !== null && requestedRaw !== null && requestedRaw > balance;
+ const needsApproval = allowance !== null && requestedRaw !== null && requestedRaw > allowance;
+
async function onSubmit(e: React.FormEvent) {
e.preventDefault();
setFormError(null);
@@ -106,6 +142,51 @@ function CreateDistributionCard({
This is the token used to pay holders — typically a stablecoin or XLM SAC.
+
+ {/* #293: surface balance + allowance so the issuer knows before submitting */}
+ {isValidPt && address && (
+
+
+ Your balance
+ {balanceLoading ? (
+
+ ) : balance !== null ? (
+
+ {formatTokenAmount(balance, PAYMENT_TOKEN_DECIMALS)}
+
+ ) : (
+ —
+ )}
+
+
+ Dividend contract allowance
+ {allowanceLoading ? (
+
+ ) : allowance !== null ? (
+
+ {formatTokenAmount(allowance, PAYMENT_TOKEN_DECIMALS)}
+
+ ) : (
+ —
+ )}
+
+
+ )}
+
+ {insufficientBalance && (
+
+ Insufficient balance — your wallet holds less than the requested distribution amount.
+
+ )}
+ {needsApproval && !insufficientBalance && (
+
+ The dividend contract is not approved to spend enough of this token on your behalf.
+ Submit an approve transaction for at least{" "}
+ {formatTokenAmount(requestedRaw ?? 0n, PAYMENT_TOKEN_DECIMALS)} tokens before funding
+ this distribution.
+
+ )}
+
Total pool amount
diff --git a/components/issuer/panels/TokenPanel.tsx b/components/issuer/panels/TokenPanel.tsx
index eb41fc2..21c3145 100644
--- a/components/issuer/panels/TokenPanel.tsx
+++ b/components/issuer/panels/TokenPanel.tsx
@@ -91,6 +91,16 @@ function MintCard({
}
>
+ {/* #294: warn the issuer when the token is paused so mint attempts don't silently fail */}
+ {metadata.paused && (
+
+ This token is currently paused. Minting will likely fail until the token is
+ unpaused below.
+
+ )}