> For the complete documentation index, see [llms.txt](https://help.tokenpocket.pro/developer-cn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.tokenpocket.pro/developer-cn/agentic-wallet/eip-7715-account-with-permissions/shi-yong-quan-xian-zhi-xing-jiao-yi.md).

# 使用权限执行交易

用户通过 `wallet_requestExecutionPermissions` 授权后，**Session Account**（`to` 地址）可调用 DelegationManager 的 `redeemDelegations`，在权限约束内代用户执行链上操作。本节说明如何构造并发送 redeem 交易。

### 前置条件 <a href="#e5-89-8d-e7-bd-ae-e6-9d-a1-e4-bb-b6" id="e5-89-8d-e7-bd-ae-e6-9d-a1-e4-bb-b6"></a>

1. 已获得 `PermissionResponse`（含 `context`、`delegationManager`）。
2. Session Account 私钥可用，且地址等于授权中的 `to`。
3. 执行链与授权 `chainId` 一致。

### 核心合约接口（EIP-7710） <a href="#e6-a0-b8-e5-bf-83-e5-90-88-e7-ba-a6-e6-8e-a5-e5-8f-a3eip-7710" id="e6-a0-b8-e5-bf-83-e5-90-88-e7-ba-a6-e6-8e-a5-e5-8f-a3eip-7710"></a>

```solidity
function redeemDelegations(
  bytes[] calldata permissionContexts,
  bytes32[] calldata modes,
  bytes[] calldata executionCallDatas
) external;
```

| 参数                   | 说明                                |
| -------------------- | --------------------------------- |
| `permissionContexts` | `[grant.context]`                 |
| `modes`              | 执行模式，单笔默认 `0x0000...0000`（32 字节零） |
| `executionCallDatas` | 编码后的 `Execution` 结构               |

#### Execution 编码 <a href="#execution-e7-bc-96-e7-a0-81" id="execution-e7-bc-96-e7-a0-81"></a>

```solidity
struct Execution {
  address target;
  uint256 value;
  bytes callData;
}
```

编码方式

```typescript
function encodeSingleExecution(execution: {
  target: `0x${string}`;
  value: bigint;
  callData: `0x${string}`;
}) {
  const target = execution.target.slice(2).toLowerCase().padStart(40, "0");
  const value = execution.value.toString(16).padStart(64, "0");
  const data = execution.callData.slice(2);
  return `0x${target}${value}${data}` as `0x${string}`;
}
```

### 按权限类型构造 Execution <a href="#e6-8c-89-e6-9d-83-e9-99-90-e7-b1-bb-e5-9e-8b-e6-9e-84-e9-80-a0-execution" id="e6-8c-89-e6-9d-83-e9-99-90-e7-b1-bb-e5-9e-8b-e6-9e-84-e9-80-a0-execution"></a>

#### ERC-20 转账 <a href="#erc-20-e8-bd-ac-e8-b4-a6" id="erc-20-e8-bd-ac-e8-b4-a6"></a>

```typescript
import { encodeFunctionData, parseUnits } from "viem";

const tokenAddress = grant.permission.data.tokenAddress;
const amount = parseUnits("1", 18);

const execution = {
  target: tokenAddress,
  value: 0n,
  callData: encodeFunctionData({
    abi: [
      {
        type: "function",
        name: "transfer",
        inputs: [
          { name: "to", type: "address" },
          { name: "amount", type: "uint256" },
        ],
        outputs: [{ type: "bool" }],
        stateMutability: "nonpayable",
      },
    ],
    functionName: "transfer",
    args: [payeeAddress, amount],
  }),
};
```

#### 原生币转账 <a href="#e5-8e-9f-e7-94-9f-e5-b8-81-e8-bd-ac-e8-b4-a6" id="e5-8e-9f-e7-94-9f-e5-b8-81-e8-bd-ac-e8-b4-a6"></a>

```typescript
const execution = {
  target: payeeAddress,
  value: parseUnits("0.001", 18),
  callData: "0x",
};
```

### 完整 Redeem 示例 <a href="#e5-ae-8c-e6-95-b4-redeem-e7-a4-ba-e4-be-8b" id="e5-ae-8c-e6-95-b4-redeem-e7-a4-ba-e4-be-8b"></a>

使用 viem 构造 calldata 并由 Session Account 发送交易：

```typescript
import { createWalletClient, http, encodeFunctionData, parseUnits } from "viem";
import { privateKeyToAccount } from "viem/accounts";

const SINGLE_DEFAULT_MODE =
  "0x0000000000000000000000000000000000000000000000000000000000000000";

const DELEGATION_MANAGER_ABI = [
  {
    type: "function",
    name: "redeemDelegations",
    inputs: [
      { name: "permissionContexts", type: "bytes[]" },
      { name: "modes", type: "bytes32[]" },
      { name: "executionCallDatas", type: "bytes[]" },
    ],
    outputs: [],
    stateMutability: "nonpayable",
  },
];

function encodeSingleExecution(execution: {
  target: `0x${string}`;
  value: bigint;
  callData: `0x${string}`;
}) {
  const target = execution.target.slice(2).toLowerCase().padStart(40, "0");
  const value = execution.value.toString(16).padStart(64, "0");
  const data = execution.callData.slice(2);
  return `0x${target}${value}${data}` as `0x${string}`;
}

async function redeemErc20Transfer(
  grant: PermissionResponse,
  payee: `0x${string}`,
  humanAmount: string,
  rpcUrl: string,
) {
  const sessionAccount = privateKeyToAccount(
    process.env.SESSION_PRIVATE_KEY as `0x${string}`,
  );

  if (sessionAccount.address.toLowerCase() !== grant.to.toLowerCase()) {
    throw new Error("Session 地址与授权 to 不一致");
  }

  const decimals = 18; // 需要根据实际 ERC-20 合约读取 decimals
  const amount = parseUnits(humanAmount, decimals);
  const tokenAddress = grant.permission.data.tokenAddress as `0x${string}`;

  const executionCallData = encodeSingleExecution({
    target: tokenAddress,
    value: 0n,
    callData: encodeFunctionData({
      abi: [
        {
          type: "function",
          name: "transfer",
          inputs: [{ type: "address" }, { type: "uint256" }],
          outputs: [{ type: "bool" }],
          stateMutability: "nonpayable",
        },
      ],
      functionName: "transfer",
      args: [payee, amount],
    }),
  });

  const data = encodeFunctionData({
    abi: DELEGATION_MANAGER_ABI,
    functionName: "redeemDelegations",
    args: [[grant.context], [SINGLE_DEFAULT_MODE], [executionCallData]],
  });

  const chainId = parseInt(grant.chainId, 16);

  const client = createWalletClient({
    account: sessionAccount,
    chain: {
      id: chainId,
      name: `Chain ${chainId}`,
      nativeCurrency: { name: "Native", symbol: "Native", decimals: 18 },
      rpcUrls: { default: { http: [rpcUrl] } },
    },
    transport: http(rpcUrl),
  });

  return client.sendTransaction({
    to: grant.delegationManager,
    value: 0n,
    data,
  });
}
```

### 执行前检查清单 <a href="#e6-89-a7-e8-a1-8c-e5-89-8d-e6-a3-80-e6-9f-a5-e6-b8-85-e5-8d-95" id="e6-89-a7-e8-a1-8c-e5-89-8d-e6-a3-80-e6-9f-a5-e6-b8-85-e5-8d-95"></a>

| 检查项                | 说明                               |
| ------------------ | -------------------------------- |
| `to` 地址匹配          | 签名者 = `grant.to`                 |
| 链 ID 一致            | 必要时 `wallet_switchEthereumChain` |
| 额度充足               | periodic/stream 规则 + 链上 enforcer |
| `context` 有效       | 未过期、未撤销                          |
| `dependencies` 已部署 | factory 部署完成后再 redeem            |
