//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
+//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
+//! SPDX-License-Identifier: GPL-3.0-or-later
+
+import { Account } from '../account'
+import { hex } from '../convert'
+
+type AccountsFrontiers = {
+ frontiers?: {
+ [address: string]: string
+ }
+ errors?: {
+ [address: string]: string
+ }
+}
+
+export function accounts_frontiers (body: unknown): AccountsFrontiers {
+ const response: AccountsFrontiers = {}
+ if (body == null || typeof body !== 'object') {
+ return response
+ }
+ const frontiers = 'frontiers' in body ? body.frontiers : null
+ const errors = 'errors' in body ? body.errors : null
+
+ if (frontiers != null) {
+ if (typeof frontiers === 'object') {
+ for (const [address, frontier] of Object.entries(frontiers) as [string, unknown][]) {
+ try {
+ Account.validate(address)
+ if (hex.is(frontier)) {
+ response.frontiers ??= {}
+ response.frontiers[address] = frontier
+ }
+ } catch (err: any) {
+ response.errors ??= {}
+ response.errors[address] = err?.message
+ }
+ }
+ }
+ }
+
+ if (errors != null) {
+ if (typeof errors === 'object') {
+ for (const [address, error] of Object.entries(errors) as [string, unknown][]) {
+ try {
+ Account.validate(address)
+ if (typeof error === 'string') {
+ throw new Error(error)
+ }
+ } catch (err: any) {
+ response.errors ??= {}
+ response.errors[address] = err?.message
+ }
+ }
+ }
+ }
-export const accounts_frontiers = Object.freeze({
- fields: [
- 'errors',
- 'frontiers',
- ],
- errors: {
- address: {
- error: {},
- },
- },
- frontiers: {
- address: {
- hash: {},
- },
- },
-})
+ return response
+}
//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
-export const block_info = Object.freeze({
- fields: [
- 'amount',
- 'balance',
- 'block_account',
- 'confirmed',
- 'contents',
- 'height',
- 'linked_account',
- 'local_timestamp',
- 'subtype',
- 'successor',
- ],
+
+export type BlockInfo = {
contents: {
- fields: [
- 'account',
- 'balance',
- 'link',
- 'link_as_account',
- 'previous',
- 'representative',
- 'signature',
- 'type',
- 'work',
- ],
- },
-})
+ account: string
+ balance: string
+ link: string
+ link_as_account: string
+ previous: string
+ representative: string
+ signature: string
+ type: string
+ work: string
+ }
+ amount: string
+ balance: string
+ block_account: string
+ confirmed: string
+ height: string
+ linked_account: string
+ local_timestamp: string
+ subtype: string
+ successor: string
+}
+
+export function block_info (body: unknown): BlockInfo {
+ if (body != null && typeof body === 'object'
+ && 'amount' in body && typeof body.amount === 'string'
+ && 'balance' in body && typeof body.balance === 'string'
+ && 'block_account' in body && typeof body.block_account === 'string'
+ && 'confirmed' in body && typeof body.confirmed === 'string'
+ && 'height' in body && typeof body.height === 'string'
+ && 'linked_account' in body && typeof body.linked_account === 'string'
+ && 'local_timestamp' in body && typeof body.local_timestamp === 'string'
+ && 'subtype' in body && typeof body.subtype === 'string'
+ && 'successor' in body && typeof body.successor === 'string'
+ && 'contents' in body && body.contents != null && typeof body.contents === 'object'
+ && 'account' in body.contents && typeof body.contents.account === 'string'
+ && 'balance' in body.contents && typeof body.contents.balance === 'string'
+ && 'link' in body.contents && typeof body.contents.link === 'string'
+ && 'link_as_account' in body.contents && typeof body.contents.link_as_account === 'string'
+ && 'previous' in body.contents && typeof body.contents.previous === 'string'
+ && 'representative' in body.contents && typeof body.contents.representative === 'string'
+ && 'signature' in body.contents && typeof body.contents.signature === 'string'
+ && 'type' in body.contents && typeof body.contents.type === 'string'
+ && 'work' in body.contents && typeof body.contents.work === 'string'
+ ) {
+ return {
+ contents: {
+ account: body.contents.account,
+ balance: body.contents.balance,
+ link: body.contents.link,
+ link_as_account: body.contents.link_as_account,
+ previous: body.contents.previous,
+ representative: body.contents.representative,
+ signature: body.contents.signature,
+ type: body.contents.type,
+ work: body.contents.work,
+ },
+ amount: body.amount,
+ balance: body.balance,
+ block_account: body.block_account,
+ confirmed: body.confirmed,
+ height: body.height,
+ linked_account: body.linked_account,
+ local_timestamp: body.local_timestamp,
+ subtype: body.subtype,
+ successor: body.successor,
+ }
+ } else {
+ throw new Error('Invalid block_info body')
+ }
+}
+
//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
-export const blocks_info = Object.freeze({
- fields: [
- 'blocks',
- ],
- blocks: {
- hash: {
- fields: [
- 'amount',
- 'balance',
- 'block_account',
- 'confirmed',
- 'contents',
- 'height',
- 'linked_account',
- 'local_timestamp',
- 'subtype',
- 'successor',
- ],
- contents: {
- fields: [
- 'account',
- 'balance',
- 'link',
- 'link_as_account',
- 'previous',
- 'representative',
- 'signature',
- 'type',
- 'work',
- ],
- },
- },
+import { hex } from '../convert'
+import { BlockInfo, block_info } from './block_info'
+
+type BlocksInfo = {
+ blocks?: {
+ [hash: string]: BlockInfo
},
-})
+ errors?: {
+ [address: string]: string
+ },
+}
+
+export function blocks_info (body: unknown): BlocksInfo {
+ const response: BlocksInfo = {}
+ if (body == null || typeof body !== 'object') {
+ return response
+ }
+ const blocks = 'blocks' in body ? body.blocks : null
+ const errors = 'errors' in body ? body.errors : null
+
+ if (blocks != null) {
+ if (typeof blocks === 'object') {
+ for (const [hash, data] of Object.entries(blocks) as [string, unknown][]) {
+ try {
+ if (hex.is(hash)) {
+ response.blocks ??= {}
+ response.blocks[hash] = block_info(data)
+ } else {
+ throw new Error('Invalid blocks_info hash')
+ }
+ } catch (err: any) {
+ response.errors ??= {}
+ response.errors[hash] = err?.message
+ }
+ }
+ }
+ }
+
+ if (errors != null) {
+ if (typeof errors === 'object') {
+ for (const [hash, error] of Object.entries(errors) as [string, unknown][]) {
+ try {
+ if (hex.is(hash) && typeof error === 'string') {
+ throw new Error(error)
+ } else {
+ throw new Error('Invalid blocks_info error')
+ }
+ } catch (err: any) {
+ response.errors ??= {}
+ response.errors[hash] = err?.message
+ }
+ }
+ }
+ }
+
+ return response
+}
//! SPDX-FileCopyrightText: 2026 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
+import { account_balance } from './account_balance'
import { account_info } from './account_info'
import { account_representative } from './account_representative'
import { accounts_balances } from './accounts_balances'
import { process } from './process'
export const Schema = Object.freeze({
+ account_balance,
// account_info,
// account_representative,
accounts_balances,
- // accounts_frontiers,
+ accounts_frontiers,
// accounts_representatives,
- // block_info,
- // blocks_info,
+ block_info,
+ blocks_info,
// process,
})
import { Rpc, Schema } from '../rpc'
import { Wallet } from '../wallet'
-export type BlockInfo = {
- blocks: {
- [hash: string]: {
- [p: string]: string
- } & {
- contents: {
- [p: string]: string
- }
- }
- }
-}
-
export async function _refresh (wallet: Wallet, rpc: Rpc | string | URL, from: number, to: number): Promise<Map<number, Account>>
export async function _refresh (wallet: Wallet, rpc: unknown, from: unknown, to: unknown): Promise<Map<number, Account>> {
try {
accounts: addresses
}
const { balances } = await rpc.post('accounts_balances', data)
- const { frontiers } = await rpc.post('accounts_frontiers', data) as { frontiers: { [address: string]: string } }
- const { blocks } = await rpc.post('blocks_info', { json_block: true, hashes: Object.values(frontiers) }) as BlockInfo
+ const { frontiers } = await rpc.post('accounts_frontiers', data)
+ const { blocks } = await rpc.post('blocks_info', { json_block: true, include_not_found: true, hashes: Object.values(frontiers) }) as BlockInfo
for (const account of accounts.values()) {
account.balance = balances?.[account.address]?.balance ?? 0
account.receivable = balances?.[account.address]?.receivable ?? 0