> ## Documentation Index
> Fetch the complete documentation index at: https://polymarketcn.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 贖回獲勝代幣

> 學習如何在市場結算後將獲勝代幣兌換為 USDC

贖回（Redeeming）是市場結算後，將獲勝代幣轉換為 USDC 的過程。這是條件代幣生命周期的最後一步。

## 什麼是贖回？

當市場結算後，Oracle 會報告最終結果。持有獲勝結果代幣的用戶可以將這些代幣兌換為 USDC：

```
如果 Yes 獲勝:
100 Yes 代幣 → 100 USDC
100 No 代幣 → 0 USDC (無價值)

如果 No 獲勝:
100 Yes 代幣 → 0 USDC (無價值)
100 No 代幣 → 100 USDC
```

<Callout type="success">
  **獲勝回報**：每個獲勝代幣可以 1:1 兌換為 USDC。如果你以 0.65 的價格買入 Yes 代幣，Yes 獲勝後，每個代幣價值 1 USDC，利潤為 0.35 USDC。
</Callout>

## 贖回流程

### 市場結算流程

1. **事件發生**：現實世界的事件結果確定
2. **Oracle 報告**：UMA Oracle 提交結果
3. **爭議期**：短暫的爭議期（通常幾小時）
4. **結算確認**：結果最終確定
5. **贖回開放**：用戶可以贖回獲勝代幣

### 方法 1：通過 Polymarket 界面

最簡單的方法：

1. 訪問已結算的市場頁面
2. 如果你持有獲勝代幣，會看到"Redeem"按鈕
3. 點擊贖回
4. 確認交易
5. USDC 會自動轉入你的錢包

<Callout type="info">
  Polymarket 會自動顯示可贖回的金額，並處理所有技術細節。
</Callout>

### 方法 2：直接調用智能合約

適合自動化和批量贖回。

#### Python 示例

```python theme={null}
from web3 import Web3

# 連接到 Polygon
w3 = Web3(Web3.HTTPProvider('https://polygon-rpc.com'))

# CTF 合約
ctf_address = '0x4D97DCd97eC945f40cF65F87097ACe5EA0476045'
ctf_abi = [...]  # CTF ABI
ctf_contract = w3.eth.contract(address=ctf_address, abi=ctf_abi)

# USDC 地址
usdc_address = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174'

# 市場信息
condition_id = '0x...'  # 已結算市場的條件 ID
parent_collection_id = '0x' + '0' * 64

# 確定獲勝結果的索引集
# 如果 Yes 獲勝，使用 [1]
# 如果 No 獲勝，使用 [2]
winning_index_sets = [1]  # Yes 獲勝

# 贖回獲勝代幣
redeem_tx = ctf_contract.functions.redeemPositions(
    usdc_address,           # 抵押品代幣 (USDC)
    parent_collection_id,   # 父集合 ID
    condition_id,           # 條件 ID
    winning_index_sets      # 獲勝結果的索引集
).build_transaction({
    'from': your_address,
    'nonce': w3.eth.get_transaction_count(your_address),
    'gas': 150000,
    'gasPrice': w3.eth.gas_price
})

# 籤署並發送交易
signed_tx = w3.eth.account.sign_transaction(redeem_tx, private_key)
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)

print(f"贖回成功! 交易哈希: {tx_hash.hex()}")
print(f"Gas 使用: {receipt['gasUsed']}")
```

#### TypeScript 示例

