Skip to content

Commit fa16643

Browse files
committed
feat: initial commit
0 parents  commit fa16643

17 files changed

+1463
-0
lines changed

.env

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
MNEMONIC = mixed trophy belt busy six obey ring blade smile energy shop kind
2+
PRIVATE_KEY = cRkcH9QdpkvRXdBzig5Er3NJJQwz4JwsK7XVmKnh5ndqvb5aYLJ5

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
MNEMONIC =
2+
PRIVATE_KEY =

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

UTXO_merge.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import networkConfig from "config/network.config";
2+
import { getUtxos, pushBTCpmt } from "./utils/mempool";
3+
import * as Bitcoin from "bitcoinjs-lib";
4+
import * as ecc from "tiny-secp256k1";
5+
import { SeedWallet } from "utils/SeedWallet";
6+
// import { WIFWallet } from 'utils/WIFWallet'
7+
import dotenv from "dotenv";
8+
import { redeemMergeUTXOPsbt, mergeUTXOPsbt } from "controller/utxo.merge.controller";
9+
10+
const TESTNET_FEERATE = 20;
11+
const MERGE_COUNT = 5;
12+
13+
dotenv.config();
14+
Bitcoin.initEccLib(ecc);
15+
16+
const networkType: string = networkConfig.networkType;
17+
const seed: string = process.env.MNEMONIC as string;
18+
// const privateKey: string = process.env.PRIVATE_KEY as string;
19+
20+
21+
const mergeUTXO = async () => {
22+
const wallet = new SeedWallet({ networkType: networkType, seed: seed });
23+
// const wallet = new WIFWallet({ networkType: networkType, privateKey: privateKey });
24+
25+
const utxos = await getUtxos(wallet.address, networkType);
26+
if (utxos.length < MERGE_COUNT) throw new Error("No btcs");
27+
28+
let redeemPsbt: Bitcoin.Psbt = redeemMergeUTXOPsbt(wallet, utxos, networkType, MERGE_COUNT);
29+
redeemPsbt = wallet.signPsbt(redeemPsbt, wallet.ecPair)
30+
let redeemFee = redeemPsbt.extractTransaction().virtualSize() * TESTNET_FEERATE;
31+
32+
let psbt = mergeUTXOPsbt(wallet, utxos, networkType, MERGE_COUNT, redeemFee);
33+
let signedPsbt = wallet.signPsbt(psbt, wallet.ecPair)
34+
35+
const txHex = signedPsbt.extractTransaction().toHex();
36+
const txId = await pushBTCpmt(txHex, networkType);
37+
console.log(`Merge_UTXO_TxId=======> ${txId}`)
38+
}
39+
40+
mergeUTXO();

UTXO_send.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import networkConfig from "config/network.config";
2+
import { getUtxos, pushBTCpmt } from "./utils/mempool";
3+
import * as Bitcoin from "bitcoinjs-lib";
4+
import * as ecc from "tiny-secp256k1";
5+
import dotenv from "dotenv";
6+
import { redeemSendUTXOPsbt, sendUTXOPsbt} from "controller/utxo.send.controller";
7+
import { SeedWallet } from "utils/SeedWallet";
8+
// import { WIFWallet } from 'utils/WIFWallet'
9+
10+
const TESTNET_FEERATE = 20;
11+
const SEND_UTXO_LIMIT = 10000;
12+
13+
dotenv.config();
14+
Bitcoin.initEccLib(ecc);
15+
16+
const networkType: string = networkConfig.networkType;
17+
const seed: string = process.env.MNEMONIC as string;
18+
// const privateKey: string = process.env.PRIVATE_KEY as string;
19+
20+
21+
const sendUTXO = async () => {
22+
const wallet = new SeedWallet({ networkType: networkType, seed: seed });
23+
// const wallet = new WIFWallet({ networkType: networkType, privateKey: privateKey });
24+
25+
const utxos = await getUtxos(wallet.address, networkType);
26+
const utxo = utxos.find((utxo) => utxo.value > SEND_UTXO_LIMIT);
27+
if (utxo === undefined) throw new Error("No btcs");
28+
29+
let redeemPsbt: Bitcoin.Psbt = redeemSendUTXOPsbt(wallet, utxo, networkType);
30+
redeemPsbt = wallet.signPsbt(redeemPsbt, wallet.ecPair)
31+
let redeemFee = redeemPsbt.extractTransaction().virtualSize() * TESTNET_FEERATE;
32+
33+
let psbt = sendUTXOPsbt(wallet, utxo, networkType, redeemFee);
34+
let signedPsbt = wallet.signPsbt(psbt, wallet.ecPair)
35+
36+
const txHex = signedPsbt.extractTransaction().toHex();
37+
38+
const txId = await pushBTCpmt(txHex, networkType);
39+
console.log(`Send_UTXO_TxId=======> ${txId}`)
40+
}
41+
42+
sendUTXO();

