meta-contract-debug
Version:
Meta Contract SDK
221 lines (220 loc) • 9.46 kB
JavaScript
"use strict";
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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Wallet = void 0;
const mvc = require("../mvc");
const utils_1 = require("../common/utils");
const api_1 = require("../api");
const tx_composer_1 = require("../tx-composer");
class Wallet {
constructor(wif, network = api_1.API_NET.MAIN, feeb, apiTarget = api_1.API_TARGET.MVC, apiUrl) {
if (wif) {
this.privateKey = mvc.PrivateKey.fromWIF(wif);
}
else {
this.privateKey = mvc.PrivateKey.fromRandom(network);
}
this.address = this.privateKey.toAddress(network);
this.blockChainApi = new api_1.Api(network, apiTarget, apiUrl);
this.feeb = feeb;
this.network = network;
}
get api() {
return this.blockChainApi;
}
getUnspents() {
return __awaiter(this, void 0, void 0, function* () {
return yield this.blockChainApi.getUnspents(this.address.toString());
});
}
getUtxos() {
return __awaiter(this, void 0, void 0, function* () {
return this.getUnspents();
});
}
getBalance() {
return __awaiter(this, void 0, void 0, function* () {
let { pendingBalance, balance } = yield this.blockChainApi.getBalance(this.address.toString());
return balance + pendingBalance;
});
}
send(address, amount, options) {
return __awaiter(this, void 0, void 0, function* () {
const txComposer = new tx_composer_1.TxComposer();
let utxos = yield this.blockChainApi.getUnspents(this.address.toString());
const pickedUtxos = this.pickUtxo(utxos, amount);
pickedUtxos.forEach((v) => {
txComposer.appendP2PKHInput({
address: new mvc.Address(v.address, this.network),
txId: v.txId,
outputIndex: v.outputIndex,
satoshis: v.satoshis,
});
});
txComposer.appendP2PKHOutput({
address: new mvc.Address(address, this.network),
satoshis: amount,
});
txComposer.appendChangeOutput(this.address, this.feeb);
pickedUtxos.forEach((v, index) => {
txComposer.unlockP2PKHInput(this.privateKey, index);
});
return yield this.broadcastTxComposer(txComposer, options);
});
}
sendArray(receivers, options) {
return __awaiter(this, void 0, void 0, function* () {
const txComposer = new tx_composer_1.TxComposer();
let utxos = yield this.blockChainApi.getUnspents(this.address.toString());
utxos.forEach((v) => {
txComposer.appendP2PKHInput({
address: new mvc.Address(v.address, this.network),
txId: v.txId,
outputIndex: v.outputIndex,
satoshis: v.satoshis,
});
});
receivers.forEach((v) => {
txComposer.appendP2PKHOutput({
address: new mvc.Address(v.address, this.network),
satoshis: v.amount,
});
});
txComposer.appendChangeOutput(this.address, this.feeb);
utxos.forEach((v, index) => {
txComposer.unlockP2PKHInput(this.privateKey, index);
});
return yield this.broadcastTxComposer(txComposer, options);
});
}
merge(options) {
return __awaiter(this, void 0, void 0, function* () {
const txComposer = new tx_composer_1.TxComposer();
let utxos = yield this.blockChainApi.getUnspents(this.address.toString());
utxos.forEach((v) => {
txComposer.appendP2PKHInput({
address: new mvc.Address(v.address, this.network),
txId: v.txId,
outputIndex: v.outputIndex,
satoshis: v.satoshis,
});
});
txComposer.appendChangeOutput(this.address, this.feeb);
utxos.forEach((v, index) => {
txComposer.unlockP2PKHInput(this.privateKey, index);
});
return yield this.broadcastTxComposer(txComposer, options);
});
}
// evenly split all amount into utxo shares, this will increase parallel for wallet
// minShareValue is used to guarantee single share value won't be too small
// the last share will cover the tx fee
evenSplit(shares, minShareValue = 0, options) {
return __awaiter(this, void 0, void 0, function* () {
const txComposer = new tx_composer_1.TxComposer();
const utxos = yield this.blockChainApi.getUnspents(this.address.toString());
const sumAmount = utxos.map((utxo) => utxo.satoshis).reduce((a, b) => a + b, 0);
utxos.forEach((v) => {
txComposer.appendP2PKHInput({
address: new mvc.Address(v.address, this.network),
txId: v.txId,
outputIndex: v.outputIndex,
satoshis: v.satoshis,
});
});
const shareValue = Math.floor(sumAmount / shares);
if (shareValue < minShareValue) {
throw new Error(`"Share value ${shareValue} is less than minShareValue ${minShareValue}"`);
}
for (let i = 0; i < shares - 1; i++) {
txComposer.appendP2PKHOutput({ address: this.address, satoshis: shareValue });
}
txComposer.appendChangeOutput(this.address, this.feeb);
utxos.forEach((v, index) => {
txComposer.unlockP2PKHInput(this.privateKey, index);
});
return yield this.broadcastTxComposer(txComposer, options);
});
}
broadcastTxComposer(txComposer, options) {
return __awaiter(this, void 0, void 0, function* () {
const { noBroadcast, dump } = options || {};
if (dump) {
(0, utils_1.dumpTx)(txComposer.getTx(), this.network);
}
if (noBroadcast) {
return txComposer;
}
return yield this.blockChainApi.broadcast(txComposer.getRawHex());
// return txComposer
});
}
sendOpReturn(opreturnData, options) {
return __awaiter(this, void 0, void 0, function* () {
const txComposer = new tx_composer_1.TxComposer();
let utxos = yield this.blockChainApi.getUnspents(this.address.toString());
utxos.forEach((v) => {
txComposer.appendP2PKHInput({
address: new mvc.Address(v.address, this.network),
txId: v.txId,
outputIndex: v.outputIndex,
satoshis: v.satoshis,
});
});
txComposer.appendOpReturnOutput(opreturnData);
txComposer.appendChangeOutput(this.address, this.feeb);
utxos.forEach((v, index) => {
txComposer.unlockP2PKHInput(this.privateKey, index);
});
return yield this.broadcastTxComposer(txComposer, options);
});
}
// pick utxo enough to pay amount and fee, use confirmed utxo in priority
// shuffle confirmed utxo for higher concurrency
pickUtxo(utxos, amount) {
// amount + 2 outputs + buffer
let requiredAmount = amount + 34 * 2 * this.feeb + 100;
const candidateUtxos = [];
// split utxo to confirmed and unconfirmed and shuffle them
const confirmedUtxos = utxos
.filter((utxo) => {
return utxo.height > 0;
})
.sort(() => Math.random() - 0.5);
const unconfirmedUtxos = utxos
.filter((utxo) => {
return utxo.height < 0;
})
.sort(() => Math.random() - 0.5);
let current = 0;
// use confirmed first
for (let utxo of confirmedUtxos) {
current += utxo.satoshis;
// add input fee
requiredAmount += this.feeb * utils_1.P2PKH_UNLOCK_SIZE;
candidateUtxos.push(utxo);
if (current > requiredAmount) {
return candidateUtxos;
}
}
for (let utxo of unconfirmedUtxos) {
current += utxo.satoshis;
// add input fee
requiredAmount += this.feeb * utils_1.P2PKH_UNLOCK_SIZE;
candidateUtxos.push(utxo);
if (current > requiredAmount) {
return candidateUtxos;
}
}
return candidateUtxos;
}
}
exports.Wallet = Wallet;