感谢您对我的帮助。
在使用coinbase API的过程中,当我调用
client.getAccounts({}, 函数(错误, 帐户){
console.log('账户', 账户)
})
我注意到有很多账户,包括以太坊、莱特币,但没有比特币 (BTC)
有人可以帮忙找出原因吗?
非常感谢!
最佳答案
TL;DR
使用 yarn add rxjs
或 npm install rxjs
将 rxjs
添加到您的项目,然后执行以下操作:
import { EMPTY, from, reduce, expand } from 'rxjs';
// Promisify: Wrap API call in a promise
const getAccountsAsync = (options) => {
return new Promise((resolve, reject) => {
client.getAccounts(options, (err, accounts, pagination) => {
if (err) return reject(err);
resolve({accounts, pagination});
})
})
}
// Number of accounts to fetch per request
const paginationLimit = 100;
from(getAccountsAsync({limit: paginationLimit})).pipe(
// As long as there is a next_uri set, continue recursion
expand(res => res.pagination.next_uri ?
getAccountsAsync({
limit: paginationLimit,
next_uri: res.pagination.next_uri,
starting_after: res.pagination.next_starting_after
}) :
EMPTY
),
// Filter and concatenate the result of all API calls
reduce((acc, current) => acc.concat(current.accounts.filter(account => account.balance.amount > 0)), [])
).subscribe(allAccounts => console.log(allAccounts));
说明
之所以只返回前 25 个帐户,是因为 coinbase API 使用分页,并且 25 是默认页面大小(请参阅 official docs )。
当您调用 getAccounts()
时,您实际上会得到三个返回值(即使 API 只指定了两个):
client.getAccounts({}, (err, accounts, pagination) => {});
分页对象看起来像这样:
{
ending_before: null,
starting_after: null,
previous_ending_before: null,
next_starting_after: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
limit: 25,
order: 'desc',
previous_uri: null,
next_uri: '/v2/accounts?limit=25&starting_after=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
}
您可以像这样增加限制:
client.getAccounts({limit: 100}, (err, accounts, pagination) => {});
但是,目前coinbase中有175个账户(币种),我们可以提供的最大分页限制是100个。
因此,为了获取其余页面,我们必须进行额外的 API 调用,提供 starting_after
和 next_uri
作为选项,如下所示:
client.getAccounts({
limit: 100,
next_uri: '/v2/accounts?limit=100&starting_after=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
starting_after: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
}, (err, accounts, pagination) => {});
关于next_uri
的旁注
当已经有 starting_after
时,我们必须提供 next_uri
,这似乎是多余的。事实上,docs不要提及我们必须提供 next_uri
。但是,如果我省略此值,则会收到以下错误:
ClientError [AuthenticationError]: invalid signature
深入挖掘 source code 后我发现在检查 starting_after
是否设置之前,他们会检查 next_uri
是否设置。所以,显然我们必须提供这个值。
解决方案 1 - 递归 Promise
要打印您的所有帐户(balance.amount > 0
的帐户),我们可以首先将 API 调用包装在 Promise 中,然后使用递归。可能的解决方案如下所示:
// Promisify: Wrap API call in a promise
const getAccountsAsync = (options) => {
return new Promise((resolve, reject) => {
client.getAccounts(options, (err, accounts, pagination) => {
if (err) return reject(err);
resolve({accounts, pagination});
})
})
}
// Fetch all accounts recursively
const fetchAllAccounts = (nextUri, lastFetchedId) => {
getAccountsAsync({limit: 100, next_uri: nextUri, starting_after: lastFetchedId})
.then(res => {
// Print your accounts from current batch
res.accounts.forEach(account => {
if (account.balance.amount > 0) {
console.log(account)
}
});
// Terminate recursion when next_uri is empty
if (res.pagination.next_uri != null) {
// Call next batch of 100 accounts, starting after lastFetchedId
fetchAllAccounts(res.pagination.next_uri, res.pagination.next_starting_after)
}
})
.catch(err => console.log(err));
};
// Initial call
fetchAllAccounts(null, null);
不幸的是,使用这种方法,帐户分散在多个回调中。我们不能轻易与他们合作。如果您想对帐户执行更多操作而不仅仅是将其打印到控制台,则可以使用 RxJS .
解决方案 2 - 使用 RxJS
更优雅的解决方案是使用 expand函数来自 RxJS 。同样,我们必须首先将 API 调用包装在 Promise 中。
使用 yarn add rxjs
或 npm install rxjs
将 rxjs
添加到您的项目,然后执行以下操作:
import { EMPTY, from, reduce, expand } from 'rxjs';
// Promisify: Wrap API call in a promise
const getAccountsAsync = (options) => {
return new Promise((resolve, reject) => {
client.getAccounts(options, (err, accounts, pagination) => {
if (err) return reject(err);
resolve({accounts, pagination});
})
})
}
// Number of accounts to fetch per request
const paginationLimit = 100;
from(getAccountsAsync({limit: paginationLimit})).pipe(
// As long as there is a next_uri set, continue recursion
expand(res => res.pagination.next_uri ?
getAccountsAsync({
limit: paginationLimit,
next_uri: res.pagination.next_uri,
starting_after: res.pagination.next_starting_after
}) :
EMPTY
),
// Filter and concatenate the result of all API calls
reduce((acc, current) => acc.concat(current.accounts.filter(account => account.balance.amount > 0)), [])
).subscribe(allAccounts => console.log(allAccounts));
这种方法的优点是,我们可以连接所有 API 调用的结果并将它们组合到一个数组中。
关于node.js - Coinbase API BTC 账户丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67343099/