From 7148b0f7d8409f44b289da778058ff904d43adad Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 20 Sep 2018 15:08:52 -0700 Subject: [PATCH] Add getAccountInfo --- web3.js/src/connection.js | 53 ++++++++++++++++++++++++++++ web3.js/test/__mocks__/node-fetch.js | 2 +- web3.js/test/budget-program.test.js | 3 ++ web3.js/test/connection.test.js | 43 ++++++++++++++++++++++ 4 files changed, 100 insertions(+), 1 deletion(-) diff --git a/web3.js/src/connection.js b/web3.js/src/connection.js index c2fb7a6266..b2090398d2 100644 --- a/web3.js/src/connection.js +++ b/web3.js/src/connection.js @@ -4,6 +4,7 @@ import assert from 'assert'; import fetch from 'node-fetch'; import jayson from 'jayson/lib/client/browser'; import {struct} from 'superstruct'; +import bs58 from 'bs58'; import {Transaction} from './transaction'; import type {Account, PublicKey} from './account'; @@ -56,6 +57,22 @@ const GetBalanceRpcResult = struct({ result: 'number?', }); + +/** + * Expected JSON RPC response for the "getAccountInfo" message + */ +const GetAccountInfoRpcResult = struct({ + jsonrpc: struct.literal('2.0'), + id: 'string', + error: 'any?', + result: struct.optional({ + contract_id: 'array', + tokens: 'number', + userdata: 'array', + }), +}); + + /** * Expected JSON RPC response for the "confirmTransaction" message */ @@ -116,6 +133,15 @@ const SendTokensRpcResult = struct({ result: 'string?', }); +/** + * Information describing an account + */ +type AccountInfo = { + tokens: number, + programId: PublicKey, + userdata: Buffer | null, +} + /** * A connection to a fullnode JSON RPC endpoint */ @@ -150,6 +176,33 @@ export class Connection { return res.result; } + /** + * Fetch all the account info for the specified public key + */ + async getAccountInfo(publicKey: PublicKey): Promise { + const unsafeRes = await this._rpcRequest( + 'getAccountInfo', + [publicKey] + ); + const res = GetAccountInfoRpcResult(unsafeRes); + if (res.error) { + throw new Error(res.error.message); + } + + const {result} = res; + assert(typeof result !== 'undefined'); + + let userdata = null; + if (result.userdata.length > 0) { + userdata = Buffer.from(result.userdata); + } + return { + tokens: result.tokens, + programId: bs58.encode(result.contract_id), + userdata, + }; + } + /** * Confirm the transaction identified by the specified signature */ diff --git a/web3.js/test/__mocks__/node-fetch.js b/web3.js/test/__mocks__/node-fetch.js index 6278983aea..6e97d03d2d 100644 --- a/web3.js/test/__mocks__/node-fetch.js +++ b/web3.js/test/__mocks__/node-fetch.js @@ -10,7 +10,7 @@ type RpcRequest = { type RpcResponseError = { message: string; } -type RpcResponseResult = boolean | string | number; +type RpcResponseResult = any; type RpcResponse = { error: ?RpcResponseError; result: ?RpcResponseResult; diff --git a/web3.js/test/budget-program.test.js b/web3.js/test/budget-program.test.js index b5b2381c34..5ba91a7c5e 100644 --- a/web3.js/test/budget-program.test.js +++ b/web3.js/test/budget-program.test.js @@ -16,6 +16,7 @@ test('pay', () => { 123, ); console.log('Pay:', transaction); + // TODO: Validate transaction contents transaction = BudgetProgram.pay( from.publicKey, @@ -25,6 +26,7 @@ test('pay', () => { BudgetProgram.signatureCondition(from.publicKey), ); console.log('After:', transaction); + // TODO: Validate transaction contents transaction = BudgetProgram.pay( from.publicKey, @@ -35,5 +37,6 @@ test('pay', () => { BudgetProgram.timestampCondition(from.publicKey, new Date()), ); console.log('Or:', transaction); + // TODO: Validate transaction contents }); diff --git a/web3.js/test/connection.test.js b/web3.js/test/connection.test.js index 6eabe34705..d6abd97f15 100644 --- a/web3.js/test/connection.test.js +++ b/web3.js/test/connection.test.js @@ -17,6 +17,24 @@ const errorResponse = { }; +test('get account info - error', () => { + const account = new Account(); + const connection = new Connection(url); + + mockRpc.push([ + url, + { + method: 'getAccountInfo', + params: [account.publicKey], + }, + errorResponse, + ]); + + expect(connection.getAccountInfo(account.publicKey)) + .rejects.toThrow(errorMessage); +}); + + test('get balance', async () => { const account = new Account(); const connection = new Connection(url); @@ -176,6 +194,31 @@ test('request airdrop', async () => { const balance = await connection.getBalance(account.publicKey); expect(balance).toBe(42); + + mockRpc.push([ + url, + { + method: 'getAccountInfo', + params: [account.publicKey], + }, + { + error: null, + result: { + contract_id: [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ], + tokens: 42, + userdata: [], + } + + } + ]); + + const accountInfo = await connection.getAccountInfo(account.publicKey); + expect(accountInfo.tokens).toBe(42); + expect(accountInfo.userdata).toBe(null); + expect(accountInfo.programId).toBe(SystemProgram.programId); }); test('request airdrop - error', () => {