```typescript theme={null}
import { ethers } from 'ethers';

// 連接到 Polygon
const provider = new ethers.providers.JsonRpcProvider('https://polygon-rpc.com');
const wallet = new ethers.Wallet(privateKey, provider);

// CTF 合約
const ctfAddress = '0x4D97DCd97eC945f40cF65F87097ACe5EA0476045';
const ctfAbi = [...];  // CTF ABI
const ctfContract = new ethers.Contract(ctfAddress, ctfAbi, wallet);

// USDC 地址
const usdcAddress = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174';

async function redeemPositions() {
  const conditionId = '0x...';  // 已結算市場的條件 ID
  const parentCollectionId = '0x' + '0'.repeat(64);
  
  // 獲勝結果 (1 = Yes, 2 = No)
  const winningIndexSets = [1];  // Yes 獲勝
  
  try {
    // 贖回代幣
    const redeemTx = await ctfContract.redeemPositions(
      usdcAddress,
      parentCollectionId,
      conditionId,
      winningIndexSets
    );
    
    console.log('贖回交易已發送:', redeemTx.hash);
    
    const receipt = await redeemTx.wait();
    console.log('贖回成功!');
    console.log('Gas 使用:', receipt.gasUsed.toString());
    
    // 檢查收到的 USDC
    const usdcContract = new ethers.Contract(usdcAddress, usdcAbi, wallet);
    const balance = await usdcContract.balanceOf(wallet.address);
    console.log('USDC 餘額:', ethers.utils.formatUnits(balance, 6));
    
  } catch (error) {
    console.error('贖回失敗:', error);
  }
}

redeemPositions();
```

## 檢查市場結算狀態

在贖回前，確認市場已結算：

```python theme={null}
def check_market_settled(condition_id):
    """
    檢查市場是否已結算
    """
    # 查詢支付向量
    payout_numerators = ctf_contract.functions.payoutNumerators(
        condition_id,
        0  # Yes 的索引
    ).call()
    
    if payout_numerators == 0:
        # 未結算
        print("市場尚未結算")
        return False, None
    else:
        # 已結算，確定獲勝方
        yes_payout = ctf_contract.functions.payoutNumerators(
            condition_id, 0
        ).call()
        
        no_payout = ctf_contract.functions.payoutNumerators(
            condition_id, 1
        ).call()
        
        if yes_payout > no_payout:
            print("市場已結算: Yes 獲勝")
            return True, 'YES'
        elif no_payout > yes_payout:
            print("市場已結算: No 獲勝")
            return True, 'NO'
        else:
            print("市場已結算: 無效/平局")
            return True, 'INVALID'

# 使用示例
settled, winner = check_market_settled(condition_id)
```

## 計算可贖回金額

檢查你可以贖回多少 USDC：

```python theme={null}
def calculate_redeemable_amount(address, position_id, condition_id):
    """
    計算可贖回的 USDC 數量
    """
    # 檢查市場結算狀態
    settled, winner = check_market_settled(condition_id)
    
    if not settled:
        print("市場尚未結算，無法贖回")
        return 0
    
    # 查詢代幣餘額
    balance = ctf_contract.functions.balanceOf(
        address,
        int(position_id, 16)
    ).call()
    
    # 查詢該位置的支付比例
    # 獲勝代幣的支付比例是 1，失敗代幣是 0
    payout = ctf_contract.functions.payoutNumerators(
        condition_id,
        0 if winner == 'YES' else 1
    ).call()
    
    payout_denominator = ctf_contract.functions.payoutDenominator(
        condition_id
    ).call()
    
    # 計算可贖回金額
    redeemable = balance * payout / payout_denominator
    
    print(f"代幣餘額: {balance / 10**6}")
    print(f"支付比例: {payout}/{payout_denominator}")
    print(f"可贖回: {redeemable / 10**6} USDC")
    
    return redeemable

# 使用示例
yes_position_id = '0x...'
redeemable = calculate_redeemable_amount(
    your_address,
    yes_position_id,
    condition_id
)
```

## 批量贖回多個市場

如果你在多個已結算市場都有獲勝代幣：

