feat: add getLargestAccounts rpc api

This commit is contained in:
Justin Starry 2020-05-23 01:23:29 +08:00 committed by Michael Vines
parent 9c677c7d3d
commit 1b8fe71230
4 changed files with 128 additions and 0 deletions

15
web3.js/module.d.ts vendored
View File

@ -48,6 +48,13 @@ declare module '@solana/web3.js' {
export type Commitment = 'max' | 'recent' | 'root' | 'single';
export type LargestAccountsFilter = 'circulating' | 'nonCirculating';
export type GetLargestAccountsConfig = {
commitment?: Commitment;
filter?: LargestAccountsFilter;
};
export type SignatureStatusConfig = {
searchTransactionHistory: boolean;
};
@ -180,6 +187,11 @@ declare module '@solana/web3.js' {
nonCirculatingAccounts: Array<PublicKey>;
};
export type AccountBalancePair = {
address: PublicKey;
lamports: number;
};
export type VoteAccountStatus = {
current: Array<VoteAccountInfo>;
delinquent: Array<VoteAccountInfo>;
@ -208,6 +220,9 @@ declare module '@solana/web3.js' {
getBlockTime(slot: number): Promise<number | null>;
getMinimumLedgerSlot(): Promise<number>;
getSupply(commitment?: Commitment): Promise<RpcResponseAndContext<Supply>>;
getLargestAccounts(
config?: GetLargestAccountsConfig,
): Promise<RpcResponseAndContext<Array<AccountBalancePair>>>;
getClusterNodes(): Promise<Array<ContactInfo>>;
getConfirmedBlock(slot: number): Promise<ConfirmedBlock>;
getConfirmedTransaction(

View File

@ -61,6 +61,13 @@ declare module '@solana/web3.js' {
declare export type Commitment = 'max' | 'recent' | 'root' | 'single';
declare export type LargestAccountsFilter = 'circulating' | 'nonCirculating';
declare export type GetLargestAccountsConfig = {
commitment: ?Commitment,
filter: ?LargestAccountsFilter,
};
declare export type SignatureStatusConfig = {
searchTransactionHistory: boolean,
};
@ -193,6 +200,11 @@ declare module '@solana/web3.js' {
nonCirculatingAccounts: Array<PublicKey>,
};
declare export type AccountBalancePair = {
address: PublicKey,
lamports: number,
};
declare export type VoteAccountStatus = {
current: Array<VoteAccountInfo>,
delinquent: Array<VoteAccountInfo>,
@ -221,6 +233,9 @@ declare module '@solana/web3.js' {
getBlockTime(slot: number): Promise<number | null>;
getMinimumLedgerSlot(): Promise<number>;
getSupply(commitment: ?Commitment): Promise<RpcResponseAndContext<Supply>>;
getLargestAccounts(
config: ?GetLargestAccountsConfig,
): Promise<RpcResponseAndContext<Array<AccountBalancePair>>>;
getClusterNodes(): Promise<Array<ContactInfo>>;
getConfirmedBlock(slot: number): Promise<ConfirmedBlock>;
getConfirmedTransaction(

View File

@ -100,6 +100,29 @@ function notificationResultAndContext(resultDescription: any) {
*/
export type Commitment = 'max' | 'recent' | 'root' | 'single';
/**
* Filter for largest accounts query
* <pre>
* 'circulating': Return the largest accounts that are part of the circulating supply
* 'nonCirculating': Return the largest accounts that are not part of the circulating supply
* </pre>
*
* @typedef {'circulating' | 'nonCirculating'} LargestAccountsFilter
*/
export type LargestAccountsFilter = 'circulating' | 'nonCirculating';
/**
* Configuration object for changing `getLargestAccounts` query behavior
*
* @typedef {Object} GetLargestAccountsConfig
* @property {Commitment|undefined} commitment The level of commitment desired
* @property {LargestAccountsFilter|undefined} filter Filter largest accounts by whether they are part of the circulating supply
*/
type GetLargestAccountsConfig = {
commitment: ?Commitment,
filter: ?LargestAccountsFilter,
};
/**
* Configuration object for changing query behavior
*
@ -431,6 +454,30 @@ const GetSupplyRpcResult = jsonRpcResultAndContext(
}),
);
/**
* Pair of an account address and its balance
*
* @typedef {Object} AccountBalancePair
* @property {PublicKey} address
* @property {number} lamports
*/
type AccountBalancePair = {
address: PublicKey,
lamports: number,
};
/**
* Expected JSON RPC response for the "getLargestAccounts" message
*/
const GetLargestAccountsRpcResult = jsonRpcResultAndContext(
struct.array([
struct({
lamports: 'number',
address: 'string',
}),
]),
);
/**
* Expected JSON RPC response for the "getVersion" message
*/
@ -1063,6 +1110,30 @@ export class Connection {
return res.result;
}
/**
* Fetch the 20 largest accounts with their current balances
*/
async getLargestAccounts(
config: ?GetLargestAccountsConfig,
): Promise<RpcResponseAndContext<Array<AccountBalancePair>>> {
const arg = {
...config,
commitment: (config && config.commitment) || this.commitment,
};
const args = arg.filter || arg.commitment ? [arg] : [];
const unsafeRes = await this._rpcRequest('getLargestAccounts', args);
const res = GetLargestAccountsRpcResult(unsafeRes);
if (res.error) {
throw new Error('failed to get largest accounts: ' + res.error.message);
}
assert(typeof res.result !== 'undefined');
res.result.value = res.result.value.map(({address, lamports}) => ({
address: new PublicKey(address),
lamports,
}));
return res.result;
}
/**
* Fetch all the account info for the specified public key, return with context
*/

View File

@ -1141,6 +1141,33 @@ test('get supply', async () => {
expect(supply.nonCirculatingAccounts.length).toBeGreaterThan(0);
});
test('get largest accounts', async () => {
const connection = new Connection(url);
mockRpc.push([
url,
{
method: 'getLargestAccounts',
params: [],
},
{
error: null,
result: {
context: {
slot: 1,
},
value: new Array(20).fill(0).map(() => ({
address: new Account().publicKey.toBase58(),
lamports: 1000,
})),
},
},
]);
const largestAccounts = (await connection.getLargestAccounts()).value;
expect(largestAccounts.length).toEqual(20);
});
test('getVersion', async () => {
const connection = new Connection(url);