API 参考:getOwnedObjects
检索由特定 32 字节 Sui 钱包地址拥有的链上对象的分页列表。
使用此方法可填充钱包仪表盘、用户库存界面和代币余额列表。由于单个账户可能持有数千个对象,Sui JSON-RPC API 会通过基于游标的分页机制,分页返回拥有的对象。由于 getOwnedObjects 是一项直接从全节点本地状态提供的读取操作,因此它会立即执行,无需提交交易或消耗 gas。
- 类:
SuiClient - 包:
@mysten/sui/client - 操作类型: 读取操作(无需 gas,无需钱包签名)
概述
调用 getOwnedObjects 会查询全节点索引,查找所有权归属于目标地址(AddressOwner)的对象。为避免高延迟和网络超时,全节点会分页返回结果,而非在单次响应中返回全部库存。
分页循环可视化
- Mermaid (图片)
- Mermaid (代码)
- ASCII
flowchart TD
Start([开始分页]) --> Init["初始化 cursor = null<br/>allObjects = []"]
Init --> Query["调用 getOwnedObjects<br/>(cursor, limit: 50)"]
Query --> Resp["收到响应:<br/>data[], hasNextPage, nextCursor"]
Resp --> Append["将项目追加到<br/>allObjects 数组"]
Append --> Check{"hasNextPage == true?"}
Check -->|是| Update["更新 cursor = nextCursor"]
Check -->|否| Done([返回所有累积的对象])
Update -.->|下一页| Query
分页流程(游标循环):
客户端 全节点
│ │
│── getOwnedObjects(cursor: null) ───────►│ (第 1 页:limit 50)
│◄── { data: [50 items], nextCursor } ────│
│ │
│── getOwnedObjects(cursor: nextCursor) ─►│ (第 2 页:limit 50)
│◄── { data: [12 items], hasNextPage: false }
签名
签名
client.getOwnedObjects(input: GetOwnedObjectsParams): Promise<PaginatedObjectsResponse>
参数
该方法接受一个包含以下属性的配置对象:
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
owner | string | 是 | 目标钱包的 32 字节十六进制地址。 |
filter | SuiObjectDataFilter | 否 | 按类型、包或模块过滤结果的条件。 |
options | SuiObjectDataOptions | 否 | 包含额外详细信息的标志(例如 showType, showContent, showDisplay)。 |
cursor | string | null | 否 | 来自先前响应的 nextCursor 令牌,用于获取后续页面。 |
limit | number | 否 | 每页返回的最大条目数(在公共 RPC 节点上,默认值和最大值通常为 50)。 |
SuiObjectDataFilter
filter 参数可缩小全节点上的查询范围,从而节省带宽并减少客户端处理负担:
| 过滤键 | 值类型 | 描述 |
|---|---|---|
MatchAll | SuiObjectDataFilter[] | 逻辑与(AND)。对象必须满足所有提供的过滤条件。 |
MatchAny | SuiObjectDataFilter[] | 逻辑或(OR)。对象只要满足所提供的任一筛选条件即可。 |
StructType | string | 对完全限定的 Move Struct 类型的精确匹配(例如 0x2::coin::Coin<0x2::sui::SUI>)。 |
Package | string | 匹配从指定包 ID 内的模块实例化的任何对象。 |
MoveModule | { package: string, module: string } | 匹配包中特定模块内定义的任何对象。 |
返回值
返回一个 Promise,该 Promise 解析为 PaginatedObjectsResponse 对象:
响应
{
"data": [
{ "data": { "objectId": "0xA...", "version": "1", "type": "0x2::coin::Coin<0x2::sui::SUI>" } },
{ "data": { "objectId": "0xB...", "version": "4", "type": "0x2::coin::Coin<0x2::sui::SUI>" } }
],
"hasNextPage": true,
"nextCursor": "0x12345...ResultCursor"
}
响应封装体包含以下字段:
| 字段 | 类型 | 描述 |
|---|---|---|
data | SuiObjectResponse[] | 当前页面的对象响应封装体数组。 |
hasNextPage | boolean | 指示是否存在其他页面的对象。 |
nextCursor | string | null | 作为下次调用中游标传递的不透明分页令牌。当 hasNextPage 为 false 时,此值为 null。 |
代码示例
获取资产列表的第一页
检索某个地址拥有的前 5 个对象:
basicInventory.js
const response = await client.getOwnedObjects({
owner: '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
limit: 5,
options: { showType: true }
});
response.data.forEach((item) => {
if (item.data) {
console.log(`ID: ${item.data.objectId}, Type: ${item.data.type}`);
}
});
按 Move 结构类型过滤资产
仅查询用户拥有的 SUI 代币对象,排除其他代币和 NFT:
filterCoins.js
const response = await client.getOwnedObjects({
owner: '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
filter: {
StructType: '0x2::coin::Coin<0x2::sui::SUI>'
},
options: { showContent: true }
});
console.log(`找到 ${response.data.length} 个 SUI 代币对象`);
分页遍历所有拥有的对象
使用 while 循环遍历地址拥有的每个对象:
pagination.js
let hasNextPage = true;
let nextCursor = null;
const allObjects = [];
while (hasNextPage) {
const response = await client.getOwnedObjects({
owner: '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
cursor: nextCursor,
limit: 50
});
allObjects.push(...response.data);
hasNextPage = response.hasNextPage;
nextCursor = response.nextCursor;
}
console.log(`共获取对象总数:${allObjects.length}`);
常见错误
| 错误代码 | 原因 | 解决方法 |
|---|---|---|
cursor_invalid | 传递给 cursor 的字符串已过期、格式错误,或源自其他查询。 | 请传入前一次查询中 nextCursor 返回的精确字符串。 |
limit_exceeded | 请求的 limit 超出了全节点允许的最大页面大小(通常为 50)。 | 将 limit 参数减少至 50 个或更少。 |
另请参阅
getObject检索单个链上对象的详细信息。multiGetObjects通过单个批量请求获取多个特定对象的详细信息。- 如何获取对象数据 提供在 Node.js 中实现读取操作的分步教程。
- SuiClient 架构 解释
SuiClient及读取操作的概念设计。