```python theme={null}
def batch_redeem(markets_info):
    """
    批量贖回多個市場的代幣
    
    Args:
        markets_info: 列表，每個元素包含 {condition_id, index_sets}
    """
    total_redeemed = 0
    
    for market in markets_info:
        condition_id = market['condition_id']
        index_sets = market['index_sets']  # [1] for Yes, [2] for No
        
        try:
            # 檢查是否已結算
            settled, winner = check_market_settled(condition_id)
            if not settled:
                print(f"市場 {condition_id[:8]}... 尚未結算，跳過")
                continue
            
            # 贖回
            redeem_tx = ctf_contract.functions.redeemPositions(
                usdc_address,
                '0x' + '0' * 64,
                condition_id,
                index_sets
            ).build_transaction({
                'from': your_address,
                'nonce': w3.eth.get_transaction_count(your_address),
            })
            
            signed_tx = w3.eth.account.sign_transaction(redeem_tx, private_key)
            tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
            
            print(f"市場 {condition_id[:8]}... 贖回交易: {tx_hash.hex()}")
            
            receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
            print(f"  ✓ 已確認，Gas: {receipt['gasUsed']}")
            
        except Exception as e:
            print(f"市場 {condition_id[:8]}... 贖回失敗: {e}")
            continue

# 使用示例
markets = [
    {'condition_id': '0xabc...', 'index_sets': [1]},  # Yes 獲勝
    {'condition_id': '0xdef...', 'index_sets': [2]},  # No 獲勝
    {'condition_id': '0x123...', 'index_sets': [1]},  # Yes 獲勝
]

batch_redeem(markets)
```

## 自動監控和贖回

創建一個自動化腳本，監控市場結算並自動贖回：

```python theme={null}
import time
from datetime import datetime

def auto_redeem_monitor(condition_ids, check_interval=300):
    """
    監控市場結算並自動贖回
    
    Args:
        condition_ids: 要監控的條件 ID 列表
        check_interval: 檢查間隔（秒）
    """
    redeemed = set()  # 已贖回的市場
    
    while condition_ids:
        print(f"\n[{datetime.now()}] 檢查市場狀態...")
        
        for condition_id in condition_ids[:]:
            if condition_id in redeemed:
                continue
            
            try:
                # 檢查是否已結算
                settled, winner = check_market_settled(condition_id)
                
                if settled:
                    print(f"市場 {condition_id[:8]}... 已結算: {winner}")
                    
                    # 確定要贖回的索引
                    if winner == 'YES':
                        index_sets = [1]
                    elif winner == 'NO':
                        index_sets = [2]
                    else:
                        # 無效結果，可能需要贖回兩邊
                        index_sets = [1, 2]
                    
                    # 執行贖回
                    redeem_tx = ctf_contract.functions.redeemPositions(
                        usdc_address,
                        '0x' + '0' * 64,
                        condition_id,
                        index_sets
                    ).build_transaction({
                        'from': your_address,
                        'nonce': w3.eth.get_transaction_count(your_address),
                    })
                    
                    signed_tx = w3.eth.account.sign_transaction(
                        redeem_tx, private_key
                    )
                    tx_hash = w3.eth.send_raw_transaction(
                        signed_tx.rawTransaction
                    )
                    
                    print(f"  → 贖回交易: {tx_hash.hex()}")
                    receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
                    print(f"  ✓ 贖回成功")
                    
                    # 標記為已贖回
                    redeemed.add(condition_id)
                    condition_ids.remove(condition_id)
                    
                else:
                    print(f"市場 {condition_id[:8]}... 尚未結算")
                    
            except Exception as e:
                print(f"市場 {condition_id[:8]}... 錯誤: {e}")
        
        if condition_ids:
            print(f"\n等待 {check_interval} 秒後再次檢查...")
            time.sleep(check_interval)
        else:
            print("\n所有市場已贖回完成!")
            break

# 使用示例
markets_to_monitor = [
    '0xabc123...',
    '0xdef456...',
    '0x789ghi...',
]

auto_redeem_monitor(markets_to_monitor, check_interval=300)  # 每5分鐘檢查
```

