修复:钱包入金功能修复

This commit is contained in:
ivan 2026-04-01 21:23:04 +08:00
parent 86974d8c54
commit 1542790e4a
9 changed files with 1403 additions and 397 deletions

File diff suppressed because it is too large Load Diff

View File

@ -7,15 +7,15 @@
content-class="withdraw-dialog" content-class="withdraw-dialog"
@update:model-value="$emit('update:modelValue', $event)" @update:model-value="$emit('update:modelValue', $event)"
> >
<v-card rounded="lg"> <v-card class="withdraw-card-shell" elevation="0">
<div class="withdraw-header"> <div class="withdraw-header">
<h2 class="withdraw-title">{{ t('withdraw.title') }}</h2> <h2 class="withdraw-title">{{ t('withdraw.title') }}</h2>
<p class="withdraw-balance">{{ t('withdraw.polymarketBalance') }} ${{ balance }}</p>
<v-btn icon variant="text" class="close-btn" :aria-label="t('withdraw.close')" @click="close"> <v-btn icon variant="text" class="close-btn" :aria-label="t('withdraw.close')" @click="close">
<v-icon>mdi-close</v-icon> <v-icon size="18">mdi-close</v-icon>
</v-btn> </v-btn>
</div> </div>
<v-card-text class="withdraw-body"> <v-card-text class="withdraw-body">
<p class="withdraw-balance">{{ t('withdraw.polymarketBalance') }} ${{ balance }}</p>
<v-text-field <v-text-field
v-model="amount" v-model="amount"
type="number" type="number"
@ -44,46 +44,19 @@
density="comfortable" density="comfortable"
hide-details hide-details
class="network-select" class="network-select"
@update:model-value="onWalletNetworkChange"
/> />
<div class="destination-section"> <div class="destination-section">
<label class="section-label">{{ t('withdraw.withdrawTo') }}</label> <label class="section-label">{{ t('withdraw.loginWalletLabel') }}</label>
<v-radio-group v-model="destinationType" hide-details class="destination-radio"> <div v-if="connecting" class="wallet-connecting">
<v-radio value="wallet" :label="t('withdraw.connectedWallet')" /> <v-progress-circular indeterminate size="20" width="2" color="primary" />
<v-radio value="address" :label="t('withdraw.customAddress')" /> <span>{{ t('withdraw.connectingWallet') }}</span>
</v-radio-group> </div>
<template v-if="destinationType === 'wallet'"> <div v-else-if="connectedAddress" class="connected-address">
<v-btn
v-if="!connectedAddress"
class="connect-wallet-btn"
variant="outlined"
rounded="lg"
block
:loading="connecting"
@click="connectWallet"
>
<v-icon start>mdi-wallet</v-icon>
{{ t('withdraw.connectWallet') }}
</v-btn>
<div v-else class="connected-address">
<v-icon color="success" size="18">mdi-check-circle</v-icon> <v-icon color="success" size="18">mdi-check-circle</v-icon>
<code>{{ shortAddress(connectedAddress) }}</code> <code>{{ shortAddress(connectedAddress) }}</code>
</div> </div>
</template>
<v-text-field
v-else
v-model="customAddress"
:label="t('withdraw.walletAddress')"
variant="outlined"
density="comfortable"
hide-details
:placeholder="t('withdraw.addressPlaceholder')"
class="address-field"
/>
</div>
<div v-if="destinationType === 'address'" class="hint-msg">
{{ t('withdraw.customAddressNotSupported') || 'Custom address is not supported for this withdrawal.' }}
</div> </div>
<div v-if="amountError" class="error-msg">{{ amountError }}</div> <div v-if="amountError" class="error-msg">{{ amountError }}</div>
<div v-if="errorMessage" class="error-msg">{{ errorMessage }}</div> <div v-if="errorMessage" class="error-msg">{{ errorMessage }}</div>
@ -112,10 +85,13 @@ import { useI18n } from 'vue-i18n'
import { BrowserProvider } from 'ethers' import { BrowserProvider } from 'ethers'
import { SiweMessage } from 'siwe' import { SiweMessage } from 'siwe'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { useToastStore } from '@/stores/toast'
import { withdrawByWallet, usdcToAmount } from '@/api/pmset' import { withdrawByWallet, usdcToAmount } from '@/api/pmset'
import { WALLET_PRIMARY_NETWORK_ID, useWalletNetworkGuard } from '@/composables/useWalletNetworkPolicy'
const { t } = useI18n() const { t } = useI18n()
const userStore = useUserStore() const userStore = useUserStore()
const toastStore = useToastStore()
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
modelValue: boolean modelValue: boolean
@ -126,9 +102,7 @@ const props = withDefaults(
const emit = defineEmits<{ 'update:modelValue': [value: boolean]; success: [] }>() const emit = defineEmits<{ 'update:modelValue': [value: boolean]; success: [] }>()
const amount = ref('') const amount = ref('')
const selectedNetwork = ref('polygon') const selectedNetwork = ref(WALLET_PRIMARY_NETWORK_ID)
const destinationType = ref<'wallet' | 'address'>('wallet')
const customAddress = ref('')
const connectedAddress = ref('') const connectedAddress = ref('')
const connecting = ref(false) const connecting = ref(false)
const submitting = ref(false) const submitting = ref(false)
@ -141,6 +115,17 @@ const networks = [
{ id: 'optimism', label: 'Optimism' }, { id: 'optimism', label: 'Optimism' },
] ]
const withdrawNetworkGuardActive = computed(() => props.modelValue)
const { onWalletNetworkChange } = useWalletNetworkGuard(
selectedNetwork,
withdrawNetworkGuardActive,
(msg, type) => {
toastStore.show(msg, type ?? 'warning')
},
t,
'deposit.networkNotSupportedYet',
)
const balanceNum = computed(() => parseFloat(props.balance) || 0) const balanceNum = computed(() => parseFloat(props.balance) || 0)
const amountNum = computed(() => parseFloat(amount.value) || 0) const amountNum = computed(() => parseFloat(amount.value) || 0)
@ -151,11 +136,8 @@ const amountError = computed(() => {
return '' return ''
}) })
/** 仅支持已连接钱包提现(需验签);自定义地址暂不支持 */ /** 仅提现到登录钱包:打开弹窗时已连接并校验地址 */
const hasValidDestination = computed(() => { const hasValidDestination = computed(() => !!connectedAddress.value)
if (destinationType.value === 'wallet') return !!connectedAddress.value
return false
})
const canSubmit = computed( const canSubmit = computed(
() => () =>
@ -185,22 +167,44 @@ function allowDecimal(e: KeyboardEvent) {
if (key !== '.' && !/^\d$/.test(key)) e.preventDefault() if (key !== '.' && !/^\d$/.test(key)) e.preventDefault()
} }
async function connectWallet() { function resolveUserLoginWalletAddress(): string | undefined {
const u = userStore.user as Record<string, unknown> | null
const raw =
(u?.externalWalletAddress as string | undefined) || (u?.walletAddress as string | undefined)
if (raw && /^0x[0-9a-fA-F]{40}$/.test(raw)) return raw
return undefined
}
/** 打开弹窗时自动连接浏览器钱包,且必须与登录账户地址一致 */
async function autoConnectWallet() {
connectedAddress.value = ''
errorMessage.value = ''
if (!window.ethereum) { if (!window.ethereum) {
errorMessage.value = t('deposit.installMetaMask') errorMessage.value = t('deposit.installMetaMask')
return return
} }
connecting.value = true connecting.value = true
errorMessage.value = ''
try { try {
const accounts = (await window.ethereum.request({ method: 'eth_requestAccounts' })) as string[] await userStore.fetchUserInfo()
connectedAddress.value = accounts[0] || '' const expected = resolveUserLoginWalletAddress()
if (!connectedAddress.value) { if (!expected) {
errorMessage.value = t('withdraw.connectFailed') || 'Failed to connect wallet' errorMessage.value = t('withdraw.externalWalletRequired')
return
} }
const accounts = (await window.ethereum.request({ method: 'eth_requestAccounts' })) as string[]
const addr = accounts[0] || ''
if (!addr) {
errorMessage.value = t('withdraw.connectFailed')
return
}
if (addr.toLowerCase() !== expected.toLowerCase()) {
errorMessage.value = t('withdraw.walletMismatch')
return
}
connectedAddress.value = addr
} catch (e) { } catch (e) {
console.error(e) console.error(e)
errorMessage.value = (e as Error)?.message || 'Failed to connect wallet' errorMessage.value = (e as Error)?.message || t('withdraw.connectFailed')
} finally { } finally {
connecting.value = false connecting.value = false
} }
@ -247,9 +251,9 @@ async function submitWithdraw() {
errorMessage.value = t('withdraw.connectWalletFirst') || 'Please connect wallet first' errorMessage.value = t('withdraw.connectWalletFirst') || 'Please connect wallet first'
return return
} }
const walletAddr = userStore.user?.externalWalletAddress as string | undefined const walletAddr = resolveUserLoginWalletAddress()
if (!walletAddr || !/^0x[0-9a-fA-F]{40}$/.test(walletAddr)) { if (!walletAddr) {
errorMessage.value = t('withdraw.externalWalletRequired') || 'External wallet address is required' errorMessage.value = t('withdraw.externalWalletRequired')
return return
} }
submitting.value = true submitting.value = true
@ -287,45 +291,70 @@ async function submitWithdraw() {
watch( watch(
() => props.modelValue, () => props.modelValue,
(open) => { async (open) => {
if (!open) { if (!open) {
amount.value = '' amount.value = ''
destinationType.value = 'wallet' selectedNetwork.value = WALLET_PRIMARY_NETWORK_ID
customAddress.value = ''
connectedAddress.value = '' connectedAddress.value = ''
errorMessage.value = '' errorMessage.value = ''
return
} }
await autoConnectWallet()
}, },
) )
</script> </script>
<style scoped> <style scoped>
.withdraw-card-shell {
display: flex;
flex-direction: column;
max-height: min(85vh, 640px);
overflow: hidden;
border-radius: 12px !important;
border: 1px solid #f3f4f6;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
}
.withdraw-header { .withdraw-header {
position: relative; display: flex;
padding: 20px 20px 8px; align-items: center;
border-bottom: 1px solid #e5e7eb; justify-content: space-between;
gap: 8px;
padding: 16px 24px 0;
}
.withdraw-divider {
height: 1px;
margin: 10px 24px 0;
background: #e5e7eb;
} }
.withdraw-title { .withdraw-title {
font-size: 1.25rem; font-size: 1rem;
font-weight: 600; font-weight: 600;
color: #111827; color: #111827;
margin: 0 0 4px 0; margin: 0;
text-align: center; text-align: left;
line-height: 1.2;
letter-spacing: normal;
} }
.withdraw-balance { .withdraw-balance {
font-size: 0.875rem; font-size: 0.8125rem;
font-weight: 500;
color: #6b7280; color: #6b7280;
margin: 0; margin: 0 0 14px;
text-align: center; text-align: left;
line-height: 1.35;
} }
.close-btn { .close-btn {
position: absolute; flex-shrink: 0;
top: 12px; align-self: center;
right: 8px; margin-top: -1px;
} }
.withdraw-body { .withdraw-body {
padding: 20px; flex: 1 1 auto;
min-height: 0;
padding: 16px 24px 24px;
overflow-y: auto;
letter-spacing: normal;
} }
.amount-field { .amount-field {
@ -350,16 +379,13 @@ watch(
color: #374151; color: #374151;
margin-bottom: 8px; margin-bottom: 8px;
} }
.destination-radio { .wallet-connecting {
margin-bottom: 12px; display: flex;
} align-items: center;
.destination-radio :deep(.v-radio-group) { gap: 10px;
flex-direction: row; padding: 12px;
gap: 24px; font-size: 0.875rem;
} color: #6b7280;
.connect-wallet-btn {
text-transform: none;
justify-content: flex-start;
} }
.connected-address { .connected-address {
display: flex; display: flex;
@ -373,15 +399,6 @@ watch(
.connected-address code { .connected-address code {
color: #166534; color: #166534;
} }
.address-field {
margin-top: 8px;
}
.hint-msg {
font-size: 0.8rem;
color: #6b7280;
margin-bottom: 12px;
}
.error-msg { .error-msg {
font-size: 0.8rem; font-size: 0.8rem;

View File

@ -0,0 +1,44 @@
import type { ComputedRef, Ref } from 'vue'
type ToastShow = (message: string, type?: 'success' | 'error' | 'warning' | 'info') => void
/**
* Polygon
* Set toast 退
*/
export const WALLET_PRIMARY_NETWORK_ID = 'polygon' as const
export const WALLET_SUPPORTED_NETWORK_IDS: ReadonlySet<string> = new Set<string>([
WALLET_PRIMARY_NETWORK_ID,
])
export function isWalletNetworkSupported(id: string | null): boolean {
return id != null && WALLET_SUPPORTED_NETWORK_IDS.has(id)
}
/**
* v-select `@update:model-value` `guardActive` true
*
* @param unsupportedMessageKey `deposit.networkNotSupportedYet`
*/
export function useWalletNetworkGuard(
selectedNetwork: Ref<string>,
guardActive: Ref<boolean> | ComputedRef<boolean>,
toastShow: ToastShow,
t: (key: string) => string,
unsupportedMessageKey: string,
) {
function onWalletNetworkChange(id: string | null) {
if (!guardActive.value) return
if (id == null || isWalletNetworkSupported(id)) return
toastShow(t(unsupportedMessageKey), 'warning')
selectedNetwork.value = WALLET_PRIMARY_NETWORK_ID
}
return {
onWalletNetworkChange,
WALLET_PRIMARY_NETWORK_ID,
WALLET_SUPPORTED_NETWORK_IDS,
isWalletNetworkSupported,
}
}

View File

@ -340,14 +340,16 @@
}, },
"deposit": { "deposit": {
"title": "Deposit", "title": "Deposit",
"polymarketBalance": "Polymarket Balance:", "polymarketBalance": "Balance:",
"transferCrypto": "Transfer Crypto", "transferCrypto": "Transfer Crypto",
"connectExchange": "Connect Exchange", "transferCryptoSub": "No limits • Fast • Sync to balance after deposit",
"connectExchange": "Transfer with current wallet",
"noLimit": "No limit", "noLimit": "No limit",
"instant": "Instant", "instant": "Instant",
"twoMin": "2 min", "twoMin": "2 min",
"network": "Network", "network": "Network",
"supportedTip": "Supported: USDC, ETH", "networkNotSupportedYet": "This network is not supported yet. Please use Polygon.",
"supportedTip": "Polygon only for now: USDC, ETH",
"depositAddress": "Deposit address", "depositAddress": "Deposit address",
"copy": "Copy", "copy": "Copy",
"copied": "Copied", "copied": "Copied",
@ -358,18 +360,46 @@
"walletConnectComingSoon": "WalletConnect (Coming soon)", "walletConnectComingSoon": "WalletConnect (Coming soon)",
"close": "Close", "close": "Close",
"installMetaMask": "Please install MetaMask or another Web3 wallet.", "installMetaMask": "Please install MetaMask or another Web3 wallet.",
"checkStatus": "Check Deposit Status", "connectingWallet": "Connecting wallet…",
"connectWalletHint": "Approve MetaMask to load your deposit address and send USDC.",
"linkMetaMask": "Connect MetaMask",
"collectInlineHint": "After sending USDC on-chain to this address, use “Collect” at the bottom to collect and sync USDC to your balance.",
"collectInlineHintExchange": "After sending USDC on-chain to this address, use “Collect” at the bottom to collect and sync USDC to your balance.",
"qrCaption": "Scan to fill the address (optional)",
"qrLoadFailed": "Could not load QR code",
"checkStatus": "Collect",
"checking": "Checking...", "checking": "Checking...",
"checkingStatus": "Checking deposit status...", "checkingStatus": "Checking deposit status...",
"nextCheckIn": "Next check in: {seconds}s", "nextCheckIn": "Next check in: {seconds}s",
"checkingNow": "Checking now...", "checkingNow": "Checking now...",
"checkSuccess": "Deposit detected! Processing...", "checkSuccess": "Deposit detected! Processing...",
"checkTimeout": "No deposit detected. Please try again later.", "checkTimeout": "No deposit detected. Please try again later.",
"checkError": "Check failed" "checkError": "Check failed",
"addressLoadFailed": "Could not load the deposit address. Please try again.",
"retry": "Retry",
"noDepositAddress": "No deposit address is available. Please contact support or try again later.",
"connectedTipMetaMask": "Wallet connected.",
"metamaskSendHint": "Match the network in your browser wallet, enter the USDC amount, then confirm in your wallet.",
"amountUsdc": "Amount (USDC)",
"amountUsdcHint": "Send USDC from this wallet to the deposit address. Keep native gas on this network.",
"sendViaMetaMask": "Send with MetaMask",
"depositFromWallet": "Deposit from wallet",
"collect": "Collect",
"sendSuccess": "Transfer confirmed on-chain",
"sendFailed": "Transfer failed",
"invalidAmount": "Enter a valid amount greater than zero",
"invalidDepositAddress": "Invalid deposit address",
"networkConfigError": "USDC is not configured for this network",
"sameAsWalletError": "Deposit address matches your wallet. Use the platform deposit address or contact support.",
"switchNetworkFailed": "Failed to switch network. Switch manually in MetaMask.",
"userRejected": "You cancelled the wallet request",
"insufficientUsdcBalance": "Not enough USDC on this network for this amount. On Polygon, native USDC and USDC.e are different tokens—use the one you actually hold, or bridge/swap first.",
"txConfirmTimeout": "Transaction was submitted but not confirmed in time. Check it in your wallet or a block explorer.",
"walletRpcIncomplete": "Your wallet returned incomplete transaction data. If issues persist, update MetaMask or change the RPC."
}, },
"withdraw": { "withdraw": {
"title": "Withdraw", "title": "Withdraw",
"polymarketBalance": "Polymarket Balance:", "polymarketBalance": "Balance:",
"amountUsd": "Amount (USD)", "amountUsd": "Amount (USD)",
"max": "Max", "max": "Max",
"network": "Network", "network": "Network",
@ -386,7 +416,10 @@
"connectFailed": "Failed to connect wallet", "connectFailed": "Failed to connect wallet",
"connectWalletFirst": "Please connect wallet first", "connectWalletFirst": "Please connect wallet first",
"externalWalletRequired": "External wallet address is required in user info", "externalWalletRequired": "External wallet address is required in user info",
"customAddressNotSupported": "Custom address is not supported for this withdrawal." "customAddressNotSupported": "Custom address is not supported for this withdrawal.",
"loginWalletLabel": "Your login wallet",
"connectingWallet": "Connecting wallet…",
"walletMismatch": "Switch your browser wallet to the same account you used to sign in."
}, },
"locale": { "locale": {
"zh": "简体中文", "zh": "简体中文",

View File

@ -340,14 +340,16 @@
}, },
"deposit": { "deposit": {
"title": "入金", "title": "入金",
"polymarketBalance": "Polymarket 残高:", "polymarketBalance": "残高:",
"transferCrypto": "暗号資産を送金", "transferCrypto": "暗号資産を送金",
"connectExchange": "取引所を接続", "transferCryptoSub": "制限なし • 即時 • 着金後に下部でコレクト",
"connectExchange": "現在のウォレットで送金",
"noLimit": "制限なし", "noLimit": "制限なし",
"instant": "即時", "instant": "即時",
"twoMin": "約2分", "twoMin": "約2分",
"network": "ネットワーク", "network": "ネットワーク",
"supportedTip": "対応USDC、ETH", "networkNotSupportedYet": "このネットワークにはまだ対応していません。Polygon をご利用ください。",
"supportedTip": "現在は Polygon のみ対応USDC、ETH",
"depositAddress": "入金アドレス", "depositAddress": "入金アドレス",
"copy": "コピー", "copy": "コピー",
"copied": "コピーしました", "copied": "コピーしました",
@ -357,11 +359,47 @@
"coinbaseComingSoon": "Coinbase Wallet近日公開", "coinbaseComingSoon": "Coinbase Wallet近日公開",
"walletConnectComingSoon": "WalletConnect近日公開", "walletConnectComingSoon": "WalletConnect近日公開",
"close": "閉じる", "close": "閉じる",
"installMetaMask": "MetaMask または他の Web3 ウォレットをインストールしてください。" "installMetaMask": "MetaMask または他の Web3 ウォレットをインストールしてください。",
"connectingWallet": "ウォレットに接続しています…",
"connectWalletHint": "入金アドレスの表示と送金のために MetaMask の承認が必要です。",
"linkMetaMask": "MetaMask を接続",
"collectInlineHint": "このアドレスへオンチェーンで USDC を送金したら、画面下の「回収」でコレクトし、残高に反映してください。",
"collectInlineHintExchange": "このアドレスへオンチェーンで USDC を送金したら、画面下の「回収」でコレクトし、残高に反映してください。",
"qrCaption": "アドレス入力用 QR任意",
"qrLoadFailed": "QR の読み込みに失敗しました",
"checkStatus": "回収",
"checking": "確認中...",
"checkingStatus": "入金状況を確認しています...",
"nextCheckIn": "次の確認: {seconds}秒",
"checkingNow": "確認中...",
"checkSuccess": "入金を検知しました。処理を送信しました。",
"checkTimeout": "入金がまだ検知されませんでした。しばらくしてからお試しください。",
"checkError": "確認に失敗しました",
"addressLoadFailed": "入金アドレスを取得できませんでした。もう一度お試しください。",
"retry": "再試行",
"noDepositAddress": "利用可能な入金アドレスがありません。サポートへお問い合わせいただくか、しばらくしてから再試行してください。",
"connectedTipMetaMask": "ウォレット接続済み。",
"metamaskSendHint": "ブラウザのウォレットのネットワークと一致するよう選び、送金する USDC 量を入力して、下のボタンからウォレットで承認してください。",
"amountUsdc": "金額 (USDC)",
"amountUsdcHint": "このウォレットから入金先へ USDC を送ります。ガス用にネイティブトークンを残してください。",
"sendViaMetaMask": "MetaMask で送金",
"depositFromWallet": "ウォレットから入金",
"collect": "回収",
"sendSuccess": "チェーン上で送金が確定しました",
"sendFailed": "送金に失敗しました",
"invalidAmount": "0 より大きい有効な金額を入力してください",
"invalidDepositAddress": "入金アドレスが無効です",
"networkConfigError": "このネットワークには USDC が設定されていません",
"sameAsWalletError": "入金先がご自身のウォレットと同じです。プラットフォームの入金先をご確認ください。",
"switchNetworkFailed": "ネットワークの切り替えに失敗しました。MetaMask で手動で切り替えてください。",
"userRejected": "ウォレットの操作をキャンセルしました",
"insufficientUsdcBalance": "このネットワーク上の USDC 残高が不足しています。Polygon ではネイティブ USDC と USDC.e は別トークンです。保有している方で送るか、ブリッジ・スワップ後に再試行してください。",
"txConfirmTimeout": "トランザクションは送信されましたが、一定時間内に確認されませんでした。ウォレットまたはブロックエクスプローラーでご確認ください。",
"walletRpcIncomplete": "ウォレットから返ったトランザクション情報が不完全です。MetaMask の更新や RPC の変更をお試しください。"
}, },
"withdraw": { "withdraw": {
"title": "出金", "title": "出金",
"polymarketBalance": "Polymarket 残高:", "polymarketBalance": "残高:",
"amountUsd": "金額 (USD)", "amountUsd": "金額 (USD)",
"max": "最大", "max": "最大",
"network": "ネットワーク", "network": "ネットワーク",
@ -378,7 +416,10 @@
"connectFailed": "ウォレットの接続に失敗しました", "connectFailed": "ウォレットの接続に失敗しました",
"connectWalletFirst": "まずウォレットを接続してください", "connectWalletFirst": "まずウォレットを接続してください",
"externalWalletRequired": "ユーザー情報に外部ウォレットアドレスが必要です", "externalWalletRequired": "ユーザー情報に外部ウォレットアドレスが必要です",
"customAddressNotSupported": "この出金ではカスタムアドレスはサポートされていません。" "customAddressNotSupported": "この出金ではカスタムアドレスはサポートされていません。",
"loginWalletLabel": "ログイン中のウォレット",
"connectingWallet": "ウォレットに接続しています…",
"walletMismatch": "ログイン時に使用したアカウントにブラウザのウォレットを切り替えてください。"
}, },
"locale": { "locale": {
"zh": "简体中文", "zh": "简体中文",

View File

@ -340,14 +340,16 @@
}, },
"deposit": { "deposit": {
"title": "입금", "title": "입금",
"polymarketBalance": "Polymarket 잔액:", "polymarketBalance": "잔액:",
"transferCrypto": "암호화폐 전송", "transferCrypto": "암호화폐 전송",
"connectExchange": "거래소 연결", "transferCryptoSub": "제한 없음 • 즉시 • 입금 후 하단에서 수집",
"connectExchange": "현재 지갑으로 송금",
"noLimit": "제한 없음", "noLimit": "제한 없음",
"instant": "즉시", "instant": "즉시",
"twoMin": "약 2분", "twoMin": "약 2분",
"network": "네트워크", "network": "네트워크",
"supportedTip": "지원: USDC, ETH", "networkNotSupportedYet": "해당 네트워크는 아직 지원하지 않습니다. Polygon을 이용해 주세요.",
"supportedTip": "현재 Polygon만 지원: USDC, ETH",
"depositAddress": "입금 주소", "depositAddress": "입금 주소",
"copy": "복사", "copy": "복사",
"copied": "복사됨", "copied": "복사됨",
@ -357,11 +359,47 @@
"coinbaseComingSoon": "Coinbase Wallet (출시 예정)", "coinbaseComingSoon": "Coinbase Wallet (출시 예정)",
"walletConnectComingSoon": "WalletConnect (출시 예정)", "walletConnectComingSoon": "WalletConnect (출시 예정)",
"close": "닫기", "close": "닫기",
"installMetaMask": "MetaMask 또는 다른 Web3 지갑을 설치해 주세요." "installMetaMask": "MetaMask 또는 다른 Web3 지갑을 설치해 주세요.",
"connectingWallet": "지갑 연결 중…",
"connectWalletHint": "입금 주소를 불러오고 전송하려면 MetaMask 승인이 필요합니다.",
"linkMetaMask": "MetaMask 연결",
"collectInlineHint": "이 주소로 온체인 USDC 전송을 마친 뒤, 화면 맨 아래「수집」으로 수집해 잔액에 반영하세요.",
"collectInlineHintExchange": "이 주소로 온체인 USDC 전송을 마친 뒤, 화면 맨 아래「수집」으로 수집해 잔액에 반영하세요.",
"qrCaption": "주소 입력용 QR (선택)",
"qrLoadFailed": "QR 코드를 불러오지 못했습니다",
"checkStatus": "수집",
"checking": "확인 중...",
"checkingStatus": "입금 상태 확인 중...",
"nextCheckIn": "다음 확인: {seconds}초",
"checkingNow": "확인 중...",
"checkSuccess": "입금이 감지되었습니다. 처리를 제출했습니다.",
"checkTimeout": "입금이 아직 감지되지 않았습니다. 잠시 후 다시 시도하세요.",
"checkError": "확인 실패",
"addressLoadFailed": "입금 주소를 불러오지 못했습니다. 다시 시도해 주세요.",
"retry": "다시 시도",
"noDepositAddress": "사용 가능한 입금 주소가 없습니다. 고객 지원에 문의하거나 잠시 후 다시 시도해 주세요.",
"connectedTipMetaMask": "지갑이 연결되었습니다.",
"metamaskSendHint": "브라우저 지갑의 네트워크와 일치하도록 선택하고, 보낼 USDC 수량을 입력한 뒤 아래 버튼으로 지갑에서 승인하세요.",
"amountUsdc": "금액 (USDC)",
"amountUsdcHint": "현재 지갑에서 입금 주소로 USDC를 보냅니다. 가스비용 네이티브 토큰을 남겨 두세요.",
"sendViaMetaMask": "MetaMask로 전송",
"depositFromWallet": "지갑에서 입금",
"collect": "수집",
"sendSuccess": "전송이 온체인에서 확인되었습니다",
"sendFailed": "전송 실패",
"invalidAmount": "0보다 큰 유효한 금액을 입력하세요",
"invalidDepositAddress": "입금 주소가 올바르지 않습니다",
"networkConfigError": "이 네트워크에 USDC가 구성되어 있지 않습니다",
"sameAsWalletError": "입금 주소가 현재 지갑과 같습니다. 플랫폼 입금 주소를 확인하거나 고객 지원에 문의하세요.",
"switchNetworkFailed": "네트워크 전환에 실패했습니다. MetaMask에서 수동으로 전환하세요.",
"userRejected": "지갑에서 작업을 취소했습니다",
"insufficientUsdcBalance": "이 네트워크의 USDC 잔액이 부족합니다. Polygon에서는 네이티브 USDC와 USDC.e가 다른 토큰입니다. 보유 중인 종류로 보내거나 브릿지/스왑 후 다시 시도하세요.",
"txConfirmTimeout": "거래는 제출되었지만 제한 시간 안에 확인되지 않았습니다. 지갑이나 블록 탐색기에서 확인해 주세요.",
"walletRpcIncomplete": "지갑에서 반환된 거래 데이터가 불완전합니다. MetaMask를 업데이트하거나 RPC를 변경해 보세요."
}, },
"withdraw": { "withdraw": {
"title": "출금", "title": "출금",
"polymarketBalance": "Polymarket 잔액:", "polymarketBalance": "잔액:",
"amountUsd": "금액 (USD)", "amountUsd": "금액 (USD)",
"max": "최대", "max": "최대",
"network": "네트워크", "network": "네트워크",
@ -378,7 +416,10 @@
"connectFailed": "지갑 연결에 실패했습니다", "connectFailed": "지갑 연결에 실패했습니다",
"connectWalletFirst": "먼저 지갑을 연결해 주세요", "connectWalletFirst": "먼저 지갑을 연결해 주세요",
"externalWalletRequired": "사용자 정보에 외부 지갑 주소가 필요합니다", "externalWalletRequired": "사용자 정보에 외부 지갑 주소가 필요합니다",
"customAddressNotSupported": "이 출금에서는 사용자 지정 주소가 지원되지 않습니다." "customAddressNotSupported": "이 출금에서는 사용자 지정 주소가 지원되지 않습니다.",
"loginWalletLabel": "로그인 지갑",
"connectingWallet": "지갑 연결 중…",
"walletMismatch": "로그인에 사용한 계정과 동일한 계정으로 브라우저 지갑을 전환해 주세요."
}, },
"locale": { "locale": {
"zh": "简体中文", "zh": "简体中文",

View File

@ -340,14 +340,16 @@
}, },
"deposit": { "deposit": {
"title": "入金", "title": "入金",
"polymarketBalance": "Polymarket 余额:", "polymarketBalance": "余额:",
"transferCrypto": "转账加密货币", "transferCrypto": "转账加密货币",
"connectExchange": "连接交易所", "transferCryptoSub": "无限制 • 即时 • 到账后可在底部一键归集",
"connectExchange": "使用当前钱包转账",
"noLimit": "无限制", "noLimit": "无限制",
"instant": "即时到账", "instant": "即时到账",
"twoMin": "约 2 分钟", "twoMin": "约 2 分钟",
"network": "网络", "network": "网络",
"supportedTip": "支持USDC、ETH", "networkNotSupportedYet": "暂不支持该网络,请使用 Polygon。",
"supportedTip": "当前仅支持 PolygonUSDC、ETH",
"depositAddress": "充值地址", "depositAddress": "充值地址",
"copy": "复制", "copy": "复制",
"copied": "已复制", "copied": "已复制",
@ -358,18 +360,46 @@
"walletConnectComingSoon": "WalletConnect即将推出", "walletConnectComingSoon": "WalletConnect即将推出",
"close": "关闭", "close": "关闭",
"installMetaMask": "请安装 MetaMask 或其他 Web3 钱包。", "installMetaMask": "请安装 MetaMask 或其他 Web3 钱包。",
"checkStatus": "检查充值状态", "connectingWallet": "正在连接钱包…",
"connectWalletHint": "需要授权 MetaMask 后才能显示充值地址并转账。",
"linkMetaMask": "连接 MetaMask",
"collectInlineHint": "向该地址完成链上转账后,请点击底部「归集」,将 USDC 同步到账户余额。",
"collectInlineHintExchange": "向该地址完成链上转账后,请点击底部「归集」,将 USDC 同步到账户余额。",
"qrCaption": "扫码填入收款地址(可选)",
"qrLoadFailed": "二维码加载失败",
"checkStatus": "归集",
"checking": "正在检测...", "checking": "正在检测...",
"checkingStatus": "正在检测充值状态...", "checkingStatus": "正在检测充值状态...",
"nextCheckIn": "下次检测: {seconds}秒", "nextCheckIn": "下次检测: {seconds}秒",
"checkingNow": "正在检测...", "checkingNow": "正在检测...",
"checkSuccess": "检测到充值!已提交处理。", "checkSuccess": "检测到充值!已提交处理。",
"checkTimeout": "未检测到充值。请稍候再试。", "checkTimeout": "未检测到充值。请稍候再试。",
"checkError": "检测失败" "checkError": "检测失败",
"addressLoadFailed": "获取充值地址失败,请重试。",
"retry": "重试",
"noDepositAddress": "暂无可用充值地址,请联系客服或稍后重试。",
"connectedTipMetaMask": "钱包已连接。",
"metamaskSendHint": "请选择与浏览器钱包中的网络一致,输入要转出的 USDC 数量,点击下方按钮在钱包中确认。",
"amountUsdc": "金额 (USDC)",
"amountUsdcHint": "从当前钱包将 USDC 转到入账地址,请预留主网币作为 Gas",
"sendViaMetaMask": "在 MetaMask 中转账",
"depositFromWallet": "从钱包转入",
"collect": "归集",
"sendSuccess": "转账已成功上链",
"sendFailed": "转账失败",
"invalidAmount": "请输入大于 0 的有效金额",
"invalidDepositAddress": "入账地址无效",
"networkConfigError": "当前网络未配置 USDC 合约",
"sameAsWalletError": "入账地址与当前钱包相同,无法向自己转账。请确认平台入金地址或联系客服。",
"switchNetworkFailed": "切换网络失败,请在 MetaMask 中手动切换到所选网络。",
"userRejected": "您已取消钱包中的操作",
"insufficientUsdcBalance": "当前网络上的 USDC 余额不足。若在 Polygon请确认您持有的是「原生 USDC」或「USDC.e」或先兑换/跨链后再试。",
"txConfirmTimeout": "交易已提交,但长时间未在链上确认,请在浏览器钱包或区块浏览器中查看该笔交易。",
"walletRpcIncomplete": "钱包返回的交易数据不完整。已改为直连接口发交易;若仍失败请更新 MetaMask 或更换 RPC。"
}, },
"withdraw": { "withdraw": {
"title": "提现", "title": "提现",
"polymarketBalance": "Polymarket 余额:", "polymarketBalance": "余额:",
"amountUsd": "金额 (USD)", "amountUsd": "金额 (USD)",
"max": "最大", "max": "最大",
"network": "网络", "network": "网络",
@ -398,7 +428,10 @@
"connectFailed": "连接钱包失败", "connectFailed": "连接钱包失败",
"connectWalletFirst": "请先连接钱包", "connectWalletFirst": "请先连接钱包",
"externalWalletRequired": "用户信息中缺少外部钱包地址", "externalWalletRequired": "用户信息中缺少外部钱包地址",
"customAddressNotSupported": "暂不支持自定义地址提现。" "customAddressNotSupported": "暂不支持自定义地址提现。",
"loginWalletLabel": "登录钱包(提现地址)",
"connectingWallet": "正在连接钱包…",
"walletMismatch": "请在浏览器钱包中切换到您登录时使用的账户。"
}, },
"locale": { "locale": {
"zh": "简体中文", "zh": "简体中文",

View File

@ -340,14 +340,16 @@
}, },
"deposit": { "deposit": {
"title": "入金", "title": "入金",
"polymarketBalance": "Polymarket 餘額:", "polymarketBalance": "餘額:",
"transferCrypto": "轉帳加密貨幣", "transferCrypto": "轉帳加密貨幣",
"connectExchange": "連接交易所", "transferCryptoSub": "無限制 • 即時 • 到帳後可在底部一鍵歸集",
"connectExchange": "使用當前錢包轉帳",
"noLimit": "無限制", "noLimit": "無限制",
"instant": "即時到帳", "instant": "即時到帳",
"twoMin": "約 2 分鐘", "twoMin": "約 2 分鐘",
"network": "網路", "network": "網路",
"supportedTip": "支援USDC、ETH", "networkNotSupportedYet": "暫不支援此網路,請使用 Polygon。",
"supportedTip": "目前僅支援 PolygonUSDC、ETH",
"depositAddress": "充值地址", "depositAddress": "充值地址",
"copy": "複製", "copy": "複製",
"copied": "已複製", "copied": "已複製",
@ -357,11 +359,47 @@
"coinbaseComingSoon": "Coinbase Wallet即將推出", "coinbaseComingSoon": "Coinbase Wallet即將推出",
"walletConnectComingSoon": "WalletConnect即將推出", "walletConnectComingSoon": "WalletConnect即將推出",
"close": "關閉", "close": "關閉",
"installMetaMask": "請安裝 MetaMask 或其他 Web3 錢包。" "installMetaMask": "請安裝 MetaMask 或其他 Web3 錢包。",
"connectingWallet": "正在連接錢包…",
"connectWalletHint": "請先授權 MetaMask才能顯示充值地址並轉帳。",
"linkMetaMask": "連接 MetaMask",
"collectInlineHint": "向該地址完成鏈上轉帳後,請點擊底部「歸集」,將 USDC 同步至帳戶餘額。",
"collectInlineHintExchange": "向該地址完成鏈上轉帳後,請點擊底部「歸集」,將 USDC 同步至帳戶餘額。",
"qrCaption": "掃碼填入收款地址(可選)",
"qrLoadFailed": "二維碼載入失敗",
"checkStatus": "歸集",
"checking": "正在檢測...",
"checkingStatus": "正在檢測充值狀態...",
"nextCheckIn": "下次檢測: {seconds}秒",
"checkingNow": "正在檢測...",
"checkSuccess": "檢測到充值!已提交處理。",
"checkTimeout": "未檢測到充值。請稍候再試。",
"checkError": "檢測失敗",
"addressLoadFailed": "取得充值地址失敗,請重試。",
"retry": "重試",
"noDepositAddress": "暫無可用充值地址,請聯絡客服或稍後再試。",
"connectedTipMetaMask": "錢包已連接。",
"metamaskSendHint": "請選擇與瀏覽器錢包中的網路一致,輸入要轉出的 USDC 數量,點擊下方按鈕在錢包中確認。",
"amountUsdc": "金額 (USDC)",
"amountUsdcHint": "從目前錢包將 USDC 轉到入帳地址,請預留主網幣作為 Gas",
"sendViaMetaMask": "在 MetaMask 中轉帳",
"depositFromWallet": "從錢包轉入",
"collect": "歸集",
"sendSuccess": "轉帳已成功上鏈",
"sendFailed": "轉帳失敗",
"invalidAmount": "請輸入大於 0 的有效金額",
"invalidDepositAddress": "入帳地址無效",
"networkConfigError": "目前網路未設定 USDC 合約",
"sameAsWalletError": "入帳地址與目前錢包相同,無法向自己轉帳。請確認平台入金地址或聯絡客服。",
"switchNetworkFailed": "切換網路失敗,請在 MetaMask 中手動切換到所選網路。",
"userRejected": "您已取消錢包中的操作",
"insufficientUsdcBalance": "目前網路上的 USDC 餘額不足。若在 Polygon請確認持有的是「原生 USDC」或「USDC.e」或先兌換/跨鏈後再試。",
"txConfirmTimeout": "交易已提交,但長時間未在鏈上確認,請在瀏覽器錢包或區塊瀏覽器中查看該筆交易。",
"walletRpcIncomplete": "錢包回傳的交易資料不完整。已改為直接介面發送;若仍失敗請更新 MetaMask 或更換 RPC。"
}, },
"withdraw": { "withdraw": {
"title": "提現", "title": "提現",
"polymarketBalance": "Polymarket 餘額:", "polymarketBalance": "餘額:",
"amountUsd": "金額 (USD)", "amountUsd": "金額 (USD)",
"max": "最大", "max": "最大",
"network": "網路", "network": "網路",
@ -378,7 +416,10 @@
"connectFailed": "連接錢包失敗", "connectFailed": "連接錢包失敗",
"connectWalletFirst": "請先連接錢包", "connectWalletFirst": "請先連接錢包",
"externalWalletRequired": "用戶資訊中缺少外部錢包地址", "externalWalletRequired": "用戶資訊中缺少外部錢包地址",
"customAddressNotSupported": "暫不支援自訂地址提現。" "customAddressNotSupported": "暫不支援自訂地址提現。",
"loginWalletLabel": "登入錢包(提現地址)",
"connectingWallet": "正在連接錢包…",
"walletMismatch": "請在瀏覽器錢包中切換至您登入時使用的帳戶。"
}, },
"locale": { "locale": {
"zh": "繁體中文", "zh": "繁體中文",

View File

@ -371,7 +371,7 @@
</div> </div>
</div> </div>
<DepositDialog v-model="depositDialogOpen" :balance="portfolioBalance" /> <DepositDialog v-model="depositDialogOpen" />
<WithdrawDialog <WithdrawDialog
v-model="withdrawDialogOpen" v-model="withdrawDialogOpen"
:balance="portfolioBalance" :balance="portfolioBalance"
@ -1497,10 +1497,14 @@ async function submitAuthorize() {
border: 1px solid #e5e7eb; border: 1px solid #e5e7eb;
background: #fff; background: #fff;
color: #111827; color: #111827;
font-size: 12px; font-size: 20px;
font-weight: 600; font-weight: 600;
} }
.design-tu-action :deep(.v-btn__content) {
font-size: 20px;
}
.design-tu-settlement { .design-tu-settlement {
padding: 12px 14px; padding: 12px 14px;
border-radius: 16px; border-radius: 16px;