File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 80 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 80 KiB |
@@ -1,3 +1,10 @@
|
||||
# React
|
||||
|
||||
TODO
|
||||
## Install
|
||||
|
||||
```sh
|
||||
npm install @xo/react
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# Svelte
|
||||
|
||||
TODO
|
||||
## Install
|
||||
|
||||
```sh
|
||||
npm install @xo/svelte
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
# Vue
|
||||
|
||||
TODO
|
||||
## Install
|
||||
|
||||
```sh
|
||||
npm install @xo/vue
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
+9
-18
@@ -1,3 +1,4 @@
|
||||
import { Transaction } from '@xo/primitives';
|
||||
import { Blockchain, WalletHD } from '@xo/wallet';
|
||||
|
||||
const blockchain = new Blockchain(
|
||||
@@ -8,24 +9,6 @@ const blockchain = new Blockchain(
|
||||
|
||||
await blockchain.start();
|
||||
|
||||
console.log(
|
||||
await blockchain.request(
|
||||
'blockchain.address.get_history',
|
||||
'bitcoincash:qqyy3mss5vmthgnu0m5sm39pcfq8z799ku2nxernca',
|
||||
861_606,
|
||||
861_607
|
||||
)
|
||||
);
|
||||
|
||||
/*
|
||||
console.log(
|
||||
await blockchain.request(
|
||||
'blockchain.transaction.get',
|
||||
'da776b9c273ec406f7ecd488950216aa17a04018201298f263e2fcdb0b903d29'
|
||||
)
|
||||
);
|
||||
*/
|
||||
|
||||
const wallet = WalletHD.fromMnemonic(
|
||||
'harsh gospel job ordinary garden clay eight cactus replace general prison permit',
|
||||
blockchain
|
||||
@@ -33,4 +16,12 @@ const wallet = WalletHD.fromMnemonic(
|
||||
|
||||
await wallet.scan();
|
||||
|
||||
const transactions = wallet.getTransactions();
|
||||
|
||||
transactions.forEach((tx) => {
|
||||
blockchain.broadcastTransaction(tx);
|
||||
});
|
||||
|
||||
console.log(blockchain.pendingTransactions.deriveUtxoState());
|
||||
|
||||
console.log(wallet.privateKey());
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc --build --clean",
|
||||
"build": "tsc --build --clean && tsc --build",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"author": "",
|
||||
|
||||
@@ -22,6 +22,35 @@ export class TransactionGraph {
|
||||
this.transactions.delete(txHash);
|
||||
}
|
||||
|
||||
removeDependentTransactions(txHash: string): string[] {
|
||||
const removedTxids: string[] = [];
|
||||
const toRemove: Set<string> = new Set([txHash]);
|
||||
|
||||
const findDependents = (id: string) => {
|
||||
for (const [otherTxid, tx] of this.transactions) {
|
||||
if (
|
||||
tx
|
||||
.getInputs()
|
||||
.some((input) => binToHex(input.outpointTransactionHash) === id)
|
||||
) {
|
||||
toRemove.add(otherTxid);
|
||||
findDependents(otherTxid);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
findDependents(txHash);
|
||||
|
||||
for (const id of toRemove) {
|
||||
if (this.transactions.has(id)) {
|
||||
this.transactions.delete(id);
|
||||
removedTxids.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
return removedTxids;
|
||||
}
|
||||
|
||||
getTransaction(txHash: string): Transaction | undefined {
|
||||
return this.transactions.get(txHash);
|
||||
}
|
||||
@@ -122,4 +151,10 @@ export class TransactionGraph {
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
getNextTransactionToBroadcast(): Transaction | undefined {
|
||||
// This is pretty inefficient in the sense we recompile the graph each time.
|
||||
// But I'm not sure if that would really have much real-world performance impact.
|
||||
return this.getBroadcastOrder()[0] ?? undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc --build --clean",
|
||||
"build": "tsc --build --clean && tsc --build",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"author": "",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc --build --clean",
|
||||
"build": "tsc --build --clean && tsc --build",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"author": "",
|
||||
|
||||
@@ -88,11 +88,8 @@ export class Blockchain {
|
||||
transaction: Uint8Array | Transaction | string,
|
||||
opts: { waitUntilSeen: boolean } = { waitUntilSeen: true }
|
||||
) {
|
||||
if (typeof transaction === 'string') {
|
||||
transaction = Transaction.fromHex(transaction);
|
||||
}
|
||||
if (transaction instanceof Uint8Array) {
|
||||
transaction = Transaction.fromBytes(transaction);
|
||||
if (!(transaction instanceof Transaction)) {
|
||||
transaction = Transaction.fromAny(transaction);
|
||||
}
|
||||
|
||||
this.pendingTransactions.addTransaction(transaction);
|
||||
@@ -107,16 +104,27 @@ export class Blockchain {
|
||||
transaction: Uint8Array | Transaction | string,
|
||||
opts: { waitUntilSeen: boolean } = { waitUntilSeen: true }
|
||||
) {
|
||||
if (typeof transaction === 'string') {
|
||||
transaction = Transaction.fromHex(transaction);
|
||||
}
|
||||
if (transaction instanceof Uint8Array) {
|
||||
transaction = Transaction.fromBytes(transaction);
|
||||
if (!(transaction instanceof Transaction)) {
|
||||
transaction = Transaction.fromAny(transaction);
|
||||
}
|
||||
|
||||
this.pendingTransactions.addTransaction(transaction);
|
||||
|
||||
// TODO: Broadcast the transaction.
|
||||
// Broadcast any pending transaction.
|
||||
// TODO: Use while loop instead.
|
||||
for (let tx of this.pendingTransactions.getBroadcastOrder()) {
|
||||
try {
|
||||
console.log('broadcasting', tx);
|
||||
|
||||
this.pendingTransactions.removeTransaction(tx.toHashHex());
|
||||
} catch (error) {
|
||||
this.pendingTransactions.removeDependentTransactions(tx.toHashHex());
|
||||
|
||||
throw new Error(
|
||||
`Broadcast failed for ${transaction.getHashHex()}. Removing dependent transactions.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Wait for transaction to be seen on network.
|
||||
console.log(opts);
|
||||
|
||||
@@ -3,3 +3,6 @@ export * from './blockchain-types.js';
|
||||
export * from './storage.js';
|
||||
export * from './wallet-hd.js';
|
||||
export * from './wallet-p2pkh.js';
|
||||
export * from './wallet-p2sh20.js';
|
||||
export * from './wallet-p2sh32.js';
|
||||
export * from './wallet-set.js';
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
* We don't want to extend this - we want to compose it.
|
||||
* Reason being that we want to support multiple storage adapters.
|
||||
* And we should allow the possibility of having non-critical storage adapters fail (e.g. remote vs local).
|
||||
*
|
||||
* Additionally, consider how we'll store data for WalletSets.
|
||||
* There will be child wallets. These will have their own data.
|
||||
* And each child may then have its own wallet. And on and on.
|
||||
* So, it's a tree hierarchy.
|
||||
* We can probably emit a "storageUpdated" event that is registered by each parent wallet.
|
||||
* The parent then "wraps" its own state into this and propagates it up to its parent.
|
||||
* Then, when it reaches root, the storage adapter stashes all of the propagated data into actual storage.
|
||||
*/
|
||||
export class Storage {
|
||||
constructor() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Import the Stamp class to derive the private keys
|
||||
import { HDPrivateNode } from '@xo/primitives';
|
||||
import { HDPrivateNode, Transaction } from '@xo/primitives';
|
||||
import { EventEmitter } from '../utils/index.js';
|
||||
import { Blockchain } from './blockchain.js';
|
||||
import {
|
||||
@@ -232,6 +232,14 @@ export class WalletHD<
|
||||
|
||||
return encodedTransaction;
|
||||
}
|
||||
|
||||
getTransactions() {
|
||||
// NOTE: We use a set so that we don't end up with duplicate transactions.
|
||||
return this.wallets.reduce((txs, wallet) => {
|
||||
wallet.transactions.forEach((tx) => txs.add(tx));
|
||||
return txs; // Make sure to return the accumulator
|
||||
}, new Set<Transaction>());
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Placeholder.
|
||||
*
|
||||
* @remarks
|
||||
* TODO Use AddressData
|
||||
*/
|
||||
export class WalletP2SH20 {
|
||||
constructor() {
|
||||
console.log('TODO');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Placeholder.
|
||||
*
|
||||
* @remarks
|
||||
* TODO Use AddressData
|
||||
*/
|
||||
export class WalletP2SH32 {
|
||||
constructor() {
|
||||
console.log('TODO');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Placeholder.
|
||||
*
|
||||
* @remarks
|
||||
* One difficult thing here is going to be storage of the subwallets.
|
||||
* We're going to have child wallets and we need to propagate their storage to the root WalletSet.
|
||||
* See remarks on Storage - it's semi-related and I'm still playing with approaches.
|
||||
*/
|
||||
export class WalletSet {
|
||||
constructor() {
|
||||
console.log('TODO');
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -14,13 +14,15 @@
|
||||
"autoConfiguration": true,
|
||||
"format": "vitepress",
|
||||
"pretty": true,
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"indexFormat": "table",
|
||||
"parametersFormat": "table",
|
||||
"interfacePropertiesFormat": "table",
|
||||
"classPropertiesFormat": "table",
|
||||
"propertyMembersFormat": "table",
|
||||
"typeDeclarationFormat": "table",
|
||||
"enumMembersFormat": "table",
|
||||
"useCodeBlocks": true,
|
||||
"sort": [
|
||||
"static-first"
|
||||
|
||||
Reference in New Issue
Block a user