UTXO_split.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import networkConfig from "config/network.config";
2+
import { getUtxos, pushBTCpmt } from "./utils/mempool";
3+
import * as Bitcoin from "bitcoinjs-lib";
4+
import * as ecc from "tiny-secp256k1";
5+
import dotenv from "dotenv";
6+
import { redeemSplitUTXOPsbt, splitUTXOPsbt} from "controller/utxo.split.controller";
7+
import { SeedWallet } from "utils/SeedWallet";
8+
// import { WIFWallet } from 'utils/WIFWallet'
9+
10+
const TESTNET_FEERATE = 20;
11+
const SPLIT_UTXO_LIMIT = 10000;
12+
const SPLIT_COUNT = 5;
13+
14+
dotenv.config();
15+
Bitcoin.initEccLib(ecc);
16+
17+
const networkType: string = networkConfig.networkType;
18+
const seed: string = process.env.MNEMONIC as string;
19+
// const privateKey: string = process.env.PRIVATE_KEY as string;
20+
21+
22+
const splitUTXO = async () => {
23+
const wallet = new SeedWallet({ networkType: networkType, seed: seed });
24+
// const wallet = new WIFWallet({ networkType: networkType, privateKey: privateKey });
25+
26+
const utxos = await getUtxos(wallet.address, networkType);
27+
const utxo = utxos.find((utxo) => utxo.value > SPLIT_UTXO_LIMIT);
28+
if (utxo === undefined) throw new Error("No btcs");
29+
30+
let redeemPsbt: Bitcoin.Psbt = redeemSplitUTXOPsbt(wallet, utxo, networkType, SPLIT_COUNT);
31+
redeemPsbt = wallet.signPsbt(redeemPsbt, wallet.ecPair)
32+
let redeemFee = redeemPsbt.extractTransaction().virtualSize() * TESTNET_FEERATE;
33+
34+
let psbt = splitUTXOPsbt(wallet, utxo, networkType, SPLIT_COUNT, redeemFee);
35+
let signedPsbt = wallet.signPsbt(psbt, wallet.ecPair)
36+
37+
const txHex = signedPsbt.extractTransaction().toHex();
38+
39+
const txId = await pushBTCpmt(txHex, networkType);
40+
console.log(`Split_UTXO_TxId=======> ${txId}`)
41+
}
42+
43+
splitUTXO();

config/network.config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const networkConfig = {
2+
networkType: "testnet",
3+
};
4+
5+
export default networkConfig;
6+

controller/utxo.merge.controller.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import * as Bitcoin from "bitcoinjs-lib";
2+
import * as ecc from "tiny-secp256k1";
3+
Bitcoin.initEccLib(ecc);
4+
5+
interface IUtxo {
6+
txid: string;
7+
vout: number;
8+
value: number;
9+
}
10+
11+
export const redeemMergeUTXOPsbt = (wallet: any, utxos: IUtxo[], networkType: string, mergeCount: number): Bitcoin.Psbt => {
12+
let value = 0;
13+
14+
const psbt = new Bitcoin.Psbt({
15+
network: networkType == "testnet" ? Bitcoin.networks.testnet : Bitcoin.networks.bitcoin
16+
});
17+
for (let i = 0; i < mergeCount; i++) {
18+
psbt.addInput({
19+
hash: utxos[i].txid,
20+
index: utxos[i].vout,
21+
witnessUtxo: {
22+
value: utxos[i].value,
23+
script: wallet.output,
24+
},
25+
tapInternalKey: Buffer.from(wallet.publicKey, "hex").subarray(1, 33),
26+
});
27+
value += utxos[i].value;
28+
}
29+
30+
psbt.addOutput({
31+
address: wallet.address,
32+
value: value - 1000,
33+
});
34+
return psbt;
35+
}
36+
37+
export const mergeUTXOPsbt = (wallet: any, utxos: IUtxo[], networkType: string, mergeCount: number, fee: number): Bitcoin.Psbt => {
38+
let value = 0;
39+
40+
const psbt = new Bitcoin.Psbt({
41+
network: networkType == "testnet" ? Bitcoin.networks.testnet : Bitcoin.networks.bitcoin
42+
});
43+
for (let i = 0; i < mergeCount; i++) {
44+
psbt.addInput({
45+
hash: utxos[i].txid,
46+
index: utxos[i].vout,
47+
witnessUtxo: {
48+
value: utxos[i].value,
49+
script: wallet.output,
50+
},
51+
tapInternalKey: Buffer.from(wallet.publicKey, "hex").subarray(1, 33),
52+
});
53+
value += utxos[i].value;
54+
}
55+
56+
psbt.addOutput({
57+
address: wallet.address,
58+
value: value - fee,
59+
});
60+
61+
if (value < fee) throw new Error("No enough Fee");
62+
return psbt;
63+
}