## Gas 成本

贖回操作的典型 Gas 成本（Polygon）：

| 操作        | Gas 使用量   | 成本 @ 100 Gwei |
| --------- | --------- | ------------- |
| 單次贖回      | \~110,000 | \$0.011       |
| 批量贖回 (3個) | \~300,000 | \$0.030       |

## 特殊情況

### 無效結果

某些情況下，市場可能被標記為無效：

* 問題模糊不清
* 結果無法驗證
* Oracle 無法確定結果

在無效結果的情況下：

```python theme={null}
# 無效結果通常意味著 Yes 和 No 各 50%
# 你可能需要贖回兩邊
index_sets = [1, 2]  # 贖回 Yes 和 No

# 每個代幣可以贖回 0.5 USDC
# 如果持有 100 Yes，可以贖回 50 USDC
```

### 部分贖回

你可以選擇只贖回部分代幣（雖然不常見）：

```python theme={null}
# 這需要更複雜的合約交互
# 通常直接贖回全部更簡單
```

## 贖回後驗證

驗證贖回是否成功：

```python theme={null}
def verify_redemption(address, condition_id):
    """
    驗證贖回後的狀態
    """
    # 檢查 USDC 餘額
    usdc_balance = usdc_contract.functions.balanceOf(address).call()
    print(f"USDC 餘額: {usdc_balance / 10**6}")
    
    # 檢查代幣餘額（應該為 0 或減少）
    yes_balance = ctf_contract.functions.balanceOf(
        address,
        int(yes_position_id, 16)
    ).call()
    
    no_balance = ctf_contract.functions.balanceOf(
        address,
        int(no_position_id, 16)
    ).call()
    
    print(f"Yes 代幣餘額: {yes_balance / 10**6}")
    print(f"No 代幣餘額: {no_balance / 10**6}")
    
    if yes_balance == 0 and no_balance == 0:
        print("✓ 所有代幣已贖回")
    else:
        print("⚠ 仍有代幣未贖回")

verify_redemption(your_address, condition_id)
```

## 注意事項

<Warning>
  **重要提示**：

  1. **等待結算**：市場必須完全結算後才能贖回
  2. **爭議期**：UMA Oracle 有爭議期，通常需要等待數小時
  3. **失敗代幣**：失敗方的代幣贖回價值為 0
  4. **Gas 費用**：需要 MATIC 支付 Gas
  5. **時間限制**：理論上沒有時間限制，但建議儘早贖回
  6. **檢查結果**：確認獲勝方後再贖回，避免 Gas 浪費
</Warning>

## 常見問題

### Q: 贖回有截止日期嗎？

A: 沒有。你可以隨時贖回獲勝代幣，即使是幾個月後。

### Q: 如果忘記贖回會怎樣？

A: 代幣會一直在你的錢包裡，不會消失。你可以隨時回來贖回。

### Q: 可以部分贖回嗎？

A: 技術上可以，但通常一次性贖回全部更簡單。

### Q: 贖回失敗的代幣有價值嗎？

A: 沒有。失敗方的代幣在結算後變為無價值，無法贖回任何 USDC。

### Q: Polymarket 會自動贖回嗎？

A: 不會。你需要手動點擊贖回按鈕或調用智能合約。

## 下一步

<CardGroup cols={2}>
  <Card title="合約部署信息" icon="code" href="/api-tutorial/conditional-tokens/deployment">
    查看合約地址和詳情
  </Card>

  <Card title="拆分 USDC" icon="scissors" href="/api-tutorial/conditional-tokens/splitting">
    學習如何拆分 USDC
  </Card>

  <Card title="CTF 概覽" icon="book" href="/api-tutorial/conditional-tokens/overview">
    返回條件代幣概覽
  </Card>

  <Card title="交易指南" icon="chart-line" href="/get-started/making-your-first-trade">
    學習如何進行交易
  </Card>
</CardGroup>
