node.js - Coinbase API BTC 账户丢失

标签 node.js api cryptography bitcoin coinbase-api

感谢您对我的帮助。 在使用coinbase API的过程中,当我调用
client.getAccounts({}, 函数(错误, 帐户){
console.log('账户', 账户) })
我注意到有很多账户,包括以太坊、莱特币,但没有比特币 (BTC) 有人可以帮忙找出原因吗? 非常感谢!

最佳答案

TL;DR

使用 yarn add rxjsnpm install rxjsrxjs 添加到您的项目,然后执行以下操作:

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_afternext_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 rxjsnpm install rxjsrxjs 添加到您的项目,然后执行以下操作:

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/

相关文章:

c# - 破解 MS Access 文件有多容易?如何保护它?

iphone - 保护在 iPhone 上访问的 RESTful API 的最佳方法是什么

javascript - node.js promise 错误未定义函数

node.js - sh : 1: rimraf: not found whenever I run npm run build within vagrant installed on Windows 10

api - Magento批量更新属性

php - 使用 flipkart api 获取特定单个产品的价格、标题和其他详细信息

javascript - 平均堆栈 : angular is not defined

node.js - 有没有办法在 Node.js 中调用 module.require 上的resolve()?

scala - 删除 DAO 模型中的可选字段

c - 为什么我的程序不能运行?