Large amount of changes. Successfully broadcasts txs
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import type { AcceptInvitationParameters, AppendInvitationParameters, Engine, FindSuitableResourcesParameters } from '@xo-cash/engine';
|
||||
import { hasInvitationExpired } from '@xo-cash/engine';
|
||||
import type { XOInvitation, XOInvitationCommit, XOInvitationInput, XOInvitationOutput, XOInvitationVariable } from '@xo-cash/types';
|
||||
import type { XOInvitation, XOInvitationCommit, XOInvitationInput, XOInvitationOutput, XOInvitationVariable, XOInvitationVariableValue } from '@xo-cash/types';
|
||||
import type { UnspentOutputData } from '@xo-cash/state';
|
||||
|
||||
import type { SSEvent } from '../utils/sse-client.js';
|
||||
@@ -9,6 +9,7 @@ import type { Storage } from './storage.js';
|
||||
|
||||
import { EventEmitter } from '../utils/event-emitter.js'
|
||||
import { decodeExtendedJsonObject } from '../utils/ext-json.js';
|
||||
import { compileCashAssemblyString } from '@xo-cash/engine';
|
||||
|
||||
export type InvitationEventMap = {
|
||||
'invitation-updated': XOInvitation;
|
||||
@@ -32,14 +33,12 @@ export class Invitation extends EventEmitter<InvitationEventMap> {
|
||||
// Try to get the invitation from the storage
|
||||
const invitationFromStorage = await dependencies.storage.get(invitation);
|
||||
if (invitationFromStorage) {
|
||||
console.log(`Invitation found in storage: ${invitation}`);
|
||||
return this.create(invitationFromStorage, dependencies);
|
||||
}
|
||||
|
||||
// Try to get the invitation from the sync server
|
||||
const invitationFromSyncServer = await dependencies.syncServer.getInvitation(invitation);
|
||||
if (invitationFromSyncServer && invitationFromSyncServer.invitationIdentifier === invitation) {
|
||||
console.log(`Invitation found in sync server: ${invitation}`);
|
||||
return this.create(invitationFromSyncServer, dependencies);
|
||||
}
|
||||
|
||||
@@ -345,6 +344,14 @@ export class Invitation extends EventEmitter<InvitationEventMap> {
|
||||
await this.syncServer.publishInvitation(this.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the locking bytecode for the invitation
|
||||
* TODO: Find out if this has side-effects or needs special handling
|
||||
*/
|
||||
async generateLockingBytecode(outputIdentifier: string, roleIdentifier?: string): Promise<string> {
|
||||
return this.engine.generateLockingBytecode(this.data.templateIdentifier, outputIdentifier, roleIdentifier);
|
||||
}
|
||||
|
||||
async addOutputs(outputs: XOInvitationOutput[]): Promise<void> {
|
||||
// Add the outputs to the invitation
|
||||
await this.append({ outputs });
|
||||
@@ -410,4 +417,89 @@ export class Invitation extends EventEmitter<InvitationEventMap> {
|
||||
async getLockingBytecode(outputIdentifier: string, roleIdentifier?: string): Promise<string> {
|
||||
return this.engine.generateLockingBytecode(this.data.templateIdentifier, outputIdentifier, roleIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sats out for the invitation
|
||||
* TODO: Clean up this function. Why is it so big? Can obviously make it 2 functions instead of recursive, but still...
|
||||
*/
|
||||
async getSatsOut(outputIdentifier?: string): Promise<bigint> {
|
||||
// If an output identifier is provided, find all outputs with that identifier, and its valueSatoshis identifier back to the variables
|
||||
if (outputIdentifier) {
|
||||
// Get the valueSatoshis identifier from the template
|
||||
const template = await this.engine.getTemplate(this.data.templateIdentifier);
|
||||
if (!template) {
|
||||
throw new Error(`Template not found: ${this.data.templateIdentifier} when trying to get sats out for output: ${outputIdentifier}`);
|
||||
}
|
||||
|
||||
const output = template.outputs[outputIdentifier];
|
||||
if (!output) {
|
||||
throw new Error(`Output not found: ${outputIdentifier} in template: ${this.data.templateIdentifier}`);
|
||||
}
|
||||
|
||||
const valueSatoshisIdentifier = output.valueSatoshis;
|
||||
if (!valueSatoshisIdentifier) {
|
||||
throw new Error(`Value satoshis identifier not found: ${outputIdentifier} in template: ${this.data.templateIdentifier}`);
|
||||
}
|
||||
|
||||
// Create a list of all the variables from the commits
|
||||
const variables = this.data.commits.flatMap(c => c.data?.variables ?? []);
|
||||
|
||||
// Create a dictionary of the variables
|
||||
const formattedVariables = variables.reduce((acc, v) => {
|
||||
acc[v.variableIdentifier ?? ''] = v.value;
|
||||
return acc;
|
||||
}, {} as Record<string, XOInvitationVariableValue>);
|
||||
|
||||
// Compile the CashAssembly expression to get the value satoshis (It handles the variable replacement for us)
|
||||
const valueSatoshis = await compileCashAssemblyString(String(valueSatoshisIdentifier), formattedVariables);
|
||||
|
||||
// Return the value satoshis as a bigint
|
||||
// TODO: Check this of a vulnerability or crash - I assume there might be one if someone made the `valueSatoshis` a malicious expression
|
||||
return BigInt(valueSatoshis);
|
||||
}
|
||||
|
||||
// If we didnt get an output identifier, go through the action outputs and sum the valueSatoshis
|
||||
const action = this.data.actionIdentifier;
|
||||
if (!action) {
|
||||
throw new Error(`Action not found: ${this.data.actionIdentifier} when trying to get sats out for output: ${outputIdentifier}`);
|
||||
}
|
||||
|
||||
// Get the template
|
||||
const template = await this.engine.getTemplate(this.data.templateIdentifier);
|
||||
if (!template) {
|
||||
throw new Error(`Template not found: ${this.data.templateIdentifier} when trying to get sats out for action: ${action}`);
|
||||
}
|
||||
|
||||
// Get the transaction ID from the action
|
||||
const transactionID = template.actions[action]?.transaction
|
||||
if (!transactionID) {
|
||||
throw new Error(`Transactions not found: ${action} in template: ${this.data.templateIdentifier}`);
|
||||
}
|
||||
|
||||
// Get the transaction from the template
|
||||
const transaction = template.transactions?.[transactionID];
|
||||
if (!transaction) {
|
||||
throw new Error(`Transaction not found: ${transactionID} in template: ${this.data.templateIdentifier}`);
|
||||
}
|
||||
|
||||
// Get the outputs from the transaction
|
||||
const outputs = transaction.outputs;
|
||||
if (!outputs) {
|
||||
throw new Error(`Outputs not found: ${transactionID} in template: ${this.data.templateIdentifier}`);
|
||||
}
|
||||
|
||||
// Create a value to store the cummulative total of the outputs
|
||||
let totalSats = 0n;
|
||||
|
||||
// Iterate through the outputs and sum the valueSatoshis
|
||||
for (const output of outputs) {
|
||||
if (typeof output === 'string') {
|
||||
totalSats += await this.getSatsOut(output);
|
||||
} else {
|
||||
totalSats += await this.getSatsOut(output.output);
|
||||
}
|
||||
}
|
||||
|
||||
return totalSats;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user