controller/utxo.send.controller.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import * as Bitcoin from "bitcoinjs-lib";
2+
import * as ecc from "tiny-secp256k1";
3+
Bitcoin.initEccLib(ecc);
4+
5+
6+
interface IUtxo {
7+
txid: string;
8+
vout: number;
9+
value: number;
10+
}
11+
12+
export const redeemSendUTXOPsbt = (wallet: any, utxo: IUtxo, networkType: string): Bitcoin.Psbt => {
13+
const psbt = new Bitcoin.Psbt({
14+
network: networkType == "testnet" ? Bitcoin.networks.testnet : Bitcoin.networks.bitcoin
15+
});
16+
17+
18+
psbt.addInput({
19+
hash: utxo.txid,
20+
index: utxo.vout,
21+
witnessUtxo: {
22+
value: utxo.value,
23+
script: wallet.output,
24+
},
25+
tapInternalKey: Buffer.from(wallet.publicKey, "hex").subarray(1, 33),
26+
});
27+
28+
psbt.addOutput({
29+
address: wallet.address,
30+
value: utxo.value - 1000,
31+
});
32+
33+
return psbt;
34+
}
35+
36+
export const sendUTXOPsbt = (wallet: any, utxo: IUtxo, networkType: string, fee: number): Bitcoin.Psbt => {
37+
const psbt = new Bitcoin.Psbt({
38+
network: networkType == "testnet" ? Bitcoin.networks.testnet : Bitcoin.networks.bitcoin
39+
});
40+
41+
psbt.addInput({
42+
hash: utxo.txid,
43+
index: utxo.vout,
44+
witnessUtxo: {
45+
value: utxo.value,
46+
script: wallet.output,
47+
},
48+
tapInternalKey: Buffer.from(wallet.publicKey, "hex").subarray(1, 33),
49+
});
50+
51+
psbt.addOutput({
52+
address: wallet.address,
53+
value: utxo.value - fee,
54+
});
55+
56+
return psbt;
57+
}
58+

controller/utxo.split.controller.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import * as Bitcoin from "bitcoinjs-lib";
2+
import * as ecc from "tiny-secp256k1";
3+
Bitcoin.initEccLib(ecc);
4+
5+
const UTXO_OUTPUT = 546;
6+
7+
interface IUtxo {
8+
txid: string;
9+
vout: number;
10+
value: number;
11+
}
12+
13+
export const redeemSplitUTXOPsbt = (wallet: any, utxo: IUtxo, networkType: string, splitCount: number): Bitcoin.Psbt => {
14+
const psbt = new Bitcoin.Psbt({
15+
network: networkType == "testnet" ? Bitcoin.networks.testnet : Bitcoin.networks.bitcoin
16+
});
17+
psbt.addInput({
18+
hash: utxo.txid,
19+
index: utxo.vout,
20+
witnessUtxo: {
21+
value: utxo.value,
22+
script: wallet.output,
23+
},
24+
tapInternalKey: Buffer.from(wallet.publicKey, "hex").subarray(1, 33),
25+
});
26+
for (let i = 0; i < splitCount; i++) {
27+
psbt.addOutput({
28+
address: wallet.address,
29+
value: UTXO_OUTPUT,
30+
});
31+
}
32+
33+
psbt.addOutput({
34+
address: wallet.address,
35+
value: utxo.value - UTXO_OUTPUT * splitCount - 1000,
36+
});
37+
38+
return psbt;
39+
}
40+
41+
export const splitUTXOPsbt = (wallet: any, utxo: IUtxo, networkType: string, splitCount: number, fee: number): Bitcoin.Psbt => {
42+
const psbt = new Bitcoin.Psbt({
43+
network: networkType == "testnet" ? Bitcoin.networks.testnet : Bitcoin.networks.bitcoin
44+
});
45+
psbt.addInput({
46+
hash: utxo.txid,
47+
index: utxo.vout,
48+
witnessUtxo: {
49+
value: utxo.value,
50+
script: wallet.output,
51+
},
52+
tapInternalKey: Buffer.from(wallet.publicKey, "hex").subarray(1, 33),
53+
});
54+
for (let i = 0; i < splitCount; i++) {
55+
psbt.addOutput({
56+
address: wallet.address,
57+
value: UTXO_OUTPUT,
58+
});
59+
}
60+
61+
psbt.addOutput({
62+
address: wallet.address,
63+
value: utxo.value - UTXO_OUTPUT * splitCount - fee,
64+
});
65+
66+
return psbt;
67+
}

0 commit comments

Comments
 (0)