关于 tres-asset-balance-validation
该技能将 Tres Finance 中的 EVM 钱包余额与 DeBank 数据进行核对,并生成交互式 HTML 和 PDF 差异报告。适用于需要验证资产余额、代币及 DeFi 仓位记录的 Tres Finance 用户。
主要功能
- 01核对 Tres Finance 与 DeBank 的代币余额
- 02比较 DeFi 仓位及其底层代币
- 03按链匹配资产并标记差异状态
- 04生成交互式 HTML 和 PDF 报告
- 05仅处理有余额的 EVM 钱包
适用场景
- 01审计 Tres Finance 追踪的 EVM 钱包余额
- 02检查链上数据与财务记录的差异
- 03核对 DeFi 仓位的底层代币数量
MCP 相关
该技能通过 TRES Finance 的 `get_viewer`、GraphQL 查询及 DeBank API 获取钱包和资产数据,随后比较结果并生成报告。README 未说明其向 MCP 客户端提供服务或工具。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ anthropics/ claude-plugins-community --skill tres-asset-balance-validation安装后在 Claude Code 中输入/tres-asset-balance-validation确认已加载。
详细介绍
Tres Finance — 资产余额验证
概述
此技能会将 Tres Finance 中的钱包余额与 DeBank 进行比对,并生成清晰的差异报告,同时提供交互式 HTML 文件和 PDF。它会比较每个 EVM 钱包中各项资产的代币数量(包括 DeFi 持仓的底层代币),并标记匹配、轻微差异、重大差异、缺失资产、未跟踪代币和未匹配持仓。
范围: 仅支持兼容 EVM 的钱包(DeBank 的限制)。交易所账户、非 EVM 链和空钱包会跳过。
适用场景
用户提出以下请求时,启用此技能:
- 验证或核实其 TRES 余额
- 根据外部链上数据交叉核对或审计钱包
- 将 TRES 数据与 DeBank 进行比较
- 检查其余额是否正确
示例短语:
- “验证我的余额”
- “对照 DeBank 检查我的钱包”
- “我的 TRES 余额正确吗?”
- “显示 TRES 与链上数据之间的差异”
前提条件
| 要求 | 详情 |
|---|---|
| TRES Finance 访问权限 | 必须通过 get_viewer 完成身份验证 |
| DeBank API 密钥 | 可在 cloud.debank.com 免费获取 |
| EVM 钱包 | TRES 中至少跟踪一个 0x... 钱包 |
流程概述
步骤 1 — 通过 TRES 验证身份
调用 get_viewer 确认组织名称。
步骤 2 — 从 TRES 获取钱包和余额
重要 — 超时处理: 对大型组织,同时包含 balances 和 positions 的 internalAccount 查询会超时。请拆分为两个独立查询:
查询 1:仅获取钱包和余额(不含持仓)
query {
internalAccount {
results {
id
name
identifier
isExchange
platforms
balances {
amount
asset {
symbol
contract { identifier }
}
fiatValue { value unitPrice fiatCurrency }
}
}
}
}
注意:
amount字段以字符串而非数字形式返回。进行算术运算前务必先用float()转换。
钱包分类:
| 类型 | 条件 | 是否验证? |
|---|---|---|
| EVM | 0x... 地址 + EVM 平台 + isExchange: false | ✅ 是 |
| 交易所 | isExchange: true | ❌ 否 |
| 非 EVM | Bitcoin、Tezos、Tron 等 | ❌ 否 |
| 空钱包 | 没有资产余额 | ❌ 否 |
支持的 EVM 平台: Ethereum、Arbitrum、Optimism、Polygon、Base、Avalanche、Binance、Gnosis Chain、zkSync、Fantom、Celo、Berachain、Linea、Scroll、Sonic、HyperEVM。
步骤 3 — 从 TRES 获取 DeFi 持仓
不要使用 internalAccount 的 positions 子字段——它会返回所有历史快照(每个钱包可能有 3000 多条记录),导致超时或超出令牌限制。
请改用专用的 getStatelessWalletsPositions 查询,该查询仅返回当前持仓:
query {
getStatelessWalletsPositions(
walletIdentifiers: ["0x..."],
platform: ETHEREUM,
application: "aave-v3"
) {
walletIdentifier
displayName
positionType
platform
children {
symbol
amount
assetIdentifier
fiatValue
}
fiatValue
id
}
}
必需参数:
walletIdentifiers:钱包地址数组platform:必须是枚举值,例如ETHEREUM、POLYGON、ARBITRUM等
可选但建议提供:
application:按协议筛选(例如"aave-v3"、"verse"、"lido"、"merkl"、"uniswap-v4"、"sablier"、"ethena"、"stakewise"、"quickswap"、"steer"、"yieldnest"、"morphoblue")
重要: 不使用 application 筛选条件时,查询会返回空结果。务必指定应用。
分批策略:
- 首先,为每个钱包获取 DeBank
all_complex_protocol_list,以确认哪些协议有持仓 - 将 DeBank 协议名称映射为 TRES 应用名称(小写并用连字符分隔)
- 使用 GraphQL 别名,将多个钱包、平台和应用的组合批量放入单个查询:
query {
a1: getStatelessWalletsPositions(walletIdentifiers: ["0x..."], platform: ETHEREUM, application: "aave-v3") {
walletIdentifier displayName positionType platform id
children { symbol amount assetIdentifier fiatValue }
}
a2: getStatelessWalletsPositions(walletIdentifiers: ["0x..."], platform: ETHEREUM, application: "verse") {
walletIdentifier displayName positionType platform id
children { symbol amount assetIdentifier fiatValue }
}
}
每个批量查询最多保留约 6 个别名,以避免超时。
步骤 4 — 获取 DeBank API 密钥
从插件用户配置中读取 DEBANK_API_KEY——不要要求用户在聊天中粘贴。
如果密钥缺失或为空,请停止并显示:
“未配置
DEBANK_API_KEY。请通过插件设置添加(请在 https://cloud.debank.com 获取密钥)。”
步骤 5 — 通过 bash 获取 DeBank 数据
对于每个 EVM 钱包,获取两个端点:
- 代币余额:
all_token_list— 涵盖所有链,无需chain_id - DeFi 协议仓位:
all_complex_protocol_list— 返回 LP、质押和借贷仓位及其底层代币数量
使用 -G 和 --data-urlencode,确保钱包地址不会通过 shell 插值到 URL 字符串中:
# Token balances
curl -s -G \
-H "AccessKey: ${user_config.DEBANK_API_KEY}" \
--data-urlencode "id=$WALLET_ADDR" \
"https://pro-openapi.debank.com/v1/user/all_token_list"
# DeFi positions
curl -s -G \
-H "AccessKey: ${user_config.DEBANK_API_KEY}" \
--data-urlencode "id=$WALLET_ADDR" \
"https://pro-openapi.debank.com/v1/user/all_complex_protocol_list"
**法币价值筛选:**丢弃所有 price < 0.01 的代币——这些代币不会参与任何匹配、显示或报告。
**速率限制:**钱包请求之间延迟 0.3s,以避免出现 429 错误。
步骤 6 — 匹配常规资产
匹配必须考虑链。DeBank 的 all_token_list 会为每个代币返回 chain 字段(例如 "eth"、"arb"、"bsc")。TRES 余额通过钱包的 platforms 数组或余额上下文与特定平台关联。应始终优先进行按链匹配,然后再回退到跨链汇总。
Chain ID 映射(DeBank chain → TRES 平台):
DeBank chain | TRES 平台 |
|---|---|
eth | ETHEREUM |
arb | ARBITRUM |
op | OPTIMISM |
matic | POLYGON |
base | BASE |
bsc | BNB (Binance) |
avax | AVALANCHE |
ftm | FANTOM |
xdai | GNOSIS |
era | ZKSYNC |
celo | CELO |
linea | LINEA |
scrl | SCROLL |
mnt | MOONBEAM |
匹配顺序(从最具体到最宽泛):
- **合约 + 链匹配(最佳):**将
asset.contract.identifier(小写)与 DeBank 代币的id(小写)进行比较,并确保链相同。这是最精确的匹配方式。 - **符号 + 链匹配:**对于原生代币(没有合约),按
asset.symbol(不区分大小写)进行匹配,并确保 DeBankchain与该余额行对应的 TRES 平台相符。这样可以正确处理常见情况:钱包在 Ethereum 和 Arbitrum 上都持有 ETH——每个 TRES 余额行都会匹配对应链上的 DeBank 条目。 - **仅按符号匹配(最后手段):**如果无法将 TRES 原生代币余额与任何特定的 DeBank 链条目匹配,则回退到仅按符号匹配。此方式可处理 TRES 或 DeBank 使用不同链标签的边缘情况。
步骤 7 — 匹配 DeFi 仓位的底层代币
这是一个关键步骤,用于比较 TRES 和 DeBank 中 DeFi 仓位的底层代币。
7a. 筛除仓位 NFT 行
从常规比较中移除仓位 NFT 代币(例如 UNI-V3-POS、RCL、SAB-LOCKUP、SLP、STEER、UNI-V4-POS)。这些代币会由仓位中的底层代币行取代。
7b. 处理 TRES 仓位
对于 getStatelessWalletsPositions 的结果,处理每个仓位:
- 按符号汇总
children——一个仓位可能包含同一代币的多个条目(例如 QuickSwap 或 Uniswap V4 中的供应量 + 未领取奖励),因此应将数量相加 - 使用
displayName识别协议和代币组成
# Example: aggregate children for a position
def aggregate_children(children):
agg = {}
for c in children:
sym = c['symbol']
amt = float(c['amount']) if isinstance(c['amount'], str) else c['amount']
if sym not in agg:
agg[sym] = {'amount': 0, 'assetIdentifier': c.get('assetIdentifier', '')}
agg[sym]['amount'] += amt
return agg
7c. 处理 DeBank 仓位
对于 all_complex_protocol_list 中每个协议的 portfolio_item_list:
- 提取供应代币的
asset_token_list和奖励的reward_token_list - 使用协议
name和项目name(例如 “Lending”“Liquidity Pool”)作为仓位标签
7d. 比较仓位代币
通过以下方式将 DeBank 协议仓位与 TRES 仓位匹配:
- 协议名称匹配(不区分大小写,取首个单词)
- 子项之间的代币符号重合
对于每个匹配的仓位代币:
- **如果存在 TRES 数据:**比较数量,计算 delta %,并分配 match/minor/major 状态
- **如果不存在 TRES 数据:**分配
position状态(紫色徽标)
步骤 8 — 构建并渲染报告
创建两种输出:
- 交互式 HTML 文件 — 深色主题,包含筛选按钮、可折叠的钱包卡片,以及每个钱包专属的 DeFi Positions 部分
- PDF 报告 — 横向 A4,展开所有钱包表格,并使用 reportlab
将两者都保存到输出目录。
报告布局 — 至关重要
DeFi 持仓必须在视觉上区分开来
报告中的每张钱包卡片都 MUST 包含 两个独立的部分:
-
DeFi 持仓部分(顶部,紫色主题)— 专属框,使用紫色边框和深紫色背景(背景色
#1a1033,边框色#7c3aed),显示所有与持仓相关的行。此部分位于常规代币表格之前。 -
常规代币表格(下方)— 标准代币余额对比行。
持仓资产指示标记
每个持仓资产行都 MUST 在资产名称旁显示一个 紫色圆点指示标记(CSS 圆形,8px,#a855f7)。这样可以让人一眼识别出持仓:
<span style="display:inline-block;width:8px;height:8px;background:#a855f7;border-radius:50%;margin-right:6px;vertical-align:middle;"></span>
不要使用表情符号或内联 SVG — 它们可能无法在所有查看器中正确显示。仅使用纯 CSS 形状。
持仓行显示双徽标
与 TRES 匹配的持仓行会显示两个徽标:
POSITION徽标(紫色)- 匹配状态徽标(
MATCH/MINOR/MAJOR)
自动展开包含持仓的钱包
包含 DeFi 持仓的钱包卡片应自动展开(<details open>),以便立即查看持仓。
数字格式规则
代币数量
- 所有数量最多保留 3 位小数
- 数量 ≥ 1,000:使用逗号分隔,并保留 3 位小数(例如,
846,492.356) - 数量 < 1,000:保留 3 位小数(例如,
0.386) - 极小数量(< 0.000001):使用科学计数法(例如,
3.54e-07) - 空值/缺失值:显示破折号
—
function formatAmount(n) {
if (n === null || n === undefined) return '\u2014';
if (Math.abs(n) < 0.000001) return n.toExponential(2);
if (Math.abs(n) >= 1000) return n.toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 3});
return n.toFixed(3);
}
法币金额
- 在每个代币数量旁以 括号 显示:
846,492.356 ($17,562.21) - 在每个 delta % 旁以 括号 显示:
5.33% ($81.21) - 格式:
($X,XXX.XX)— 始终保留 2 位小数,并使用逗号分隔千位 - 空值/缺失值:完全省略(不显示空括号)
法币金额计算 — 至关重要
使用单一价格来源(DeBank 的代币价格)计算 TRES 和 DeBank 两列的法币金额。这样可以确保:
- 数量匹配时,法币差额为 $0(不会因价格来源不同而虚增)
- delta % 旁的法币差额代表数量差异的实际美元价值
# For regular tokens:
price = debank_token['price'] # single source
tres_fiat = tres_amount * price
debank_fiat = debank_amount * price
delta_fiat = abs(tres_amount - debank_amount) * price
# For position tokens — same principle:
price = debank_asset_token['price']
tres_fiat = tres_aggregated_amount * price
debank_fiat = debank_amount * price
delta_fiat = abs(tres_aggregated_amount - debank_amount) * price
不要在 TRES 列使用 TRES 的 fiatValue,同时在 DeBank 列使用 DeBank 价格 — 当 TRES 和 DeBank 使用不同的代币价格时,这会造成误导性的法币差额。
原生代币匹配(多链钱包)
对于单个钱包,原生代币(ETH、BNB 等)通常会在 TRES 中出现在多条链上(例如,以太坊上的 ETH + Arbitrum 上的 ETH)。DeBank 的 all_token_list 会返回按链分别列出的条目,其中包含 chain 字段 — 它不会进行汇总。
规则:优先按链匹配,仅在最后手段时才汇总。
-
按链匹配(默认): 对于每个 TRES 原生代币余额,使用该余额的平台上下文,通过代币符号 + 链查找对应的 DeBank 条目。例如,某钱包在以太坊上有 0.00956 ETH、在 Arbitrum 上有 0.001168 ETH,应生成两个独立的对比行 — 一个匹配 DeBank 的
chain: "eth"条目,另一个匹配chain: "arb"。 -
汇总回退方案(少见): 仅当对于同一代币符号,DeBank 返回的条目数少于 TRES 时,才汇总不同链上的 TRES 余额。如果 DeBank 合并了某些跨链代币余额,就可能出现这种情况。汇总时,应添加类似
"Aggregated: ETH (eth) + ETH (arb)"的备注。
为何重要: 比较前盲目汇总会造成错误差异。如果以太坊上的 ETH 完全匹配,但 Arbitrum 上的 ETH 存在差额,汇总就会掩盖以太坊上的匹配,并产生单个误导性差额。按链匹配可保留细分信息,便于准确找出不同步的链。
状态徽章
| 徽章 | 颜色 | 十六进制 | 含义 |
|---|---|---|---|
| 匹配 | 绿色 | #22c55e | 差异 < 1% |
| 轻微 | 橙色 | #f59e0b | 差异 1–10% |
| 严重 | 红色 | #ef4444 | 差异 > 10% |
| 缺失 | 灰色 | #6b7280 | TRES 中存在此资产,但在 DeBank 中未找到 |
| 未跟踪 | 蓝色 | #3b82f6 | DeBank 中存在此资产,但 TRES 未跟踪 |
| 仓位 | 紫色 | #a855f7 | DeFi 仓位代币(有或没有 TRES 数据) |
报告章节
渲染后的报告(HTML 和 PDF)包括:
- 摘要卡片 — 已检查的钱包数、已比较的资产数、匹配、轻微、严重、缺失、未跟踪、仓位,以及匹配率 %
- 筛选栏(仅 HTML)— 按状态筛选的按钮:全部、匹配、轻微、严重、缺失、未跟踪、仓位
- 每个钱包的卡片,包含:
- DeFi 仓位框(顶部,紫色主题)— 仓位资产带有紫色圆点指示器、协议标签和双状态徽章
- 常规代币表格 — 每项资产包含符号、链、TRES 数量(+ 法币金额)、DeBank 数量(+ 法币金额)、差异 %(+ 法币差额)和状态徽章
- 已跳过的钱包 — 未验证的钱包列表及跳过原因
- 备注与注意事项 — 同步延迟、DeFi 仓位说明、原生代币汇总、价格筛选,以及缺失/未跟踪项说明
重要注意事项
- 同步延迟: TRES 余额反映最近一次同步时间。近期链上活动可能会显示为差异。
- DeFi 仓位: LP、质押和借贷仓位中的底层代币会在专门的紫色区域中按行显示。若有 TRES 仓位数据,则会比较 TRES 和 DeBank 的数量。由于 TRES 和 DeBank 的快照时间不同,活跃 LP 仓位自然会显示出一些差异。
- 原生代币匹配: ETH、BNB 等会先按链匹配(将 DeBank 的
chain字段映射到 TRES 平台)。只有当 DeBank 返回的同符号条目少于 TRES 时,才会将多链余额汇总作为后备方案。 - 多链覆盖范围: DeBank 的
all_token_list涵盖所有链;TRES 中未配置的链上的代币会显示为“未跟踪”。 - 价格筛选: 所有报告都会排除
price < $0.01的代币(价格为零、为空或属于微型市值代币)。 - DeBank 中缺失: 通常是 DeBank 过滤掉的垃圾/空投代币(HEX、ASCZBR 等)。
- TRES 中未跟踪: 位于 TRES 未配置链上的代币,或数量很少的零散余额。
错误处理
| 情况 | 响应 |
|---|---|
DeBank 401 错误 | 在产物中显示“API 密钥无效” |
DeBank 429 错误 | 显示“请求过于频繁 — 60 秒后重新加载” |
| 非空钱包的代币列表为空 | 将钱包标记为可疑 |
| 非 EVM 钱包 | 跳过,并列入“已跳过的钱包”部分 |
internalAccount 仓位请求超时 | 改为按每个钱包/平台/应用使用 getStatelessWalletsPositions |
getStatelessWalletsPositions 返回空结果 | 确保提供了 application 参数;不提供该参数时,查询会返回空结果 |
| 无法提取仓位 ID | 跳过该仓位(不要导致程序崩溃) |
amount 字段是字符串而非数字 | 算术运算前始终使用 float() 进行转换 |
后续步骤(报告渲染完成后)
- 重新运行 — 随时使用最新数据重新生成报告
- 深入调查 — 对于任何严重差异,在 TRES 中检查各平台上的具体资产,以确定哪个链未同步
- 仓位差异 — 由于 TRES 和 DeBank 的快照时间不同,活跃 LP 仓位出现轻微差异是预期情况