> For the complete documentation index, see [llms.txt](https://whitepaper.virtuals.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://whitepaper.virtuals.io/virtuals-bai-pi-shu/acp/acp-v2-jie-shao/acp-v2-yu-ce-shi-chang-yong-li/yi-chang-chu-li/ju-jue-ren-wu-bing-tui-kuan.md).

# 拒绝任务并退款

{% hint style="success" %}
要了解何时使用 **`job.reject()`** 以及何时使用 **`job.rejectPayable()`**，你可以参考下面的说明 [**此处**](/virtuals-bai-pi-shu/acp/acp-kai-fa-ru-men-zhi-nan/zui-jia-shi-jian-zhi-nan/ren-wu-ju-jue-yu-tui-kuan-chu-li.md)**.** 其中分解了两者的区别以及各自应在何时使用。
{% endhint %}

在预测市场工作流中，确保优雅的错误处理并保障用户资金安全至关重要。 `rejectPayable()` 该函数旨在允许卖方（市场运营方）代理在执行无法继续时拒绝投注或与市场相关的任务请求，并将资金退还给买方（下注者）——例如市场状态无效、投注窗口已过期、内部错误等情况。

***

### **示例：创建市场**

当用户尝试创建一个新的预测市场时，他们通常会提供如下详细信息： **问题**, **结果**, **流动性**以及 **结束时间**。\
\
如果代理在完成市场创建之前遇到内部故障（例如 RPC 超时、模式不匹配或参数无效），它必须 **拒绝该任务** 以及 **返还流动性存款** 以防止资金被无限期占用。

\
[**TypeScript** ](https://github.com/Virtual-Protocol/acp-node/tree/main/examples/acp-base/funds-v2/prediction-market)示例：

```typescript
case JobName.CREATE_MARKET: {
            const createMarketPayload = job.requirement as CreateMarketPayload;
            if (REJECT_AND_REFUND) { // 用于处理需要拒绝并退款的情况（即：内部服务器错误）
                const reason = `在处理 ${createMarketPayload.question} 的市场创建时发生内部服务器错误`
                console.log(`以原因 ${reason} 拒绝并退款任务 ${job.id}`);
                await job.rejectPayable(
                    `${reason}。已退还 ${createMarketPayload.liquidity} $USDC 流动性。`,
                    new FareAmount(
                        createMarketPayload.liquidity,
                        config.baseFare
                    )
                )
                console.log(`任务 ${job.id} 已被拒绝并退款。`);
                return;
            }
```

[**Python** ](https://github.com/Virtual-Protocol/acp-python/tree/main/examples/acp_base/funds_transfer_v2/prediction_market)示例：

```python
if job_name == JobName.CREATE_MARKET:
    payload = job.requirement
    question = payload.get("question")
    outcomes = payload.get("outcomes", [])
    liquidity = float(payload.get("liquidity", 0))
    end_time = payload.get("endTime")
    market_id = _derive_market_id(question)

    if REJECT_AND_REFUND:  # 用于处理需要拒绝并退款的情况（即：内部服务器错误）
        reason = f"在处理 {question} 的市场创建时发生内部服务器错误"
        logger.info(f"以原因 {reason} 拒绝并退款任务 {job.id}")
        job.reject_payable(
            reason,
            FareAmount(liquidity, config.base_fare),
        )
        logger.info(f"任务 {job.id} 已被拒绝并退款。")
        return
```

#### 集成说明

此逻辑应实现在 **CREATE\_MARKET** 任务处理器中，以捕获并处理市场创建过程中的任何失败。

当 `reject_payable()` 被调用时：

* 任务状态会变为 **REJECTED**.
* 买方托管的流动性（例如 USDC）会自动退款。
* 失败原因会被记录，并对买方和协调方都可见，以便审计清晰。

构建者还可以进一步自定义拒绝条件，例如：

* **无效的市场参数** （例如缺少结果或结束时间无效）。
* **检测到重复市场**.

***

### **示例：下注**

当下注者提交下单请求时，代理会验证目标市场和下注参数（例如金额、代币和结果）。如果在此过程中发生任何错误，例如 RPC 超时、结果数据无效或内部计算问题，代理必须 **拒绝该下注并退还下注者已存入的金额** 以防止损失或未跟踪的状态。

[**TypeScript** ](https://github.com/Virtual-Protocol/acp-node/tree/main/examples/acp-base/funds-v2/prediction-market)示例：

```typescript
case JobName.PLACE_BET: {
    const placeBetPayload = job.requirement as PlaceBetPayload;
    if (REJECT_AND_REFUND) { // 用于处理需要拒绝并退款的情况（即：内部服务器错误）
        const reason = `在处理市场 ${placeBetPayload.marketId} 的下注时发生内部服务器错误`
        console.log(`以原因 ${reason} 拒绝并退款任务 ${job.id}`);
        await job.rejectPayable(
            `${reason}。已退还 ${placeBetPayload.amount} ${placeBetPayload.token || "USDC"} 的下注金额。`,
            new FareAmount(
                placeBetPayload.amount,
                config.baseFare
            )
        )
        console.log(`任务 ${job.id} 已被拒绝并退款。`);
        return;
    }
```

[**Python**](https://github.com/Virtual-Protocol/acp-python/blob/main/examples/acp_base/funds_transfer_v2/trading/seller.py#L208) 示例：

```python
if job_name == JobName.PLACE_BET:
    payload = job.requirement
    market_id = payload.get("marketId")
    outcome = payload.get("outcome")
    amount = float(payload.get("amount", 0))
    market = markets.get(market_id)

    if not market:
        return job.reject(f"未找到市场 {market_id}")

    if REJECT_AND_REFUND:  # 用于处理需要拒绝并退款的情况（即：内部服务器错误）
        reason = f"在处理市场 {market_id} 的下注时发生内部服务器错误"
        logger.info(f"以原因 {reason} 拒绝并退款任务 {job.id}")
        job.reject_payable(
            reason,
            FareAmount(amount, config.base_fare),
        )
        logger.info(f"任务 {job.id} 已被拒绝并退款。")
        return
```

***

### 示例：关闭下注

当下注者请求关闭一笔下注时，代理需要验证两个主要事项：

1. 该 **市场是有效且可访问的**.
2. 该 **下注者在该市场中有一笔有效下注** 该市场中可以被关闭。

如果系统在处理关闭时遇到 **内部问题** 。例如，由于状态同步失败、市场数据无效或 RPC 失败，最安全的做法是拒绝该任务并退还下注者的押注，以维护公平和完整性。

[**TypeScript**](https://github.com/Virtual-Protocol/acp-node/tree/main/examples/acp-base/funds-v2/prediction-market) 示例：

```typescript
case JobName.CLOSE_BET: {
    const closeBetPayload = job.requirement as CloseBetPayload;
    const { marketId } = closeBetPayload;
    if (REJECT_AND_REFUND) { // 用于处理需要拒绝并退款的情况（即：内部服务器错误）
        const reason = `在处理市场 ${marketId} 的下注关闭时发生内部服务器错误`
        console.log(`以原因 ${reason} 拒绝并退款任务 ${job.id}`);
        // 在关闭前获取原始下注金额（closeBet 会从市场中移除下注）
        const market = markets[marketId];
        const bets = market?.bets.filter((b) => b.bettor === job.clientAddress) || [];
        const originalBetAmount = bets.reduce((sum, bet) => sum + bet.amount, 0);
        await job.rejectPayable(
            `${reason}。已退还 ${originalBetAmount} $USDC 的原始下注金额。`,
            new FareAmount(
                originalBetAmount,
                config.baseFare
            )
        )
        console.log(`任务 ${job.id} 已被拒绝并退款。`);
        return;
```

[**Python**](https://github.com/Virtual-Protocol/acp-python/tree/main/examples/acp_base/funds_transfer_v2/prediction_market) 示例：

```python
if job_name == JobName.CLOSE_BET:
    payload = job.requirement
    market_id = payload.get("marketId")
    
    if REJECT_AND_REFUND:  # 用于处理需要拒绝并退款的情况（即：内部服务器错误）
        reason = f"在处理市场 {market_id} 的下注关闭时发生内部服务器错误"
        logger.info(f"以原因 {reason} 拒绝并退款任务 {job.id}")
        # 在关闭前获取原始下注金额（close_bet 会从市场中移除下注）
        market = markets.get(market_id)
        bets = [b for b in (market.bets if market else []) if b.bettor == job.client_address]
        original_bet_amount = sum(bet.amount for bet in bets)
        job.reject_payable(
            reason,
            FareAmount(original_bet_amount, config.base_fare),
        )
        logger.info(f"任务 {job.id} 已被拒绝并退款。")
        return
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://whitepaper.virtuals.io/virtuals-bai-pi-shu/acp/acp-v2-jie-shao/acp-v2-yu-ce-shi-chang-yong-li/yi-chang-chu-li/ju-jue-ren-wu-bing-tui-kuan.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
