diff --git a/packages/kos-go/demo/go.mod b/packages/kos-go/demo/go.mod index 7cebd7f2..d61afb71 100644 --- a/packages/kos-go/demo/go.mod +++ b/packages/kos-go/demo/go.mod @@ -2,6 +2,7 @@ module github.com/klever-io/kos-rs/packages/kos-go/demo go 1.24.7 -require github.com/klever-io/kos-rs/packages/kos-go v0.2.37 -replace github.com/klever-io/kos-rs/packages/kos-go => ../ +require github.com/klever-io/kos-rs/packages/kos-go v0.2.40 + +replace github.com/klever-io/kos-rs/packages/kos-go => ../ \ No newline at end of file diff --git a/packages/kos-go/demo/go.sum b/packages/kos-go/demo/go.sum index e69de29b..1d215ccd 100644 --- a/packages/kos-go/demo/go.sum +++ b/packages/kos-go/demo/go.sum @@ -0,0 +1,2 @@ +github.com/klever-io/kos-rs/packages/kos-go v0.2.40 h1:uMYtIRfGioNz+uYXW4fs7rUDmV6hgW1gEZ8tmhZjst0= +github.com/klever-io/kos-rs/packages/kos-go v0.2.40/go.mod h1:ekYnxLsNZh51RGO8/X4WrhDWbUGmW0uUM7NxqE1P5sQ= diff --git a/packages/kos-web/demo/README.md b/packages/kos-web/demo/README.md deleted file mode 100644 index bee1eb06..00000000 --- a/packages/kos-web/demo/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# KOS Wallet Demo - -A demonstration of the KOS (Klever OS) TypeScript library capabilities, showcasing wallet management, cryptography, and signing operations in a simple web interface. - -## Overview - -This demo provides a user-friendly interface to interact with key functionality of the KOS library, including: - -- **Mnemonic Phrase Generation**: Create BIP39 mnemonic phrases with varying word counts (12 or 24 words) -- **Wallet Creation**: Generate wallets from either mnemonic phrases or private keys -- **Encryption/Decryption**: Encrypt and decrypt data with password protection -- **Message Signing**: Sign messages using a wallet's private key - -## Getting Started - -### Prerequisites - -- A modern web browser -- Node.js and npm (for development) - -### Installation - -1. Install dependencies: - -```bash -npm install -``` - -2. Serve the application: - -```bash -npm run dev -``` diff --git a/packages/kos-web/demo/index.html b/packages/kos-web/demo/index.html deleted file mode 100644 index b5655ef2..00000000 --- a/packages/kos-web/demo/index.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - KOS-Rust example - - -
-

KOS-Rust example

- -
-

Wallet Generator

-
-
- -
-

Transaction Signer

-
-
- -
-

Cryptography

-
-
- -
-

SDK Usage Examples in TypeScript

-

