Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,40 @@ import {
scaleAmount,
type AdminActionKey,
} from "../adminActions";
import { LEDGERS_PER_DAY } from "@/lib/soroban";

/**
* `AdminPanel` had no test at all, because nothing inside a 2,351-line
* component with two parallel if/else chains was independently reachable.
* With the capabilities declared as data, the mapping from form input to
* contract call is now directly assertable.
*/

const TOKEN = "CBTSFDGN5MU5NRKWSIBCMAMUGCHOC52H7KLZ44OKSGLC26BUKBZCCERJ";
const VESTING = "CD6RZ6E2HJHMSRRHEPCE2FWZWWVC543P67QSOPYKRAC7FIX52MZ6LMOF";
const ALICE = "GAEQZ5WIT3VJQ35W2JCQXFFKGUKOCKSCUZGWGVXQLZCMNXKXWKFQ7TV6";
const ADMIN = "GBONK2FUFJBONR6E7H6UN7H26ZNQYUCCF6YQRATRYWK3FOJGDBD3MXKX";

/** `create_schedule` / `extend_cliff` resolve ledgers relative to "now". */
const CURRENT_LEDGER = 1_000_000;


function makeContext(): AdminActionContext {
return {
contractId: TOKEN,
decimals: 7,
publicKey: ADMIN,
server: {
getLatestLedger: async () => ({ sequence: CURRENT_LEDGER }),
} as unknown as AdminActionContext["server"],
simulator: {} as AdminActionContext["simulator"],
};
}

/** Decode an Address ScVal back to its strkey. */
function addressOf(value: xdr.ScVal): string {
return Address.fromScVal(value).toString();
}

