feat: deno ffi bindings (#40)
* initial ts commit * monero.ts improvements * test on latest, build on debian:bookworm * feat: upstream changes to bindings * chore: update checksums * feat: allow manually loading dylib * chore: add readme * fix: free strings after being read to prevent potential memory leaks * fix: load dylib * fix: checksum checks segfaulting because of freeing const variables --------- Co-authored-by: Mateusz Franik <47059999+Im-Beast@users.noreply.github.com> Co-authored-by: Im-Beast <franik.mateusz@gmail.com>
This commit is contained in:
@@ -137,7 +137,7 @@ jobs:
|
||||
coin: [monero, wownero]
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: debian:bookworm
|
||||
image: debian:bullseye
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -698,6 +698,123 @@ jobs:
|
||||
with:
|
||||
name: ${{ matrix.coin }} xmruw apk
|
||||
path: unnamed_monero_wallet/build/app/outputs/flutter-apk/*.apk
|
||||
bulk_lib_release:
|
||||
name: create single release file
|
||||
runs-on: ubuntu-latest
|
||||
needs: [
|
||||
lib_mingw, lib_android, lib_linux, lib_sailfishos_aarch64, lib_sailfishos_i486, lib_darwin, lib_macos, lib_ios
|
||||
]
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: android monero
|
||||
path: release/monero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: android wownero
|
||||
path: release/wownero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: darwin monero
|
||||
path: release/monero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: darwin wownero
|
||||
path: release/wownero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ios monero
|
||||
path: release/monero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ios wownero
|
||||
path: release/wownero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: linux monero
|
||||
path: release/monero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: linux wownero
|
||||
path: release/wownero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: macos monero
|
||||
path: release/monero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: macos wownero
|
||||
path: release/wownero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: mingw monero
|
||||
path: release/monero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: mingw wownero
|
||||
path: release/wownero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: sfos aarch64 monero
|
||||
path: release/monero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: sfos aarch64 wownero
|
||||
path: release/wownero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: sfos_i486 monero
|
||||
path: release/monero
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: sfos_i486 wownero
|
||||
path: release/wownero
|
||||
- name: zip release dir
|
||||
run: zip -r release-bundle.zip release
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
files: release-bundle.zip
|
||||
token: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
|
||||
- name: Upload lib
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-bulk
|
||||
path: release
|
||||
deno_monerots_test_linux:
|
||||
name: test ts library
|
||||
runs-on: ubuntu-24.04
|
||||
needs: [
|
||||
lib_linux
|
||||
]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: linux monero
|
||||
path: release/monero
|
||||
- name: unpack and move monero_c
|
||||
run: |
|
||||
unxz -f -k release/*/*.xz
|
||||
- uses: denoland/setup-deno@v1
|
||||
with:
|
||||
deno-version: vx.x.x
|
||||
- name: Create symlink
|
||||
run: |
|
||||
cd impls/monero.ts
|
||||
mkdir lib
|
||||
cd lib
|
||||
ln -s ../../../release/monero/x86_64-linux-gnu_libwallet2_api_c.so
|
||||
mv x86_64-linux-gnu_libwallet2_api_c.so monero_libwallet2_api_c.so
|
||||
cd ..
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd impls/monero.ts
|
||||
deno run --unstable-ffi --allow-ffi checksum.ts
|
||||
|
||||
comment_pr:
|
||||
name: comment on pr
|
||||
@@ -752,4 +869,4 @@ jobs:
|
||||
with:
|
||||
issue-number: ${{steps.get_issue_number.outputs.result}}
|
||||
body: |
|
||||
[download artifacts #${{github.run_id}}](https://nightly.link/MrCyjaneK/monero_c/actions/runs/${{github.run_id}}) (this comment will update whenever you push)
|
||||
[download artifacts #${{github.run_id}}](https://nightly.link/MrCyjaneK/monero_c/actions/runs/${{github.run_id}}) (this comment will update whenever you push)
|
||||
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"deno.enable": true
|
||||
}
|
||||
+13
-1
@@ -1,6 +1,11 @@
|
||||
#!/bin/bash
|
||||
cd "$(realpath $(dirname $0))"
|
||||
function sha256sum() { shasum -a 256 "$@" ; } && export -f sha256sum
|
||||
|
||||
if [[ "$(uname)" == "Darwin" ]];
|
||||
then
|
||||
function sha256sum() { shasum -a 256 "$@" ; } && export -f sha256sum
|
||||
fi
|
||||
|
||||
for coin in monero wownero;
|
||||
do
|
||||
submodule_hash=$(git ls-tree HEAD ${coin} | xargs | awk '{ print $3 }')
|
||||
@@ -22,6 +27,13 @@ EOF
|
||||
const String wallet2_api_c_h_sha256 = "${COIN_wallet2_api_c_h_sha256}";
|
||||
const String wallet2_api_c_cpp_sha256 = "${COIN_wallet2_api_c_cpp_sha256}";
|
||||
const String wallet2_api_c_exp_sha256 = "${COIN_wallet2_api_c_exp_sha256}";
|
||||
EOF
|
||||
cat > impls/monero.ts/checksum_${coin}.ts << EOF
|
||||
export const ${coin}Checksum = {
|
||||
wallet2_api_c_h_sha256: "${COIN_wallet2_api_c_h_sha256}",
|
||||
wallet2_api_c_cpp_sha256: "${COIN_wallet2_api_c_cpp_sha256}",
|
||||
wallet2_api_c_exp_sha256: "${COIN_wallet2_api_c_exp_sha256}",
|
||||
}
|
||||
EOF
|
||||
done
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
*_libwallet2_api_c.*
|
||||
lib
|
||||
@@ -0,0 +1,42 @@
|
||||
# monero.ts
|
||||
|
||||
`monero_c` bindings for Deno.
|
||||
|
||||
## Usage
|
||||
|
||||
This library does not ship with `monero_c` libraries.\
|
||||
To use these bindings you have to bring your own `monero_c` libraries.\
|
||||
There are at least two ways to do so:
|
||||
- Ahead-of-time, during builds where you only ship necessary library for a given platform.\
|
||||
See [monero-tui](https://github.com/Im-Beast/monero-tui/blob/main/.github/workflows/dev-build.yml) build workflow as an example of doing so.
|
||||
```ts
|
||||
import { loadDylib, Wallet, WalletManager } from "https://raw.githubusercontent.com/MrCyjaneK/monero_c/master/impls/monero.ts/mod.ts";
|
||||
|
||||
// Try to load dylib from the default lib/* path
|
||||
loadDylib();
|
||||
|
||||
const wm = await WalletManager.new();
|
||||
const wallet = await Wallet.create(wm, "./my_wallet", "password");
|
||||
|
||||
console.log(await wallet.address());
|
||||
|
||||
await wallet.store();
|
||||
```
|
||||
- Just-in-time, where you download and cache the library at runtime.\
|
||||
You can use something like [plug](https://jsr.io/@denosaurs/plug) to achieve the result.
|
||||
```ts
|
||||
import { dlopen } from "jsr:@denosaurs/plug";
|
||||
// It's recommened to put the monero.ts github link into your import_map to reduce the url clutter
|
||||
import { loadDylib, symbols, Wallet, WalletManager } from "https://raw.githubusercontent.com/MrCyjaneK/monero_c/master/impls/monero.ts/mod.ts";
|
||||
|
||||
// Load dylib loaded by plug
|
||||
const lib = await dlopen(..., symbols);
|
||||
loadDylib(lib);
|
||||
|
||||
const wm = await WalletManager.new();
|
||||
const wallet = await Wallet.create(wm, "./my_wallet", "password");
|
||||
|
||||
console.log(await wallet.address());
|
||||
|
||||
await wallet.store();
|
||||
```
|
||||
@@ -0,0 +1,65 @@
|
||||
import { moneroChecksum } from "./checksum_monero.ts";
|
||||
import { readCString } from "./src/utils.ts";
|
||||
import { dylib, loadDylib } from "./src/bindings.ts";
|
||||
|
||||
loadDylib();
|
||||
|
||||
export class ChecksumError extends Error {
|
||||
readonly code: number;
|
||||
readonly errors: string[];
|
||||
|
||||
constructor(code: number, errors: string[]) {
|
||||
super("MoneroC binding checksum failed:\n" + errors.join("\n"));
|
||||
this.code = code;
|
||||
this.errors = errors;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates MoneroC checksums
|
||||
* @returns {null} if checksums are correct
|
||||
* @returns {ChecksumError} which contains information about why checksum failed
|
||||
*/
|
||||
export async function validateChecksum(): Promise<ChecksumError | null> {
|
||||
const cppHeaderHash = await readCString(await dylib.symbols.MONERO_checksum_wallet2_api_c_h(), false);
|
||||
const tsHeaderHash = moneroChecksum.wallet2_api_c_h_sha256;
|
||||
|
||||
const errors: string[] = [];
|
||||
|
||||
let errorCode = 0;
|
||||
if (cppHeaderHash !== tsHeaderHash) {
|
||||
errors.push("ERR: Header file check mismatch");
|
||||
errorCode++;
|
||||
}
|
||||
|
||||
const cppSourceHash = await readCString(await dylib.symbols.MONERO_checksum_wallet2_api_c_cpp(), false);
|
||||
const tsSourceHash = moneroChecksum.wallet2_api_c_cpp_sha256;
|
||||
if (cppSourceHash !== tsSourceHash) {
|
||||
errors.push(`ERR: CPP source file check mismatch ${cppSourceHash} == ${tsSourceHash}`);
|
||||
errorCode++;
|
||||
}
|
||||
|
||||
const cppExportHash = await readCString(await dylib.symbols.MONERO_checksum_wallet2_api_c_exp(), false);
|
||||
const tsExportHash = moneroChecksum.wallet2_api_c_exp_sha256;
|
||||
if (cppExportHash !== tsExportHash) {
|
||||
if (Deno.build.os !== "darwin") {
|
||||
errors.push("WARN: EXP source file check mismatch");
|
||||
} else {
|
||||
errors.push(`ERR: EXP source file check mismatch ${cppExportHash} == ${tsExportHash}`);
|
||||
}
|
||||
errorCode++;
|
||||
}
|
||||
|
||||
if (errorCode) {
|
||||
return new ChecksumError(errorCode, errors);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
const maybeError = await validateChecksum();
|
||||
if (maybeError) {
|
||||
throw maybeError;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export const moneroChecksum = {
|
||||
wallet2_api_c_h_sha256: "e8db0ef0324a153f5e3ecca4c0db23c54f4576e84988f04bd4f11c1142f9d7ad",
|
||||
wallet2_api_c_cpp_sha256: "dca52ac9ee009fda9fb5726543a454885e61d8eb74fb33112288029ed625bec5-b089f9ee69924882c5d14dd1a6991deb05d9d1cd",
|
||||
wallet2_api_c_exp_sha256: "c8913ac41068f67b57c9b0a3c7dd8973e3c1273b66c2ff0aadb0003931da748c",
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export const wowneroChecksum = {
|
||||
wallet2_api_c_h_sha256: "8a8d386dd5d996c89a0586c55b295ef95ca584bf1ffa26255152b291910a0a77",
|
||||
wallet2_api_c_cpp_sha256: "07d67f34a07869aaa4af6ca04e142dbad2fb1fba0e2ebdefd22bc333fd982e25-e25963cbc11ca0a0fe5eb34b9bd7c72e4f51b795",
|
||||
wallet2_api_c_exp_sha256: "3673e40e1a7115552276d1d541f6e4d5a0fef47c40fff7b988f49923af84c8a4",
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"fmt": {
|
||||
"lineWidth": 120
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export * from "./src/bindings.ts";
|
||||
export * from "./src/pending_transaction.ts";
|
||||
export * from "./src/transaction_history.ts";
|
||||
export * from "./src/transaction_info.ts";
|
||||
export * from "./src/wallet.ts";
|
||||
export * from "./src/wallet_manager.ts";
|
||||
@@ -0,0 +1,562 @@
|
||||
export const symbols = {
|
||||
"MONERO_WalletManagerFactory_getWalletManager": {
|
||||
nonblocking: true,
|
||||
parameters: [],
|
||||
// void*
|
||||
result: "pointer",
|
||||
},
|
||||
|
||||
//#region WalletManager
|
||||
"MONERO_WalletManager_createWallet": {
|
||||
nonblocking: true,
|
||||
// void* wm_ptr, const char* path, const char* password, const char* language, int networkType
|
||||
parameters: ["pointer", "pointer", "pointer", "pointer", "i32"],
|
||||
// void*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_WalletManager_openWallet": {
|
||||
nonblocking: true,
|
||||
// void* wm_ptr, const char* path, const char* password, int networkType
|
||||
"parameters": ["pointer", "pointer", "pointer", "i32"],
|
||||
// void*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_WalletManager_recoveryWallet": {
|
||||
nonblocking: true,
|
||||
// void* wm_ptr, const char* path, const char* password, const char* mnemonic,
|
||||
// int networkType, uint64_t restoreHeight, uint64_t kdfRounds, const char* seedOffset
|
||||
parameters: ["pointer", "pointer", "pointer", "pointer", "i32", "u64", "u64", "pointer"],
|
||||
// void*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_WalletManager_blockchainHeight": {
|
||||
nonblocking: true,
|
||||
// void* wm_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_WalletManager_blockchainTargetHeight": {
|
||||
nonblocking: true,
|
||||
// void* wm_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_WalletManager_setDaemonAddress": {
|
||||
nonblocking: true,
|
||||
// void* wm_ptr, const char* address
|
||||
parameters: ["pointer", "pointer"],
|
||||
// void
|
||||
result: "void",
|
||||
},
|
||||
//#endregion
|
||||
|
||||
//#region Wallet
|
||||
"MONERO_Wallet_init": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr, const char* daemon_address, uint64_t upper_transaction_size_limit,
|
||||
// const char* daemon_username, const char* daemon_password, bool use_ssl, bool lightWallet,
|
||||
// const char* proxy_address
|
||||
parameters: ["pointer", "pointer", "u64", "pointer", "pointer", "bool", "bool", "pointer"],
|
||||
// bool
|
||||
result: "bool",
|
||||
},
|
||||
"MONERO_Wallet_init3": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr, const char* argv0, const char* default_log_base_name,
|
||||
// const char* log_path, bool console
|
||||
parameters: ["pointer", "pointer", "pointer", "pointer", "bool"],
|
||||
// void
|
||||
result: "void",
|
||||
},
|
||||
"MONERO_Wallet_setTrustedDaemon": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr, bool arg
|
||||
parameters: ["pointer", "bool"],
|
||||
// void
|
||||
result: "void",
|
||||
},
|
||||
"MONERO_Wallet_startRefresh": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr
|
||||
parameters: ["pointer"],
|
||||
// void
|
||||
result: "void",
|
||||
},
|
||||
"MONERO_Wallet_refreshAsync": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr
|
||||
parameters: ["pointer"],
|
||||
// void
|
||||
result: "void",
|
||||
},
|
||||
"MONERO_Wallet_blockChainHeight": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_Wallet_daemonBlockChainHeight": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_Wallet_synchronized": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr
|
||||
parameters: ["pointer"],
|
||||
// bool
|
||||
result: "bool",
|
||||
},
|
||||
"MONERO_Wallet_store": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr, const char* path
|
||||
parameters: ["pointer", "pointer"],
|
||||
// bool
|
||||
result: "bool",
|
||||
},
|
||||
"MONERO_Wallet_address": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr, uint64_t accountIndex, uint64_t addressIndex
|
||||
parameters: ["pointer", "u64", "u64"],
|
||||
// char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_Wallet_balance": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr, uint32_t accountIndex
|
||||
parameters: ["pointer", "u32"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_Wallet_unlockedBalance": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr, uint32_t accountIndex
|
||||
parameters: ["pointer", "u32"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_Wallet_addSubaddressAccount": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr, const char* label
|
||||
parameters: ["pointer", "pointer"],
|
||||
// void
|
||||
result: "void",
|
||||
},
|
||||
"MONERO_Wallet_numSubaddressAccounts": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr
|
||||
parameters: ["pointer"],
|
||||
// size_t
|
||||
result: "usize",
|
||||
},
|
||||
"MONERO_Wallet_addSubaddress": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr, uint32_t accountIndex, const char* label
|
||||
parameters: ["pointer", "u32", "pointer"],
|
||||
// void
|
||||
result: "void",
|
||||
},
|
||||
"MONERO_Wallet_numSubaddresses": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr, uint32_t accountIndex
|
||||
parameters: ["pointer", "u32"],
|
||||
// size_t
|
||||
result: "usize",
|
||||
},
|
||||
"MONERO_Wallet_getSubaddressLabel": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr, uint32_t accountIndex, uint32_t addressIndex
|
||||
parameters: ["pointer", "u32", "u32"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_Wallet_setSubaddressLabel": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr, uint32_t accountIndex, uint32_t addressIndex, const char* label
|
||||
parameters: ["pointer", "u32", "u32", "pointer"],
|
||||
// void
|
||||
result: "void",
|
||||
},
|
||||
"MONERO_Wallet_status": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr
|
||||
parameters: ["pointer"],
|
||||
// int
|
||||
result: "i32",
|
||||
},
|
||||
"MONERO_Wallet_errorString": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr
|
||||
parameters: ["pointer"],
|
||||
// char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_Wallet_history": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr
|
||||
parameters: ["pointer"],
|
||||
// void*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_Wallet_createTransaction": {
|
||||
nonblocking: true,
|
||||
// void* wallet_ptr, const char* dst_addr, const char* payment_id
|
||||
// uint64_t amount, uint32_t mixin_count, int pendingTransactionPriority,
|
||||
// uint32_t subaddr_account, const char* preferredInputs, const char* separator
|
||||
parameters: ["pointer", "pointer", "pointer", "u64", "u32", "i32", "u32", "pointer", "pointer"],
|
||||
// void*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_Wallet_amountFromString": {
|
||||
nonblocking: true,
|
||||
// const char* amount
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
//#endregion
|
||||
|
||||
//#region TransactionHistory
|
||||
"MONERO_TransactionHistory_count": {
|
||||
nonblocking: true,
|
||||
// void* txHistory_ptr
|
||||
parameters: ["pointer"],
|
||||
// int
|
||||
result: "i32",
|
||||
},
|
||||
"MONERO_TransactionHistory_transaction": {
|
||||
nonblocking: true,
|
||||
// void* txHistory_ptr, int index
|
||||
parameters: ["pointer", "i32"],
|
||||
// void*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_TransactionHistory_transactionById": {
|
||||
nonblocking: true,
|
||||
// void* txHistory_ptr, const char* id
|
||||
parameters: ["pointer", "pointer"],
|
||||
// void*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_TransactionHistory_refresh": {
|
||||
nonblocking: true,
|
||||
// void* txHistory_ptr
|
||||
parameters: ["pointer"],
|
||||
// void
|
||||
result: "void",
|
||||
},
|
||||
"MONERO_TransactionHistory_setTxNote": {
|
||||
nonblocking: true,
|
||||
// void* txHistory_ptr, const char* txid, const char* note
|
||||
parameters: ["pointer", "pointer", "pointer"],
|
||||
// void
|
||||
result: "void",
|
||||
},
|
||||
//#endregion
|
||||
|
||||
//#region TransactionInfo
|
||||
"MONERO_TransactionInfo_direction": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// int
|
||||
result: "i32",
|
||||
},
|
||||
"MONERO_TransactionInfo_isPending": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// bool
|
||||
result: "bool",
|
||||
},
|
||||
"MONERO_TransactionInfo_isFailed": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// bool
|
||||
result: "bool",
|
||||
},
|
||||
"MONERO_TransactionInfo_isCoinbase": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// bool
|
||||
result: "bool",
|
||||
},
|
||||
"MONERO_TransactionInfo_amount": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_TransactionInfo_fee": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_TransactionInfo_blockHeight": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_TransactionInfo_description": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_TransactionInfo_subaddrIndex": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_TransactionInfo_subaddrAccount": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint32_t
|
||||
result: "u32",
|
||||
},
|
||||
"MONERO_TransactionInfo_label": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_TransactionInfo_confirmations": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_TransactionInfo_unlockTime": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_TransactionInfo_hash": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_TransactionInfo_timestamp": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_TransactionInfo_paymentId": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_TransactionInfo_transfers_count": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr
|
||||
parameters: ["pointer"],
|
||||
// int
|
||||
result: "i32",
|
||||
},
|
||||
"MONERO_TransactionInfo_transfers_amount": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr, int index
|
||||
parameters: ["pointer", "i32"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_TransactionInfo_transfers_address": {
|
||||
nonblocking: true,
|
||||
// void* txInfo_ptr, int index
|
||||
parameters: ["pointer", "i32"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
//#endregion
|
||||
|
||||
//#region PendingTransaction
|
||||
"MONERO_PendingTransaction_status": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr
|
||||
parameters: ["pointer"],
|
||||
// int
|
||||
result: "i32",
|
||||
},
|
||||
"MONERO_PendingTransaction_errorString": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr
|
||||
parameters: ["pointer"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_PendingTransaction_commit": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr, const char* filename, bool overwrite
|
||||
parameters: ["pointer", "pointer", "bool"],
|
||||
// bool
|
||||
result: "bool",
|
||||
},
|
||||
"MONERO_PendingTransaction_commitUR": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr, int max_fragment_length
|
||||
parameters: ["pointer", "i32"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_PendingTransaction_amount": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_PendingTransaction_dust": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_PendingTransaction_fee": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_PendingTransaction_txid": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr, const char* separator
|
||||
parameters: ["pointer", "pointer"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_PendingTransaction_txCount": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr
|
||||
parameters: ["pointer"],
|
||||
// uint64_t
|
||||
result: "u64",
|
||||
},
|
||||
"MONERO_PendingTransaction_subaddrAccount": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr, const char* separator
|
||||
parameters: ["pointer", "pointer"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_PendingTransaction_subaddrIndices": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr, const char* separator
|
||||
parameters: ["pointer", "pointer"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_PendingTransaction_multisigSignData": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr
|
||||
parameters: ["pointer"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_PendingTransaction_signMultisigTx": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr
|
||||
parameters: ["pointer"],
|
||||
// void
|
||||
result: "void",
|
||||
},
|
||||
"MONERO_PendingTransaction_signersKeys": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr
|
||||
parameters: ["pointer"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_PendingTransaction_hex": {
|
||||
nonblocking: true,
|
||||
// void* pendingTx_ptr, const char* separator
|
||||
parameters: ["pointer", "pointer"],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
//#endregion
|
||||
|
||||
//#region Checksum
|
||||
"MONERO_checksum_wallet2_api_c_h": {
|
||||
nonblocking: true,
|
||||
parameters: [],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_checksum_wallet2_api_c_cpp": {
|
||||
nonblocking: true,
|
||||
parameters: [],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
"MONERO_checksum_wallet2_api_c_exp": {
|
||||
nonblocking: true,
|
||||
parameters: [],
|
||||
// const char*
|
||||
result: "pointer",
|
||||
},
|
||||
//#endregion
|
||||
|
||||
"MONERO_free": {
|
||||
nonblocking: true,
|
||||
// void* ptr
|
||||
parameters: ["pointer"],
|
||||
// void
|
||||
result: "void",
|
||||
},
|
||||
} as const;
|
||||
|
||||
type MoneroTsDylib = Deno.DynamicLibrary<typeof symbols>;
|
||||
|
||||
export let dylib: MoneroTsDylib;
|
||||
export function loadDylib(newDylib?: MoneroTsDylib) {
|
||||
if (newDylib) {
|
||||
dylib = newDylib;
|
||||
return;
|
||||
}
|
||||
|
||||
let libPath: string;
|
||||
switch (Deno.build.os) {
|
||||
case "darwin":
|
||||
libPath = "./lib/monero_libwallet2_api_c.dylib";
|
||||
break;
|
||||
case "android":
|
||||
libPath = "./lib/libmonero_libwallet2_api_c.so";
|
||||
break;
|
||||
case "windows":
|
||||
libPath = "./lib/monero_libwallet2_api_c.dll";
|
||||
break;
|
||||
default:
|
||||
libPath = "./lib/monero_libwallet2_api_c.so";
|
||||
break;
|
||||
}
|
||||
|
||||
dylib = Deno.dlopen(libPath, symbols);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import { dylib } from "./bindings.ts";
|
||||
import { CString, readCString, type Sanitizer } from "./utils.ts";
|
||||
|
||||
export type PendingTransactionPtr = Deno.PointerObject<"transactionInfo">;
|
||||
|
||||
export class PendingTransaction {
|
||||
#pendingTxPtr: PendingTransactionPtr;
|
||||
sanitizer?: Sanitizer;
|
||||
|
||||
constructor(pendingTxPtr: PendingTransactionPtr, sanitizer?: Sanitizer) {
|
||||
this.sanitizer = sanitizer;
|
||||
this.#pendingTxPtr = pendingTxPtr;
|
||||
}
|
||||
|
||||
async status(): Promise<number> {
|
||||
return await dylib.symbols.MONERO_PendingTransaction_status(this.#pendingTxPtr);
|
||||
}
|
||||
|
||||
async errorString(): Promise<string | null> {
|
||||
if (!await this.status()) return null;
|
||||
|
||||
const error = await dylib.symbols.MONERO_PendingTransaction_errorString(this.#pendingTxPtr);
|
||||
if (!error) return null;
|
||||
|
||||
return await readCString(error) || null;
|
||||
}
|
||||
|
||||
async throwIfError(sanitize = true): Promise<void> {
|
||||
const maybeError = await this.errorString();
|
||||
if (maybeError) {
|
||||
if (sanitize) this.sanitizer?.();
|
||||
throw new Error(maybeError);
|
||||
}
|
||||
}
|
||||
|
||||
async commit(fileName: string, overwrite: boolean, sanitize = true): Promise<boolean> {
|
||||
const bool = await dylib.symbols.MONERO_PendingTransaction_commit(
|
||||
this.#pendingTxPtr,
|
||||
CString(fileName),
|
||||
overwrite,
|
||||
);
|
||||
await this.throwIfError(sanitize);
|
||||
return bool;
|
||||
}
|
||||
|
||||
async commitUR(maxFragmentLength: number): Promise<string | null> {
|
||||
const result = await dylib.symbols.MONERO_PendingTransaction_commitUR(
|
||||
this.#pendingTxPtr,
|
||||
maxFragmentLength,
|
||||
);
|
||||
if (!result) return null;
|
||||
await this.throwIfError();
|
||||
return await readCString(result) || null;
|
||||
}
|
||||
|
||||
async amount(): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_PendingTransaction_amount(this.#pendingTxPtr);
|
||||
}
|
||||
|
||||
async dust(): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_PendingTransaction_dust(this.#pendingTxPtr);
|
||||
}
|
||||
|
||||
async fee(): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_PendingTransaction_fee(this.#pendingTxPtr);
|
||||
}
|
||||
|
||||
async txid(separator: string, sanitize = true): Promise<string | null> {
|
||||
const result = await dylib.symbols.MONERO_PendingTransaction_txid(
|
||||
this.#pendingTxPtr,
|
||||
CString(separator),
|
||||
);
|
||||
if (!result) return null;
|
||||
await this.throwIfError(sanitize);
|
||||
return await readCString(result) || null;
|
||||
}
|
||||
|
||||
async txCount(): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_PendingTransaction_txCount(this.#pendingTxPtr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { dylib } from "./bindings.ts";
|
||||
import { TransactionInfo, TransactionInfoPtr } from "./transaction_info.ts";
|
||||
import { CString } from "./utils.ts";
|
||||
|
||||
export type TransactionHistoryPtr = Deno.PointerObject<"transactionHistory">;
|
||||
|
||||
export class TransactionHistory {
|
||||
#txHistoryPtr: TransactionHistoryPtr;
|
||||
|
||||
constructor(txHistoryPtr: TransactionHistoryPtr) {
|
||||
this.#txHistoryPtr = txHistoryPtr;
|
||||
}
|
||||
|
||||
async count(): Promise<number> {
|
||||
return await dylib.symbols.MONERO_TransactionHistory_count(this.#txHistoryPtr);
|
||||
}
|
||||
|
||||
async transaction(index: number): Promise<TransactionInfo> {
|
||||
return new TransactionInfo(
|
||||
(await dylib.symbols.MONERO_TransactionHistory_transaction(
|
||||
this.#txHistoryPtr,
|
||||
index,
|
||||
)) as TransactionInfoPtr,
|
||||
);
|
||||
}
|
||||
|
||||
async refresh(): Promise<void> {
|
||||
await dylib.symbols.MONERO_TransactionHistory_refresh(this.#txHistoryPtr);
|
||||
}
|
||||
|
||||
async setTxNote(transactionId: string, note: string): Promise<void> {
|
||||
await dylib.symbols.MONERO_TransactionHistory_setTxNote(
|
||||
this.#txHistoryPtr,
|
||||
CString(transactionId),
|
||||
CString(note),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import { dylib } from "./bindings.ts";
|
||||
import { readCString, Sanitizer } from "./utils.ts";
|
||||
|
||||
export type TransactionInfoPtr = Deno.PointerObject<"transactionInfo">;
|
||||
|
||||
export class TransactionInfo {
|
||||
#txInfoPtr: TransactionInfoPtr;
|
||||
sanitizer?: Sanitizer;
|
||||
|
||||
constructor(txInfoPtr: TransactionInfoPtr, sanitizer?: Sanitizer) {
|
||||
this.#txInfoPtr = txInfoPtr;
|
||||
this.sanitizer = sanitizer;
|
||||
}
|
||||
|
||||
async direction(): Promise<"in" | "out"> {
|
||||
switch (await dylib.symbols.MONERO_TransactionInfo_direction(this.#txInfoPtr)) {
|
||||
case 0:
|
||||
return "in";
|
||||
case 1:
|
||||
return "out";
|
||||
default:
|
||||
await this.sanitizer?.();
|
||||
throw new Error("Invalid TransactionInfo direction");
|
||||
}
|
||||
}
|
||||
|
||||
async isPending(): Promise<boolean> {
|
||||
return await dylib.symbols.MONERO_TransactionInfo_isPending(this.#txInfoPtr);
|
||||
}
|
||||
|
||||
async isFailed(): Promise<boolean> {
|
||||
return await dylib.symbols.MONERO_TransactionInfo_isFailed(this.#txInfoPtr);
|
||||
}
|
||||
|
||||
async isCoinbase(): Promise<boolean> {
|
||||
return await dylib.symbols.MONERO_TransactionInfo_isCoinbase(this.#txInfoPtr);
|
||||
}
|
||||
|
||||
async amount(): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_TransactionInfo_amount(this.#txInfoPtr);
|
||||
}
|
||||
|
||||
async fee(): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_TransactionInfo_fee(this.#txInfoPtr);
|
||||
}
|
||||
|
||||
async blockHeight(): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_TransactionInfo_blockHeight(this.#txInfoPtr);
|
||||
}
|
||||
|
||||
async description(): Promise<string> {
|
||||
const description = await dylib.symbols.MONERO_TransactionInfo_description(this.#txInfoPtr);
|
||||
return await readCString(description) || "";
|
||||
}
|
||||
|
||||
async subaddrIndex(): Promise<string> {
|
||||
const subaddrIndex = await dylib.symbols.MONERO_TransactionInfo_subaddrIndex(this.#txInfoPtr);
|
||||
return await readCString(subaddrIndex) || "";
|
||||
}
|
||||
|
||||
async subaddrAccount(): Promise<number> {
|
||||
return await dylib.symbols.MONERO_TransactionInfo_subaddrAccount(this.#txInfoPtr);
|
||||
}
|
||||
|
||||
async label(): Promise<string> {
|
||||
const label = await dylib.symbols.MONERO_TransactionInfo_label(this.#txInfoPtr);
|
||||
return await readCString(label) || "";
|
||||
}
|
||||
|
||||
async confirmations(): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_TransactionInfo_confirmations(this.#txInfoPtr);
|
||||
}
|
||||
|
||||
async unlockTime(): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_TransactionInfo_unlockTime(this.#txInfoPtr);
|
||||
}
|
||||
|
||||
async hash(): Promise<string> {
|
||||
const hash = await dylib.symbols.MONERO_TransactionInfo_hash(this.#txInfoPtr);
|
||||
return await readCString(hash) || "";
|
||||
}
|
||||
|
||||
async timestamp(): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_TransactionInfo_timestamp(this.#txInfoPtr);
|
||||
}
|
||||
|
||||
async paymentId(): Promise<string> {
|
||||
const paymentId = await dylib.symbols.MONERO_TransactionInfo_paymentId(this.#txInfoPtr);
|
||||
return await readCString(paymentId) || "";
|
||||
}
|
||||
|
||||
async transfersCount(): Promise<number> {
|
||||
return await dylib.symbols.MONERO_TransactionInfo_transfers_count(this.#txInfoPtr);
|
||||
}
|
||||
|
||||
async transfersAmount(index: number): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_TransactionInfo_transfers_amount(this.#txInfoPtr, index);
|
||||
}
|
||||
|
||||
async transfersAddress(index: number): Promise<string> {
|
||||
const transfersAddress = await dylib.symbols.MONERO_TransactionInfo_transfers_address(this.#txInfoPtr, index);
|
||||
return await readCString(transfersAddress) || "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { dylib } from "../mod.ts";
|
||||
|
||||
export type Sanitizer = () => void | PromiseLike<void>;
|
||||
|
||||
const textEncoder = new TextEncoder();
|
||||
export function CString(string: string): Deno.PointerValue<string> {
|
||||
return Deno.UnsafePointer.of(textEncoder.encode(`${string}\x00`));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method reads string from the given pointer and frees the string.
|
||||
*
|
||||
* SAFETY: Do not use readCString twice on the same pointer as it will cause double free\
|
||||
* If you want to read CString without freeing it set the {@linkcode free} parameter to false
|
||||
*/
|
||||
export async function readCString(pointer: Deno.PointerObject, free?: boolean): Promise<string>;
|
||||
export async function readCString(pointer: Deno.PointerValue, free?: boolean): Promise<string | null>;
|
||||
export async function readCString(pointer: Deno.PointerValue, free = true): Promise<string | null> {
|
||||
if (!pointer) return null;
|
||||
const string = new Deno.UnsafePointerView(pointer).getCString();
|
||||
if (free) {
|
||||
await dylib.symbols.MONERO_free(pointer);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
import { dylib } from "./bindings.ts";
|
||||
import { CString, readCString, Sanitizer } from "./utils.ts";
|
||||
import { WalletManager, type WalletManagerPtr } from "./wallet_manager.ts";
|
||||
import { TransactionHistory, TransactionHistoryPtr } from "./transaction_history.ts";
|
||||
|
||||
import { PendingTransaction } from "./pending_transaction.ts";
|
||||
import { PendingTransactionPtr } from "./pending_transaction.ts";
|
||||
|
||||
export type WalletPtr = Deno.PointerObject<"walletManager">;
|
||||
|
||||
export class Wallet {
|
||||
#walletManagerPtr: WalletManagerPtr;
|
||||
#walletPtr: WalletPtr;
|
||||
sanitizer?: Sanitizer;
|
||||
|
||||
constructor(walletManagerPtr: WalletManager, walletPtr: WalletPtr, sanitizer?: Sanitizer) {
|
||||
this.#walletPtr = walletPtr;
|
||||
this.#walletManagerPtr = walletManagerPtr.getPointer();
|
||||
this.sanitizer = sanitizer;
|
||||
}
|
||||
|
||||
async store(path = ""): Promise<boolean> {
|
||||
const bool = await dylib.symbols.MONERO_Wallet_store(this.#walletPtr, CString(path));
|
||||
await this.throwIfError();
|
||||
return bool;
|
||||
}
|
||||
|
||||
async initWallet(): Promise<void> {
|
||||
await this.init();
|
||||
await this.setTrustedDaemon(true);
|
||||
await this.setDaemonAddress("http://nodex.monerujo.io:18081");
|
||||
await this.startRefresh();
|
||||
await this.refreshAsync();
|
||||
await this.throwIfError();
|
||||
}
|
||||
|
||||
async setDaemonAddress(address: string): Promise<void> {
|
||||
await dylib.symbols.MONERO_WalletManager_setDaemonAddress(
|
||||
this.#walletManagerPtr,
|
||||
CString(address),
|
||||
);
|
||||
}
|
||||
|
||||
async startRefresh(): Promise<void> {
|
||||
await dylib.symbols.MONERO_Wallet_startRefresh(this.#walletPtr);
|
||||
await this.throwIfError();
|
||||
}
|
||||
|
||||
async refreshAsync(): Promise<void> {
|
||||
await dylib.symbols.MONERO_Wallet_refreshAsync(this.#walletPtr);
|
||||
await this.throwIfError();
|
||||
}
|
||||
|
||||
async init(): Promise<boolean> {
|
||||
const bool = await dylib.symbols.MONERO_Wallet_init(
|
||||
this.#walletPtr,
|
||||
CString("http://nodex.monerujo.io:18081"),
|
||||
0n,
|
||||
CString(""),
|
||||
CString(""),
|
||||
false,
|
||||
false,
|
||||
CString(""),
|
||||
);
|
||||
await this.throwIfError();
|
||||
return bool;
|
||||
}
|
||||
|
||||
async setTrustedDaemon(value: boolean): Promise<void> {
|
||||
await dylib.symbols.MONERO_Wallet_setTrustedDaemon(this.#walletPtr, value);
|
||||
}
|
||||
|
||||
static async create(
|
||||
walletManager: WalletManager,
|
||||
path: string,
|
||||
password: string,
|
||||
sanitizeError = true,
|
||||
): Promise<Wallet> {
|
||||
// We assign holder of the pointer in Wallet constructor
|
||||
const walletManagerPtr = walletManager.getPointer();
|
||||
|
||||
const walletPtr = await dylib.symbols.MONERO_WalletManager_createWallet(
|
||||
walletManagerPtr,
|
||||
CString(path),
|
||||
CString(password),
|
||||
CString("English"),
|
||||
0,
|
||||
);
|
||||
|
||||
const wallet = new Wallet(walletManager, walletPtr as WalletPtr, walletManager.sanitizer);
|
||||
await wallet.throwIfError(sanitizeError);
|
||||
await wallet.initWallet();
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
static async open(
|
||||
walletManager: WalletManager,
|
||||
path: string,
|
||||
password: string,
|
||||
sanitizeError = true,
|
||||
): Promise<Wallet> {
|
||||
// We assign holder of the pointer in Wallet constructor
|
||||
const walletManagerPtr = walletManager.getPointer();
|
||||
|
||||
const walletPtr = await dylib.symbols.MONERO_WalletManager_openWallet(
|
||||
walletManagerPtr,
|
||||
CString(path),
|
||||
CString(password),
|
||||
0,
|
||||
);
|
||||
|
||||
const wallet = new Wallet(walletManager, walletPtr as WalletPtr, walletManager.sanitizer);
|
||||
await wallet.throwIfError(sanitizeError);
|
||||
await wallet.initWallet();
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
static async recover(
|
||||
walletManager: WalletManager,
|
||||
path: string,
|
||||
password: string,
|
||||
mnemonic: string,
|
||||
restoreHeight: bigint,
|
||||
seedOffset: string = "",
|
||||
sanitizeError = true,
|
||||
): Promise<Wallet> {
|
||||
// We assign holder of the pointer in Wallet constructor
|
||||
const walletManagerPtr = walletManager.getPointer();
|
||||
|
||||
const walletPtr = await dylib.symbols.MONERO_WalletManager_recoveryWallet(
|
||||
walletManagerPtr,
|
||||
CString(path),
|
||||
CString(password),
|
||||
CString(mnemonic),
|
||||
0,
|
||||
restoreHeight,
|
||||
1n,
|
||||
CString(seedOffset),
|
||||
);
|
||||
|
||||
const wallet = new Wallet(walletManager, walletPtr as WalletPtr, walletManager.sanitizer);
|
||||
await wallet.throwIfError(sanitizeError);
|
||||
await wallet.initWallet();
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
async address(accountIndex = 0n, addressIndex = 0n): Promise<string> {
|
||||
const address = await dylib.symbols.MONERO_Wallet_address(this.#walletPtr, accountIndex, addressIndex);
|
||||
if (!address) {
|
||||
const error = await this.errorString();
|
||||
throw new Error(`Failed getting address from a wallet: ${error ?? "<Error unknown>"}`);
|
||||
}
|
||||
return await readCString(address);
|
||||
}
|
||||
|
||||
async balance(accountIndex = 0): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_Wallet_balance(this.#walletPtr, accountIndex);
|
||||
}
|
||||
|
||||
async unlockedBalance(accountIndex = 0): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_Wallet_unlockedBalance(this.#walletPtr, accountIndex);
|
||||
}
|
||||
|
||||
status(): Promise<number> {
|
||||
return dylib.symbols.MONERO_Wallet_status(this.#walletPtr);
|
||||
}
|
||||
|
||||
async errorString(): Promise<string | null> {
|
||||
if (!await this.status()) return null;
|
||||
|
||||
const error = await dylib.symbols.MONERO_Wallet_errorString(this.#walletPtr);
|
||||
if (!error) return null;
|
||||
|
||||
return await readCString(error) || null;
|
||||
}
|
||||
|
||||
async throwIfError(sanitize = true): Promise<void> {
|
||||
const maybeError = await this.errorString();
|
||||
if (maybeError) {
|
||||
if (sanitize) this.sanitizer?.();
|
||||
throw new Error(maybeError);
|
||||
}
|
||||
}
|
||||
|
||||
async synchronized(): Promise<boolean> {
|
||||
const synchronized = await dylib.symbols.MONERO_Wallet_synchronized(this.#walletPtr);
|
||||
await this.throwIfError();
|
||||
return synchronized;
|
||||
}
|
||||
|
||||
async blockChainHeight(): Promise<bigint> {
|
||||
const height = await dylib.symbols.MONERO_Wallet_blockChainHeight(this.#walletPtr);
|
||||
await this.throwIfError();
|
||||
return height;
|
||||
}
|
||||
|
||||
async daemonBlockChainHeight(): Promise<bigint> {
|
||||
const height = await dylib.symbols.MONERO_Wallet_daemonBlockChainHeight(this.#walletPtr);
|
||||
await this.throwIfError();
|
||||
return height;
|
||||
}
|
||||
|
||||
async managerBlockChainHeight(): Promise<bigint> {
|
||||
const height = await dylib.symbols.MONERO_WalletManager_blockchainHeight(this.#walletManagerPtr);
|
||||
await this.throwIfError();
|
||||
return height;
|
||||
}
|
||||
|
||||
async managerTargetBlockChainHeight(): Promise<bigint> {
|
||||
const height = await dylib.symbols.MONERO_WalletManager_blockchainTargetHeight(this.#walletManagerPtr);
|
||||
await this.throwIfError();
|
||||
return height;
|
||||
}
|
||||
|
||||
async addSubaddressAccount(label: string): Promise<void> {
|
||||
await dylib.symbols.MONERO_Wallet_addSubaddressAccount(
|
||||
this.#walletPtr,
|
||||
CString(label),
|
||||
);
|
||||
await this.throwIfError();
|
||||
}
|
||||
|
||||
async numSubaddressAccounts(): Promise<bigint> {
|
||||
const accountsLen = await dylib.symbols.MONERO_Wallet_numSubaddressAccounts(this.#walletPtr);
|
||||
await this.throwIfError();
|
||||
return accountsLen;
|
||||
}
|
||||
|
||||
async addSubaddress(accountIndex: number, label: string): Promise<void> {
|
||||
await dylib.symbols.MONERO_Wallet_addSubaddress(
|
||||
this.#walletPtr,
|
||||
accountIndex,
|
||||
CString(label),
|
||||
);
|
||||
await this.throwIfError();
|
||||
}
|
||||
|
||||
async numSubaddresses(accountIndex: number): Promise<bigint> {
|
||||
const address = await dylib.symbols.MONERO_Wallet_numSubaddresses(
|
||||
this.#walletPtr,
|
||||
accountIndex,
|
||||
);
|
||||
await this.throwIfError();
|
||||
return address;
|
||||
}
|
||||
|
||||
async getSubaddressLabel(accountIndex: number, addressIndex: number): Promise<string> {
|
||||
const label = await dylib.symbols.MONERO_Wallet_getSubaddressLabel(this.#walletPtr, accountIndex, addressIndex);
|
||||
if (!label) {
|
||||
const error = await this.errorString();
|
||||
throw new Error(`Failed getting subaddress label from a wallet: ${error ?? "<Error unknown>"}`);
|
||||
}
|
||||
return await readCString(label);
|
||||
}
|
||||
|
||||
async setSubaddressLabel(accountIndex: number, addressIndex: number, label: string): Promise<void> {
|
||||
await dylib.symbols.MONERO_Wallet_setSubaddressLabel(
|
||||
this.#walletPtr,
|
||||
accountIndex,
|
||||
addressIndex,
|
||||
CString(label),
|
||||
);
|
||||
await this.throwIfError();
|
||||
}
|
||||
|
||||
async getHistory(): Promise<TransactionHistory> {
|
||||
const transactionHistoryPointer = await dylib.symbols.MONERO_Wallet_history(this.#walletPtr);
|
||||
await this.throwIfError();
|
||||
return new TransactionHistory(transactionHistoryPointer as TransactionHistoryPtr);
|
||||
}
|
||||
|
||||
async createTransaction(
|
||||
destinationAddress: string,
|
||||
amount: bigint,
|
||||
pendingTransactionPriority = 0 | 1 | 2 | 3,
|
||||
subaddressAccount: number,
|
||||
sanitize = true,
|
||||
prefferedInputs = "",
|
||||
mixinCount = 0,
|
||||
paymentId = "",
|
||||
separator = ",",
|
||||
): Promise<PendingTransaction> {
|
||||
const pendingTxPtr = await dylib.symbols.MONERO_Wallet_createTransaction(
|
||||
this.#walletPtr,
|
||||
CString(destinationAddress),
|
||||
CString(paymentId),
|
||||
amount,
|
||||
mixinCount,
|
||||
pendingTransactionPriority,
|
||||
subaddressAccount,
|
||||
CString(prefferedInputs),
|
||||
CString(separator),
|
||||
);
|
||||
await this.throwIfError(sanitize);
|
||||
return new PendingTransaction(pendingTxPtr as PendingTransactionPtr);
|
||||
}
|
||||
|
||||
async amountFromString(amount: string): Promise<bigint> {
|
||||
return await dylib.symbols.MONERO_Wallet_amountFromString(CString(amount));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { dylib } from "./bindings.ts";
|
||||
import { Sanitizer } from "./utils.ts";
|
||||
|
||||
export type WalletManagerPtr = Deno.PointerObject<"walletManager">;
|
||||
|
||||
export class WalletManager {
|
||||
#ptr: WalletManagerPtr;
|
||||
sanitizer?: Sanitizer;
|
||||
|
||||
constructor(walletManagerPtr: WalletManagerPtr, sanitizer?: Sanitizer) {
|
||||
this.#ptr = walletManagerPtr;
|
||||
this.sanitizer = sanitizer;
|
||||
}
|
||||
|
||||
getPointer(): WalletManagerPtr {
|
||||
return this.#ptr;
|
||||
}
|
||||
|
||||
static async new(sanitizer?: Sanitizer) {
|
||||
const ptr = await dylib.symbols.MONERO_WalletManagerFactory_getWalletManager();
|
||||
if (!ptr) {
|
||||
sanitizer?.();
|
||||
throw new Error("Failed retrieving wallet manager");
|
||||
}
|
||||
return new WalletManager(ptr as WalletManagerPtr, sanitizer);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user