- {isProxyEnabled && !selectedProxyId && (
+ {isProxyEnabled && proxies && proxies.length > 0 && !selectedProxyId && (
diff --git a/src/components/pages/wallet/governance/proposal/voteButtton.tsx b/src/components/pages/wallet/governance/proposal/voteButtton.tsx
index 5f5a72e3..8c99ab2c 100644
--- a/src/components/pages/wallet/governance/proposal/voteButtton.tsx
+++ b/src/components/pages/wallet/governance/proposal/voteButtton.tsx
@@ -87,14 +87,13 @@ export default function VoteButton({
{ enabled: !!(appWallet?.id || userAddress) }
);
+ // Check if we have valid proxy data (proxy enabled, selected, proxies exist, and selected proxy is found)
+ const hasValidProxy = !!(isProxyEnabled && selectedProxyId && proxies && proxies.length > 0 && proxies.find((p: any) => p.id === selectedProxyId));
+
async function voteProxy() {
- if (!isProxyEnabled || !selectedProxyId) {
- toast({
- title: "Proxy Error",
- description: "Proxy mode not enabled or no proxy selected",
- variant: "destructive",
- });
- return;
+ if (!hasValidProxy) {
+ // Fall back to standard vote if no valid proxy
+ return vote();
}
setLoading(true);
@@ -102,12 +101,8 @@ export default function VoteButton({
// Get the selected proxy
const proxy = proxies?.find((p: any) => p.id === selectedProxyId);
if (!proxy) {
- toast({
- title: "Proxy Error",
- description: "Selected proxy not found",
- variant: "destructive",
- });
- return;
+ // Fall back to standard vote if proxy not found
+ return vote();
}
// Create proxy contract instance
@@ -125,14 +120,14 @@ export default function VoteButton({
);
proxyContract.proxyAddress = proxy.proxyAddress;
- // Prepare vote
- const vote = {
+ // Prepare vote data
+ const voteData = {
proposalId,
voteKind: voteKind,
};
// Vote using proxy
- const txBuilderResult = await proxyContract.voteProxyDrep([vote], utxos, multisigWallet?.getScript().address);
+ const txBuilderResult = await proxyContract.voteProxyDrep([voteData], utxos, multisigWallet?.getScript().address);
await newTransaction({
txBuilder: txBuilderResult,
@@ -386,7 +381,7 @@ export default function VoteButton({
- {isProxyEnabled && !selectedProxyId && (
+ {isProxyEnabled && proxies && proxies.length > 0 && !selectedProxyId && (
Proxy Mode Active - Select a proxy to continue
@@ -398,11 +393,11 @@ export default function VoteButton({
)}
- {loading ? "Voting..." : utxos.length > 0 ? `Vote${isProxyEnabled ? " (Proxy Mode)" : ""}` : "No UTxOs Available"}
+ {loading ? "Voting..." : utxos.length > 0 ? `Vote${hasValidProxy ? " (Proxy Mode)" : ""}` : "No UTxOs Available"}
{selectedBallotId && (
diff --git a/src/components/pages/wallet/info/card-info.tsx b/src/components/pages/wallet/info/card-info.tsx
index 4c0203ad..39f1491a 100644
--- a/src/components/pages/wallet/info/card-info.tsx
+++ b/src/components/pages/wallet/info/card-info.tsx
@@ -173,25 +173,36 @@ function EditInfo({
function ShowInfo({ appWallet }: { appWallet: Wallet }) {
const { multisigWallet } = useMultisigWallet();
+
+ const address = multisigWallet?.getKeysByRole(2) ? multisigWallet?.getScript().address : appWallet.address;
// Get DRep ID from multisig wallet if available, otherwise fallback to appWallet
const dRepId = multisigWallet?.getKeysByRole(3) ? multisigWallet?.getDRepId() : appWallet?.dRepId;
- if (!dRepId) {
- throw new Error("DRep not found");
- }
+
+ // For rawImportBodies wallets, dRepId may not be available
+ const hasRawImportBodies = !!appWallet.rawImportBodies?.multisig;
+ const showDRepId = dRepId && dRepId.length > 0;
return (
<>
-
+ {showDRepId ? (
+
+ ) : hasRawImportBodies ? (
+
+ ) : null}
>
);
}
diff --git a/src/components/pages/wallet/staking/StakingActions/stake.tsx b/src/components/pages/wallet/staking/StakingActions/stake.tsx
index 64d6d8a9..36ac6bc3 100644
--- a/src/components/pages/wallet/staking/StakingActions/stake.tsx
+++ b/src/components/pages/wallet/staking/StakingActions/stake.tsx
@@ -38,7 +38,9 @@ export default function StakeButton({
const rewardAddress = mWallet.getStakeAddress();
if (!rewardAddress) throw new Error("Reward Address could not be built.");
- const stakingScript = mWallet.getStakingScript();
+ // For wallets with rawImportBodies, use stored stake script
+ // Otherwise, derive from MultisigWallet
+ const stakingScript = appWallet.stakeScriptCbor || mWallet.getStakingScript();
if (!stakingScript) throw new Error("Staking Script could not be built.");
const txBuilder = getTxBuilder(network);
diff --git a/src/hooks/common.ts b/src/hooks/common.ts
index f377d42a..8cdf67cc 100644
--- a/src/hooks/common.ts
+++ b/src/hooks/common.ts
@@ -1,5 +1,4 @@
-import { Wallet as DbWallet } from "@prisma/client";
-import { Wallet } from "@/types/wallet";
+import { DbWalletWithLegacy, Wallet } from "@/types/wallet";
import {
NativeScript,
resolveNativeScriptHash,
@@ -14,9 +13,15 @@ import { Address, getDRepIds } from "@meshsdk/core-cst";
import { MultisigKey, MultisigWallet } from "@/utils/multisigSDK";
export function buildMultisigWallet(
- wallet: DbWallet,
+ wallet: DbWalletWithLegacy,
network: number,
): MultisigWallet | undefined {
+ // For wallets with rawImportBodies, skip MultisigWallet building
+ // These wallets use a build process not supported by our SDK
+ if (wallet.rawImportBodies?.multisig) {
+ return undefined;
+ }
+
const keys: MultisigKey[] = [];
if (wallet.signersAddresses.length > 0) {
wallet.signersAddresses.forEach((addr, i) => {
@@ -79,19 +84,64 @@ export function buildMultisigWallet(
}
export function buildWallet(
- wallet: DbWallet,
+ wallet: DbWalletWithLegacy,
network: number,
utxos?: UTxO[],
): Wallet {
+ // For wallets with rawImportBodies, use stored values instead of deriving
+ if (wallet.rawImportBodies?.multisig) {
+ const multisig = wallet.rawImportBodies.multisig;
+
+ // Always use stored address from rawImportBodies
+ const address = multisig.address;
+ if (!address) {
+ throw new Error("rawImportBodies.multisig.address is required");
+ }
+
+ // Always use stored payment script from rawImportBodies
+ const scriptCbor = multisig.payment_script;
+ if (!scriptCbor) {
+ throw new Error("rawImportBodies.multisig.payment_script is required");
+ }
+
+ // Extract stake script from rawImportBodies
+ const stakeScriptCbor = multisig.stake_script;
+
+ // For rawImportBodies wallets, we need a minimal nativeScript for type compatibility
+ // This won't be used for actual script derivation, but is required by the Wallet type
+ const scriptType = (wallet.type as "all" | "any" | "atLeast") ?? "atLeast";
+ const nativeScript: NativeScript = scriptType === "atLeast"
+ ? {
+ type: "atLeast",
+ required: wallet.numRequiredSigners ?? 1,
+ scripts: [],
+ }
+ : {
+ type: scriptType,
+ scripts: [],
+ };
+
+ // For rawImportBodies wallets, dRepId cannot be easily derived from stored CBOR
+ // Set to empty string - it can be derived later if needed from the actual script
+ const dRepId = "";
+
+ return {
+ ...wallet,
+ scriptCbor,
+ nativeScript,
+ address,
+ dRepId,
+ stakeScriptCbor,
+ } as Wallet;
+ }
+
+ // For wallets without rawImportBodies, use existing derivation logic
const mWallet = buildMultisigWallet(wallet, network);
if (!mWallet) {
console.error("error when building Multisig Wallet!");
throw new Error("Failed to build Multisig Wallet");
}
- //depricated -> only payment-script left in for compatibility
- //uses unordered keys for payment script
- //Remove later when refactoring
const nativeScript = {
type: wallet.type ? wallet.type : "atLeast",
scripts: wallet.signersAddresses.map((addr) => ({
@@ -117,8 +167,7 @@ export function buildWallet(
const paymentAddrEmpty =
utxos?.filter((f) => f.output.address === paymentAddress).length === 0;
- if (paymentAddrEmpty && mWallet.stakingEnabled()) address = stakeableAddress
-
+ if (paymentAddrEmpty && mWallet.stakingEnabled()) address = stakeableAddress;
const dRepIdCip105 = resolveScriptHashDRepId(
resolveNativeScriptHash(nativeScript as NativeScript),
diff --git a/src/hooks/useAppWallet.ts b/src/hooks/useAppWallet.ts
index daa30352..4450b4e7 100644
--- a/src/hooks/useAppWallet.ts
+++ b/src/hooks/useAppWallet.ts
@@ -4,6 +4,7 @@ import { buildWallet } from "./common";
import { useSiteStore } from "@/lib/zustand/site";
import { useRouter } from "next/router";
import { useWalletsStore } from "@/lib/zustand/wallets";
+import { DbWalletWithLegacy } from "@/types/wallet";
export default function useAppWallet() {
const router = useRouter();
@@ -21,7 +22,7 @@ export default function useAppWallet() {
);
if (wallet) {
- return { appWallet: buildWallet(wallet, network, walletsUtxos[walletId]), isLoading };
+ return { appWallet: buildWallet(wallet as DbWalletWithLegacy, network, walletsUtxos[walletId]), isLoading };
}
return { appWallet: undefined, isLoading };
diff --git a/src/hooks/useMultisigWallet.ts b/src/hooks/useMultisigWallet.ts
index 3cf7c16a..e8fe63c3 100644
--- a/src/hooks/useMultisigWallet.ts
+++ b/src/hooks/useMultisigWallet.ts
@@ -4,6 +4,7 @@ import { api } from "@/utils/api";
import { useSiteStore } from "@/lib/zustand/site";
import { useUserStore } from "@/lib/zustand/user";
import { buildMultisigWallet } from "./common";
+import { DbWalletWithLegacy } from "@/types/wallet";
export default function useMultisigWallet() {
const router = useRouter();
@@ -19,7 +20,7 @@ export default function useMultisigWallet() {
},
);
if (wallet) {
- return { multisigWallet: buildMultisigWallet(wallet, network), wallet, isLoading };
+ return { multisigWallet: buildMultisigWallet(wallet as DbWalletWithLegacy, network), wallet, isLoading };
}
return { multisigWallet: undefined, wallet: undefined, isLoading };
diff --git a/src/hooks/useUserWallets.ts b/src/hooks/useUserWallets.ts
index eaae3723..1f5aff9c 100644
--- a/src/hooks/useUserWallets.ts
+++ b/src/hooks/useUserWallets.ts
@@ -2,6 +2,7 @@ import { useUserStore } from "@/lib/zustand/user";
import { useSiteStore } from "@/lib/zustand/site";
import { api } from "@/utils/api";
import { buildWallet } from "./common";
+import { DbWalletWithLegacy } from "@/types/wallet";
export default function useUserWallets() {
const network = useSiteStore((state) => state.network);
@@ -17,7 +18,7 @@ export default function useUserWallets() {
if (wallets) {
_wallets = wallets.map((wallet) => {
- return buildWallet(wallet, network);
+ return buildWallet(wallet as DbWalletWithLegacy, network);
});
return { wallets: _wallets, isLoading };
}
diff --git a/src/pages/api/v1/freeUtxos.ts b/src/pages/api/v1/freeUtxos.ts
index f619f81a..06cc2c5a 100644
--- a/src/pages/api/v1/freeUtxos.ts
+++ b/src/pages/api/v1/freeUtxos.ts
@@ -11,6 +11,7 @@ import type { UTxO } from "@meshsdk/core";
import { createCaller } from "@/server/api/root";
import { db } from "@/server/db";
import { verifyJwt } from "@/lib/verifyJwt";
+import { DbWalletWithLegacy } from "@/types/wallet";
export default async function handler(
req: NextApiRequest,
@@ -75,7 +76,7 @@ export default async function handler(
if (!walletFetch) {
return res.status(404).json({ error: "Wallet not found" });
}
- const mWallet = buildMultisigWallet(walletFetch);
+ const mWallet = buildMultisigWallet(walletFetch as DbWalletWithLegacy);
if (!mWallet) {
return res.status(500).json({ error: "Wallet could not be constructed" });
}
diff --git a/src/pages/api/v1/nativeScript.ts b/src/pages/api/v1/nativeScript.ts
index fe0eb443..2e610bc4 100644
--- a/src/pages/api/v1/nativeScript.ts
+++ b/src/pages/api/v1/nativeScript.ts
@@ -5,6 +5,7 @@ import { buildMultisigWallet } from "@/utils/common";
import { verifyJwt } from "@/lib/verifyJwt";
import { createCaller } from "@/server/api/root";
import { db } from "@/server/db";
+import { DbWalletWithLegacy } from "@/types/wallet";
export default async function handler(
req: NextApiRequest,
@@ -57,7 +58,7 @@ export default async function handler(
if (!walletFetch) {
return res.status(404).json({ error: "Wallet not found" });
}
- const mWallet = buildMultisigWallet(walletFetch);
+ const mWallet = buildMultisigWallet(walletFetch as DbWalletWithLegacy);
if (!mWallet) {
return res.status(500).json({ error: "Wallet could not be constructed" });
}
diff --git a/src/pages/api/v1/stats/run-snapshots-batch.ts b/src/pages/api/v1/stats/run-snapshots-batch.ts
index 8a2f249f..942695b1 100644
--- a/src/pages/api/v1/stats/run-snapshots-batch.ts
+++ b/src/pages/api/v1/stats/run-snapshots-batch.ts
@@ -9,6 +9,7 @@ import { getBalance } from "@/utils/getBalance";
import { addressToNetwork } from "@/utils/multisigSDK";
import type { Wallet as DbWallet } from "@prisma/client";
import { Decimal } from "@prisma/client/runtime/library";
+import { DbWalletWithLegacy } from "@/types/wallet";
interface WalletBalance {
walletId: string;
@@ -305,7 +306,7 @@ export default async function handler(
walletAddress = mWallet.getScript().address;
} else {
// Fallback: build the wallet without enforcing key ordering (legacy payment-script build)
- const builtWallet = buildWallet(wallet, network);
+ const builtWallet = buildWallet(wallet as DbWalletWithLegacy, network);
walletAddress = builtWallet.address;
}
} catch (error) {
diff --git a/src/server/api/routers/wallets.ts b/src/server/api/routers/wallets.ts
index cb04392f..856136a0 100644
--- a/src/server/api/routers/wallets.ts
+++ b/src/server/api/routers/wallets.ts
@@ -37,32 +37,55 @@ export const walletRouter = createTRPCRouter({
description: z.string(),
signersAddresses: z.array(z.string()),
signersDescriptions: z.array(z.string()),
- signersStakeKeys: z.array(z.string()),
- signersDRepKeys: z.array(z.string()),
+ signersStakeKeys: z.array(z.string().nullable()).nullable(),
+ signersDRepKeys: z.array(z.string().optional()).nullable(),
numRequiredSigners: z.number(),
scriptCbor: z.string(),
stakeCredentialHash: z.string().optional(),
type: z.enum(["atLeast", "all", "any"]),
- rawImportBodies: z.custom().optional().nullable(),
+ rawImportBodies: z.any().optional().nullable(),
}),
)
.mutation(async ({ ctx, input }) => {
- const numRequired = (input.type === "all" || input.type === "any") ? null : input.numRequiredSigners;
- const data = {
- name: input.name,
- description: input.description,
- signersAddresses: input.signersAddresses,
- signersDescriptions: input.signersDescriptions,
- signersStakeKeys: input.signersStakeKeys,
- signersDRepKeys: input.signersDRepKeys,
- numRequiredSigners: numRequired as any,
- scriptCbor: input.scriptCbor,
- stakeCredentialHash: input.stakeCredentialHash,
- type: input.type,
- rawImportBodies: input.rawImportBodies as Prisma.InputJsonValue,
- } as unknown as Prisma.WalletCreateInput;
+ try {
+ const numRequired = (input.type === "all" || input.type === "any") ? null : input.numRequiredSigners;
+
+ // Convert null/undefined values to empty strings to match Prisma schema
+ // Keep array length to match signersAddresses
+ const signersStakeKeys = (input.signersStakeKeys || []).map(key =>
+ key === null || key === undefined ? "" : key
+ );
+ const signersDRepKeys = (input.signersDRepKeys || []).map(key =>
+ key === null || key === undefined ? "" : key
+ );
+
+ // Ensure rawImportBodies is properly serialized if present
+ let rawImportBodiesValue: Prisma.InputJsonValue | undefined = undefined;
+ if (input.rawImportBodies) {
+ // If it's already a plain object, use it directly
+ // Otherwise, serialize it to ensure it's JSON-compatible
+ rawImportBodiesValue = JSON.parse(JSON.stringify(input.rawImportBodies)) as Prisma.InputJsonValue;
+ }
+
+ const data: Prisma.WalletCreateInput = {
+ name: input.name,
+ description: input.description,
+ signersAddresses: input.signersAddresses,
+ signersDescriptions: input.signersDescriptions,
+ signersStakeKeys: signersStakeKeys,
+ signersDRepKeys: signersDRepKeys,
+ numRequiredSigners: numRequired as any,
+ scriptCbor: input.scriptCbor,
+ stakeCredentialHash: input.stakeCredentialHash,
+ type: input.type,
+ rawImportBodies: rawImportBodiesValue,
+ };
- return ctx.db.wallet.create({ data });
+ return ctx.db.wallet.create({ data });
+ } catch (error) {
+ console.error("Error creating wallet:", error);
+ throw error;
+ }
}),
updateWalletVerifiedList: publicProcedure
diff --git a/src/types/wallet.ts b/src/types/wallet.ts
index 6e2e1274..11a74f5d 100644
--- a/src/types/wallet.ts
+++ b/src/types/wallet.ts
@@ -1,12 +1,6 @@
import { NativeScript } from "@meshsdk/core";
import { Wallet as DbWallet } from "@prisma/client";
-export type Wallet = DbWallet & {
- nativeScript: NativeScript;
- address: string;
- dRepId: string;
-};
-
export interface RawImportBodiesUser {
ada_handle?: string;
address_bech32?: string;
@@ -45,3 +39,14 @@ export interface RawImportBodies {
[key: string]: unknown;
}
+export type DbWalletWithLegacy = DbWallet & {
+ rawImportBodies?: RawImportBodies | null;
+};
+
+export type Wallet = DbWalletWithLegacy & {
+ nativeScript: NativeScript;
+ address: string;
+ dRepId: string;
+ stakeScriptCbor?: string;
+};
+
diff --git a/src/utils/common.ts b/src/utils/common.ts
index 79499342..887615aa 100644
--- a/src/utils/common.ts
+++ b/src/utils/common.ts
@@ -1,5 +1,4 @@
-import { Wallet as DbWallet } from "@prisma/client";
-import { Wallet } from "@/types/wallet";
+import { DbWalletWithLegacy, Wallet } from "@/types/wallet";
import {
NativeScript,
resolveNativeScriptHash,
@@ -18,9 +17,15 @@ function addressToNetwork(address: string): number {
}
export function buildMultisigWallet(
- wallet: DbWallet,
+ wallet: DbWalletWithLegacy,
network?: number,
): MultisigWallet | undefined {
+ // For wallets with rawImportBodies, skip MultisigWallet building
+ // These wallets use a build process not supported by our SDK
+ if (wallet.rawImportBodies?.multisig) {
+ return undefined;
+ }
+
console.log(
"buildMultisigWallet - stakeCredentialHash",
wallet.stakeCredentialHash,
@@ -81,11 +86,58 @@ export function buildMultisigWallet(
}
export function buildWallet(
- wallet: DbWallet,
+ wallet: DbWalletWithLegacy,
network: number,
utxos?: UTxO[],
): Wallet {
-
+ // For wallets with rawImportBodies, use stored values instead of deriving
+ if (wallet.rawImportBodies?.multisig) {
+ const multisig = wallet.rawImportBodies.multisig;
+
+ // Always use stored address from rawImportBodies
+ const address = multisig.address;
+ if (!address) {
+ throw new Error("rawImportBodies.multisig.address is required");
+ }
+
+ // Always use stored payment script from rawImportBodies
+ const scriptCbor = multisig.payment_script;
+ if (!scriptCbor) {
+ throw new Error("rawImportBodies.multisig.payment_script is required");
+ }
+
+ // Extract stake script from rawImportBodies
+ const stakeScriptCbor = multisig.stake_script;
+
+ // For rawImportBodies wallets, we need a minimal nativeScript for type compatibility
+ // This won't be used for actual script derivation, but is required by the Wallet type
+ const scriptType = (wallet.type as "all" | "any" | "atLeast") ?? "atLeast";
+ const nativeScript: NativeScript = scriptType === "atLeast"
+ ? {
+ type: "atLeast",
+ required: wallet.numRequiredSigners ?? 1,
+ scripts: [],
+ }
+ : {
+ type: scriptType,
+ scripts: [],
+ };
+
+ // For rawImportBodies wallets, dRepId cannot be easily derived from stored CBOR
+ // Set to empty string - it can be derived later if needed from the actual script
+ const dRepId = "";
+
+ return {
+ ...wallet,
+ scriptCbor,
+ nativeScript,
+ address,
+ dRepId,
+ stakeScriptCbor,
+ } as Wallet;
+ }
+
+ // For wallets without rawImportBodies, use existing derivation logic
const mWallet = buildMultisigWallet(wallet, network);
if (!mWallet) {
console.error("error when building Multisig Wallet!");