Skip to content

Commit 80c6e14

Browse files
committed
init project
1 parent a7a4f36 commit 80c6e14

29 files changed

+4416
-1
lines changed

.env.example

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
MNEMONIC =
2+
PRIVATE_KEY =

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
.env

Delegate_inscription.ts

+212
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
import {
2+
Transaction,
3+
script,
4+
Psbt,
5+
initEccLib,
6+
networks,
7+
Signer as BTCSigner,
8+
crypto,
9+
payments,
10+
opcodes,
11+
address as Address
12+
} from "bitcoinjs-lib";
13+
14+
import { Taptree } from "bitcoinjs-lib/src/types";
15+
import { ECPairFactory, ECPairAPI } from "ecpair";
16+
import ecc from "@bitcoinerlab/secp256k1";
17+
import axios, { AxiosResponse } from "axios";
18+
import networkConfig from "config/network.config";
19+
import { WIFWallet } from 'utils/WIFWallet'
20+
import { SeedWallet } from "utils/SeedWallet";
21+
import cbor from 'cbor'
22+
//test
23+
const network = networks.testnet;
24+
// const network = networks.bitcoin;
25+
26+
initEccLib(ecc as any);
27+
const ECPair: ECPairAPI = ECPairFactory(ecc);
28+
29+
// const seed: string = process.env.MNEMONIC as string;
30+
// const networkType: string = networkConfig.networkType;
31+
// const wallet = new SeedWallet({ networkType: networkType, seed: seed });
32+
33+
const privateKey: string = process.env.PRIVATE_KEY as string;
34+
const networkType: string = networkConfig.networkType;
35+
const wallet = new WIFWallet({ networkType: networkType, privateKey: privateKey });
36+
37+
const txhash: string = 'dd476bdd2039161c50196d9a8f8412d56be3710de8bda5de4674429e5f8e3649';
38+
const txidBuffer = Buffer.from(txhash, 'hex');
39+
const delegateBuffer = txidBuffer.reverse();
40+
41+
const receiveAddress: string = "tb1ppx220ln489s5wqu8mqgezm7twwpj0avcvle3vclpdkpqvdg3mwqsvydajn";
42+
const transaction_fee = 28000;
43+
44+
45+
export function createdelegateInscriptionTapScript(): Array<Buffer> {
46+
47+
const keyPair = wallet.ecPair;
48+
const delegateOrdinalStacks: any = [
49+
toXOnly(keyPair.publicKey),
50+
opcodes.OP_CHECKSIG,
51+
opcodes.OP_FALSE,
52+
opcodes.OP_IF,
53+
Buffer.from("ord", "utf8"),
54+
1,
55+
11,
56+
delegateBuffer,
57+
opcodes.OP_ENDIF,
58+
];
59+
return delegateOrdinalStacks;
60+
}
61+
62+
async function delegateInscribe() {
63+
const keyPair = wallet.ecPair;
64+
const delegateOrdinalStack = createdelegateInscriptionTapScript();
65+
66+
const ordinal_script = script.compile(delegateOrdinalStack);
67+
68+
const scriptTree: Taptree = {
69+
output: ordinal_script,
70+
};
71+
72+
const redeem = {
73+
output: ordinal_script,
74+
redeemVersion: 192,
75+
};
76+
77+
const ordinal_p2tr = payments.p2tr({
78+
internalPubkey: toXOnly(keyPair.publicKey),
79+
network,
80+
scriptTree,
81+
redeem,
82+
});
83+
84+
const address = ordinal_p2tr.address ?? "";
85+
console.log("send coin to address", address);
86+
87+
const utxos = await waitUntilUTXO(address as string);
88+
console.log(`Using UTXO ${utxos[0].txid}:${utxos[0].vout}`);
89+
90+
const psbt = new Psbt({ network });
91+
92+
psbt.addInput({
93+
hash: utxos[0].txid,
94+
index: utxos[0].vout,
95+
tapInternalKey: toXOnly(keyPair.publicKey),
96+
witnessUtxo: { value: utxos[0].value, script: ordinal_p2tr.output! },
97+
tapLeafScript: [
98+
{
99+
leafVersion: redeem.redeemVersion,
100+
script: redeem.output,
101+
controlBlock: ordinal_p2tr.witness![ordinal_p2tr.witness!.length - 1],
102+
},
103+
],
104+
});
105+
106+
107+
const change = utxos[0].value - 546 - transaction_fee;
108+
109+
psbt.addOutput({
110+
address: receiveAddress, //Destination Address
111+
value: 546,
112+
});
113+
114+
psbt.addOutput({
115+
address: receiveAddress, // Change address
116+
value: change,
117+
});
118+
119+
await signAndSend(keyPair, psbt);
120+
}
121+
122+
delegateInscribe()
123+
124+
export async function signAndSend(
125+
keypair: BTCSigner,
126+
psbt: Psbt,
127+
) {
128+
psbt.signInput(0, keypair);
129+
psbt.finalizeAllInputs()
130+
const tx = psbt.extractTransaction();
131+
132+
console.log(tx.virtualSize())
133+
console.log(tx.toHex())
134+
135+
const txid = await broadcast(tx.toHex());
136+
console.log(`Success! Txid is ${txid}`);
137+
}
138+
139+
export async function waitUntilUTXO(address: string) {
140+
return new Promise<IUTXO[]>((resolve, reject) => {
141+
let intervalId: any;
142+
const checkForUtxo = async () => {
143+
try {
144+
const response: AxiosResponse<string> = await blockstream.get(
145+
`/address/${address}/utxo`
146+
);
147+
const data: IUTXO[] = response.data
148+
? JSON.parse(response.data)
149+
: undefined;
150+
console.log(data);
151+
if (data.length > 0) {
152+
resolve(data);
153+
clearInterval(intervalId);
154+
}
155+
} catch (error) {
156+
reject(error);
157+
clearInterval(intervalId);
158+
}
159+
};
160+
intervalId = setInterval(checkForUtxo, 4000);
161+
});
162+
}
163+
export async function getTx(id: string): Promise<string> {
164+
const response: AxiosResponse<string> = await blockstream.get(
165+
`/tx/${id}/hex`
166+
);
167+
return response.data;
168+
}
169+
const blockstream = new axios.Axios({
170+
baseURL: `https://mempool.space/testnet/api`,
171+
// baseURL: `https://mempool.space/api`,
172+
});
173+
export async function broadcast(txHex: string) {
174+
const response: AxiosResponse<string> = await blockstream.post("/tx", txHex);
175+
return response.data;
176+
}
177+
function tapTweakHash(pubKey: Buffer, h: Buffer | undefined): Buffer {
178+
return crypto.taggedHash(
179+
"TapTweak",
180+
Buffer.concat(h ? [pubKey, h] : [pubKey])
181+
);
182+
}
183+
function toXOnly(pubkey: Buffer): Buffer {
184+
return pubkey.subarray(1, 33);
185+
}
186+
function tweakSigner(signer: any, opts: any = {}) {
187+
let privateKey = signer.privateKey;
188+
if (!privateKey) {
189+
throw new Error('Private key is required for tweaking signer!');
190+
}
191+
if (signer.publicKey[0] === 3) {
192+
privateKey = ecc.privateNegate(privateKey);
193+
}
194+
const tweakedPrivateKey = ecc.privateAdd(privateKey, tapTweakHash(toXOnly(signer.publicKey), opts.tweakHash));
195+
if (!tweakedPrivateKey) {
196+
throw new Error('Invalid tweaked private key!');
197+
}
198+
return ECPair.fromPrivateKey(Buffer.from(tweakedPrivateKey), {
199+
network: opts.network,
200+
});
201+
}
202+
interface IUTXO {
203+
txid: string;
204+
vout: number;
205+
status: {
206+
confirmed: boolean;
207+
block_height: number;
208+
block_hash: string;
209+
block_time: number;
210+
};
211+
value: number;
212+
}

Encipher_Decipher_Runestone.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Runestone, Transaction } from '@ordjs/runestone';
2+
3+
// See https://mempool.space/tx/2bb85f4b004be6da54f766c17c1e855187327112c231ef2ff35ebad0ea67c69e
4+
const tx: any = {
5+
output: [{
6+
// // OP_RETURN OP_PUSHNUM_13 ...
7+
script_pubkey: '00dbfeab01f711904e020000904e030000904e040000904e05',
8+
value: 0,
9+
}],
10+
};
11+
12+
const runestone = Runestone.decipher(tx);
13+
// runestone.divisibility => 2
14+
// runestone.premine => 11000000000
15+
// runestone.symbol => ᚠ
16+
// runestone.terms.amount => 100
17+
console.log(runestone)

0 commit comments

Comments
 (0)