@@ -8,3 +8,8 @@ yarn.lock
|
|||||||
yarn-error.log
|
yarn-error.log
|
||||||
unit-tests.xml
|
unit-tests.xml
|
||||||
e2e-tests.xml
|
e2e-tests.xml
|
||||||
|
|
||||||
|
# Ignore Vitepress builds/cache/generated-API.
|
||||||
|
docs/.vitepress/dist
|
||||||
|
docs/.vitepress/cache
|
||||||
|
docs/api
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
image: node:20
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- docs
|
||||||
|
|
||||||
|
cache:
|
||||||
|
# The cache is shared for same values of cache key
|
||||||
|
# Here, we use CI_PIPELINE_ID which is defined as:
|
||||||
|
# "The instance-level ID of the current pipeline. This ID is unique across all projects on the GitLab instance."
|
||||||
|
# This should ensure that we only cache the "node_modules" folder for this given pipeline instance.
|
||||||
|
# Refer to this docs to know more about the predefined variables used in the key here: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
|
||||||
|
key: $CI_PIPELINE_ID
|
||||||
|
# configure the path to be cached
|
||||||
|
paths:
|
||||||
|
- node_modules/
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- npm install
|
||||||
|
- npm run build
|
||||||
|
|
||||||
|
# Publish the documentation to GitLab Pages (for now).
|
||||||
|
pages:
|
||||||
|
stage: publish
|
||||||
|
script:
|
||||||
|
- npm run docs:build
|
||||||
|
- mv docs/.vitepress/dist public
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- public
|
||||||
|
only:
|
||||||
|
- main
|
||||||
@@ -1,3 +1,95 @@
|
|||||||
# XO Stack
|
# XO Stack
|
||||||
|
|
||||||
TODO
|
This is a monorepo project containing multiple packages managed with NPM workspaces.
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
xo/
|
||||||
|
├── packages/
|
||||||
|
│ ├── primitives/
|
||||||
|
│ ├── wallet/
|
||||||
|
│ └── vue/
|
||||||
|
├── package.json
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Node.js (version 20.0.0 or later)
|
||||||
|
- NPM (version 7 or later, which includes workspaces support)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
To install all dependencies for all packages in the monorepo, run the following command from the root directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
This command will install dependencies for the root project and all packages in the `packages/` directory.
|
||||||
|
|
||||||
|
## Building Packages
|
||||||
|
|
||||||
|
To build all packages, run the following command from the root directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
This will execute the build script for each package in the monorepo.
|
||||||
|
|
||||||
|
To build a specific package, you can use the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build --workspace=@my-monorepo/<package-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `<package-name>` with the name of the package you want to build (e.g., primitives, network-wallet, or vue).
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
To run tests for all packages:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
To run tests for a specific package:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm test --workspace=@my-monorepo/<package-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
During development, you can use the following command to watch for changes and rebuild packages automatically:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Useful NPM Workspace Commands
|
||||||
|
|
||||||
|
- List all packages in the workspace:
|
||||||
|
```bash
|
||||||
|
npm ls -w
|
||||||
|
```
|
||||||
|
|
||||||
|
- Run a command in a specific package:
|
||||||
|
```bash
|
||||||
|
npm run <command> --workspace=@my-monorepo/<package-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
- Add a dependency to a specific package:
|
||||||
|
```bash
|
||||||
|
npm install <dependency> --workspace=@my-monorepo/<package-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import { defineConfig } from 'vitepress';
|
||||||
|
import typedocSidebar from '../api/typedoc-sidebar.json';
|
||||||
|
|
||||||
|
function capitalizeFirstLetter(str: string) {
|
||||||
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: We can filter the generated sidebar to produce relevant links to documentation.
|
||||||
|
// See the contents of the typedocSidear import for structure.
|
||||||
|
function classesOnlySidebar() {
|
||||||
|
return typedocSidebar.map((rootItem) => {
|
||||||
|
const srcItem = rootItem.items.find(
|
||||||
|
(childItem) => childItem.text === 'src'
|
||||||
|
);
|
||||||
|
|
||||||
|
const classes = srcItem?.items.find(
|
||||||
|
(childItem) => childItem.text === 'Classes'
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...rootItem,
|
||||||
|
text: capitalizeFirstLetter(rootItem.text),
|
||||||
|
items: classes?.items,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://vitepress.dev/reference/site-config
|
||||||
|
export default defineConfig({
|
||||||
|
title: 'XO Stack',
|
||||||
|
description: 'XO Stack',
|
||||||
|
themeConfig: {
|
||||||
|
// Enable search functionality.
|
||||||
|
search: {
|
||||||
|
provider: 'local',
|
||||||
|
},
|
||||||
|
|
||||||
|
// https://vitepress.dev/reference/default-theme-config
|
||||||
|
nav: [
|
||||||
|
{ text: 'Home', link: '/' },
|
||||||
|
{ text: 'Tools', link: '/tools' },
|
||||||
|
],
|
||||||
|
|
||||||
|
sidebar: [
|
||||||
|
{
|
||||||
|
text: 'Guide',
|
||||||
|
items: [
|
||||||
|
{ text: 'Quick Start', link: '/markdown-examples' },
|
||||||
|
{ text: 'Best Practices', link: '/api-examples' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Frameworks',
|
||||||
|
items: [
|
||||||
|
{ text: 'Vue', link: '/frameworks/vue' },
|
||||||
|
{ text: 'React', link: '/frameworks/react' },
|
||||||
|
{ text: 'Svelte', link: '/frameworks/svelte' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'API',
|
||||||
|
// NOTE: In future, we may want to manually specify API items in the sidebar.
|
||||||
|
// This would allow us to keep some experimental things undocumented.
|
||||||
|
// But, for now, let's use an autogenerated sidebar so that we don't have to maintain this.
|
||||||
|
// We can polish it later.
|
||||||
|
items: classesOnlySidebar(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
socialLinks: [
|
||||||
|
{ icon: 'github', link: 'https://gitlab.com/GeneralProtocols/xo/stack' },
|
||||||
|
],
|
||||||
|
|
||||||
|
// This is the outline on the right-hand side of the page.
|
||||||
|
outline: {
|
||||||
|
level: [2, 3],
|
||||||
|
label: 'On this page',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// https://vitepress.dev/guide/custom-theme
|
||||||
|
import { h } from 'vue'
|
||||||
|
import type { Theme } from 'vitepress'
|
||||||
|
import DefaultTheme from 'vitepress/theme'
|
||||||
|
import './style.css'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
extends: DefaultTheme,
|
||||||
|
Layout: () => {
|
||||||
|
return h(DefaultTheme.Layout, null, {
|
||||||
|
// https://vitepress.dev/guide/extending-default-theme#layout-slots
|
||||||
|
})
|
||||||
|
},
|
||||||
|
enhanceApp({ app, router, siteData }) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
} satisfies Theme
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/**
|
||||||
|
* Customize default theme styling by overriding CSS variables:
|
||||||
|
* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colors
|
||||||
|
*
|
||||||
|
* Each colors have exact same color scale system with 3 levels of solid
|
||||||
|
* colors with different brightness, and 1 soft color.
|
||||||
|
*
|
||||||
|
* - `XXX-1`: The most solid color used mainly for colored text. It must
|
||||||
|
* satisfy the contrast ratio against when used on top of `XXX-soft`.
|
||||||
|
*
|
||||||
|
* - `XXX-2`: The color used mainly for hover state of the button.
|
||||||
|
*
|
||||||
|
* - `XXX-3`: The color for solid background, such as bg color of the button.
|
||||||
|
* It must satisfy the contrast ratio with pure white (#ffffff) text on
|
||||||
|
* top of it.
|
||||||
|
*
|
||||||
|
* - `XXX-soft`: The color used for subtle background such as custom container
|
||||||
|
* or badges. It must satisfy the contrast ratio when putting `XXX-1` colors
|
||||||
|
* on top of it.
|
||||||
|
*
|
||||||
|
* The soft color must be semi transparent alpha channel. This is crucial
|
||||||
|
* because it allows adding multiple "soft" colors on top of each other
|
||||||
|
* to create a accent, such as when having inline code block inside
|
||||||
|
* custom containers.
|
||||||
|
*
|
||||||
|
* - `default`: The color used purely for subtle indication without any
|
||||||
|
* special meanings attched to it such as bg color for menu hover state.
|
||||||
|
*
|
||||||
|
* - `brand`: Used for primary brand colors, such as link text, button with
|
||||||
|
* brand theme, etc.
|
||||||
|
*
|
||||||
|
* - `tip`: Used to indicate useful information. The default theme uses the
|
||||||
|
* brand color for this by default.
|
||||||
|
*
|
||||||
|
* - `warning`: Used to indicate warning to the users. Used in custom
|
||||||
|
* container, badges, etc.
|
||||||
|
*
|
||||||
|
* - `danger`: Used to show error, or dangerous message to the users. Used
|
||||||
|
* in custom container, badges, etc.
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--vp-c-default-1: var(--vp-c-gray-1);
|
||||||
|
--vp-c-default-2: var(--vp-c-gray-2);
|
||||||
|
--vp-c-default-3: var(--vp-c-gray-3);
|
||||||
|
--vp-c-default-soft: var(--vp-c-gray-soft);
|
||||||
|
|
||||||
|
--vp-c-brand-1: var(--vp-c-indigo-1);
|
||||||
|
--vp-c-brand-2: var(--vp-c-indigo-2);
|
||||||
|
--vp-c-brand-3: var(--vp-c-indigo-3);
|
||||||
|
--vp-c-brand-soft: var(--vp-c-indigo-soft);
|
||||||
|
|
||||||
|
--vp-c-tip-1: var(--vp-c-brand-1);
|
||||||
|
--vp-c-tip-2: var(--vp-c-brand-2);
|
||||||
|
--vp-c-tip-3: var(--vp-c-brand-3);
|
||||||
|
--vp-c-tip-soft: var(--vp-c-brand-soft);
|
||||||
|
|
||||||
|
--vp-c-warning-1: var(--vp-c-yellow-1);
|
||||||
|
--vp-c-warning-2: var(--vp-c-yellow-2);
|
||||||
|
--vp-c-warning-3: var(--vp-c-yellow-3);
|
||||||
|
--vp-c-warning-soft: var(--vp-c-yellow-soft);
|
||||||
|
|
||||||
|
--vp-c-danger-1: var(--vp-c-red-1);
|
||||||
|
--vp-c-danger-2: var(--vp-c-red-2);
|
||||||
|
--vp-c-danger-3: var(--vp-c-red-3);
|
||||||
|
--vp-c-danger-soft: var(--vp-c-red-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component: Button
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--vp-button-brand-border: transparent;
|
||||||
|
--vp-button-brand-text: var(--vp-c-white);
|
||||||
|
--vp-button-brand-bg: var(--vp-c-brand-3);
|
||||||
|
--vp-button-brand-hover-border: transparent;
|
||||||
|
--vp-button-brand-hover-text: var(--vp-c-white);
|
||||||
|
--vp-button-brand-hover-bg: var(--vp-c-brand-2);
|
||||||
|
--vp-button-brand-active-border: transparent;
|
||||||
|
--vp-button-brand-active-text: var(--vp-c-white);
|
||||||
|
--vp-button-brand-active-bg: var(--vp-c-brand-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component: Home
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--vp-home-hero-name-color: transparent;
|
||||||
|
--vp-home-hero-name-background: -webkit-linear-gradient(
|
||||||
|
120deg,
|
||||||
|
#bd34fe 30%,
|
||||||
|
#41d1ff
|
||||||
|
);
|
||||||
|
|
||||||
|
--vp-home-hero-image-background-image: linear-gradient(
|
||||||
|
-45deg,
|
||||||
|
#bd34fe 50%,
|
||||||
|
#47caff 50%
|
||||||
|
);
|
||||||
|
--vp-home-hero-image-filter: blur(44px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
:root {
|
||||||
|
--vp-home-hero-image-filter: blur(56px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 960px) {
|
||||||
|
:root {
|
||||||
|
--vp-home-hero-image-filter: blur(68px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component: Custom Block
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--vp-custom-block-tip-border: transparent;
|
||||||
|
--vp-custom-block-tip-text: var(--vp-c-text-1);
|
||||||
|
--vp-custom-block-tip-bg: var(--vp-c-brand-soft);
|
||||||
|
--vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component: Algolia
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
.DocSearch {
|
||||||
|
--docsearch-primary-color: var(--vp-c-brand-1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
outline: deep
|
||||||
|
---
|
||||||
|
|
||||||
|
# Runtime API Examples
|
||||||
|
|
||||||
|
This page demonstrates usage of some of the runtime APIs provided by VitePress.
|
||||||
|
|
||||||
|
The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files:
|
||||||
|
|
||||||
|
```md
|
||||||
|
<script setup>
|
||||||
|
import { useData } from 'vitepress'
|
||||||
|
|
||||||
|
const { theme, page, frontmatter } = useData()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
## Results
|
||||||
|
|
||||||
|
### Theme Data
|
||||||
|
<pre>{{ theme }}</pre>
|
||||||
|
|
||||||
|
### Page Data
|
||||||
|
<pre>{{ page }}</pre>
|
||||||
|
|
||||||
|
### Page Frontmatter
|
||||||
|
<pre>{{ frontmatter }}</pre>
|
||||||
|
```
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useData } from 'vitepress'
|
||||||
|
|
||||||
|
const { site, theme, page, frontmatter } = useData()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
## Results
|
||||||
|
|
||||||
|
### Theme Data
|
||||||
|
<pre>{{ theme }}</pre>
|
||||||
|
|
||||||
|
### Page Data
|
||||||
|
<pre>{{ page }}</pre>
|
||||||
|
|
||||||
|
### Page Frontmatter
|
||||||
|
<pre>{{ frontmatter }}</pre>
|
||||||
|
|
||||||
|
## More
|
||||||
|
|
||||||
|
Check out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata).
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# React
|
||||||
|
|
||||||
|
TODO
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Svelte
|
||||||
|
|
||||||
|
TODO
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Vue
|
||||||
|
|
||||||
|
TODO
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
# https://vitepress.dev/reference/default-theme-home-page
|
||||||
|
layout: home
|
||||||
|
|
||||||
|
hero:
|
||||||
|
name: "XO Stack"
|
||||||
|
text: "XO Stack"
|
||||||
|
tagline: My great project tagline
|
||||||
|
actions:
|
||||||
|
- theme: brand
|
||||||
|
text: Quick Start
|
||||||
|
link: /markdown-examples
|
||||||
|
- theme: alt
|
||||||
|
text: APIs
|
||||||
|
link: /api
|
||||||
|
|
||||||
|
features:
|
||||||
|
- title: Feature A
|
||||||
|
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||||
|
- title: Feature B
|
||||||
|
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||||
|
- title: Feature C
|
||||||
|
details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||||
|
---
|
||||||
|
|
||||||
|
I haven't played with custom theming much yet and have been working with more the configuration side of things for Docs.
|
||||||
|
|
||||||
|
However, it does seem like there's quite a lot of flexibility with VitePress.
|
||||||
|
|
||||||
|
We probably won't want to create an entirely custom theme, but extend the default instead:
|
||||||
|
|
||||||
|
https://vitepress.dev/guide/extending-default-theme
|
||||||
|
|
||||||
|
Also, don't take what's in these docs here literally. I'm still toying around with things.
|
||||||
|
|
||||||
|
But having the API docs generate is probably quite useful in even the early-dev/experimental phase: It allows us to get a feel for the API.
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# Markdown Extension Examples
|
||||||
|
|
||||||
|
This page demonstrates some of the built-in markdown extensions provided by VitePress.
|
||||||
|
|
||||||
|
## Syntax Highlighting
|
||||||
|
|
||||||
|
VitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting:
|
||||||
|
|
||||||
|
**Input**
|
||||||
|
|
||||||
|
````md
|
||||||
|
```js{4}
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
msg: 'Highlighted!'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
**Output**
|
||||||
|
|
||||||
|
```js{4}
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
msg: 'Highlighted!'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom Containers
|
||||||
|
|
||||||
|
**Input**
|
||||||
|
|
||||||
|
```md
|
||||||
|
::: info
|
||||||
|
This is an info box.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
This is a tip.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
This is a warning.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: danger
|
||||||
|
This is a dangerous warning.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: details
|
||||||
|
This is a details block.
|
||||||
|
:::
|
||||||
|
```
|
||||||
|
|
||||||
|
**Output**
|
||||||
|
|
||||||
|
::: info
|
||||||
|
This is an info box.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: tip
|
||||||
|
This is a tip.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: warning
|
||||||
|
This is a warning.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: danger
|
||||||
|
This is a dangerous warning.
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: details
|
||||||
|
This is a details block.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## More
|
||||||
|
|
||||||
|
Check out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown).
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Tools
|
||||||
|
|
||||||
|
May want to have a Tools/Sandbox section.
|
||||||
|
|
||||||
|
I'd leave until later before exploring this more, but it sounds like we can (technically) create custom components.
|
||||||
|
|
||||||
|
https://vitepress.dev/guide/using-vue
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { Blockchain, WalletHD } from '@xo/wallet';
|
||||||
|
|
||||||
|
const blockchain = new Blockchain(
|
||||||
|
['bch.imaginary.cash', 'cashnode.bch.ninja', 'electrum.imaginary.cash'],
|
||||||
|
'Test App',
|
||||||
|
'1.5'
|
||||||
|
);
|
||||||
|
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
await wallet.scan();
|
||||||
|
|
||||||
|
console.log(wallet.privateKey());
|
||||||
Generated
+598
@@ -0,0 +1,598 @@
|
|||||||
|
{
|
||||||
|
"name": "@xo/node-demo",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "@xo/node-demo",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@xo/network-wallet": "file:../../packages/network-wallet",
|
||||||
|
"@xo/primitives": "file:../../packages/primitives"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vite": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../../packages/network-wallet": {},
|
||||||
|
"../../packages/primitives": {
|
||||||
|
"name": "@xo/primitives",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-arm": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-arm64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/android-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/darwin-arm64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/darwin-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/freebsd-arm64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/freebsd-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"freebsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-arm": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-arm64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-ia32": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-loong64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
|
||||||
|
"cpu": [
|
||||||
|
"loong64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-mips64el": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
|
||||||
|
"cpu": [
|
||||||
|
"mips64el"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-ppc64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-riscv64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-s390x": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
|
||||||
|
"cpu": [
|
||||||
|
"s390x"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/linux-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/netbsd-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"netbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/openbsd-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openbsd"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/sunos-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"sunos"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-arm64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-ia32": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@esbuild/win32-x64": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@xo/network-wallet": {
|
||||||
|
"resolved": "../../packages/network-wallet",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/@xo/primitives": {
|
||||||
|
"resolved": "../../packages/primitives",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/esbuild": {
|
||||||
|
"version": "0.18.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
|
||||||
|
"integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"esbuild": "bin/esbuild"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@esbuild/android-arm": "0.18.20",
|
||||||
|
"@esbuild/android-arm64": "0.18.20",
|
||||||
|
"@esbuild/android-x64": "0.18.20",
|
||||||
|
"@esbuild/darwin-arm64": "0.18.20",
|
||||||
|
"@esbuild/darwin-x64": "0.18.20",
|
||||||
|
"@esbuild/freebsd-arm64": "0.18.20",
|
||||||
|
"@esbuild/freebsd-x64": "0.18.20",
|
||||||
|
"@esbuild/linux-arm": "0.18.20",
|
||||||
|
"@esbuild/linux-arm64": "0.18.20",
|
||||||
|
"@esbuild/linux-ia32": "0.18.20",
|
||||||
|
"@esbuild/linux-loong64": "0.18.20",
|
||||||
|
"@esbuild/linux-mips64el": "0.18.20",
|
||||||
|
"@esbuild/linux-ppc64": "0.18.20",
|
||||||
|
"@esbuild/linux-riscv64": "0.18.20",
|
||||||
|
"@esbuild/linux-s390x": "0.18.20",
|
||||||
|
"@esbuild/linux-x64": "0.18.20",
|
||||||
|
"@esbuild/netbsd-x64": "0.18.20",
|
||||||
|
"@esbuild/openbsd-x64": "0.18.20",
|
||||||
|
"@esbuild/sunos-x64": "0.18.20",
|
||||||
|
"@esbuild/win32-arm64": "0.18.20",
|
||||||
|
"@esbuild/win32-ia32": "0.18.20",
|
||||||
|
"@esbuild/win32-x64": "0.18.20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "3.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/picocolors": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/postcss": {
|
||||||
|
"version": "8.4.43",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.43.tgz",
|
||||||
|
"integrity": "sha512-gJAQVYbh5R3gYm33FijzCZj7CHyQ3hWMgJMprLUlIYqCwTeZhBQ19wp0e9mA25BUbEvY5+EXuuaAjqQsrBxQBQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^3.3.7",
|
||||||
|
"picocolors": "^1.0.1",
|
||||||
|
"source-map-js": "^1.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rollup": {
|
||||||
|
"version": "3.29.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
|
||||||
|
"integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"rollup": "dist/bin/rollup"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.18.0",
|
||||||
|
"npm": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/source-map-js": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vite": {
|
||||||
|
"version": "4.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz",
|
||||||
|
"integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"esbuild": "^0.18.10",
|
||||||
|
"postcss": "^8.4.27",
|
||||||
|
"rollup": "^3.27.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"vite": "bin/vite.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.18.0 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "~2.3.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/node": ">= 14",
|
||||||
|
"less": "*",
|
||||||
|
"lightningcss": "^1.21.0",
|
||||||
|
"sass": "*",
|
||||||
|
"stylus": "*",
|
||||||
|
"sugarss": "*",
|
||||||
|
"terser": "^5.4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/node": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"less": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"lightningcss": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sass": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"stylus": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sugarss": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"terser": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "@xo/node-demo",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node index.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@xo/primitives": "file:../../packages/primitives",
|
||||||
|
"@xo/network-wallet": "file:../../packages/network-wallet"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vite": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
These will be removed (or moved) later, but please leave them for now.
|
||||||
|
|
||||||
|
These are experiments that I (Jim) am doing on Reactivity and I don't want to lose this code.
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import React, { useSyncExternalStore, useMemo } from 'react';
|
||||||
|
import { Blockchain, WalletHD } from '../wallet/index.js';
|
||||||
|
import { WalletP2PKHReact, useWalletP2PKH } from './wallet-p2pkh-react.js';
|
||||||
|
import { HdPrivateNodeValid } from '@bitauth/libauth';
|
||||||
|
|
||||||
|
class WalletHDReact extends WalletHD<WalletP2PKHReact> {
|
||||||
|
private rWallets: Array<WalletP2PKHReact> = [];
|
||||||
|
private rShouldMonitor: boolean = false;
|
||||||
|
private walletsListeners: Set<() => void> = new Set();
|
||||||
|
private shouldMonitorListeners: Set<() => void> = new Set();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
node: HdPrivateNodeValid,
|
||||||
|
electrum: Blockchain,
|
||||||
|
walletFactory = (privateKeyBytes: Uint8Array, electrum: Blockchain) =>
|
||||||
|
new WalletP2PKHReact(privateKeyBytes, electrum)
|
||||||
|
) {
|
||||||
|
super(node, electrum, walletFactory);
|
||||||
|
|
||||||
|
this.events.on('walletsUpdated', (wallets) => {
|
||||||
|
this.rWallets = wallets;
|
||||||
|
this.setupWalletListeners();
|
||||||
|
this.walletsListeners.forEach((listener) => listener());
|
||||||
|
});
|
||||||
|
|
||||||
|
this.events.on('shouldMonitorUpdated', (shouldMonitor) => {
|
||||||
|
this.rShouldMonitor = shouldMonitor;
|
||||||
|
this.shouldMonitorListeners.forEach((listener) => listener());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribeToWallets = (listener: () => void) => {
|
||||||
|
this.walletsListeners.add(listener);
|
||||||
|
return () => {
|
||||||
|
this.walletsListeners.delete(listener);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
subscribeToShouldMonitor = (listener: () => void) => {
|
||||||
|
this.shouldMonitorListeners.add(listener);
|
||||||
|
return () => {
|
||||||
|
this.shouldMonitorListeners.delete(listener);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
getWallets = () => {
|
||||||
|
return this.rWallets;
|
||||||
|
};
|
||||||
|
|
||||||
|
getShouldMonitor = () => {
|
||||||
|
return this.rShouldMonitor;
|
||||||
|
};
|
||||||
|
|
||||||
|
private setupWalletListeners() {
|
||||||
|
this.rWallets.forEach((wallet) => {
|
||||||
|
wallet.subscribeToUnspents(() => {
|
||||||
|
this.walletsListeners.forEach((listener) => listener());
|
||||||
|
});
|
||||||
|
wallet.subscribeToTransactions(() => {
|
||||||
|
this.walletsListeners.forEach((listener) => listener());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useWalletHD(node: HdPrivateNodeValid, electrum: Blockchain) {
|
||||||
|
const walletHD = useMemo(
|
||||||
|
() => new WalletHDReact(node, electrum),
|
||||||
|
[node, electrum]
|
||||||
|
);
|
||||||
|
|
||||||
|
const wallets = useSyncExternalStore(
|
||||||
|
walletHD.subscribeToWallets,
|
||||||
|
walletHD.getWallets
|
||||||
|
);
|
||||||
|
|
||||||
|
const shouldMonitor = useSyncExternalStore(
|
||||||
|
walletHD.subscribeToShouldMonitor,
|
||||||
|
walletHD.getShouldMonitor
|
||||||
|
);
|
||||||
|
|
||||||
|
const balance = useMemo(() => {
|
||||||
|
return wallets.reduce((total, wallet) => total + wallet.getBalance(), 0);
|
||||||
|
}, [wallets]);
|
||||||
|
|
||||||
|
return { walletHD, wallets, shouldMonitor, balance };
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import { useSyncExternalStore } from 'react';
|
||||||
|
import { Transaction } from '../primitives/index.js';
|
||||||
|
import {
|
||||||
|
WalletP2PKH,
|
||||||
|
Blockchain,
|
||||||
|
AddressListUnspent,
|
||||||
|
} from '../wallet/index.js';
|
||||||
|
|
||||||
|
export function useWalletP2PKH(
|
||||||
|
privateKeyBytes: Uint8Array,
|
||||||
|
electrum: Blockchain
|
||||||
|
) {
|
||||||
|
const wallet = React.useMemo(
|
||||||
|
() => new WalletP2PKHReact(privateKeyBytes, electrum),
|
||||||
|
[privateKeyBytes, electrum]
|
||||||
|
);
|
||||||
|
|
||||||
|
const unspents = useSyncExternalStore(
|
||||||
|
wallet.subscribeToUnspents,
|
||||||
|
wallet.getUnspents
|
||||||
|
);
|
||||||
|
|
||||||
|
const transactions = useSyncExternalStore(
|
||||||
|
wallet.subscribeToTransactions,
|
||||||
|
wallet.getTransactions
|
||||||
|
);
|
||||||
|
|
||||||
|
const balance = React.useMemo(() => {
|
||||||
|
return unspents.reduce((total, unspent) => total + unspent.value, 0);
|
||||||
|
}, [unspents]);
|
||||||
|
|
||||||
|
return { wallet, unspents, transactions, balance };
|
||||||
|
}
|
||||||
|
|
||||||
|
class WalletP2PKHReact extends WalletP2PKH {
|
||||||
|
private rUnspents: AddressListUnspent['response'] = [];
|
||||||
|
private rTransactions: Array<Transaction> = [];
|
||||||
|
private unspentsListeners: Set<() => void> = new Set();
|
||||||
|
private transactionsListeners: Set<() => void> = new Set();
|
||||||
|
|
||||||
|
constructor(privateKeyBytes: Uint8Array, blockchain: Blockchain) {
|
||||||
|
super(privateKeyBytes, blockchain);
|
||||||
|
this.events.on('unspentsUpdated', (unspents) => {
|
||||||
|
this.rUnspents = unspents;
|
||||||
|
this.unspentsListeners.forEach((listener) => listener());
|
||||||
|
});
|
||||||
|
this.events.on('transactionsUpdated', (transactions) => {
|
||||||
|
this.rTransactions = transactions;
|
||||||
|
this.transactionsListeners.forEach((listener) => listener());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribeToUnspents = (listener: () => void) => {
|
||||||
|
this.unspentsListeners.add(listener);
|
||||||
|
return () => {
|
||||||
|
this.unspentsListeners.delete(listener);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
subscribeToTransactions = (listener: () => void) => {
|
||||||
|
this.transactionsListeners.add(listener);
|
||||||
|
return () => {
|
||||||
|
this.transactionsListeners.delete(listener);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
getUnspents = () => {
|
||||||
|
return this.rUnspents;
|
||||||
|
};
|
||||||
|
|
||||||
|
getTransactions = () => {
|
||||||
|
return this.rTransactions;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { writable, derived } from 'svelte/store';
|
||||||
|
import type { Writable, Readable } from 'svelte/store';
|
||||||
|
import { WalletP2PKH, WalletHD } from '../wallet/index.js'; // Adjust import path as needed
|
||||||
|
import type { AddressListUnspent, Blockchain } from '../wallet/index.js'; // Adjust import path as needed
|
||||||
|
import type { Transaction } from '../primitives/index.js';
|
||||||
|
import type { HdPrivateNodeValid } from '@bitauth/libauth';
|
||||||
|
|
||||||
|
export class WalletP2PKHSvelte extends WalletP2PKH {
|
||||||
|
// Svelte stores
|
||||||
|
public unspents: Writable<AddressListUnspent['response']> = writable([]);
|
||||||
|
public transactions: Writable<Array<Transaction>> = writable([]);
|
||||||
|
|
||||||
|
// Derived store for balance
|
||||||
|
public balance: Readable<number> = derived(this.unspents, ($unspents) =>
|
||||||
|
$unspents.reduce((total, unspent) => total + unspent.value, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
constructor(privateKeyBytes: Uint8Array, electrum: Blockchain) {
|
||||||
|
super(privateKeyBytes, electrum);
|
||||||
|
this.events.on('unspentsUpdated', (unspents) => {
|
||||||
|
this.unspents.set(unspents);
|
||||||
|
});
|
||||||
|
this.events.on('transactionsUpdated', (transactions) => {
|
||||||
|
this.transactions.set(transactions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useWalletP2PKHSvelte(
|
||||||
|
privateKeyBytes: Uint8Array,
|
||||||
|
electrum: Blockchain
|
||||||
|
): WalletP2PKHSvelte {
|
||||||
|
return new WalletP2PKHSvelte(privateKeyBytes, electrum);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WalletHDSvelte extends WalletHD<WalletP2PKHSvelte> {
|
||||||
|
// Svelte stores
|
||||||
|
public shouldMonitor: Writable<boolean> = writable(false);
|
||||||
|
public wallets: Writable<Array<WalletP2PKHSvelte>> = writable([]);
|
||||||
|
|
||||||
|
// Derived store for total balance
|
||||||
|
public balance: Readable<number> = derived(this.wallets, ($wallets) =>
|
||||||
|
$wallets.reduce((total, wallet) => {
|
||||||
|
let walletBalance = 0;
|
||||||
|
wallet.balance.subscribe((value) => (walletBalance = value))();
|
||||||
|
return total + walletBalance;
|
||||||
|
}, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
node: HdPrivateNodeValid,
|
||||||
|
electrum: Blockchain,
|
||||||
|
walletFactory = useWalletP2PKHSvelte
|
||||||
|
) {
|
||||||
|
super(node, electrum, walletFactory);
|
||||||
|
this.events.on('walletsUpdated', (wallets) => this.wallets.set(wallets));
|
||||||
|
this.events.on('shouldMonitorUpdated', (shouldMonitor) =>
|
||||||
|
this.shouldMonitor.set(shouldMonitor)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
-35
@@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"tags": {
|
|
||||||
"allowUnknownTags": false
|
|
||||||
},
|
|
||||||
"source": {
|
|
||||||
"include": ["lib/", "./README.md"],
|
|
||||||
"includePattern": "\\.(jsx|js|ts|tsx)$",
|
|
||||||
"excludePattern": "(node_modules/|docs)"
|
|
||||||
},
|
|
||||||
"plugins": ["node_modules/better-docs/typescript"],
|
|
||||||
"opts": {
|
|
||||||
"template": "node_modules/docdash",
|
|
||||||
"encoding": "utf8",
|
|
||||||
"destination": "public/",
|
|
||||||
"recurse": true,
|
|
||||||
"verbose": false
|
|
||||||
},
|
|
||||||
"templates": {
|
|
||||||
"cleverLinks": false,
|
|
||||||
"monospaceLinks": false,
|
|
||||||
"default": {
|
|
||||||
"outputSourceFiles": true,
|
|
||||||
"includeDate": true,
|
|
||||||
"useLongnameInNav": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"docdash": {
|
|
||||||
"collapse": false,
|
|
||||||
"static": true,
|
|
||||||
"sort": true,
|
|
||||||
"search": false,
|
|
||||||
"private": false,
|
|
||||||
"typedefs": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||||
|
"packages": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
|
"version": "0.0.0"
|
||||||
|
}
|
||||||
Generated
+10947
File diff suppressed because it is too large
Load Diff
+18
-20
@@ -7,16 +7,20 @@
|
|||||||
"module": "dist/index.mjs.js",
|
"module": "dist/index.mjs.js",
|
||||||
"typings": "dist/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
"workspaces": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run clean && npm run compile && npm run rollup && npm run post-processing",
|
"build": "lerna run build",
|
||||||
"compile": "tsc",
|
"build:primitives": "lerna run build --scope=@xo/primitives --include-dependencies",
|
||||||
"clean": "del dist",
|
"build:wallet": "lerna run build --scope=@xo/wallet --include-dependencies",
|
||||||
"post-processing": "del ./dist/module",
|
"build:vue": "lerna run build --scope=@xo/vue --include-dependencies",
|
||||||
"docs": "jsdoc -c jsdoc.json",
|
"docs:api": "typedoc --skipErrorChecking",
|
||||||
|
"docs:dev": "npm run docs:api && vitepress dev docs",
|
||||||
|
"docs:build": "npm run docs:api && vitepress build docs",
|
||||||
|
"docs:preview": "npm run docs:api && vitepress preview docs",
|
||||||
"format": "prettier --write \"**/*.{js,ts,md,json}\" --ignore-path .gitignore",
|
"format": "prettier --write \"**/*.{js,ts,md,json}\" --ignore-path .gitignore",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"rollup": "rollup -c",
|
|
||||||
"spellcheck": "cspell '**'",
|
|
||||||
"test": "ava"
|
"test": "ava"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -36,25 +40,19 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://gitlab.com/GeneralProtocols/xo/stack",
|
"homepage": "https://gitlab.com/GeneralProtocols/xo/stack",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bitauth/libauth": "^3.0.0",
|
"@bitauth/libauth": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^6.3.0",
|
"@typescript-eslint/eslint-plugin": "^6.3.0",
|
||||||
"@typescript-eslint/parser": "^6.3.0",
|
"@typescript-eslint/parser": "^6.3.0",
|
||||||
"eslint": "^8.10.0",
|
"eslint": "^8.10.0",
|
||||||
"eslint-config-prettier": "^8.1.0",
|
"eslint-config-prettier": "^8.1.0",
|
||||||
|
"lerna": "^8.1.8",
|
||||||
"prettier": "^2.5.1",
|
"prettier": "^2.5.1",
|
||||||
"rollup": "^3.29.2",
|
"typedoc": "^0.26.6",
|
||||||
"rollup-plugin-dts": "^6.0.2",
|
"typedoc-plugin-markdown": "^4.2.6",
|
||||||
"tsc-watch": "^6.0.4",
|
"typedoc-vitepress-theme": "^1.0.1",
|
||||||
"typescript": "^5.1.3"
|
"typescript": "^5.1.3",
|
||||||
},
|
"vitepress": "^1.3.4"
|
||||||
"ava": {
|
|
||||||
"extensions": {
|
|
||||||
"ts": "module"
|
|
||||||
},
|
|
||||||
"nodeArguments": [
|
|
||||||
"--loader=ts-node/esm"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# XO Primitives
|
||||||
|
|
||||||
|
TODO
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "@xo/primitives",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "XO Stack Primitives",
|
||||||
|
"type": "module",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"module": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"build-old": "rollup -c"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
import {
|
||||||
|
binToHex,
|
||||||
|
hexToBin,
|
||||||
|
isHex,
|
||||||
|
base64ToBin,
|
||||||
|
binToBase64,
|
||||||
|
isBase64,
|
||||||
|
binToUtf8,
|
||||||
|
utf8ToBin,
|
||||||
|
bigIntToBinUint64LE,
|
||||||
|
bigIntToBinUintLE,
|
||||||
|
binToBigIntUintLE,
|
||||||
|
} from '@bitauth/libauth';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bytes Primitive.
|
||||||
|
*/
|
||||||
|
export class Bytes {
|
||||||
|
public readonly bytes: Uint8Array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate Bytes from a Uint8Array.
|
||||||
|
*
|
||||||
|
* @param bytes {Uint8Array} The bytes to use.
|
||||||
|
*/
|
||||||
|
constructor(bytes: Uint8Array) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates bytes from a Base64 string.
|
||||||
|
*
|
||||||
|
* @param utf8 {string} The Base64 string.
|
||||||
|
*
|
||||||
|
* @throws {Error} If Base64 is invalid.
|
||||||
|
*
|
||||||
|
* @returns {Bytes} Instance of Bytes.
|
||||||
|
*/
|
||||||
|
public static fromBase64(base64: string): Bytes {
|
||||||
|
// If the Base64 is invalid, throw an error.
|
||||||
|
if (!isBase64(base64)) {
|
||||||
|
throw new Error('Invalid base64 string');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Bytes(base64ToBin(base64));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates bytes from a BigInt (LE encoded).
|
||||||
|
*
|
||||||
|
* @param number {number} The bigint number.
|
||||||
|
*
|
||||||
|
* @throws {Error} If number is invalid.
|
||||||
|
*
|
||||||
|
* @returns {Bytes} Instance of Bytes.
|
||||||
|
*/
|
||||||
|
public static fromBigInt(number: bigint): Bytes {
|
||||||
|
return new Bytes(bigIntToBinUintLE(number));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates bytes from a BigInt (64 Bit LE encoded).
|
||||||
|
*
|
||||||
|
* @param number {number} The bigint number.
|
||||||
|
*
|
||||||
|
* @throws {Error} If number is invalid.
|
||||||
|
*
|
||||||
|
* @returns {Bytes} Instance of Bytes.
|
||||||
|
*/
|
||||||
|
public static fromBigInt64(number: bigint): Bytes {
|
||||||
|
return new Bytes(bigIntToBinUint64LE(number));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates bytes from a hex string.
|
||||||
|
*
|
||||||
|
* @param hex {string} The hex string.
|
||||||
|
*
|
||||||
|
* @throws {Error} If hex is invalid.
|
||||||
|
*
|
||||||
|
* @returns {Bytes} Instance of Bytes.
|
||||||
|
*/
|
||||||
|
public static fromHex(hex: string): Bytes {
|
||||||
|
// If the hex is invalid, throw an error.
|
||||||
|
if (!isHex(hex)) {
|
||||||
|
throw new Error('Invalid hexidecimal string');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Bytes(hexToBin(hex));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates bytes from a UTF8 string.
|
||||||
|
*
|
||||||
|
* @param utf8 {string} The UTF8 string.
|
||||||
|
*
|
||||||
|
* @returns {Bytes} Instance of Bytes.
|
||||||
|
*/
|
||||||
|
public static fromUtf8(utf8: string): Bytes {
|
||||||
|
return new Bytes(utf8ToBin(utf8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return bytes as a Base64 string.
|
||||||
|
*
|
||||||
|
* @returns {string} Bytes as a Base64 string.
|
||||||
|
*/
|
||||||
|
public toBase64(): string {
|
||||||
|
return binToBase64(this.bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public toBigInt(): bigint {
|
||||||
|
return binToBigIntUintLE(this.bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return bytes as a hex string.
|
||||||
|
*
|
||||||
|
* @returns {string} Bytes as a hex string.
|
||||||
|
*/
|
||||||
|
public toHex(): string {
|
||||||
|
return binToHex(this.bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return bytes as a UTF8 string
|
||||||
|
*
|
||||||
|
* @returns {string} Bytes as a UTF8 string.
|
||||||
|
*/
|
||||||
|
public toUtf8(): string {
|
||||||
|
return binToUtf8(this.bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return bytes as a Uint8Array
|
||||||
|
*
|
||||||
|
* @returns {Uint8Array} Bytes as a Uint8Array.
|
||||||
|
*/
|
||||||
|
public toBytes(): Uint8Array {
|
||||||
|
return this.bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import {
|
||||||
|
ripemd160,
|
||||||
|
sha256,
|
||||||
|
} from '@bitauth/libauth';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crypto Module.
|
||||||
|
*/
|
||||||
|
export class Crypto
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* SHA256 hash the given input
|
||||||
|
*
|
||||||
|
* @param input {Uint8Array} The input to hash.
|
||||||
|
*
|
||||||
|
* @returns {Uint8Array} The SHA256 Hash of the given input.
|
||||||
|
*/
|
||||||
|
public static sha256(input: Uint8Array): Uint8Array
|
||||||
|
{
|
||||||
|
return sha256.hash(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RIPEMD160 hash the given input
|
||||||
|
*
|
||||||
|
* @param input {Uint8Array} The input to hash.
|
||||||
|
*
|
||||||
|
* @returns {Uint8Array} The RIPEMD160 Hash of the given input.
|
||||||
|
*/
|
||||||
|
public static ripemd160(input: Uint8Array): Uint8Array
|
||||||
|
{
|
||||||
|
return ripemd160.hash(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Double SHA256 hash the given input
|
||||||
|
*
|
||||||
|
* @param input {Uint8Array} The input to hash.
|
||||||
|
*
|
||||||
|
* @returns {Uint8Array} The Double SHA256 Hash of the given input.
|
||||||
|
*/
|
||||||
|
public static hash256(input: Uint8Array): Uint8Array
|
||||||
|
{
|
||||||
|
return sha256.hash(sha256.hash(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RIPEMD160 and then SHA256 hash the given input
|
||||||
|
*
|
||||||
|
* @param input {Uint16Array} The input to hash.
|
||||||
|
*
|
||||||
|
* @returns {Uint8Array} The RIPEMD160+SHA256 Hash of the given input.
|
||||||
|
*/
|
||||||
|
public static hash160(input: Uint8Array): Uint8Array
|
||||||
|
{
|
||||||
|
return ripemd160.hash(sha256.hash(input));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
export * from './address.js';
|
export * from './address.js';
|
||||||
|
export * from './bytes.js';
|
||||||
|
export * from './crypto.js';
|
||||||
export * from './hd-private-node.js';
|
export * from './hd-private-node.js';
|
||||||
export * from './hd-public-node.js';
|
export * from './hd-public-node.js';
|
||||||
export * from './private-key.js';
|
export * from './private-key.js';
|
||||||
export * from './public-key.js';
|
export * from './public-key.js';
|
||||||
export * from './satoshis.js';
|
export * from './satoshis.js';
|
||||||
|
export * from './script.js';
|
||||||
export * from './transaction.js';
|
export * from './transaction.js';
|
||||||
@@ -89,7 +89,7 @@ export class Satoshis {
|
|||||||
*/
|
*/
|
||||||
public static roundToDigits(numberToRound: number, digits: number): number {
|
public static roundToDigits(numberToRound: number, digits: number): number {
|
||||||
// Set the options of the Number Format object.
|
// Set the options of the Number Format object.
|
||||||
const options = {
|
const options: Intl.NumberFormatOptions = {
|
||||||
style: 'decimal',
|
style: 'decimal',
|
||||||
minimumFractionDigits: digits,
|
minimumFractionDigits: digits,
|
||||||
maximumFractionDigits: digits,
|
maximumFractionDigits: digits,
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
import {
|
||||||
|
assembleBytecodeBCH,
|
||||||
|
disassembleBytecodeBCH,
|
||||||
|
base58AddressToLockingBytecode,
|
||||||
|
cashAddressToLockingBytecode,
|
||||||
|
binToHex,
|
||||||
|
hexToBin,
|
||||||
|
isHex,
|
||||||
|
} from '@bitauth/libauth';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Script Entity.
|
||||||
|
*/
|
||||||
|
export class Script {
|
||||||
|
public readonly bytes: Uint8Array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new Script
|
||||||
|
*
|
||||||
|
* @param bytes {Uint8Array} The raw bytes of the Script.
|
||||||
|
*/
|
||||||
|
constructor(bytes: Uint8Array) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Script Entity from the given Assembly String.
|
||||||
|
*
|
||||||
|
* @param asm {string} String of assembly code.
|
||||||
|
*
|
||||||
|
* @throws {Error} If script cannot be decoded.
|
||||||
|
*
|
||||||
|
* @returns {Script} The created Script Entity.
|
||||||
|
*/
|
||||||
|
public static fromASM(asm: string): Script {
|
||||||
|
// Attempt to convert the given ASM to bytecode.
|
||||||
|
const assembleResult = assembleBytecodeBCH(asm);
|
||||||
|
|
||||||
|
// If a string is returned, this indicates an error...
|
||||||
|
if (typeof assembleResult === 'string') {
|
||||||
|
throw new Error(assembleResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the success flag is not marked, this indicates an error...
|
||||||
|
if (!assembleResult.success) {
|
||||||
|
throw new Error('Could not assemble bytecode from assembly.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return new Script Entity from the assembled bytecode.
|
||||||
|
return new Script(assembleResult.bytecode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Script Entity from the given bytes (as hexadecimal string).
|
||||||
|
*
|
||||||
|
* @param hex {string} Raw script bytes encoded as hexadecimal.
|
||||||
|
*
|
||||||
|
* @throws {Error} If script cannot be decoded.
|
||||||
|
*
|
||||||
|
* @returns {Script} The created Script Entity.
|
||||||
|
*/
|
||||||
|
public static fromHex(hex: string): Script {
|
||||||
|
// Ensure that the given string is hex.
|
||||||
|
if (!isHex(hex)) {
|
||||||
|
throw new Error(`The given string (${hex}) is not valid hexadecimal.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conver the given hex to binary (Uint8Array).
|
||||||
|
const scriptBin = hexToBin(hex);
|
||||||
|
|
||||||
|
// Return new Script entity constructed from the binary.
|
||||||
|
return new Script(scriptBin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Script Entity from the given CashAddr.
|
||||||
|
*
|
||||||
|
* @param cashAddr {string} The Address in CashAddr format.
|
||||||
|
*
|
||||||
|
* @throws {Error} If address cannot be decoded.
|
||||||
|
*
|
||||||
|
* @returns {Script} The created Script Entity.
|
||||||
|
*/
|
||||||
|
public static fromCashAddr(cashAddr: string): Script {
|
||||||
|
const decodeResult = cashAddressToLockingBytecode(cashAddr);
|
||||||
|
|
||||||
|
if (typeof decodeResult === 'string') {
|
||||||
|
throw new Error(decodeResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Script(decodeResult.bytecode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Script Entity from the given Legacy Address.
|
||||||
|
*
|
||||||
|
* @param legacyAddress {string} The Address in Legacy format.
|
||||||
|
*
|
||||||
|
* @throws {Error} If address cannot be decoded.
|
||||||
|
*
|
||||||
|
* @returns {Script} The created Script Entity.
|
||||||
|
*/
|
||||||
|
public static fromLegacyAddress(legacyAddress: string): Script {
|
||||||
|
const decodeResult = base58AddressToLockingBytecode(legacyAddress);
|
||||||
|
|
||||||
|
if (typeof decodeResult === 'string') {
|
||||||
|
throw new Error(decodeResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Script(decodeResult.bytecode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert this script to a human-readable string of assembly.
|
||||||
|
*
|
||||||
|
* @returns {string} Human-readable assembly.
|
||||||
|
*/
|
||||||
|
public toASM(joinWith = '\n'): string {
|
||||||
|
const disassembledBytecode = disassembleBytecodeBCH(this.bytes);
|
||||||
|
|
||||||
|
if (joinWith) {
|
||||||
|
return disassembledBytecode.split(' ').join(joinWith);
|
||||||
|
}
|
||||||
|
|
||||||
|
return disassembledBytecode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the raw bytecode for this script.
|
||||||
|
*
|
||||||
|
* @returns {Uint8Array} The compiled bytes.
|
||||||
|
*/
|
||||||
|
public toBytes(): Uint8Array {
|
||||||
|
return this.bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the raw bytecode for this script as a hex string.
|
||||||
|
*
|
||||||
|
* @returns {string} The compiled bytes as a hex string.
|
||||||
|
*/
|
||||||
|
public toHex(): string {
|
||||||
|
return binToHex(this.bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# XO Wallet
|
||||||
|
|
||||||
|
TODO
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "@xo/vue",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "XO Stack Wallet - Vue",
|
||||||
|
"type": "module",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"module": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"build-old": "rollup -c",
|
||||||
|
"prepublishOnly": "npm run build"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@xo/primitives": "^0.0.1",
|
||||||
|
"@xo/wallet": "^0.0.1",
|
||||||
|
"vue": "^3.4.38"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import { ElectrumService } from 'src/services/electrum.js';
|
import { Blockchain, WalletHD } from '@xo/wallet';
|
||||||
import { WalletHD } from 'src/libcash/wallet/index.js';
|
|
||||||
import { WalletP2PKHVue, useWalletP2PKHVue } from './wallet-p2pkh-vue.js';
|
import { WalletP2PKHVue, useWalletP2PKHVue } from './wallet-p2pkh-vue.js';
|
||||||
|
|
||||||
import { computed, ref, shallowRef } from 'vue';
|
import { computed, ref, shallowRef } from 'vue';
|
||||||
@@ -21,7 +20,7 @@ export class WalletHDVue extends WalletHD<WalletP2PKHVue> {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
node: HdPrivateNodeValid,
|
node: HdPrivateNodeValid,
|
||||||
electrum: ElectrumService,
|
electrum: Blockchain,
|
||||||
walletFactory = useWalletP2PKHVue
|
walletFactory = useWalletP2PKHVue
|
||||||
) {
|
) {
|
||||||
super(node, electrum, walletFactory);
|
super(node, electrum, walletFactory);
|
||||||
@@ -1,11 +1,18 @@
|
|||||||
import { WalletP2PKH } from 'src/libcash/wallet/index.js';
|
import { Transaction } from '@xo/primitives';
|
||||||
|
import { type AddressListUnspent, Blockchain, WalletP2PKH } from '@xo/wallet';
|
||||||
import { type AddressListUnspent } from 'src/services/electrum-types';
|
|
||||||
import { ElectrumService } from 'src/services/electrum.js';
|
|
||||||
import { Transaction } from 'src/libcash/primitives/index.js';
|
|
||||||
|
|
||||||
import { computed, shallowRef } from 'vue';
|
import { computed, shallowRef } from 'vue';
|
||||||
|
/**
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const walletP2PKH = WalletP2PKHVue.fromMnemonic('12 words');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Reactive variables are prefixed with `r`.
|
||||||
|
* ```vue
|
||||||
|
* <div>{{ walletP2PKH.rBalance.value }}</div>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export class WalletP2PKHVue extends WalletP2PKH {
|
export class WalletP2PKHVue extends WalletP2PKH {
|
||||||
// Reactive State.
|
// Reactive State.
|
||||||
public rUnspents = shallowRef<AddressListUnspent['response']>([]);
|
public rUnspents = shallowRef<AddressListUnspent['response']>([]);
|
||||||
@@ -19,7 +26,7 @@ export class WalletP2PKHVue extends WalletP2PKH {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor(privateKeyBytes: Uint8Array, electrum: ElectrumService) {
|
constructor(privateKeyBytes: Uint8Array, electrum: Blockchain) {
|
||||||
super(privateKeyBytes, electrum);
|
super(privateKeyBytes, electrum);
|
||||||
|
|
||||||
this.events.on('unspentsUpdated', (unspents) => {
|
this.events.on('unspentsUpdated', (unspents) => {
|
||||||
@@ -34,7 +41,7 @@ export class WalletP2PKHVue extends WalletP2PKH {
|
|||||||
|
|
||||||
export function useWalletP2PKHVue(
|
export function useWalletP2PKHVue(
|
||||||
privateKeyBytes: Uint8Array,
|
privateKeyBytes: Uint8Array,
|
||||||
electrum: ElectrumService
|
electrum: Blockchain
|
||||||
): WalletP2PKHVue {
|
): WalletP2PKHVue {
|
||||||
return new WalletP2PKHVue(privateKeyBytes, electrum);
|
return new WalletP2PKHVue(privateKeyBytes, electrum);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# XO Wallet
|
||||||
|
|
||||||
|
TODO
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "@xo/wallet",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "XO Stack Wallet",
|
||||||
|
"type": "module",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"module": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"build-old": "rollup -c",
|
||||||
|
"prepublishOnly": "npm run build"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@electrum-cash/network": "^3.3.0",
|
||||||
|
"@xo/primitives": "^0.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './utils/index.js';
|
||||||
|
export * from './wallet/index.js';
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
// TODO: I think @monsterbitar (Jonathan) is working on something like this too.
|
||||||
|
// So I haven't bothered making this complete. We'll just use his once it's done.
|
||||||
|
// Or, if he's busy with other stuff, we can complete this and create an MR into Electrum-Cash.
|
||||||
|
|
||||||
|
import type { RequestResponse } from '@electrum-cash/network';
|
||||||
|
|
||||||
|
// TODO: This should be imported from electrum-cash library.
|
||||||
|
// But it is not exported yet.
|
||||||
|
export type RPCParameter = string | number | boolean | null;
|
||||||
|
|
||||||
|
export interface ElectrumRequest {
|
||||||
|
method: string;
|
||||||
|
params: Array<RPCParameter>;
|
||||||
|
response: RequestResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddressGetBalance extends ElectrumRequest {
|
||||||
|
method: 'blockchain.address.get_balance';
|
||||||
|
params: [string];
|
||||||
|
response: {
|
||||||
|
confirmed: number;
|
||||||
|
unconfirmed: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddressGetHistory extends ElectrumRequest {
|
||||||
|
method: 'blockchain.address.get_history';
|
||||||
|
// TODO: RPCParameter accepts a null type, but this should probably be changed to undefined instead.
|
||||||
|
params: [string, number | null, number | null];
|
||||||
|
response: Array<{
|
||||||
|
height: number;
|
||||||
|
tx_hash: string;
|
||||||
|
fee?: number;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddressGetMempool extends ElectrumRequest {
|
||||||
|
method: 'blockchain.address.get_mempool';
|
||||||
|
params: [string];
|
||||||
|
response: Array<{
|
||||||
|
height: number;
|
||||||
|
tx_hash: string;
|
||||||
|
fee?: number;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddressGetScriptHash extends ElectrumRequest {
|
||||||
|
method: 'blockchain.address.get_scripthash';
|
||||||
|
params: [string];
|
||||||
|
response: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddressListUnspent extends ElectrumRequest {
|
||||||
|
method: 'blockchain.address.listunspent';
|
||||||
|
params: [string, 'include_tokens' | 'exclude_tokens' | 'tokens_only'];
|
||||||
|
response: Array<{
|
||||||
|
height: number;
|
||||||
|
token_data?: {
|
||||||
|
amount: string;
|
||||||
|
category: string;
|
||||||
|
nft?: {
|
||||||
|
capability: 'none' | 'mutable' | 'minting';
|
||||||
|
commitment: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
tx_hash: string;
|
||||||
|
tx_pos: number;
|
||||||
|
value: number;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddressSubscribe extends ElectrumRequest {
|
||||||
|
method: 'blockchain.address.subscribe';
|
||||||
|
params: [string];
|
||||||
|
// [Address, Status]
|
||||||
|
response: [string, string | null];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddressUnsubscribe extends ElectrumRequest {
|
||||||
|
method: 'blockchain.address.unsubscribe';
|
||||||
|
params: [string];
|
||||||
|
response: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScriptHashGetBalance extends ElectrumRequest {
|
||||||
|
method: 'blockchain.scripthash.get_balance';
|
||||||
|
params: [string];
|
||||||
|
response: {
|
||||||
|
confirmed: number;
|
||||||
|
unconfirmed: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransactionBroadcast extends ElectrumRequest {
|
||||||
|
method: 'blockchain.transaction.broadcast';
|
||||||
|
params: [string];
|
||||||
|
response: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransactionGet extends ElectrumRequest {
|
||||||
|
method: 'blockchain.transaction.get';
|
||||||
|
params: [string, boolean];
|
||||||
|
response: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransactionGetVerbose extends ElectrumRequest {
|
||||||
|
method: 'blockchain.transaction.get';
|
||||||
|
params: [string, true];
|
||||||
|
response: {
|
||||||
|
// TODO
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransactionSubscribe extends ElectrumRequest {
|
||||||
|
method: 'blockchain.transaction.subscribe';
|
||||||
|
params: [string];
|
||||||
|
response: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransactionUnsubscribe extends ElectrumRequest {
|
||||||
|
method: 'blockchain.transaction.unsubscribe';
|
||||||
|
params: [string];
|
||||||
|
response: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddressNotification {
|
||||||
|
jsonrpc: '2.0';
|
||||||
|
method: 'blockchain.address.subscribe';
|
||||||
|
// [Address, Status]
|
||||||
|
params: [string, string | null];
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import { AddressNotification, ElectrumRequest } from './blockchain-types.js';
|
||||||
|
|
||||||
|
import { ElectrumClient } from '@electrum-cash/network';
|
||||||
|
|
||||||
|
export type AddressCallback = (status: string | null) => void;
|
||||||
|
|
||||||
|
// TODO: Rename this to Blockcain Service and refactor such that it can store local state.
|
||||||
|
// For local state, we'll want to track a tree of dependencies locally.
|
||||||
|
// Might be able to copy whatever structure a proper node uses (DAG?).
|
||||||
|
export class Blockchain {
|
||||||
|
electrumClient!: ElectrumClient;
|
||||||
|
|
||||||
|
// Address subscriptions.
|
||||||
|
addressSubscriptions: { [address: string]: AddressCallback } = {};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public readonly servers: string[],
|
||||||
|
public readonly application = 'BCHApp',
|
||||||
|
public readonly version = '1.5'
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async start(): Promise<void> {
|
||||||
|
// TODO: We want to use a Cluster instead of a Client, but as of 2022-07-07 there are issues with Subscriptions on Cluster.
|
||||||
|
// See: https://gitlab.com/GeneralProtocols/anyhedge/whitelabel/frontend/-/issues/76
|
||||||
|
|
||||||
|
// Iterate over each server in our list of servers.
|
||||||
|
// NOTE: We are still using an Electrum Client due to the above bug.
|
||||||
|
// But, if we cannot connect to the first server, we will try the second (and third if given, etc) as a fallback.
|
||||||
|
for (const electrumServer of this.servers) {
|
||||||
|
// Initialize an Electrum client using the given server.
|
||||||
|
const electrum = new ElectrumClient(
|
||||||
|
this.application,
|
||||||
|
this.version,
|
||||||
|
electrumServer,
|
||||||
|
50004,
|
||||||
|
'wss'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Attempt to connect to this Electrum Server.
|
||||||
|
try {
|
||||||
|
await electrum.connect();
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error);
|
||||||
|
|
||||||
|
// If it fails to connect, try the next server in our list.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the client.
|
||||||
|
this.electrumClient = electrum;
|
||||||
|
|
||||||
|
// Setup notification handler.
|
||||||
|
this.electrumClient.on('notification', this.onNotification.bind(this));
|
||||||
|
|
||||||
|
// Return to prevent further execution.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw an error if we failed to connect to any of our Electrum Servers.
|
||||||
|
throw new Error(
|
||||||
|
'Failed to connect to Electrum. Please try restarting your browser and ensure you are currently connected to the internet.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async request<T extends ElectrumRequest>(
|
||||||
|
endpoint: T['method'],
|
||||||
|
...params: T['params']
|
||||||
|
): Promise<T['response']> {
|
||||||
|
const response = await this.electrumClient.request(endpoint, ...params);
|
||||||
|
|
||||||
|
if (response instanceof Error) {
|
||||||
|
throw response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
async subscribeAddress(address: string, callback: AddressCallback) {
|
||||||
|
await this.electrumClient.subscribe(
|
||||||
|
'blockchain.address.subscribe',
|
||||||
|
address
|
||||||
|
);
|
||||||
|
|
||||||
|
this.addressSubscriptions[address] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
async unsubscribeAddress(address: string, _callback: AddressCallback) {
|
||||||
|
if (!this.addressSubscriptions[address]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete this.addressSubscriptions[address];
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.electrumClient.unsubscribe(
|
||||||
|
'blockchain.address.unsubscribe',
|
||||||
|
address
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onNotification(data: AddressNotification) {
|
||||||
|
// Handle Address notification.
|
||||||
|
if (data.method === 'blockchain.address.subscribe') {
|
||||||
|
const address = data.params[0];
|
||||||
|
const status = data.params[1];
|
||||||
|
const subscription = this.addressSubscriptions[address];
|
||||||
|
|
||||||
|
if (!subscription) {
|
||||||
|
console.warn(
|
||||||
|
`Notification for address ${address} subscribed to, but has no handler`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger the subscription's callback.
|
||||||
|
subscription(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { ElectrumService } from 'src/services/electrum.js';
|
import { Blockchain } from './blockchain.js';
|
||||||
|
|
||||||
export type ServiceConfig<BlockchainType, WalletType> = {
|
export type ServiceConfig<BlockchainType, WalletType> = {
|
||||||
createBlockchain: () => BlockchainType;
|
createBlockchain: () => BlockchainType;
|
||||||
createWallet: (
|
createWallet: (
|
||||||
privateKeyBytes: Uint8Array,
|
privateKeyBytes: Uint8Array,
|
||||||
electrum: ElectrumService
|
electrum: Blockchain
|
||||||
) => WalletType;
|
) => WalletType;
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export * from './blockchain.js';
|
||||||
|
export * from './blockchain-types.js';
|
||||||
|
export * from './storage.js';
|
||||||
|
export * from './wallet-hd.js';
|
||||||
|
export * from './wallet-p2pkh.js';
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* Storage should support Adapters.
|
||||||
|
* 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).
|
||||||
|
*/
|
||||||
|
export class Storage {
|
||||||
|
constructor() {
|
||||||
|
console.log('TODO');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { PrivateKey, Transaction } from 'src/libcash/primitives/index.js';
|
import { type AddressListUnspent } from './blockchain-types.js';
|
||||||
import { EventEmitter } from 'src/libcash/utils/index.js';
|
import { Blockchain } from './blockchain.js';
|
||||||
import { type AddressListUnspent } from 'src/services/electrum-types';
|
|
||||||
import { ElectrumService } from 'src/services/electrum';
|
import { PrivateKey, Transaction } from '@xo/primitives';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type CompilerBCH,
|
type CompilerBCH,
|
||||||
@@ -17,9 +17,9 @@ export type InputTemplateBCH = InputTemplate<
|
|||||||
|
|
||||||
export abstract class WalletBase extends PrivateKey {
|
export abstract class WalletBase extends PrivateKey {
|
||||||
// Dependencies/Services
|
// Dependencies/Services
|
||||||
public electrum: ElectrumService;
|
public electrum: Blockchain;
|
||||||
|
|
||||||
constructor(privateKeyBytes: Uint8Array, electrum: ElectrumService) {
|
constructor(privateKeyBytes: Uint8Array, electrum: Blockchain) {
|
||||||
super(privateKeyBytes);
|
super(privateKeyBytes);
|
||||||
this.electrum = electrum;
|
this.electrum = electrum;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Import the Stamp class to derive the private keys
|
// Import the Stamp class to derive the private keys
|
||||||
import { HDPrivateNode } from 'src/libcash/primitives/index.js';
|
import { HDPrivateNode } from '@xo/primitives';
|
||||||
import { EventEmitter } from 'src/libcash/utils/index.js';
|
import { EventEmitter } from '../utils/index.js';
|
||||||
import { ElectrumService } from 'src/services/electrum';
|
import { Blockchain } from './blockchain.js';
|
||||||
import {
|
import {
|
||||||
WalletP2PKH,
|
WalletP2PKH,
|
||||||
WalletP2PKHFactory,
|
WalletP2PKHFactory,
|
||||||
@@ -36,7 +36,7 @@ export class WalletHD<
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public node: HdPrivateNodeValid,
|
public node: HdPrivateNodeValid,
|
||||||
public electrum: ElectrumService,
|
public electrum: Blockchain,
|
||||||
private walletFactory: WalletP2PKHFactory<WalletType> = useWalletP2PKH
|
private walletFactory: WalletP2PKHFactory<WalletType> = useWalletP2PKH
|
||||||
) {
|
) {
|
||||||
// Instantiate parent class.
|
// Instantiate parent class.
|
||||||
@@ -50,7 +50,7 @@ export class WalletHD<
|
|||||||
static fromMnemonic<T extends WalletHD<any>>(
|
static fromMnemonic<T extends WalletHD<any>>(
|
||||||
this: WalletHDConstructor<T>,
|
this: WalletHDConstructor<T>,
|
||||||
mnemonic: string,
|
mnemonic: string,
|
||||||
electrum: ElectrumService,
|
electrum: Blockchain,
|
||||||
walletFactory?: WalletP2PKHFactory<any>
|
walletFactory?: WalletP2PKHFactory<any>
|
||||||
): T {
|
): T {
|
||||||
// Derive the seed from the mnemonic.
|
// Derive the seed from the mnemonic.
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Transaction } from 'src/libcash/primitives/index.js';
|
import { Transaction } from '@xo/primitives';
|
||||||
import { EventEmitter } from 'src/libcash/utils/index.js';
|
import { EventEmitter } from '../utils/index.js';
|
||||||
import {
|
import {
|
||||||
type AddressListUnspent,
|
type AddressListUnspent,
|
||||||
type AddressGetHistory,
|
type AddressGetHistory,
|
||||||
type TransactionGet,
|
type TransactionGet,
|
||||||
} from 'src/services/electrum-types';
|
} from './blockchain-types.js';
|
||||||
import { ElectrumService } from 'src/services/electrum';
|
import { Blockchain } from './blockchain.js';
|
||||||
|
|
||||||
import { WalletBase } from './wallet-base.js';
|
import { WalletBase } from './wallet-base.js';
|
||||||
|
|
||||||
@@ -20,6 +20,16 @@ export type WalletP2PKHEvents = {
|
|||||||
unspentsUpdated: AddressListUnspent['response'];
|
unspentsUpdated: AddressListUnspent['response'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* // Instantiate P2PKH Wallet.
|
||||||
|
* const walletP2PKH = WalletP2PKH.fromWIF('someWif');
|
||||||
|
*
|
||||||
|
* // Start monitoring the balance.
|
||||||
|
* await walletP2PKH.startMonitoring();
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export class WalletP2PKH extends WalletBase {
|
export class WalletP2PKH extends WalletBase {
|
||||||
// Events.
|
// Events.
|
||||||
public events: EventEmitter<WalletP2PKHEvents> = new EventEmitter();
|
public events: EventEmitter<WalletP2PKHEvents> = new EventEmitter();
|
||||||
@@ -28,7 +38,7 @@ export class WalletP2PKH extends WalletBase {
|
|||||||
public transactions: Array<Transaction> = [];
|
public transactions: Array<Transaction> = [];
|
||||||
public unspents: AddressListUnspent['response'] = [];
|
public unspents: AddressListUnspent['response'] = [];
|
||||||
|
|
||||||
constructor(privateKeyBytes: Uint8Array, electrum: ElectrumService) {
|
constructor(privateKeyBytes: Uint8Array, electrum: Blockchain) {
|
||||||
super(privateKeyBytes, electrum);
|
super(privateKeyBytes, electrum);
|
||||||
|
|
||||||
// Monitor the following properties and emit an event when they change.
|
// Monitor the following properties and emit an event when they change.
|
||||||
@@ -162,12 +172,12 @@ export class WalletP2PKH extends WalletBase {
|
|||||||
|
|
||||||
export type WalletP2PKHFactory<T extends WalletP2PKH = WalletP2PKH> = (
|
export type WalletP2PKHFactory<T extends WalletP2PKH = WalletP2PKH> = (
|
||||||
privateKeyBytes: Uint8Array,
|
privateKeyBytes: Uint8Array,
|
||||||
electrum: ElectrumService
|
electrum: Blockchain
|
||||||
) => T;
|
) => T;
|
||||||
|
|
||||||
export function useWalletP2PKH<T extends WalletP2PKH = WalletP2PKH>(
|
export function useWalletP2PKH<T extends WalletP2PKH = WalletP2PKH>(
|
||||||
privateKeyBytes: Uint8Array,
|
privateKeyBytes: Uint8Array,
|
||||||
electrum: ElectrumService
|
electrum: Blockchain
|
||||||
): T {
|
): T {
|
||||||
return new WalletP2PKH(privateKeyBytes, electrum) as T;
|
return new WalletP2PKH(privateKeyBytes, electrum) as T;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
// Import package.json to reduce name repetition.
|
|
||||||
// eslint-disable-next-line import/extensions
|
|
||||||
import pkg from './package.json';
|
|
||||||
import dts from 'rollup-plugin-dts';
|
|
||||||
|
|
||||||
export default [
|
|
||||||
// Build main module in both ES and CJS
|
|
||||||
{
|
|
||||||
// Specify entry point for building
|
|
||||||
input: 'dist/module/lib/index.js',
|
|
||||||
|
|
||||||
// Omit all dependencies and peer dependencies from the final bundle
|
|
||||||
external: [
|
|
||||||
...Object.keys(pkg.dependencies || {}),
|
|
||||||
...Object.keys(pkg.peerDependencies || {}),
|
|
||||||
],
|
|
||||||
|
|
||||||
// Produce outputs for ES and CJS
|
|
||||||
output: [
|
|
||||||
{ file: pkg.module, format: 'es' },
|
|
||||||
{ file: pkg.main, format: 'cjs' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
// Build type definitions for the library
|
|
||||||
{
|
|
||||||
input: 'dist/module/lib/index.d.ts',
|
|
||||||
output: [{ file: pkg.typings, format: 'es' }],
|
|
||||||
plugins: [dts()],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export * from './wallet-hd.js';
|
|
||||||
export * from './wallet-p2pkh.js';
|
|
||||||
+15
-29
@@ -1,38 +1,24 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
// Target esnext (rollup step will transpile to CJS and EJS)
|
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
|
|
||||||
// Use node as module resolution strategy for best compatibility with dependencies
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
// Set the root directory and output directory
|
|
||||||
"rootDir": "./src",
|
|
||||||
"outDir": "./build/lib",
|
|
||||||
|
|
||||||
// Allow ES modules to be used
|
|
||||||
"esModuleInterop": true,
|
|
||||||
|
|
||||||
// Allow importing .json files in project
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
|
|
||||||
// Generate declarations, declaration maps and sourcemaps
|
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"declarationMap": true,
|
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
|
"outDir": "./dist",
|
||||||
// Use strict Typescript rules
|
"rootDir": "src",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"strictPropertyInitialization": true,
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
// Allow use of ES2017 and DOM features/libraries
|
"baseUrl": ".",
|
||||||
"lib": ["es2017", "dom"]
|
"paths": {
|
||||||
|
"*": [
|
||||||
|
"src/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
"exclude": [
|
||||||
// Exclude these directories from the Typescript transpile
|
"node_modules",
|
||||||
"exclude": ["node_modules/**", "dist/**", "public/**"],
|
"dist"
|
||||||
|
]
|
||||||
// Do not compile upon save - this feature requires tsc-w(atch)
|
|
||||||
"compileOnSave": true
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"entryPoints": [
|
||||||
|
"./packages/primitives/src/index.ts",
|
||||||
|
"./packages/wallet/src/index.ts",
|
||||||
|
"./packages/vue/src/index.ts"
|
||||||
|
],
|
||||||
|
"plugin": [
|
||||||
|
"typedoc-plugin-markdown",
|
||||||
|
"typedoc-vitepress-theme"
|
||||||
|
],
|
||||||
|
"docsRoot": "./docs",
|
||||||
|
"out": "./docs/api",
|
||||||
|
"sidebar": {
|
||||||
|
"autoConfiguration": true,
|
||||||
|
"format": "vitepress",
|
||||||
|
"pretty": true,
|
||||||
|
"collapsed": false
|
||||||
|
},
|
||||||
|
"indexFormat": "table",
|
||||||
|
"parametersFormat": "table",
|
||||||
|
"interfacePropertiesFormat": "table",
|
||||||
|
"classPropertiesFormat": "table",
|
||||||
|
"propertyMembersFormat": "table",
|
||||||
|
"useCodeBlocks": true,
|
||||||
|
"sort": [
|
||||||
|
"static-first"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user