Skip to content

Commit

Permalink
chore: remove send module, add to client
Browse files Browse the repository at this point in the history
  • Loading branch information
jowparks committed Sep 14, 2023
1 parent 0b2389a commit 7448b5b
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 110 deletions.
108 changes: 107 additions & 1 deletion example/src/Client/Client.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { credentials } from "@grpc/grpc-js";
import { LightStreamerClient } from "../../../src/models/lightstreamer";
import { BlockProcessor } from "./utils/BlockProcessor";
import { AccountsManager } from "./utils/AccountsManager";
import { AccountData, AccountsManager } from "./utils/AccountsManager";
import { BlockCache } from "./utils/BlockCache";

import {
Transaction as NativeTransaction,
Note as NativeNote,
Asset,
} from "@ironfish/rust-nodejs";
import { MerkleWitness, notesTree } from "./utils/MerkleTree";
import { BufferMap } from "buffer-map";

const client = new LightStreamerClient(
process.env["WALLET_SERVER_HOST"] ?? "localhost:50051",
credentials.createInsecure(),
Expand Down Expand Up @@ -61,4 +69,102 @@ export class Client {
this.blockProcessor.stop();
this.handleStop?.();
}

/*
This function is meant as example as to how to create a transaction using the core ironfish rust codebase, instead of the sdk.
For an example of using the sdk, see the ironfish wallet
In this case, we are using our own ironfish-rust-nodejs bindings, but other languages could be used as well with
separate bindings to the underlying functions.
*/
public async createTransaction(
account: AccountData,
to: { publicAddress: string },
sendAmount: bigint,
sendAssetId: Buffer,
fee: bigint, // fee is always in native asset, $IRON
memo: string,
): Promise<NativeTransaction> {
const transaction = new NativeTransaction(account.key.spendingKey, 1);
const amountsNeeded = this.buildAmountsNeeded(sendAssetId, sendAmount, fee);

// fund the transaction and calculate the witnesses
for (const [assetId, amount] of amountsNeeded) {
const fundNotes = await this.fundTransaction(account, assetId, amount);
fundNotes.map(({ note, witness }) => transaction.spend(note, witness));

const sendNote = new NativeNote(
to.publicAddress,
sendAmount,
memo,
assetId,
account.key.publicAddress,
);
transaction.output(sendNote);
}
// TODO mark notes as spent, not absolutely critical as syncer should catch
return transaction;
}

private buildAmountsNeeded(
assetId: Buffer,
amount: bigint,
fee: bigint,
): BufferMap<bigint> {
// add fee
const amountsNeeded = new BufferMap<bigint>();
amountsNeeded.set(Asset.nativeId(), fee);

// add spend
const currentAmount = amountsNeeded.get(assetId) ?? 0n;
amountsNeeded.set(assetId, currentAmount + amount);

return amountsNeeded;
}

private async fundTransaction(
from: AccountData,
assetId: Buffer,
amount: bigint,
): Promise<{ note: NativeNote; witness: MerkleWitness }[]> {
let currentValue = 0n;
const notesToSpend: { note: NativeNote; witness: MerkleWitness }[] = [];
const notes = from.assets.get(assetId);
if (!notes) {
throw new Error("No notes found for asset: " + assetId.toString("hex"));
}
for (const note of notes.values()) {
if (currentValue >= amount) {
break;
}
if (
!note.note.assetId().equals(assetId) ||
note.spent === true ||
!note.sequence ||
!note.merkleIndex
) {
continue;
}
const witness = await notesTree.witness(note.merkleIndex);
if (!witness) {
console.warn(
"Could not calculate witness for note: ",
note.note.hash().toString("hex"),
);
continue;
}
currentValue += note.note.value();
notesToSpend.push({ note: note.note, witness });
}
if (currentValue < amount) {
throw new Error(
"Insufficient funds for asset: " +
assetId.toString("hex") +
" needed: " +
amount.toString() +
" have: " +
currentValue.toString(),
);
}
return notesToSpend;
}
}
107 changes: 0 additions & 107 deletions example/src/Client/utils/send.ts

This file was deleted.

3 changes: 1 addition & 2 deletions example/src/send.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Client } from "./Client/Client";
import { createTransaction } from "./Client/utils/send";
import { generateKeyFromPrivateKey } from "@ironfish/rust-nodejs";

export async function send(
Expand All @@ -20,7 +19,7 @@ export async function send(
if (!account) {
throw new Error(`Account not found for intput spending key`);
}
const transaction = await createTransaction(
const transaction = await client.createTransaction(
account,
{ publicAddress: toPublicAddress },
BigInt(amount),
Expand Down

0 comments on commit 7448b5b

Please sign in to comment.