-// Example 1: Create a wallet from a mnemonic
-import { Wallet } from '@klever/kos-web';
-
-const mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
-const path = "m/44'/0'/0'/0/0";
-const wallet = Wallet.fromMnemonic(0, mnemonic, path);
-
-console.log("Address:", wallet.getAddress());
-console.log("Public Key:", wallet.getPublicKey());
-
-// Example 2: Sign a message
-const message = "Hello, World!";
-const messageBytes = new TextEncoder().encode(message);
-const signature = wallet.signMessage(messageBytes);
-
-console.log("Signature:", Array.from(signature).map(b => b.toString(16).padStart(2, '0')).join(''));
-
-// Example 3: Encrypt and decrypt data
-import { encrypt, decrypt, toBytes, toString } from '@klever/kos-web';
-
-const data = "Confidential data";
-const password = "secret-password";
-
-const encryptedData = encrypt(toBytes(data), password);
-const decryptedData = decrypt(encryptedData, password);
-
-console.log("Original data:", data);
-console.log("Decrypted data:", toString(decryptedData));
-
-// Don't forget to free resources
-wallet.free();
-          
-
-
- - - - diff --git a/packages/kos-web/demo/package.json b/packages/kos-web/demo/package.json deleted file mode 100644 index 7f3a0fe1..00000000 --- a/packages/kos-web/demo/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "demo", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "typescript": "~5.7.2", - "vite": "^6.2.0" - }, - "dependencies": { - "kos": "file:./kos", - "vite-plugin-wasm": "^3.4.1" - } -} diff --git a/packages/kos-web/demo/src/components/cryptography-demo.ts b/packages/kos-web/demo/src/components/cryptography-demo.ts deleted file mode 100644 index 13fb7345..00000000 --- a/packages/kos-web/demo/src/components/cryptography-demo.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { decrypt, encrypt, fromPem, toBytes, toPem, toString } from "kos"; - -export class CryptographyDemo { - private container: HTMLElement; - private result: HTMLDivElement; - - constructor(containerId: string) { - const container = document.getElementById(containerId); - if (!container) { - throw new Error(`Container element with id "${containerId}" not found`); - } - this.container = container; - this.initUI(); - this.result = document.createElement("div"); - this.result.className = "result"; - this.result.style.display = "none"; - this.container.appendChild(this.result); - } - - private initUI(): void { - const html = ` -
- - -
- -
- - -
- -
- - -
- - - - - `; - - this.container.innerHTML = html; - - // Add event listeners - this.addEventListeners(); - } - - private addEventListeners(): void { - const cryptoAction = document.getElementById( - "crypto-action" - ) as HTMLSelectElement; - const pemTagGroup = document.getElementById( - "pem-tag-group" - ) as HTMLDivElement; - const dataInputLabel = document.querySelector( - "#data-input-group label" - ) as HTMLLabelElement; - const executeBtn = document.getElementById( - "execute-crypto" - ) as HTMLButtonElement; - - // Toggle between encryption options - cryptoAction.addEventListener("change", () => { - switch (cryptoAction.value) { - case "encrypt": - dataInputLabel.textContent = "Data:"; - pemTagGroup.style.display = "none"; - break; - case "decrypt": - dataInputLabel.textContent = "Data (Hex):"; - pemTagGroup.style.display = "none"; - break; - case "to-pem": - dataInputLabel.textContent = "Data (Hex):"; - pemTagGroup.style.display = "block"; - break; - case "from-pem": - dataInputLabel.textContent = "PEM Data:"; - pemTagGroup.style.display = "none"; - break; - } - }); - - // Execute the cryptography action - executeBtn.addEventListener("click", () => { - this.executeCryptoAction(); - }); - } - - private executeCryptoAction(): void { - try { - const action = ( - document.getElementById("crypto-action") as HTMLSelectElement - ).value; - const inputData = ( - document.getElementById("data-input") as HTMLTextAreaElement - ).value.trim(); - const password = ( - document.getElementById("password-input") as HTMLInputElement - ).value; - - if (!inputData) { - throw new Error("Input data is required"); - } - - switch (action) { - case "encrypt": - this.encryptData(inputData, password); - break; - case "decrypt": - this.decryptData(inputData, password); - break; - case "to-pem": - this.convertToPem(inputData); - break; - case "from-pem": - this.convertFromPem(inputData, password); - break; - } - } catch (error) { - if (error instanceof Error) { - this.showError(error.message); - return; - } - if (typeof error === "string") { - this.showError(error); - return; - } - - this.showError("An unknown error occurred"); - } - } - - private encryptData(data: string, password: string): void { - if (!password) { - throw new Error("Password is required for encryption"); - } - - const dataBytes = toBytes(data); - const encryptedBytes = encrypt(dataBytes, password); - - // Convert encrypted bytes to hexadecimal for display - const hexEncrypted = Array.from(encryptedBytes) - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); - - this.showResult(` -

Encrypted Data

-

Original Data: ${data}

-

Encrypted Data (hex): ${hexEncrypted}

- `); - } - - private decryptData(hexData: string, password: string): void { - if (!password) { - throw new Error("Password is required for decryption"); - } - - // Convert the hex string to bytes - try { - const encryptedBytes = new Uint8Array( - hexData.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16)) - ); - const decryptedBytes = decrypt(encryptedBytes, password); - const decryptedText = toString(decryptedBytes); - - this.showResult(` -

Decrypted Data

-

Encrypted Data (hex): ${hexData}

-

Decrypted Data: ${decryptedText}

- `); - } catch (e) { - throw new Error(`Error converting hex to bytes: ${e}`); - } - } - - private convertToPem(hexData: string): void { - // Convert the hex string to bytes - try { - const dataBytes = new Uint8Array( - hexData.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16)) - ); - const tag = ( - document.getElementById("pem-tag") as HTMLInputElement - ).value.trim(); - - if (!tag) { - throw new Error("PEM tag is required"); - } - - const pemData = toPem(tag, dataBytes); - - this.showResult(` -

Conversion to PEM

-

Original Data (hex): ${hexData}

-

PEM Format:

-
${pemData}
- `); - } catch (e) { - throw new Error(`Error converting hex to bytes: ${e}`); - } - } - - private convertFromPem(pemData: string, password: string): void { - try { - if (!password) { - throw new Error("Password is required for PEM decryption"); - } - - const bytes = fromPem(pemData, password); - - // Convert bytes to hexadecimal for display - const hexData = Array.from(bytes) - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); - - this.showResult(` -

Conversion from PEM

-

Original PEM Data:

-
${pemData}
-

Converted Data (hex): ${hexData}

- `); - } catch (e) { - throw new Error(`Error converting from PEM: ${e}`); - } - } - - private showResult(html: string): void { - this.result.innerHTML = html; - this.result.style.display = "flex"; - } - - private showError(message: string): void { - this.result.innerHTML = `
${message}
`; - this.result.style.display = "flex"; - } -} diff --git a/packages/kos-web/demo/src/components/transaction-signer.ts b/packages/kos-web/demo/src/components/transaction-signer.ts deleted file mode 100644 index 8f24a11b..00000000 --- a/packages/kos-web/demo/src/components/transaction-signer.ts +++ /dev/null @@ -1,420 +0,0 @@ -import { - ChainData, - getSupportedChains, - toBytes, - TransactionChainOptions, - Wallet, -} from "kos"; - -export class TransactionSigner { - private container: HTMLElement; - private wallet: Wallet | null = null; - private result: HTMLDivElement; - private chainMap: Map = new Map(); - - constructor(containerId: string) { - const container = document.getElementById(containerId); - if (!container) { - throw new Error(`Container element with id "${containerId}" not found`); - } - this.container = container; - this.initUI(); - this.result = document.createElement("div"); - this.result.className = "result"; - this.result.style.display = "none"; - this.container.appendChild(this.result); - - this.populateBlockchainSelect(); - } - - private initUI(): void { - const html = ` -
- - -
- -
- - -
- -
- - -
- -
- - -
- - - - - - `; - - this.container.innerHTML = html; - - // Add event listeners - this.addEventListeners(); - } - - private populateBlockchainSelect(): void { - try { - const blockchainSelect = document.getElementById( - "blockchain-tx" - ) as HTMLSelectElement; - if (!blockchainSelect) return; - - blockchainSelect.innerHTML = ""; - - const chains = getSupportedChains(); - - chains.forEach((chain) => { - this.chainMap.set(chain.id, chain); - }); - - chains.sort((a, b) => a.getName().localeCompare(b.getName())); - - chains.forEach((chain) => { - const option = document.createElement("option"); - option.value = chain.getId().toString(); - option.textContent = `${chain.getName()} (${chain.getSymbol()})`; - blockchainSelect.appendChild(option); - }); - - // Free the chains after populating the select element - chains.forEach((chain) => { - chain.free(); - }); - } catch (error) { - console.error("Erro ao carregar blockchains:", error); - const blockchainSelect = document.getElementById( - "blockchain-tx" - ) as HTMLSelectElement; - if (blockchainSelect) { - blockchainSelect.innerHTML = - ''; - } - } - } - - private addEventListeners(): void { - const txType = document.getElementById("tx-type") as HTMLSelectElement; - const messageGroup = document.getElementById( - "message-group" - ) as HTMLDivElement; - const transactionGroup = document.getElementById( - "transaction-group" - ) as HTMLDivElement; - const loadWalletBtn = document.getElementById( - "load-wallet-btn" - ) as HTMLButtonElement; - const signBtn = document.getElementById("sign-btn") as HTMLButtonElement; - const chainOptionType = document.getElementById( - "chain-option-type" - ) as HTMLSelectElement; - const ethereumOptions = document.getElementById( - "ethereum-options" - ) as HTMLDivElement; - const bitcoinOptions = document.getElementById( - "bitcoin-options" - ) as HTMLDivElement; - const cosmosOptions = document.getElementById( - "cosmos-options" - ) as HTMLDivElement; - - // Toggle between message and transaction - txType.addEventListener("change", () => { - if (txType.value === "message") { - messageGroup.style.display = "block"; - transactionGroup.style.display = "none"; - } else { - messageGroup.style.display = "none"; - transactionGroup.style.display = "block"; - } - }); - - // Toggle between chain options - chainOptionType.addEventListener("change", () => { - ethereumOptions.style.display = "none"; - bitcoinOptions.style.display = "none"; - cosmosOptions.style.display = "none"; - - switch (chainOptionType.value) { - case "ethereum": - ethereumOptions.style.display = "block"; - break; - case "bitcoin": - bitcoinOptions.style.display = "block"; - break; - case "cosmos": - cosmosOptions.style.display = "block"; - break; - } - }); - - // Load the wallet - loadWalletBtn.addEventListener("click", () => { - this.loadWallet(); - signBtn.disabled = false; - }); - - // Sign the message or transaction - signBtn.addEventListener("click", () => { - if (txType.value === "message") { - this.signMessage(); - } else { - this.signTransaction(); - } - }); - } - - private loadWallet(): void { - try { - const privateKey = ( - document.getElementById("private-key-tx") as HTMLInputElement - ).value.trim(); - const chainId = parseInt( - (document.getElementById("blockchain-tx") as HTMLSelectElement).value - ); - - if (!privateKey) { - throw new Error("Private key is required"); - } - - // Free the previous wallet if it exists - if (this.wallet) { - this.wallet.free(); - } - - this.wallet = Wallet.fromPrivateKey(chainId, privateKey); - - this.showSuccess( - `Wallet successfully loaded! Address: ${this.wallet.getAddress()}` - ); - } catch (error) { - if (error instanceof Error) { - this.showError(error.message); - return; - } - if (typeof error === "string") { - this.showError(error); - return; - } - - this.showError("An unknown error occurred"); - } - } - - private signMessage(): void { - if (!this.wallet) { - this.showError("Wallet not loaded"); - return; - } - - try { - const message = ( - document.getElementById("message-input") as HTMLTextAreaElement - ).value; - if (!message) { - throw new Error("Message is required"); - } - - const messageBytes = toBytes(message); - const signature = this.wallet.signMessage(messageBytes); - - // Convert to hexadecimal for display - const hexSignature = Array.from(signature) - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); - - this.showResult(` -

Message Signature

-

Message: ${message}

-

Signature (hex): ${hexSignature}

- `); - } catch (error) { - if (error instanceof Error) { - this.showError(error.message); - return; - } - if (typeof error === "string") { - this.showError(error); - return; - } - - this.showError("An unknown error occurred"); - } - } - - private signTransaction(): void { - if (!this.wallet) { - this.showError("Wallet not loaded"); - return; - } - - try { - const txDataHex = ( - document.getElementById("transaction-data") as HTMLTextAreaElement - ).value.trim(); - if (!txDataHex) { - throw new Error("Transaction data is required"); - } - - // Convert the hex string to bytes - const txData = new Uint8Array( - txDataHex.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16)) - ); - - // Get chain options, if any - let chainOptions: TransactionChainOptions | null = null; - const chainOptionType = ( - document.getElementById("chain-option-type") as HTMLSelectElement - ).value; - - if (chainOptionType !== "none") { - chainOptions = this.createChainOptions(chainOptionType); - } - - const transaction = this.wallet.sign(txData, chainOptions); - - // Convert values to hexadecimal for display - const rawDataHex = Array.from(transaction.getRawData()) - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); - - const signatureHex = Array.from(transaction.getSignature()) - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); - - const txHashHex = Array.from(transaction.getTxHash()) - .map((b) => b.toString(16).padStart(2, "0")) - .join(""); - - this.showResult(` -

Transaction Hash: ${txHashHex}

-

Signature (hex): ${signatureHex}

-

Raw Data (hex): ${rawDataHex}

- `); - - // Free the transaction - transaction.free(); - } catch (error) { - if (error instanceof Error) { - this.showError(error.message); - return; - } - if (typeof error === "string") { - this.showError(error); - return; - } - - this.showError("An unknown error occurred"); - } - } - - private createChainOptions(optionType: string): TransactionChainOptions { - switch (optionType) { - case "ethereum": { - const chainId = parseInt( - (document.getElementById("eth-chain-id") as HTMLInputElement).value - ); - return TransactionChainOptions.newEthereumSignOptions(chainId); - } - case "bitcoin": { - const amountsStr = ( - document.getElementById("btc-input-amounts") as HTMLInputElement - ).value; - const scriptsStr = ( - document.getElementById("btc-prev-scripts") as HTMLTextAreaElement - ).value; - - const amounts = amountsStr.split(",").map((a) => BigInt(a.trim())); - const scripts = scriptsStr.split(",").map((s) => s.trim()); - - // Create array of BigUint64Array - const inputAmounts = new BigUint64Array(amounts.length); - amounts.forEach((amount, index) => { - inputAmounts[index] = amount; - }); - - return TransactionChainOptions.newBitcoinSignOptions( - inputAmounts, - scripts - ); - } - case "cosmos": { - const chainId = ( - document.getElementById("cosmos-chain-id") as HTMLInputElement - ).value; - const accountNumber = BigInt( - (document.getElementById("cosmos-account-number") as HTMLInputElement) - .value - ); - return TransactionChainOptions.newCosmosSignOptions( - chainId, - accountNumber - ); - } - default: - throw new Error(`Unsupported chain option type: ${optionType}`); - } - } - - private showResult(html: string): void { - this.result.innerHTML = html; - this.result.style.display = "flex"; - } - - private showError(message: string): void { - this.result.innerHTML = `
${message}
`; - this.result.style.display = "flex"; - } - - private showSuccess(message: string): void { - this.result.innerHTML = `
${message}
`; - this.result.style.display = "flex"; - } -} diff --git a/packages/kos-web/demo/src/components/wallet-generator.ts b/packages/kos-web/demo/src/components/wallet-generator.ts deleted file mode 100644 index 8155cd54..00000000 --- a/packages/kos-web/demo/src/components/wallet-generator.ts +++ /dev/null @@ -1,294 +0,0 @@ -import { - AccountType, - ChainData, - generateMnemonicPhrase, - getSupportedChains, - isChainSupported, - PathOptions, - Wallet, -} from "kos"; - -export class WalletGenerator { - private container: HTMLElement; - private result: HTMLDivElement; - private chainMap: Map = new Map(); - - constructor(containerId: string) { - const container = document.getElementById(containerId); - if (!container) { - throw new Error(`Container element with id "${containerId}" not found`); - } - this.container = container; - this.initUI(); - this.result = document.createElement("div"); - this.result.className = "result"; - this.result.style.display = "none"; - this.container.appendChild(this.result); - - this.populateBlockchainSelect(); - } - - private initUI(): void { - const html = ` -
- - -
- -
- - - - - - - -
- - -
- -
- - - - -
-
- - - -
- - -
- - - `; - - this.container.innerHTML = html; - - // Add event listeners - this.addEventListeners(); - } - - private populateBlockchainSelect(): void { - try { - const blockchainSelect = document.getElementById( - "blockchain" - ) as HTMLSelectElement; - if (!blockchainSelect) return; - - blockchainSelect.innerHTML = ""; - - const chains = getSupportedChains(); - - chains.forEach((chain) => { - this.chainMap.set(chain.id, chain); - }); - - chains.sort((a, b) => a.getName().localeCompare(b.getName())); - - chains.forEach((chain) => { - const option = document.createElement("option"); - option.value = chain.getId().toString(); - option.textContent = `${chain.getName()} (${chain.getSymbol()})`; - blockchainSelect.appendChild(option); - }); - - chains.forEach((chain) => { - chain.free(); - }); - } catch (error) { - console.error(error); - const blockchainSelect = document.getElementById( - "blockchain" - ) as HTMLSelectElement; - if (blockchainSelect) { - blockchainSelect.innerHTML = - ''; - } - } - } - - private addEventListeners(): void { - const walletType = document.getElementById( - "wallet-type" - ) as HTMLSelectElement; - const mnemonicOptions = document.getElementById( - "mnemonic-options" - ) as HTMLDivElement; - const privateKeyGroup = document.getElementById( - "private-key-group" - ) as HTMLDivElement; - const generateMnemonicBtn = document.getElementById( - "generate-mnemonic" - ) as HTMLButtonElement; - const mnemonicInputGroup = document.getElementById( - "mnemonic-input-group" - ) as HTMLDivElement; - const mnemonicInput = document.getElementById( - "mnemonic-input" - ) as HTMLTextAreaElement; - const useIndexCheckbox = document.getElementById( - "use-index" - ) as HTMLInputElement; - const indexOptions = document.getElementById( - "index-options" - ) as HTMLDivElement; - const createWalletBtn = document.getElementById( - "create-wallet" - ) as HTMLButtonElement; - - // Toggle wallet options - walletType.addEventListener("change", () => { - if (walletType.value === "mnemonic") { - mnemonicOptions.style.display = "block"; - privateKeyGroup.style.display = "none"; - } else { - mnemonicOptions.style.display = "none"; - privateKeyGroup.style.display = "block"; - } - }); - - // Generate a new mnemonic - generateMnemonicBtn.addEventListener("click", () => { - const wordCount = parseInt( - (document.getElementById("mnemonic-words") as HTMLSelectElement).value - ); - const mnemonic = generateMnemonicPhrase(wordCount); - mnemonicInput.value = mnemonic; - mnemonicInputGroup.style.display = "block"; - }); - - // Toggle index options - useIndexCheckbox.addEventListener("change", () => { - indexOptions.style.display = useIndexCheckbox.checked ? "block" : "none"; - }); - - // Create the wallet - createWalletBtn.addEventListener("click", () => { - this.createWallet(); - }); - } - - private createWallet(): void { - try { - const walletType = ( - document.getElementById("wallet-type") as HTMLSelectElement - ).value; - const chainId = parseInt( - (document.getElementById("blockchain") as HTMLSelectElement).value - ); - - if (!isChainSupported(chainId)) { - throw new Error(`Blockchain with ID ${chainId} is not supported`); - } - - let wallet: Wallet; - - if (walletType === "mnemonic") { - const mnemonic = ( - document.getElementById("mnemonic-input") as HTMLTextAreaElement - ).value.trim(); - if (!mnemonic) { - throw new Error("Mnemonic is required"); - } - - const useIndex = ( - document.getElementById("use-index") as HTMLInputElement - ).checked; - - if (useIndex) { - const index = parseInt( - (document.getElementById("wallet-index") as HTMLInputElement).value - ); - const useLegacy = ( - document.getElementById("use-legacy") as HTMLInputElement - ).checked; - - const pathOptions = PathOptions.new(index); - pathOptions.setLegacy(useLegacy); - - wallet = Wallet.fromMnemonicIndex(chainId, mnemonic, pathOptions); - } else { - const path = ( - document.getElementById("derivation-path") as HTMLInputElement - ).value; - wallet = Wallet.fromMnemonic(chainId, mnemonic, path); - } - } else { - const privateKey = ( - document.getElementById("private-key-input") as HTMLTextAreaElement - ).value.trim(); - if (!privateKey) { - throw new Error("Private key is required"); - } - wallet = Wallet.fromPrivateKey(chainId, privateKey); - } - - this.displayWalletInfo(wallet); - - // Free resources - wallet.free(); - } catch (error) { - if (error instanceof Error) { - this.showError(error.message); - return; - } - if (typeof error === "string") { - this.showError(error); - return; - } - - this.showError("An unknown error occurred"); - } - } - - private displayWalletInfo(wallet: Wallet): void { - const accountTypeLabels = { - [AccountType.Mnemonic]: "Mnemonic", - [AccountType.PrivateKey]: "Private Key", - [AccountType.KleverSafe]: "KleverSafe", - [AccountType.ReadOnly]: "Read Only", - }; - - let info = `

Wallet Information

-

Type: ${ - accountTypeLabels[wallet.getAccountType()] - }

-

Address: ${wallet.getAddress()}

-

Public Key: ${wallet.getPublicKey()}

-

Private Key: ${wallet.getPrivateKey()}

- `; - - this.result.innerHTML = info; - this.result.style.display = "flex"; - } - - private showError(message: string): void { - this.result.innerHTML = `
${message}
`; - this.result.style.display = "flex"; - } -} diff --git a/packages/kos-web/demo/src/index.js b/packages/kos-web/demo/src/index.js new file mode 100644 index 00000000..10784ce9 --- /dev/null +++ b/packages/kos-web/demo/src/index.js @@ -0,0 +1,92 @@ +import { + Wallet, + PathOptions, + TransactionChainOptions +} from '@klever/kos-web'; + +function main() { + try { + const chainID = 18; // BCH + + const pathOptions = PathOptions.new(0); + pathOptions.setLegacy(false); + + const mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; + + const account = Wallet.fromMnemonicIndex( + chainID, + mnemonic, + pathOptions, + null, + null + ); + + console.log("Address:", account.getAddress()); + console.log("Public Key:", account.getPublicKey()); + + const rawTx = "0100000002afa8838dbaa03cd3e4fee38bdcb6a428965559ae941dca5a8f91999cfd6d8b0d0100000000ffffffffdb6d60d4a93a95738e72f641bcdd166c94f6e1f439dfe695e40583997284463c0100000000ffffffff0240420f00000000001976a91434bf902df5d66f0e9b89d0f83fbcad638ad19ae988acea970700000000001976a9145bb0ba5ba58cdab459f27f2d29f40e1dd5db238188ac00000000"; + + // Convert hex to base64 for JavaScript binding + const hexToBase64 = (hex) => { + const bytes = new Uint8Array(hex.length / 2); + for (let i = 0; i < hex.length; i += 2) { + bytes[i / 2] = parseInt(hex.substr(i, 2), 16); + } + return btoa(String.fromCharCode(...bytes)); + }; + + const prevScript1 = hexToBase64("76a9145bb0ba5ba58cdab459f27f2d29f40e1dd5db238188ac"); + const prevScript2 = hexToBase64("76a9145bb0ba5ba58cdab459f27f2d29f40e1dd5db238188ac"); + + const inputAmounts = new BigUint64Array([498870n, 1001016n]); + const prevScripts = [prevScript1, prevScript2]; + + const options = TransactionChainOptions.newBitcoinSignOptions( + inputAmounts, + prevScripts + ); + + + // Convert raw transaction hex string to bytes using custom hex decoder + const hexToUint8Array = (hex) => { + const bytes = new Uint8Array(hex.length / 2); + for (let i = 0; i < hex.length; i += 2) { + bytes[i / 2] = parseInt(hex.substr(i, 2), 16); + } + return bytes; + }; + + const uint8ArrayToHex = (bytes) => { + return Array.from(bytes) + .map(b => b.toString(16).padStart(2, '0')) + .join(''); + }; + + const rawTxBytes = hexToUint8Array(rawTx); + + const transaction = account.sign(rawTxBytes, options); + + const signedRawBytes = transaction.getRawData(); + const signedRaw = uint8ArrayToHex(signedRawBytes); + + const expectedRaw = "0100000002afa8838dbaa03cd3e4fee38bdcb6a428965559ae941dca5a8f91999cfd6d8b0d010000006b48304502210099626d28374fa3d1a0034330fee7745ab02db07cd37649e6d3ffbe046ff92e9402203793bee2372ab59a05b45188c2bace3b48e73209a01e4d5d862925971632c80a412102bbe7dbcdf8b2261530a867df7180b17a90b482f74f2736b8a30d3f756e42e217ffffffffdb6d60d4a93a95738e72f641bcdd166c94f6e1f439dfe695e40583997284463c010000006a4730440220447084aae4c6800db7c86b8bc8da675e464991a035b2b4010cde48b64a1013a10220582acfb5265c22eae9c2880e07ae66fc86cbef2e97a2ca1bc513535ba322360d412102bbe7dbcdf8b2261530a867df7180b17a90b482f74f2736b8a30d3f756e42e217ffffffff0240420f00000000001976a91434bf902df5d66f0e9b89d0f83fbcad638ad19ae988acea970700000000001976a9145bb0ba5ba58cdab459f27f2d29f40e1dd5db238188ac00000000"; + + if (signedRaw !== expectedRaw) { + throw new Error( + `Signed transaction mismatch.\nExpected: ${expectedRaw}\nGot: ${signedRaw}` + ); + } + + console.log("\nTransaction signed correctly!"); + + console.log("\nSigned raw transaction:"); + console.log(signedRaw + "\n"); + } catch (error) { + const err = error instanceof Error ? error : new Error(String(error)); + console.error("Error:", err.message); + console.error("Stack:", err.stack); + process.exitCode = 1; + } +} + +main(); \ No newline at end of file diff --git a/packages/kos-web/demo/src/main.ts b/packages/kos-web/demo/src/main.ts deleted file mode 100644 index 10bcbd47..00000000 --- a/packages/kos-web/demo/src/main.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { CryptographyDemo } from "./components/cryptography-demo"; -import { TransactionSigner } from "./components/transaction-signer"; -import { WalletGenerator } from "./components/wallet-generator"; -import "./style.css"; - -// Initialize components -try { - console.log("starting"); - new WalletGenerator("wallet-generator"); - new TransactionSigner("transaction-signer"); - new CryptographyDemo("cryptography-demo"); -} catch (error) { - console.error("Error initializing the demonstration:", error); -} diff --git a/packages/kos-web/demo/src/package.json b/packages/kos-web/demo/src/package.json new file mode 100644 index 00000000..c6d073e5 --- /dev/null +++ b/packages/kos-web/demo/src/package.json @@ -0,0 +1,17 @@ +{ + "name": "kos-web-demo", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "node index.js", + "dev": "node index.js" + }, + "keywords": [], + "author": "", + "license": "MIT", + "type": "module", + "dependencies": { + "@klever/kos-web": "^0.2.41" + } +} diff --git a/packages/kos-web/demo/src/style.css b/packages/kos-web/demo/src/style.css deleted file mode 100644 index 7137b9ea..00000000 --- a/packages/kos-web/demo/src/style.css +++ /dev/null @@ -1,107 +0,0 @@ -:root { - font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -body { - margin: 0; - display: flex; - min-width: 320px; - min-height: 100vh; -} - -.container { - max-width: 1200px; - margin: 0 auto; - padding: 2rem; - width: 100%; -} - -h1 { - font-size: 2.5rem; - line-height: 1.1; - text-align: center; - margin-bottom: 2rem; -} - -.card { - padding: 1.5rem; - border-radius: 8px; - background-color: #1a1a1a; - margin-bottom: 1.5rem; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); -} - -h2 { - margin-top: 0; - margin-bottom: 1rem; -} - -button { - padding: 0.6em 1.2em; - cursor: pointer; -} - -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -input, -select, -textarea { - border-radius: 4px; - padding: 0.5rem; - margin-bottom: 1rem; - background-color: #2a2a2a; - border: 1px solid #3a3a3a; - color: white; - width: 100%; -} - -.form-group { - margin-bottom: 1rem; -} - -.form-group label { - display: block; - margin-bottom: 0.5rem; -} - -.result { - display: flex; - flex-direction: column; - padding: 1rem; - margin-top: 1rem; - overflow-wrap: break-word; - white-space: pre-wrap; -} - -.error { - color: #ff6b6b; - font-size: 0.9rem; - margin-top: 0.5rem; -} - -.success { - color: #4caf50; - font-size: 0.9rem; - margin-top: 0.5rem; -} - -@media (prefers-color-scheme: light) { - input, - select, - textarea { - border: 1px solid #ddd; - color: #213547; - } -} diff --git a/packages/kos-web/demo/src/vite-env.d.ts b/packages/kos-web/demo/src/vite-env.d.ts deleted file mode 100644 index 11f02fe2..00000000 --- a/packages/kos-web/demo/src/vite-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/packages/kos-web/demo/tsconfig.json b/packages/kos-web/demo/tsconfig.json deleted file mode 100644 index a4883f28..00000000 --- a/packages/kos-web/demo/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/packages/kos-web/demo/vite.config.ts b/packages/kos-web/demo/vite.config.ts deleted file mode 100644 index eb74f2c9..00000000 --- a/packages/kos-web/demo/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from "vite"; -import wasm from "vite-plugin-wasm"; - -export default defineConfig({ - plugins: [wasm()], -});