Format with prettier. Use screen mode for invitation import - dialog mode is broken.
This commit is contained in:
@@ -1,28 +1,28 @@
|
||||
import {
|
||||
import {
|
||||
Engine,
|
||||
type XOEngineOptions,
|
||||
// This is temporary. Will likely be moved to where we import templates in the cli. I think that makes more sense as this is a library thing
|
||||
generateTemplateIdentifier,
|
||||
} from '@xo-cash/engine';
|
||||
import type { XOInvitation } from '@xo-cash/types';
|
||||
} from "@xo-cash/engine";
|
||||
import type { XOInvitation } from "@xo-cash/types";
|
||||
|
||||
import { Invitation } from './invitation.js';
|
||||
import { Storage } from './storage.js';
|
||||
import { SyncServer } from '../utils/sync-server.js';
|
||||
import { HistoryService } from './history.js';
|
||||
import { ElectrumService } from './electrum.js';
|
||||
import { Invitation } from "./invitation.js";
|
||||
import { Storage } from "./storage.js";
|
||||
import { SyncServer } from "../utils/sync-server.js";
|
||||
import { HistoryService } from "./history.js";
|
||||
import { ElectrumService } from "./electrum.js";
|
||||
|
||||
import { EventEmitter } from '../utils/event-emitter.js';
|
||||
import { EventEmitter } from "../utils/event-emitter.js";
|
||||
|
||||
// TODO: Remove this. Exists to hash the seed for database namespace.
|
||||
import { createHash } from 'crypto';
|
||||
import { p2pkhTemplate } from '@xo-cash/templates';
|
||||
import { hexToBin } from '@bitauth/libauth';
|
||||
import { createHash } from "crypto";
|
||||
import { p2pkhTemplate } from "@xo-cash/templates";
|
||||
import { hexToBin } from "@bitauth/libauth";
|
||||
|
||||
export type AppEventMap = {
|
||||
'invitation-added': Invitation;
|
||||
'invitation-removed': Invitation;
|
||||
}
|
||||
"invitation-added": Invitation;
|
||||
"invitation-removed": Invitation;
|
||||
};
|
||||
|
||||
export interface AppConfig {
|
||||
syncServerUrl: string;
|
||||
@@ -38,14 +38,14 @@ export class AppService extends EventEmitter<AppEventMap> {
|
||||
public config: AppConfig;
|
||||
public history: HistoryService;
|
||||
public electrum: ElectrumService;
|
||||
|
||||
|
||||
public invitations: Invitation[] = [];
|
||||
|
||||
|
||||
static async create(seed: string, config: AppConfig): Promise<AppService> {
|
||||
// Because of a bug that lets wallets read the unspents of other wallets, we are going to manually namespace the storage paths for the app.
|
||||
// We are going to do this by computing a hash of the seed and prefixing the storage paths with it.
|
||||
const seedHash = createHash('sha256').update(seed).digest('hex');
|
||||
|
||||
const seedHash = createHash("sha256").update(seed).digest("hex");
|
||||
|
||||
// We want to only prefix the file name
|
||||
const prefixedStoragePath = `${seedHash.slice(0, 8)}-${config.engineConfig.databaseFilename}`;
|
||||
|
||||
@@ -66,13 +66,13 @@ export class AppService extends EventEmitter<AppEventMap> {
|
||||
// TODO: Add discovery for funds in the first index? Or until we return 0 TXs?
|
||||
await engine.setDefaultLockingParameters(
|
||||
generateTemplateIdentifier(p2pkhTemplate),
|
||||
'receiveOutput',
|
||||
'receiver',
|
||||
"receiveOutput",
|
||||
"receiver",
|
||||
);
|
||||
|
||||
// Create our own storage for the invitations
|
||||
const storage = await Storage.create(config.invitationStoragePath);
|
||||
const walletStorage = await storage.child(seedHash.slice(0, 8))
|
||||
const walletStorage = await storage.child(seedHash.slice(0, 8));
|
||||
|
||||
// Create the app service
|
||||
const electrum = new ElectrumService({
|
||||
@@ -86,23 +86,35 @@ export class AppService extends EventEmitter<AppEventMap> {
|
||||
const allUnspentOutputs = await engine.listUnspentOutputsData();
|
||||
|
||||
// Get a set of all the invitation identifiers
|
||||
const allInvitationIdentifiers = new Set(allUnspentOutputs.map(output => output.invitationIdentifier));
|
||||
const allInvitationIdentifiers = new Set(
|
||||
allUnspentOutputs.map((output) => output.invitationIdentifier),
|
||||
);
|
||||
|
||||
// Iterate over the invitation identifiers and unreserve the outputs
|
||||
for (const invitationIdentifier of allInvitationIdentifiers) {
|
||||
// Get the outputs for the invitation
|
||||
const outputs = allUnspentOutputs.filter(output => output.invitationIdentifier === invitationIdentifier);
|
||||
const outputs = allUnspentOutputs.filter(
|
||||
(output) => output.invitationIdentifier === invitationIdentifier,
|
||||
);
|
||||
// Unreserve the outputs
|
||||
await engine.unreserveResources(outputs.map(output => ({
|
||||
outpointTransactionHash: hexToBin(output.outpointTransactionHash),
|
||||
outpointIndex: output.outpointIndex,
|
||||
})), invitationIdentifier);
|
||||
await engine.unreserveResources(
|
||||
outputs.map((output) => ({
|
||||
outpointTransactionHash: hexToBin(output.outpointTransactionHash),
|
||||
outpointIndex: output.outpointIndex,
|
||||
})),
|
||||
invitationIdentifier,
|
||||
);
|
||||
}
|
||||
|
||||
return new AppService(engine, walletStorage, config, electrum);
|
||||
}
|
||||
|
||||
constructor(engine: Engine, storage: Storage, config: AppConfig, electrum: ElectrumService) {
|
||||
constructor(
|
||||
engine: Engine,
|
||||
storage: Storage,
|
||||
config: AppConfig,
|
||||
electrum: ElectrumService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.engine = engine;
|
||||
@@ -112,10 +124,17 @@ export class AppService extends EventEmitter<AppEventMap> {
|
||||
this.history = new HistoryService(engine, this.invitations);
|
||||
}
|
||||
|
||||
async createInvitation(invitation: XOInvitation | string): Promise<Invitation> {
|
||||
async createInvitation(
|
||||
invitation: XOInvitation | string,
|
||||
): Promise<Invitation> {
|
||||
// Make sure the engine has the template imported
|
||||
const invitationStorage = this.storage.child('invitations')
|
||||
const invitationSyncServer = new SyncServer(this.config.syncServerUrl, typeof invitation === 'string' ? invitation : invitation.invitationIdentifier);
|
||||
const invitationStorage = this.storage.child("invitations");
|
||||
const invitationSyncServer = new SyncServer(
|
||||
this.config.syncServerUrl,
|
||||
typeof invitation === "string"
|
||||
? invitation
|
||||
: invitation.invitationIdentifier,
|
||||
);
|
||||
|
||||
const deps = {
|
||||
engine: this.engine,
|
||||
@@ -138,26 +157,31 @@ export class AppService extends EventEmitter<AppEventMap> {
|
||||
this.invitations.push(invitation);
|
||||
|
||||
// Emit the invitation-added event
|
||||
this.emit('invitation-added', invitation);
|
||||
this.emit("invitation-added", invitation);
|
||||
}
|
||||
|
||||
async removeInvitation(invitation: Invitation): Promise<void> {
|
||||
// Remove the invitation from the invitations array
|
||||
this.invitations = this.invitations.filter(i => i !== invitation);
|
||||
this.invitations = this.invitations.filter((i) => i !== invitation);
|
||||
|
||||
// Emit the invitation-removed event
|
||||
this.emit('invitation-removed', invitation);
|
||||
this.emit("invitation-removed", invitation);
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
// Get the invitations db
|
||||
const invitationsDb = this.storage.child('invitations');
|
||||
const invitationsDb = this.storage.child("invitations");
|
||||
|
||||
// Load invitations from storage
|
||||
const invitations = await invitationsDb.all() as { key: string; value: XOInvitation }[];
|
||||
const invitations = (await invitationsDb.all()) as {
|
||||
key: string;
|
||||
value: XOInvitation;
|
||||
}[];
|
||||
|
||||
await Promise.all(invitations.map(async ({ key }) => {
|
||||
await this.createInvitation(key);
|
||||
}));
|
||||
await Promise.all(
|
||||
invitations.map(async ({ key }) => {
|
||||
await this.createInvitation(key);
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user