describe("scaleAmount", () => {
it("scales a decimal string into base units", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { rpc, Address, xdr } from "@stellar/stellar-sdk";
import { addressToScVal, i128ToScVal, nativeToScVal, daysToLedgers } from "@/lib/soroban";
import { Client as TokenClient } from "@/lib/bindings/token/src/index";
import type { AssembledTransaction } from "@stellar/stellar-sdk/contract";
import { Client as VestingClient } from "@/lib/bindings/vesting/src/index";
import { addressToScVal, i128ToScVal, nativeToScVal } from "@/lib/soroban";
import type { PreflightCheckResult } from "@/lib/transactionSimulator";
import type { useTransactionSimulator } from "@/hooks/useTransactionSimulator";
import type { BatchMintEntry } from "@/lib/batch";
Expand Down Expand Up @@ -34,8 +34,6 @@ import type {
* Adding a capability means adding one entry here plus the UI that calls it.
*/

/** Soroban ledgers per day, assuming 5-second ledgers. */
const LEDGERS_PER_DAY = 17280;

type Simulator = ReturnType<typeof useTransactionSimulator>;

Expand Down Expand Up @@ -127,7 +125,7 @@ function indexToScVal(scheduleIndex: string): xdr.ScVal {
/** "N days from now" as an absolute ledger sequence. */
async function ledgerInDays(server: rpc.Server, days: string | number) {
const { sequence } = await server.getLatestLedger();
return sequence + Math.round(Number(days) * LEDGERS_PER_DAY);
return daysToLedgers(days, sequence);
}

type AdminActionRegistry = {
Expand Down Expand Up @@ -216,8 +214,7 @@ export const ADMIN_ACTIONS: AdminActionRegistry = {
label: "Vesting",
resolve: async (data, ctx) => {
const cliffLedger = await ledgerInDays(ctx.server, data.cliffDays);
const endLedger =
cliffLedger + Math.round(Number(data.durationDays) * LEDGERS_PER_DAY);
const endLedger = daysToLedgers(data.durationDays, cliffLedger);

return ctx.getVestingClient(data.vestingContract).create_schedule({
recipient: data.recipient,
Expand All @@ -228,8 +225,7 @@ export const ADMIN_ACTIONS: AdminActionRegistry = {
},
preflight: async (data, ctx) => {
const cliffLedger = await ledgerInDays(ctx.server, data.cliffDays);
const endLedger =
cliffLedger + Math.round(Number(data.durationDays) * LEDGERS_PER_DAY);
const endLedger = daysToLedgers(data.durationDays, cliffLedger);
return ctx.simulator.checkCreateSchedule(
data.vestingContract,
data.recipient,
Expand Down
3 changes: 2 additions & 1 deletion frontend/components/forms/ApproveForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { PreflightCheckDisplay } from "@/components/ui/PreflightCheck";
import { useTransactionSimulator } from "@/hooks/useTransactionSimulator";
import { useWallet } from "@/app/hooks/useWallet";
import { buildApproveTransaction, fetchCurrentLedger, fetchTokenDecimals, parseTokenAmount, submitTransaction } from "@/lib/stellar";
import { daysToLedgers } from "@/lib/soroban";
import { useNetwork } from "@/app/providers/NetworkProvider";
import { AlertCircle, CheckCircle, Rocket, Loader2 } from "lucide-react";

Expand Down Expand Up @@ -67,7 +68,7 @@ export function ApproveForm({ onSuccess, onError }: ApproveFormProps) {

const getExpirationLedger = async (days: string): Promise<number> => {
const currentLedger = await fetchCurrentLedger(networkConfig);
return currentLedger + parseInt(days || "365") * 17280;
return daysToLedgers(days || "365", currentLedger);
};

const handleCheck = async () => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/hooks/useContractEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from "@/lib/stellar";

// Convert the exported array to a Set for efficient lookup
const TRACKED_TOPICS = new Set(TRACKED_EVENT_TOPICS);
const TRACKED_TOPICS = new Set<string>(TRACKED_EVENT_TOPICS);

interface UseContractEventsOptions {
intervalMs?: number;
Expand Down
3 changes: 2 additions & 1 deletion frontend/lib/recentTokens.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as StellarSdk from "@stellar/stellar-sdk";
import { type NetworkConfig } from "../types/network";
import { fetchTokenInfo, type TokenInfo } from "./stellar";
import { LEDGERS_PER_DAY } from "./soroban";

export interface RecentToken extends TokenInfo {
deployedAt: string;
Expand All @@ -15,7 +16,7 @@ interface RpcEvent {
value?: string;
}

const LOOKBACK_LEDGERS = 17280; // ~24 hours at ~5s per ledger
const LOOKBACK_LEDGERS = LEDGERS_PER_DAY; // ~24 hours at ~5s per ledger
const MAX_CANDIDATES = 20;
const MAX_RESULTS = 12;

Expand Down
7 changes: 7 additions & 0 deletions frontend/lib/soroban.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ import {

export { nativeToScVal, scValToNative };

/** Soroban ledgers per day, assuming 5-second ledgers. */
export const LEDGERS_PER_DAY = 17280;

export function daysToLedgers(days: number | string, currentLedger?: number): number {
const ledgers = Math.round(Number(days) * LEDGERS_PER_DAY);
return currentLedger !== undefined ? currentLedger + ledgers : ledgers;
}
/* ─────────────────────────────────────────────────────────────────────────
* Contract error code → human message mapping
*
Expand Down
16 changes: 1 addition & 15 deletions frontend/lib/stellar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1130,21 +1130,7 @@ export async function fetchTransactionHistory(
return { items: items.reverse(), nextCursor };
}

export type TokenActivityType =
| "mint"
| "transfer"
| "burn"
| "clawback"
| "freeze"
| "unfreeze"
| "pause"
| "unpause"
| "authorize"
| "unauthorize"
| "set_admin"
| "revoke_admin"
| "upgrade"
| "other";
export type TokenActivityType = (typeof TRACKED_EVENT_TOPICS)[number] | "other";

export interface TokenActivityInfo {
id: string;
Expand Down