mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-22 04:27:56 +00:00
fix: universal getSigner helper for WalletConnect + extension signing
Replace all web3FromAddress calls with getSigner() that auto-detects walletSource and uses WC signer or extension signer accordingly. This fixes all signing operations when connected via WalletConnect.
This commit is contained in:
@@ -4,11 +4,13 @@
|
||||
// Handles citizenship verification, status checks, and workflow logic
|
||||
|
||||
import type { ApiPromise } from '@pezkuwi/api';
|
||||
import { web3Enable, web3FromAddress as web3FromAddressOriginal } from '@pezkuwi/extension-dapp';
|
||||
import { getSigner } from '@/lib/get-signer';
|
||||
import type { InjectedAccountWithMeta } from '@pezkuwi/extension-inject/types';
|
||||
|
||||
import type { Signer } from '@pezkuwi/api/types';
|
||||
|
||||
type WalletSource = 'extension' | 'walletconnect' | 'native' | null;
|
||||
|
||||
interface SignRawPayload {
|
||||
address: string;
|
||||
data: string;
|
||||
@@ -23,20 +25,6 @@ interface InjectedSigner {
|
||||
signRaw?: (payload: SignRawPayload) => Promise<SignRawResult>;
|
||||
}
|
||||
|
||||
interface InjectedExtension {
|
||||
signer: Signer & InjectedSigner;
|
||||
}
|
||||
|
||||
// Use real extension in browser, throw error in unsupported environments
|
||||
const web3FromAddress = async (address: string): Promise<InjectedExtension> => {
|
||||
// Check if we're in a browser environment with extension support
|
||||
if (typeof window !== 'undefined') {
|
||||
await web3Enable('PezkuwiChain');
|
||||
return web3FromAddressOriginal(address) as Promise<InjectedExtension>;
|
||||
}
|
||||
throw new Error('Pezkuwi Wallet extension not available. Please install the extension.');
|
||||
};
|
||||
|
||||
// ========================================
|
||||
// TYPE DEFINITIONS
|
||||
// ========================================
|
||||
@@ -477,7 +465,8 @@ export async function submitKycApplication(
|
||||
api: ApiPromise,
|
||||
account: InjectedAccountWithMeta,
|
||||
identityHash: string,
|
||||
referrerAddress?: string
|
||||
referrerAddress?: string,
|
||||
walletSource?: WalletSource
|
||||
): Promise<{ success: boolean; error?: string; blockHash?: string }> {
|
||||
try {
|
||||
if (!api?.tx?.identityKyc?.applyForCitizenship) {
|
||||
@@ -502,7 +491,7 @@ export async function submitKycApplication(
|
||||
};
|
||||
}
|
||||
|
||||
const injector = await web3FromAddress(account.address);
|
||||
const injector = await getSigner(account.address, walletSource ?? 'extension', api);
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
console.log('=== submitKycApplication Debug ===');
|
||||
@@ -629,14 +618,15 @@ export function subscribeToKycApproval(
|
||||
export async function approveReferral(
|
||||
api: ApiPromise,
|
||||
account: InjectedAccountWithMeta,
|
||||
applicantAddress: string
|
||||
applicantAddress: string,
|
||||
walletSource?: WalletSource
|
||||
): Promise<{ success: boolean; error?: string; blockHash?: string }> {
|
||||
try {
|
||||
if (!api?.tx?.identityKyc?.approveReferral) {
|
||||
return { success: false, error: 'Identity KYC pallet not available' };
|
||||
}
|
||||
|
||||
const injector = await web3FromAddress(account.address);
|
||||
const injector = await getSigner(account.address, walletSource ?? 'extension', api);
|
||||
|
||||
const result = await new Promise<{ success: boolean; error?: string; blockHash?: string }>((resolve, reject) => {
|
||||
api.tx.identityKyc
|
||||
@@ -679,14 +669,15 @@ export async function approveReferral(
|
||||
*/
|
||||
export async function cancelApplication(
|
||||
api: ApiPromise,
|
||||
account: InjectedAccountWithMeta
|
||||
account: InjectedAccountWithMeta,
|
||||
walletSource?: WalletSource
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
try {
|
||||
if (!api?.tx?.identityKyc?.cancelApplication) {
|
||||
return { success: false, error: 'Identity KYC pallet not available' };
|
||||
}
|
||||
|
||||
const injector = await web3FromAddress(account.address);
|
||||
const injector = await getSigner(account.address, walletSource ?? 'extension', api);
|
||||
|
||||
const result = await new Promise<{ success: boolean; error?: string }>((resolve, reject) => {
|
||||
api.tx.identityKyc
|
||||
@@ -723,14 +714,15 @@ export async function cancelApplication(
|
||||
*/
|
||||
export async function confirmCitizenship(
|
||||
api: ApiPromise,
|
||||
account: InjectedAccountWithMeta
|
||||
account: InjectedAccountWithMeta,
|
||||
walletSource?: WalletSource
|
||||
): Promise<{ success: boolean; error?: string; blockHash?: string }> {
|
||||
try {
|
||||
if (!api?.tx?.identityKyc?.confirmCitizenship) {
|
||||
return { success: false, error: 'Identity KYC pallet not available' };
|
||||
}
|
||||
|
||||
const injector = await web3FromAddress(account.address);
|
||||
const injector = await getSigner(account.address, walletSource ?? 'extension', api);
|
||||
|
||||
const result = await new Promise<{ success: boolean; error?: string; blockHash?: string }>((resolve, reject) => {
|
||||
api.tx.identityKyc
|
||||
@@ -850,10 +842,12 @@ export function generateAuthChallenge(tikiNumber: string): AuthChallenge {
|
||||
*/
|
||||
export async function signChallenge(
|
||||
account: InjectedAccountWithMeta,
|
||||
challenge: AuthChallenge
|
||||
challenge: AuthChallenge,
|
||||
walletSource?: WalletSource,
|
||||
api?: ApiPromise | null
|
||||
): Promise<string> {
|
||||
try {
|
||||
const injector = await web3FromAddress(account.address);
|
||||
const injector = await getSigner(account.address, walletSource ?? 'extension', api);
|
||||
|
||||
if (!injector?.signer?.signRaw) {
|
||||
throw new Error('Signer not available');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { X, Plus, Info, AlertCircle } from 'lucide-react';
|
||||
import { web3Enable, web3FromAddress } from '@pezkuwi/extension-dapp';
|
||||
import { getSigner } from '@/lib/get-signer';
|
||||
import { usePezkuwi } from '@/contexts/PezkuwiContext';
|
||||
import { useWallet } from '@/contexts/WalletContext';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -62,7 +62,7 @@ export const AddLiquidityModal: React.FC<AddLiquidityModalProps> = ({
|
||||
asset1 = 1 // Default to PEZ
|
||||
}) => {
|
||||
// Use Asset Hub API for DEX operations (assetConversion pallet is on Asset Hub)
|
||||
const { assetHubApi, selectedAccount, isAssetHubReady } = usePezkuwi();
|
||||
const { assetHubApi, selectedAccount, isAssetHubReady, walletSource } = usePezkuwi();
|
||||
const { balances, refreshBalances } = useWallet();
|
||||
|
||||
const [amount0, setAmount0] = useState('');
|
||||
@@ -357,9 +357,8 @@ export const AddLiquidityModal: React.FC<AddLiquidityModalProps> = ({
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the signer from the extension
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
// Get the signer (extension or WalletConnect)
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, assetHubApi);
|
||||
|
||||
// Convert amounts to proper decimals
|
||||
const amount0BN = BigInt(Math.floor(parseFloat(amount0) * Math.pow(10, asset0Decimals)));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { X, Lock, AlertCircle, Loader2, Clock } from 'lucide-react';
|
||||
import { web3Enable, web3FromAddress } from '@pezkuwi/extension-dapp';
|
||||
import { getSigner } from '@/lib/get-signer';
|
||||
import { usePezkuwi } from '@/contexts/PezkuwiContext';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
@@ -50,7 +50,7 @@ export const LPStakeModal: React.FC<LPStakeModalProps> = ({
|
||||
onStakeSuccess,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { assetHubApi, selectedAccount, isAssetHubReady } = usePezkuwi();
|
||||
const { assetHubApi, selectedAccount, isAssetHubReady, walletSource } = usePezkuwi();
|
||||
const [isProcessing, setIsProcessing] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [success, setSuccess] = useState<string | null>(null);
|
||||
@@ -85,8 +85,7 @@ export const LPStakeModal: React.FC<LPStakeModalProps> = ({
|
||||
|
||||
try {
|
||||
const amountBN = BigInt(Math.floor(amount * 1e12));
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, assetHubApi);
|
||||
|
||||
const tx = assetHubApi.tx.assetRewards.stake(poolId, amountBN.toString());
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { X, Lock, Unlock, Gift, AlertCircle, Loader2, Info } from 'lucide-react';
|
||||
import { web3Enable, web3FromAddress } from '@pezkuwi/extension-dapp';
|
||||
import { getSigner } from '@/lib/get-signer';
|
||||
import { usePezkuwi } from '@/contexts/PezkuwiContext';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
@@ -31,7 +31,7 @@ const LP_TOKEN_NAMES: Record<number, string> = {
|
||||
};
|
||||
|
||||
export const LPStakingModal: React.FC<LPStakingModalProps> = ({ isOpen, onClose }) => {
|
||||
const { assetHubApi, selectedAccount, isAssetHubReady } = usePezkuwi();
|
||||
const { assetHubApi, selectedAccount, isAssetHubReady, walletSource } = usePezkuwi();
|
||||
const { t } = useTranslation();
|
||||
const [pools, setPools] = useState<StakingPool[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
@@ -143,8 +143,7 @@ export const LPStakingModal: React.FC<LPStakingModalProps> = ({ isOpen, onClose
|
||||
if (!pool) throw new Error('Pool not found');
|
||||
|
||||
const amountBN = BigInt(Math.floor(parseFloat(stakeAmount) * 1e12));
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, assetHubApi);
|
||||
|
||||
const tx = assetHubApi.tx.assetRewards.stake(selectedPool, amountBN.toString());
|
||||
|
||||
@@ -190,8 +189,7 @@ export const LPStakingModal: React.FC<LPStakingModalProps> = ({ isOpen, onClose
|
||||
if (!pool) throw new Error('Pool not found');
|
||||
|
||||
const amountBN = BigInt(Math.floor(parseFloat(unstakeAmount) * 1e12));
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, assetHubApi);
|
||||
|
||||
const tx = assetHubApi.tx.assetRewards.unstake(selectedPool, amountBN.toString());
|
||||
|
||||
@@ -233,8 +231,7 @@ export const LPStakingModal: React.FC<LPStakingModalProps> = ({ isOpen, onClose
|
||||
setSuccess(null);
|
||||
|
||||
try {
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, assetHubApi);
|
||||
const tx = assetHubApi.tx.assetRewards.harvestRewards(selectedPool);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { X, Minus, AlertCircle, Info } from 'lucide-react';
|
||||
import { web3Enable, web3FromAddress } from '@pezkuwi/extension-dapp';
|
||||
import { getSigner } from '@/lib/get-signer';
|
||||
import { usePezkuwi } from '@/contexts/PezkuwiContext';
|
||||
import { useWallet } from '@/contexts/WalletContext';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -63,7 +63,7 @@ export const RemoveLiquidityModal: React.FC<RemoveLiquidityModalProps> = ({
|
||||
asset1,
|
||||
}) => {
|
||||
// Use Asset Hub API for DEX operations (assetConversion pallet is on Asset Hub)
|
||||
const { assetHubApi, selectedAccount } = usePezkuwi();
|
||||
const { assetHubApi, selectedAccount, walletSource } = usePezkuwi();
|
||||
const { refreshBalances } = useWallet();
|
||||
|
||||
const [percentage, setPercentage] = useState(100);
|
||||
@@ -159,9 +159,8 @@ export const RemoveLiquidityModal: React.FC<RemoveLiquidityModalProps> = ({
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
// Get the signer from the extension
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
// Get the signer (extension or WalletConnect)
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, assetHubApi);
|
||||
|
||||
// Get decimals for each asset
|
||||
const asset0Decimals = getAssetDecimals(asset0);
|
||||
|
||||
@@ -25,7 +25,7 @@ const AVAILABLE_TOKENS = [
|
||||
|
||||
const TokenSwap = () => {
|
||||
// Use Asset Hub API for DEX operations (assetConversion pallet is on Asset Hub)
|
||||
const { assetHubApi, isAssetHubReady, selectedAccount } = usePezkuwi();
|
||||
const { assetHubApi, isAssetHubReady, selectedAccount, walletSource } = usePezkuwi();
|
||||
const { balances, refreshBalances } = useWallet();
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
@@ -583,10 +583,9 @@ const TokenSwap = () => {
|
||||
minAmountOut: minAmountOut.toString()
|
||||
});
|
||||
|
||||
// Get signer from extension
|
||||
const { web3Enable, web3FromAddress } = await import('@pezkuwi/extension-dapp');
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
// Get signer (extension or WalletConnect)
|
||||
const { getSigner } = await import('@/lib/get-signer');
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, assetHubApi);
|
||||
|
||||
// Build transaction based on token types
|
||||
let tx;
|
||||
|
||||
@@ -67,7 +67,7 @@ const TOKENS: Token[] = [
|
||||
];
|
||||
|
||||
export const TransferModal: React.FC<TransferModalProps> = ({ isOpen, onClose, selectedAsset }) => {
|
||||
const { api, assetHubApi, isApiReady, isAssetHubReady, selectedAccount } = usePezkuwi();
|
||||
const { api, assetHubApi, isApiReady, isAssetHubReady, selectedAccount, walletSource } = usePezkuwi();
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -129,10 +129,9 @@ export const TransferModal: React.FC<TransferModalProps> = ({ isOpen, onClose, s
|
||||
setTxStatus('signing');
|
||||
|
||||
try {
|
||||
// Import web3FromAddress to get the injector
|
||||
const { web3Enable, web3FromAddress } = await import('@pezkuwi/extension-dapp');
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
// Get signer (extension or WalletConnect)
|
||||
const { getSigner } = await import('@/lib/get-signer');
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, isAssetHubTransfer ? assetHubApi : api);
|
||||
|
||||
// Convert amount to smallest unit
|
||||
const amountInSmallestUnit = BigInt(parseFloat(amount) * Math.pow(10, currentToken.decimals));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { X, ArrowDown, ArrowUp, AlertCircle, Info, Clock, CheckCircle2 } from 'lucide-react';
|
||||
import { web3Enable, web3FromAddress } from '@pezkuwi/extension-dapp';
|
||||
import { getSigner } from '@/lib/get-signer';
|
||||
import { usePezkuwi } from '@/contexts/PezkuwiContext';
|
||||
import { useWallet } from '@/contexts/WalletContext';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -30,7 +30,7 @@ export const USDTBridge: React.FC<USDTBridgeProps> = ({
|
||||
specificAddresses = {},
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { api, selectedAccount, isApiReady } = usePezkuwi();
|
||||
const { api, selectedAccount, isApiReady, walletSource } = usePezkuwi();
|
||||
const { refreshBalances } = useWallet();
|
||||
|
||||
const [depositAmount, setDepositAmount] = useState('');
|
||||
@@ -114,8 +114,7 @@ export const USDTBridge: React.FC<USDTBridgeProps> = ({
|
||||
setSuccess(null);
|
||||
|
||||
try {
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, api);
|
||||
|
||||
// Burn wUSDT
|
||||
const amountBN = BigInt(Math.floor(amount * 1e6)); // 6 decimals
|
||||
|
||||
@@ -54,7 +54,7 @@ interface XCMTeleportModalProps {
|
||||
}
|
||||
|
||||
export const XCMTeleportModal: React.FC<XCMTeleportModalProps> = ({ isOpen, onClose }) => {
|
||||
const { api, assetHubApi, peopleApi, isApiReady, isAssetHubReady, isPeopleReady, selectedAccount } = usePezkuwi();
|
||||
const { api, assetHubApi, peopleApi, isApiReady, isAssetHubReady, isPeopleReady, selectedAccount, walletSource } = usePezkuwi();
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -157,9 +157,8 @@ export const XCMTeleportModal: React.FC<XCMTeleportModalProps> = ({ isOpen, onCl
|
||||
setTxStatus('signing');
|
||||
|
||||
try {
|
||||
const { web3Enable, web3FromAddress } = await import('@pezkuwi/extension-dapp');
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const { getSigner } = await import('@/lib/get-signer');
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, api);
|
||||
|
||||
// Convert to smallest unit (12 decimals)
|
||||
const amountInSmallestUnit = BigInt(Math.floor(parseFloat(amount) * 1e12));
|
||||
|
||||
@@ -11,7 +11,7 @@ import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
|
||||
export function CommissionSetupTab() {
|
||||
const { t } = useTranslation();
|
||||
const { api, isApiReady, selectedAccount } = usePezkuwi();
|
||||
const { api, isApiReady, selectedAccount, walletSource } = usePezkuwi();
|
||||
const { toast } = useToast();
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -70,9 +70,8 @@ export function CommissionSetupTab() {
|
||||
|
||||
setProcessing(true);
|
||||
try {
|
||||
const { web3Enable, web3FromAddress } = await import('@pezkuwi/extension-dapp');
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const { getSigner } = await import('@/lib/get-signer');
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, api);
|
||||
|
||||
// Parse addresses (one per line, trim whitespace)
|
||||
const newAddresses = newMemberAddress
|
||||
@@ -175,9 +174,8 @@ export function CommissionSetupTab() {
|
||||
|
||||
setProcessing(true);
|
||||
try {
|
||||
const { web3Enable, web3FromAddress } = await import('@pezkuwi/extension-dapp');
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const { getSigner } = await import('@/lib/get-signer');
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, api);
|
||||
|
||||
if (import.meta.env.DEV) console.log('Initializing KYC Commission...');
|
||||
if (import.meta.env.DEV) console.log('Proxy account:', COMMISSIONS.KYC.proxyAccount);
|
||||
|
||||
@@ -28,7 +28,7 @@ interface Proposal {
|
||||
|
||||
export function CommissionVotingTab() {
|
||||
const { t } = useTranslation();
|
||||
const { api, isApiReady, selectedAccount } = usePezkuwi();
|
||||
const { api, isApiReady, selectedAccount, walletSource } = usePezkuwi();
|
||||
const { toast } = useToast();
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -150,9 +150,8 @@ export function CommissionVotingTab() {
|
||||
|
||||
setVoting(proposal.hash);
|
||||
try {
|
||||
const { web3Enable, web3FromAddress } = await import('@pezkuwi/extension-dapp');
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const { getSigner } = await import('@/lib/get-signer');
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, api);
|
||||
|
||||
if (import.meta.env.DEV) console.log(`Voting ${approve ? 'AYE' : 'NAY'} on proposal:`, proposal.hash);
|
||||
|
||||
@@ -258,9 +257,8 @@ export function CommissionVotingTab() {
|
||||
|
||||
setVoting(proposal.hash);
|
||||
try {
|
||||
const { web3Enable, web3FromAddress } = await import('@pezkuwi/extension-dapp');
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const { getSigner } = await import('@/lib/get-signer');
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, api);
|
||||
|
||||
if (import.meta.env.DEV) console.log('Executing proposal:', proposal.hash);
|
||||
|
||||
@@ -433,9 +431,8 @@ export function CommissionVotingTab() {
|
||||
if (!api || !selectedAccount) return;
|
||||
|
||||
try {
|
||||
const { web3Enable, web3FromAddress } = await import('@pezkuwi/extension-dapp');
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const { getSigner } = await import('@/lib/get-signer');
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, api);
|
||||
|
||||
// Get current members
|
||||
const currentMembers = await api.query.dynamicCommissionCollective.members();
|
||||
|
||||
@@ -21,7 +21,7 @@ import type { PendingApproval } from '@pezkuwi/lib/citizenship-workflow';
|
||||
export function KycApprovalTab() {
|
||||
const { t } = useTranslation();
|
||||
// identityKyc pallet is on People Chain - use peopleApi
|
||||
const { peopleApi, isPeopleReady, selectedAccount, connectWallet } = usePezkuwi();
|
||||
const { peopleApi, isPeopleReady, selectedAccount, connectWallet, walletSource } = usePezkuwi();
|
||||
const { toast } = useToast();
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -75,7 +75,7 @@ export function KycApprovalTab() {
|
||||
|
||||
setProcessingAddress(applicantAddress);
|
||||
try {
|
||||
const result = await approveReferral(peopleApi, selectedAccount, applicantAddress);
|
||||
const result = await approveReferral(peopleApi, selectedAccount, applicantAddress, walletSource);
|
||||
|
||||
if (!result.success) {
|
||||
toast({
|
||||
|
||||
@@ -17,7 +17,7 @@ interface ExistingCitizenAuthProps {
|
||||
|
||||
export const ExistingCitizenAuth: React.FC<ExistingCitizenAuthProps> = ({ onClose }) => {
|
||||
const { t } = useTranslation();
|
||||
const { peopleApi, isPeopleReady, selectedAccount, connectWallet } = usePezkuwi();
|
||||
const { peopleApi, isPeopleReady, selectedAccount, connectWallet, walletSource } = usePezkuwi();
|
||||
|
||||
const [citizenNumber, setCitizenNumber] = useState('');
|
||||
const [step, setStep] = useState<'input' | 'verifying' | 'signing' | 'success' | 'error'>('input');
|
||||
@@ -69,7 +69,7 @@ export const ExistingCitizenAuth: React.FC<ExistingCitizenAuthProps> = ({ onClos
|
||||
|
||||
try {
|
||||
// Sign the challenge
|
||||
const signature = await signChallenge(selectedAccount, challenge);
|
||||
const signature = await signChallenge(selectedAccount, challenge, walletSource, peopleApi);
|
||||
|
||||
// Verify signature (self-verification for demonstration)
|
||||
const isValid = await verifySignature(signature, challenge, selectedAccount.address);
|
||||
|
||||
@@ -25,7 +25,7 @@ type FormData = Omit<CitizenshipData, 'walletAddress' | 'timestamp'>;
|
||||
|
||||
export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ onClose, referrerAddress }) => {
|
||||
// identityKyc pallet is on People Chain
|
||||
const { peopleApi, isPeopleReady, selectedAccount, connectWallet } = usePezkuwi();
|
||||
const { peopleApi, isPeopleReady, selectedAccount, connectWallet, walletSource } = usePezkuwi();
|
||||
const { t } = useTranslation();
|
||||
const { register, handleSubmit, watch, setValue, formState: { errors } } = useForm<FormData>();
|
||||
|
||||
@@ -51,7 +51,7 @@ export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ on
|
||||
setConfirming(true);
|
||||
setError(null);
|
||||
try {
|
||||
const result = await confirmCitizenship(peopleApi, selectedAccount);
|
||||
const result = await confirmCitizenship(peopleApi, selectedAccount, walletSource);
|
||||
|
||||
if (!result.success) {
|
||||
setError(result.error || t('newCitizen.failedToConfirm'));
|
||||
@@ -83,7 +83,7 @@ export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ on
|
||||
setCanceling(true);
|
||||
setError(null);
|
||||
try {
|
||||
const result = await cancelApplication(peopleApi, selectedAccount);
|
||||
const result = await cancelApplication(peopleApi, selectedAccount, walletSource);
|
||||
|
||||
if (!result.success) {
|
||||
setError(result.error || t('newCitizen.failedToCancel'));
|
||||
@@ -243,7 +243,8 @@ export const NewCitizenApplication: React.FC<NewCitizenApplicationProps> = ({ on
|
||||
peopleApi,
|
||||
selectedAccount,
|
||||
identityHash,
|
||||
effectiveReferrer
|
||||
effectiveReferrer,
|
||||
walletSource
|
||||
);
|
||||
|
||||
if (!result.success) {
|
||||
|
||||
@@ -19,7 +19,7 @@ interface Proposal {
|
||||
|
||||
export function CommissionProposalsCard() {
|
||||
const { t } = useTranslation();
|
||||
const { api, isApiReady, selectedAccount } = usePezkuwi();
|
||||
const { api, isApiReady, selectedAccount, walletSource } = usePezkuwi();
|
||||
const { toast } = useToast();
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -109,9 +109,8 @@ export function CommissionProposalsCard() {
|
||||
|
||||
setVoting(proposal.hash);
|
||||
try {
|
||||
const { web3Enable, web3FromAddress } = await import('@pezkuwi/extension-dapp');
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const { getSigner } = await import('@/lib/get-signer');
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, api);
|
||||
|
||||
const tx = api.tx.dynamicCommissionCollective.vote(
|
||||
proposal.hash,
|
||||
@@ -200,9 +199,8 @@ export function CommissionProposalsCard() {
|
||||
|
||||
setVoting(proposal.hash);
|
||||
try {
|
||||
const { web3Enable, web3FromAddress } = await import('@pezkuwi/extension-dapp');
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const { getSigner } = await import('@/lib/get-signer');
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, api);
|
||||
|
||||
// Get proposal length bound
|
||||
const proposalOption = await api.query.dynamicCommissionCollective.proposalOf(proposal.hash);
|
||||
|
||||
@@ -23,7 +23,7 @@ interface InviteUserModalProps {
|
||||
|
||||
export const InviteUserModal: React.FC<InviteUserModalProps> = ({ isOpen, onClose }) => {
|
||||
const { t } = useTranslation();
|
||||
const { peopleApi, isPeopleReady, selectedAccount } = usePezkuwi();
|
||||
const { peopleApi, isPeopleReady, selectedAccount, walletSource } = usePezkuwi();
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [inviteeAddress, setInviteeAddress] = useState('');
|
||||
const [initiating, setInitiating] = useState(false);
|
||||
@@ -81,9 +81,8 @@ export const InviteUserModal: React.FC<InviteUserModalProps> = ({ isOpen, onClos
|
||||
setInitiateSuccess(false);
|
||||
|
||||
try {
|
||||
const { web3Enable, web3FromAddress } = await import('@pezkuwi/extension-dapp');
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const { getSigner } = await import('@/lib/get-signer');
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, peopleApi);
|
||||
|
||||
if (import.meta.env.DEV) console.log(`Initiating referral from ${selectedAccount.address} to ${inviteeAddress}...`);
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import type { PendingApproval } from '@pezkuwi/lib/citizenship-workflow';
|
||||
export const ReferralDashboard: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const { stats, myReferrals, loading } = useReferral();
|
||||
const { peopleApi, isPeopleReady, selectedAccount } = usePezkuwi();
|
||||
const { peopleApi, isPeopleReady, selectedAccount, walletSource } = usePezkuwi();
|
||||
const { toast } = useToast();
|
||||
const [showInviteModal, setShowInviteModal] = useState(false);
|
||||
const [pendingApprovals, setPendingApprovals] = useState<PendingApproval[]>([]);
|
||||
@@ -45,7 +45,7 @@ export const ReferralDashboard: React.FC = () => {
|
||||
|
||||
setProcessingAddress(applicantAddress);
|
||||
try {
|
||||
const result = await approveReferral(peopleApi, selectedAccount, applicantAddress);
|
||||
const result = await approveReferral(peopleApi, selectedAccount, applicantAddress, walletSource);
|
||||
if (result.success) {
|
||||
toast({
|
||||
title: 'Referral Approved',
|
||||
|
||||
@@ -11,7 +11,7 @@ import { usePezkuwi } from '@/contexts/PezkuwiContext';
|
||||
import { useWallet } from '@/contexts/WalletContext';
|
||||
import { toast } from 'sonner';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { web3FromAddress, web3Enable } from '@pezkuwi/extension-dapp';
|
||||
import { getSigner } from '@/lib/get-signer';
|
||||
import {
|
||||
getStakingInfo,
|
||||
getActiveValidators,
|
||||
@@ -31,21 +31,8 @@ import { LoadingState } from '@pezkuwi/components/AsyncComponent';
|
||||
import { ValidatorPoolDashboard } from './ValidatorPoolDashboard';
|
||||
import { handleBlockchainError, handleBlockchainSuccess } from '@pezkuwi/lib/error-handler';
|
||||
|
||||
// Get signer with auto-reconnect if extension session expired
|
||||
async function getInjectorSigner(address: string) {
|
||||
let injector = await web3FromAddress(address);
|
||||
if (!injector?.signer) {
|
||||
await web3Enable('PezkuwiChain');
|
||||
injector = await web3FromAddress(address);
|
||||
if (!injector?.signer) {
|
||||
throw new Error('Wallet signer not available. Please reconnect your wallet.');
|
||||
}
|
||||
}
|
||||
return injector;
|
||||
}
|
||||
|
||||
export const StakingDashboard: React.FC = () => {
|
||||
const { assetHubApi, peopleApi, selectedAccount, isAssetHubReady, isPeopleReady } = usePezkuwi();
|
||||
const { assetHubApi, peopleApi, selectedAccount, isAssetHubReady, isPeopleReady, walletSource } = usePezkuwi();
|
||||
const { balances, refreshBalances } = useWallet();
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -129,7 +116,7 @@ export const StakingDashboard: React.FC = () => {
|
||||
|
||||
setIsRecordingScore(true);
|
||||
try {
|
||||
const injector = await getInjectorSigner(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, peopleApi);
|
||||
const result = await recordTrustScore(peopleApi, selectedAccount.address, injector.signer);
|
||||
|
||||
if (result.success) {
|
||||
@@ -157,7 +144,7 @@ export const StakingDashboard: React.FC = () => {
|
||||
|
||||
setIsClaimingReward(true);
|
||||
try {
|
||||
const injector = await getInjectorSigner(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, peopleApi);
|
||||
const result = await claimPezReward(peopleApi, selectedAccount.address, epochIndex, injector.signer);
|
||||
|
||||
if (result.success) {
|
||||
@@ -198,7 +185,7 @@ export const StakingDashboard: React.FC = () => {
|
||||
throw new Error(t('staking.insufficientHez'));
|
||||
}
|
||||
|
||||
const injector = await getInjectorSigner(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, assetHubApi);
|
||||
|
||||
// If already bonded, use bondExtra, otherwise use bond
|
||||
let tx;
|
||||
@@ -251,7 +238,7 @@ export const StakingDashboard: React.FC = () => {
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const injector = await getInjectorSigner(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, assetHubApi);
|
||||
|
||||
const tx = assetHubApi.tx.staking.nominate(selectedValidators);
|
||||
|
||||
@@ -294,7 +281,7 @@ export const StakingDashboard: React.FC = () => {
|
||||
throw new Error(t('staking.insufficientStaked'));
|
||||
}
|
||||
|
||||
const injector = await getInjectorSigner(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, assetHubApi);
|
||||
const tx = assetHubApi.tx.staking.unbond(amount);
|
||||
|
||||
await tx.signAndSend(
|
||||
@@ -338,7 +325,7 @@ export const StakingDashboard: React.FC = () => {
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const injector = await getInjectorSigner(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, assetHubApi);
|
||||
|
||||
// Number of slashing spans (usually 0)
|
||||
const tx = assetHubApi.tx.staking.withdrawUnbonded(0);
|
||||
@@ -381,7 +368,7 @@ export const StakingDashboard: React.FC = () => {
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const injector = await getInjectorSigner(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, peopleApi);
|
||||
// stakingScore pallet is on People Chain - uses cached staking data from Asset Hub
|
||||
const tx = peopleApi.tx.stakingScore.startScoreTracking();
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Universal signer helper - works with both browser extension and WalletConnect
|
||||
*
|
||||
* Usage:
|
||||
* const injector = await getSigner(selectedAccount.address, walletSource, api);
|
||||
* // injector.signer works for signAndSend, signRaw, etc.
|
||||
*/
|
||||
|
||||
import { web3Enable, web3FromAddress } from '@pezkuwi/extension-dapp';
|
||||
import { createWCSigner, isWCConnected, validateSession } from '@/lib/walletconnect-service';
|
||||
import type { ApiPromise } from '@pezkuwi/api';
|
||||
|
||||
type WalletSource = 'extension' | 'walletconnect' | 'native' | null;
|
||||
|
||||
interface SignerResult {
|
||||
signer: any; // Compatible with @pezkuwi/api Signer
|
||||
}
|
||||
|
||||
export async function getSigner(
|
||||
address: string,
|
||||
walletSource: WalletSource,
|
||||
api?: ApiPromise | null
|
||||
): Promise<SignerResult> {
|
||||
if (walletSource === 'walletconnect') {
|
||||
if (!isWCConnected() || !validateSession()) {
|
||||
throw new Error('WalletConnect session expired. Please reconnect your wallet.');
|
||||
}
|
||||
if (!api) {
|
||||
throw new Error('API not ready');
|
||||
}
|
||||
const genesisHash = api.genesisHash.toHex();
|
||||
const wcSigner = createWCSigner(genesisHash, address);
|
||||
return { signer: wcSigner };
|
||||
}
|
||||
|
||||
// Extension or native: use web3FromAddress
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(address);
|
||||
return injector;
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import { User, Mail, Phone, Globe, MapPin, Calendar, Shield, AlertCircle, ArrowL
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { fetchUserTikis, getPrimaryRole, getTikiDisplayName, getTikiColor, getTikiEmoji, getUserRoleCategories, getAllTikiNFTDetails, generateCitizenNumber, type TikiNFTDetails } from '@pezkuwi/lib/tiki';
|
||||
import { getAllScores, getStakingScoreStatus, startScoreTracking, getPezRewards, recordTrustScore, claimPezReward, type UserScores, type StakingScoreStatus, type PezRewardInfo, formatDuration } from '@pezkuwi/lib/scores';
|
||||
import { web3Enable, web3FromAddress } from '@pezkuwi/extension-dapp';
|
||||
import { getSigner } from '@/lib/get-signer';
|
||||
import { getKycStatus } from '@pezkuwi/lib/kyc';
|
||||
import { ReferralDashboard } from '@/components/referral/ReferralDashboard';
|
||||
// Commission proposals card removed - no longer using notary system for KYC approval
|
||||
@@ -21,7 +21,7 @@ import { ReferralDashboard } from '@/components/referral/ReferralDashboard';
|
||||
export default function Dashboard() {
|
||||
const { t } = useTranslation();
|
||||
const { user } = useAuth();
|
||||
const { api, isApiReady, peopleApi, isPeopleReady, selectedAccount } = usePezkuwi();
|
||||
const { api, isApiReady, peopleApi, isPeopleReady, selectedAccount, walletSource } = usePezkuwi();
|
||||
const navigate = useNavigate();
|
||||
const { toast } = useToast();
|
||||
const [profile, setProfile] = useState<Record<string, unknown> | null>(null);
|
||||
@@ -157,8 +157,7 @@ export default function Dashboard() {
|
||||
|
||||
setStartingScoreTracking(true);
|
||||
try {
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, peopleApi);
|
||||
// startScoreTracking on People Chain - staking data comes from Asset Hub via XCM
|
||||
const result = await startScoreTracking(peopleApi, selectedAccount.address, injector.signer);
|
||||
|
||||
@@ -193,8 +192,7 @@ export default function Dashboard() {
|
||||
|
||||
setIsRecordingScore(true);
|
||||
try {
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, peopleApi);
|
||||
const result = await recordTrustScore(peopleApi, selectedAccount.address, injector.signer);
|
||||
|
||||
if (result.success) {
|
||||
@@ -215,8 +213,7 @@ export default function Dashboard() {
|
||||
|
||||
setIsClaimingReward(true);
|
||||
try {
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, peopleApi);
|
||||
const result = await claimPezReward(peopleApi, selectedAccount.address, epochIndex, injector.signer);
|
||||
|
||||
if (result.success) {
|
||||
@@ -332,9 +329,7 @@ export default function Dashboard() {
|
||||
|
||||
setRenouncingCitizenship(true);
|
||||
try {
|
||||
const { web3Enable, web3FromAddress } = await import('@pezkuwi/extension-dapp');
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, peopleApi);
|
||||
|
||||
if (import.meta.env.DEV) console.log('Renouncing citizenship...');
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { NftList } from '@/components/NftList';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ArrowUpRight, ArrowDownRight, History, ArrowLeft, RefreshCw, Coins, Loader2 } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
import { web3Enable, web3FromAddress } from '@pezkuwi/extension-dapp';
|
||||
import { getSigner } from '@/lib/get-signer';
|
||||
import { getPezRewards, recordTrustScore, claimPezReward, type PezRewardInfo } from '@pezkuwi/lib/scores';
|
||||
|
||||
interface Transaction {
|
||||
@@ -29,7 +29,7 @@ interface Transaction {
|
||||
const WalletDashboard: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const { api, isApiReady, peopleApi, isPeopleReady, selectedAccount } = usePezkuwi();
|
||||
const { api, isApiReady, peopleApi, isPeopleReady, selectedAccount, walletSource } = usePezkuwi();
|
||||
const [isTransferModalOpen, setIsTransferModalOpen] = useState(false);
|
||||
const [isReceiveModalOpen, setIsReceiveModalOpen] = useState(false);
|
||||
const [isHistoryModalOpen, setIsHistoryModalOpen] = useState(false);
|
||||
@@ -239,8 +239,7 @@ const WalletDashboard: React.FC = () => {
|
||||
if (!peopleApi || !selectedAccount) return;
|
||||
setIsRecordingScore(true);
|
||||
try {
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, peopleApi);
|
||||
const result = await recordTrustScore(peopleApi, selectedAccount.address, injector.signer);
|
||||
if (result.success) {
|
||||
toast.success(t('wallet.trustScoreRecorded'));
|
||||
@@ -260,8 +259,7 @@ const WalletDashboard: React.FC = () => {
|
||||
if (!peopleApi || !selectedAccount) return;
|
||||
setIsClaimingReward(true);
|
||||
try {
|
||||
await web3Enable('PezkuwiChain');
|
||||
const injector = await web3FromAddress(selectedAccount.address);
|
||||
const injector = await getSigner(selectedAccount.address, walletSource, peopleApi);
|
||||
const result = await claimPezReward(peopleApi, selectedAccount.address, epochIndex, injector.signer);
|
||||
if (result.success) {
|
||||
const rewardInfo = pezRewards?.claimableRewards.find(r => r.epoch === epochIndex);
|
||||
|
||||
Reference in New Issue
Block a user