Skip to content

Commit

Permalink
initial ts commit
Browse files Browse the repository at this point in the history
  • Loading branch information
MrCyjaneK committed Aug 21, 2024
1 parent 41c58ac commit b1794b5
Show file tree
Hide file tree
Showing 10 changed files with 347 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"deno.enable": true
}
10 changes: 10 additions & 0 deletions generate_checksum.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#!/bin/bash
cd "$(realpath $(dirname $0))"

if [[ "$(uname)" == "Darwin" ]];
then
function sha256sum() { shasum -a 256 "$@" ; } && export -f sha256sum
fi

for coin in monero wownero;
do
COIN=$(echo "$coin" | tr a-z A-Z)
Expand All @@ -23,6 +28,11 @@ 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}_wallet2_api_c_h_sha256 = "${COIN_wallet2_api_c_h_sha256}";
export const ${COIN}_wallet2_api_c_cpp_sha256 = "${COIN_wallet2_api_c_cpp_sha256}";
export const ${COIN}_wallet2_api_c_exp_sha256 = "${COIN_wallet2_api_c_exp_sha256}";
EOF
done

1 change: 1 addition & 0 deletions impls/monero.ts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*_libwallet2_api_c.*
1 change: 1 addition & 0 deletions impls/monero.ts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# monero.ts wip library
3 changes: 3 additions & 0 deletions impls/monero.ts/checksum_monero.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const MONERO_wallet2_api_c_h_sha256 = "e8db0ef0324a153f5e3ecca4c0db23c54f4576e84988f04bd4f11c1142f9d7ad";
export const MONERO_wallet2_api_c_cpp_sha256 = "d1842cded0040c16b8886878681c8938005f69ec1378fa9be68a430311cc3666";
export const MONERO_wallet2_api_c_exp_sha256 = "c8913ac41068f67b57c9b0a3c7dd8973e3c1273b66c2ff0aadb0003931da748c";
3 changes: 3 additions & 0 deletions impls/monero.ts/checksum_wownero.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const WOWNERO_wallet2_api_c_h_sha256 = "8a8d386dd5d996c89a0586c55b295ef95ca584bf1ffa26255152b291910a0a77";
export const WOWNERO_wallet2_api_c_cpp_sha256 = "ed400bd9c4709383ffd42a9fbe68be37a2a47a42f92eacaf3a2dbd248c422739";
export const WOWNERO_wallet2_api_c_exp_sha256 = "3673e40e1a7115552276d1d541f6e4d5a0fef47c40fff7b988f49923af84c8a4";
186 changes: 186 additions & 0 deletions impls/monero.ts/monero_bindings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import { Wallet } from "./wallet.ts";
import { WalletManager } from "./wallet_manager.ts";
import { platform } from 'node:process';

const libPath = () => {
if (platform == 'win32') return 'monero_libwallet2_api_c.dll'
// ios missing, if you ever happen to run this on iOS
// 1) seek help
// 2) return
// 2.1) if compliant with app store - MoneroWallet.framework/MoneroWallet
// 2.2) if hacked around 'monero_libwallet2_api_c.dylib'
if (platform == 'darwin') return './monero_libwallet2_api_c.dylib'
if (platform == 'android') return 'libmonero_libwallet2_api_c.so'
return 'monero_libwallet2_api_c.so'
};

export const dylib = Deno.dlopen(libPath(), {
"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",
},
//#endregion

//#region Wallet
"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_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_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",
},
//#endregion
});

if (import.meta.main) {
let option: string | null = null;
while (option !== "o" && option !== "c") {
const message = option
? "Your option has to be either (c)reate or (o)pen"
: "Do you want to (c)reate or (o)pen a wallet?";
option = prompt(message);
}

const path = prompt("Wallet path:");
if (!path) throw "You have to set path";
const absolutePath = import.meta.resolve(path).replace("file://", "");

const password = prompt("Password:");
if (!password) throw "You have to choose password";

const walletManager = await WalletManager.new();
const wallet = option === "c"
? await Wallet.create(walletManager, absolutePath, password)
: await Wallet.open(walletManager, absolutePath, password);

const error = await wallet.error();
if (error) throw error;

const address = await wallet.address();

if (address !== null) {
console.log("Your address is:", address);
}
}

