bsv-p2p-wallet-uat
Version:
A Bitcoin SV Wallet Library
420 lines (367 loc) • 11.9 kB
JavaScript
;
var __rest =
(this && this.__rest) ||
function (s, e) {
var t = {};
for (var p in s)
if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (
e.indexOf(p[i]) < 0 &&
Object.prototype.propertyIsEnumerable.call(s, p[i])
)
t[p[i]] = s[p[i]];
}
return t;
};
var __awaiter =
(this && this.__awaiter) ||
function (thisArg, _arguments, P, generator) {
function adopt(value) {
return value instanceof P
? value
: new P(function (resolve) {
resolve(value);
});
}
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done
? resolve(result.value)
: adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault =
(this && this.__importDefault) ||
function (mod) {
return mod && mod.__esModule
? mod
: {
default: mod,
};
};
Object.defineProperty(exports, "__esModule", {
value: true,
});
const HDPrivateKey_1 = __importDefault(require("./HDPrivateKey"));
const Blockchain_1 = __importDefault(require("./Blockchain"));
const {
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS,
} = require("bsv/lib/script/interpreter");
const _1 = require(".");
const Tx_1 = require("./Utils/Tx");
const fs = __importDefault(require("fs"));
const axios_1 = __importDefault(require("axios"));
const BSVWallet_1 = __importDefault(require("./Wallet"));
// const senderWallet = new BSVWallet.default({ key: "" });
// const walletSender = new Wallet({ key: "" });
class PeerToPeerWallet extends HDPrivateKey_1.default {
constructor(_a) {
var {
key = "",
keyFormat = "mnemonic",
language = "ENGLISH",
network = "testnet",
} = _a,
options = __rest(_a, ["key", "keyFormat", "language", "network"]);
super(
Object.assign(
{
key,
keyFormat,
language,
network,
},
options
)
);
this.index = 0;
this.blockchain = new Blockchain_1.default(network);
this.cache = new _1.BlockchainCache();
this.api = axios_1.default.create({
baseURL: `https://api.whatsonchain.com/v1/bsv/main`,
});
this.dbName = "PeerToPeer";
this.storeName = "Transactions";
this.existingTransactions = [];
this.wallet = new BSVWallet_1.default({ key: "" });
}
sync() {
throw new Error("not yet implemented");
}
sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async getBalance(walletAddress) {
let dbValues = [];
//await this.getDetails(existingTransactions);
dbValues = await this.getExistingTransactions(walletAddress)
console.log("Existing Transactions 2", dbValues);
existingTransactions = dbValues.Transactions.map( x => x.value)
let total = existingTransactions.reduce((a, b) => a + b, 0);
return total;
}
remove_Pairs(inputArr) {
var inputCount = {};
for (let index = 0; index < inputArr.length; index++) {
if (inputArr[index] in inputCount) {
inputCount[inputArr[index]] += 1;
} else {
inputCount[inputArr[index]] = 1;
}
}
let ans = [];
for (const [key, value] of Object.entries(inputCount)) {
if (-key in inputCount) {
let noOfTimes = inputCount[key] - inputCount[-key];
for (let index = 0; index < Math.abs(noOfTimes); index++) {
ans.push(Math.abs(key));
}
inputCount[-key] = 0;
} else {
for (let index = 0; index < inputCount[key]; index++) {
ans.push(key);
}
}
inputCount[key] = 0;
}
return ans.map((x) => Number(x));
}
isBalanceEnough(allTransactions, amountToSend) {
let sum = allTransactions.reduce((a, b) => a + b, 0);
console.log("Balance = ", sum, " Amount to send = ", amountToSend);
if (sum && amountToSend <= sum) {
return true;
} else {
return false;
}
}
async sendBitcoin(senderWallet, receiverWallet, sendBitcoinQuantity) {
console.log("sender wallet", senderWallet);
let existingTransactions = [];
let dbValues = [];
//await this.getDetails(existingTransactions);
dbValues = await this.getExistingTransactions(senderWallet)
console.log("Existing Transactions 2", dbValues);
existingTransactions = dbValues.Transactions.map( x => x.value)
if (!this.isBalanceEnough(existingTransactions, sendBitcoinQuantity))
{
console.log("Balance is not enough. Returning")
return null;
}
this.remove_Pairs(existingTransactions);
//optimal array = result here
let optimalArray = []
let temp = this.initOptimalArray(existingTransactions, sendBitcoinQuantity);
if (temp.length == 0 || temp === undefined) return;
optimalArray = temp[0];
let resultArrayUtxo = [];
let transactions = [];
try {
let sum = optimalArray.reduce((a, b) => a + b, 0);
for (let index = 0; index < optimalArray.length; index++) {
const element = optimalArray[index];
console.log("Element ", element);
let trUtxo = {};
trUtxo.to = receiverWallet;
trUtxo.amount = element;
resultArrayUtxo.push(trUtxo);
let transaction = {}
transaction.receiver= receiverWallet;
transaction.amount = -1*element;
transaction.wallet = senderWallet;
transactions.push(transaction)
}
if ( sum != sendBitcoinQuantity )
{
let trUtxo = {}
trUtxo.to = senderWallet;
trUtxo.amount = sum - sendBitcoinQuantity;
resultArrayUtxo.push(trUtxo);
let transaction = {}
transaction.receiver= senderWallet;
transaction.amount = sum - sendBitcoinQuantity;
transaction.wallet = senderWallet;
transactions.push(transaction)
}
console.log("ResultArray UTXO ", resultArrayUtxo);
let tx = await this.wallet.signTx(resultArrayUtxo);
transactions.forEach( x => x.txId = tx)
dbValues.Transactions.push(transactions)
console.log("dbValues.Transactions", dbValues.Transactions)
this.addItemToDb(dbValues);
return existingTransactions;
} catch (error) {
console.log(error);
}
}
async createWallet() {
this.wallet = new BSVWallet_1.default({ key: "" });
let address = await this.wallet.getAddress();
return address;
}
initOptimalArray(arr, sendBitcoinQuantity) {
console.log(arr);
let ans = [];
this.subsetsSumGreaterThanK(
arr,
sendBitcoinQuantity,
[],
0,
0,
ans,
Infinity
);
console.log("Optimal ", ans.join(", "));
return ans;
}
subsetsSumGreaterThanK(nums, k, subset, csum, ind, ans, subSetSumClosestToK) {
if (ind === nums.length) {
if (csum >= k) {
if (csum < subSetSumClosestToK) {
ans[0] = [...subset];
subSetSumClosestToK = csum;
}
if (csum === subSetSumClosestToK && subset.length < ans[0].length) {
ans[0] = [...subset];
}
}
return subSetSumClosestToK;
}
subset.push(nums[ind]);
subSetSumClosestToK = this.subsetsSumGreaterThanK(
nums,
k,
subset,
csum + nums[ind],
ind + 1,
ans,
subSetSumClosestToK
);
subset.pop();
subSetSumClosestToK = this.subsetsSumGreaterThanK(
nums,
k,
subset,
csum,
ind + 1,
ans,
subSetSumClosestToK
);
return subSetSumClosestToK;
}
async decodeAllTransactions(wallet) {
//await this.getDetails(existingTransactions);
let dbValues = [];
dbValues = await this.getExistingTransactions(wallet)
console.log("Decoding All Transactions ", dbValues);
var result = []
let existingTransactions = []
dbValues.Transactions.forEach( x => {
if( Array.isArray(x) )
existingTransactions.push(x[0].txId);
else
existingTransactions.push(x.txId)
});
existingTransactions.map( async (x) => {
console.log("X", x)
if ( x != "")
{
let tx = await this.blockchain.getTxDecode(x)
await this.sleep(2000)
console.log("Transaction ", tx)
result.push(tx)
}
});
return result;
}
async initIndexedDb(idb) {
if (!idb) {
console.log("This browser doesn't support IndexedDB");
return false;
}
this.idb = idb;
const request = idb.open(this.dbName, 1);
request.onerror = async (event) => {
console.error("An error occurred with IndexedDB");
console.error(event);
return false;
};
request.onupgradeneeded = async (event) => {
console.log(event);
const db = request.result;
if (!db.objectStoreNames.contains(this.storeName)) {
const objectStore = await db.createObjectStore(this.storeName, {
keyPath: "wallet",
});
}
return true;
};
}
async getExistingTransactions(receiverWallet) {
return new Promise(async (resolve, reject) => {
let request = this.idb.open(this.dbName, 1);
request.onerror = async (event) => await reject(event);
request.onsuccess = async (event) => {
const db = request.result;
let tx = await db.transaction(this.storeName, "readonly");
request.onerror = (event) => reject(event);
let store = tx.objectStore(this.storeName);
let result = await store.get(receiverWallet);
tx.oncomplete = async () => await resolve(result.result);
};
});
}
async getAllDataIndexedDb() {
return new Promise(async (resolve, reject) => {
let request = this.idb.open(this.dbName, 1);
request.onerror = async (event) => {
await reject(event);
console.log("Db opening failed");
}
request.onsuccess = async (event) => {
console.log(event);
const db = request.result;
let tx = await db.transaction(this.storeName, "readonly");
request.onerror = (event) => reject(event);
let store = tx.objectStore(this.storeName);
let result = await store.getAll();
// console.log(result, "RESULT");
tx.oncomplete = async () => await resolve(result);
};
});
}
async addItemToDb(itemObj) {
const dbPromise = this.idb.open(this.dbName, 1);
dbPromise.onsuccess = () => {
const db = dbPromise.result;
var tx = db.transaction(this.storeName, "readwrite");
var userData = tx.objectStore(this.storeName);
const users = userData.put(itemObj);
users.onsuccess = (query) => {
tx.oncomplete = function () {
db.close();
};
};
};
}
}
exports.default = PeerToPeerWallet;