if (import.meta.main) {
let option: string | null = null;
while (option !== "o" && option !== "c") {
const message = option
? "Your option has to be either (c)reate or (o)pen"
: "Do you want to (c)reate or (o)pen a wallet?";
option = prompt(message);
}

const path = prompt("Wallet path:");
if (!path) throw "You have to set path";
const absolutePath = import.meta.resolve(path).replace("file://", "");

const password = prompt("Password:");
if (!password) throw "You have to choose password";

const walletManager = await WalletManager.new();
const wallet = option === "c"
? await Wallet.create(walletManager, absolutePath, password)
: await Wallet.open(walletManager, absolutePath, password);

const error = await wallet.error();
if (error) throw error;

const address = await wallet.address();

if (address !== null) {
console.log("Your address is:", address);
}
}

if (import.meta.main) {
let option: string | null = null;
while (option !== "o" && option !== "c") {
const message = option
? "Your option has to be either (c)reate or (o)pen"
: "Do you want to (c)reate or (o)pen a wallet?";
option = prompt(message);
}

const path = prompt("Wallet path:");
if (!path) throw "You have to set path";
const absolutePath = import.meta.resolve(path).replace("file://", "");

const password = prompt("Password:");
if (!password) throw "You have to choose password";

const walletManager = await WalletManager.new();
const wallet = option === "c"
? await Wallet.create(walletManager, absolutePath, password)
: await Wallet.open(walletManager, absolutePath, password);

const error = await wallet.error();
if (error) throw error;

const address = await wallet.address();

if (address !== null) {
console.log("Your address is:", address);
}
}
4 changes: 4 additions & 0 deletions impls/monero.ts/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const textEncoder = new TextEncoder();
export function CString(string: string): Deno.PointerValue<string> {
return Deno.UnsafePointer.of(textEncoder.encode(`${string}\x00`));
}
111 changes: 111 additions & 0 deletions impls/monero.ts/wallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { dylib } from "./monero_bindings.ts";
import { CString } from "./utils.ts";
import { WalletManager, type WalletManagerPtr } from "./wallet_manager.ts";

export type WalletPtr = Deno.PointerObject<"walletManager">;

export class Wallet {
#walletManagerPtr: WalletManagerPtr;
#walletPtr: WalletPtr;

constructor(walletManagerPtr: WalletManager, walletPtr: WalletPtr) {
this.#walletPtr = walletPtr;
this.#walletManagerPtr = walletManagerPtr.getPointer(this);
}

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.error();
throw new Error(`Failed getting address from a wallet: ${error ?? "<Error unknown>"}`);
}
return new Deno.UnsafePointerView(address).getCString();
}

async balance(accountIndex = 0): Promise<bigint> {
return await dylib.symbols.MONERO_Wallet_balance(this.#walletPtr, accountIndex);
}

static async create(walletManager: WalletManager, path: string, password: string): 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);

const maybeError = await wallet.error();
if (maybeError) throw new Error(maybeError);

return wallet;
}

static async open(walletManager: WalletManager, path: string, password: string): 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);

const maybeError = await wallet.error();
if (maybeError) throw new Error(maybeError);

return wallet;
}

static async recover(
walletManager: WalletManager,
path: string,
password: string,
mnemonic: string,
restoreHeight: bigint = 0n,
seedOffset: string = "",
): 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);

const maybeError = await wallet.error();
if (maybeError) throw new Error(maybeError);

return wallet;
}

status(): Promise<number> {
return dylib.symbols.MONERO_Wallet_status(this.#walletPtr);
}

async error(): Promise<string | null> {
if (!await this.status()) return null;

const error = await dylib.symbols.MONERO_Wallet_errorString(this.#walletPtr);
if (!error) return null;

const errorString = new Deno.UnsafePointerView(error).getCString();
return errorString || null;
}
}
25 changes: 25 additions & 0 deletions impls/monero.ts/wallet_manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { dylib } from "./monero_bindings.ts";

export type WalletManagerPtr = Deno.PointerObject<"walletManager">;

export class WalletManager {
#ptr: WalletManagerPtr;
// Stores data about who uses the pointer
#pointerUsers: WeakSet<object>;

constructor(walletManagerPtr: WalletManagerPtr) {
this.#ptr = walletManagerPtr;
this.#pointerUsers = new WeakSet();
}

getPointer(holder?: object) {
if (holder) this.#pointerUsers.add(holder);
return this.#ptr;
}

static async new() {
const ptr = await dylib.symbols.MONERO_WalletManagerFactory_getWalletManager();
if (!ptr) throw new Error("Failed retrieving wallet manager");
return new WalletManager(ptr as WalletManagerPtr);
}
}

0 comments on commit b1794b5

Please sign in to comment.