Skip to content

Instantly share code, notes, and snippets.

@hoffmabc
Last active November 25, 2024 17:57
Show Gist options
  • Save hoffmabc/7b9851495a49be608f771edfdc68f8da to your computer and use it in GitHub Desktop.
Save hoffmabc/7b9851495a49be608f771edfdc68f8da to your computer and use it in GitHub Desktop.
import express from 'express';
import { RpcConnection, MessageUtil, PubkeyUtil } from '@saturnbtcio/arch-sdk';
import * as borsh from 'borsh';
import Bitcoin from 'bitcoinjs-lib';
// import { ECPairFactory } from 'bitcoinjs-lib/src/ecpair';
import { ECPairFactory } from 'ecpair';
import * as ecc from 'tiny-secp256k1';
import cors from 'cors';
import { hexToBytes } from '@noble/hashes/utils';
import dotenv from 'dotenv';
import bip322 from 'bip322-js';
import { Buffer } from 'buffer';
import wif from 'wif';
const ECPair = ECPairFactory(ecc);
dotenv.config();
const app = express();
app.use(cors());
app.use(express.json());
Bitcoin.initEccLib(ecc);
const client = new RpcConnection("http://rpc-01.test.arch.network");
const PRIVATE_KEY = process.env.ARCH_PRIVATE_KEY;
const SwapInscriptionRuneSchema = {
struct: {
inscription_txid: 'string',
inscription_vout: 'u8',
user_swap_psbt: { array: { type: 'u8' } }
}
}
const sendData = async () => {
try {
const inscriptionUtxo = {
txid: "f4abb75e0332db56a2692090d0997d26acc3fad3da255c4ed0aee00d018d0e4a",
vout: 0,
value: 330,
};
const signedPSBT = "70736274ff0100fd22010200000002050c744048ecb622eb4b151288f9d028a49c27bbfbbd387b6f9da53936cf67a90000000000ffffffff66b18a5cb6d5c67e11a94f4a4d0d8b3c727dda0e1f918f2cfd91e19177a4a61c0100000000ffffffff054a01000000000000225120437b4b5eee07f1e96da29d43fc7621ed77e922271620193f7be12c7bce54086f0000000000000000116a5d0e009e9e030ee807020000d8fc3c032202000000000000225120b5f7cb3d25a2b19d9d9fe56fa4ac31ad77e1efa47d047d0740617dbcecd6acf12202000000000000225120437b4b5eee07f1e96da29d43fc7621ed77e922271620193f7be12c7bce54086ff498070000000000225120437b4b5eee07f1e96da29d43fc7621ed77e922271620193f7be12c7bce54086f000000000001012b1027000000000000225120437b4b5eee07f1e96da29d43fc7621ed77e922271620193f7be12c7bce54086f010304810000000113412f3dcb1c018590b191e492cb3e9e1a3ce01572f66290757164076fa5c72574741b5b4e8f7f016a8bdf779d3452aa4b5c47681b2a61ccd22a12f2aee93545e97f810117206272fe4cf7746c9c3de3d48afc5f27fe4ba052fc8f72913a6020fa970f7f58230001012b20a1070000000000225120437b4b5eee07f1e96da29d43fc7621ed77e922271620193f7be12c7bce54086f01030481000000011341f54b672ef668e086b2c5dc99a0cb3e60a54117ffccc569335f2aa3caf4cd63eaecb38b9d7287fa52ce20a700e84db25efa37e5ec61f640fa1a8c0cb6d3a838f9810117206272fe4cf7746c9c3de3d48afc5f27fe4ba052fc8f72913a6020fa970f7f5823000000000000";
const psbt = Bitcoin.Psbt.fromHex(signedPSBT);
psbt.finalizeAllInputs();
const transaction = psbt.extractTransaction();
const rawTxHex = transaction.toHex();
console.log("rawTxHex => ", rawTxHex);
const hexData = hexToBytes(rawTxHex);
const programPubkey = "14fd5c20f2d2dc718782435bee94901281abc9860c263fbffbd43bbde5673261";
// Prepare the data to be sent
const sendValue = {
inscription_txid: inscriptionUtxo.txid,
inscription_vout: inscriptionUtxo.vout,
user_swap_psbt: hexData
};
const encoded = borsh.serialize(SwapInscriptionRuneSchema, sendValue);
const instructionData = new Uint8Array(encoded.length + 1);
instructionData[0] = 0;
instructionData.set(encoded, 1);
// Create the instruction with proper account structure
const instruction = {
program_id: PubkeyUtil.fromHex(programPubkey),
accounts: [
{
pubkey: PubkeyUtil.fromHex(PRIVATE_KEY),
is_signer: true,
is_writable: false
},
{
pubkey: PubkeyUtil.fromHex(programPubkey),
is_signer: false,
is_writable: true
}
],
data: instructionData,
};
const messageObj = {
signers: [PubkeyUtil.fromHex(PRIVATE_KEY)],
instructions: [instruction],
};
// Get message hash
const messageHash = MessageUtil.hash(messageObj);
console.log(`Message hash: ${messageHash.toString('hex')}`);
// Convert private key and create key pair
const privateKeyBytes = Buffer.from(PRIVATE_KEY.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
const keyPair = ECPair.fromPrivateKey(privateKeyBytes, {
compressed: true,
network: Bitcoin.networks.testnet
});
// Get the address from the key pair
const { address } = Bitcoin.payments.p2wpkh({
pubkey: keyPair.publicKey,
network: Bitcoin.networks.testnet
});
console.log(`Address: ${address}`);
// Convert message hash to base58 format
const messageHashBase58 = messageHash.toString('base58');
// Create BIP322 signature
const signature = bip322.Signer.sign(
wif.encode(0x80, privateKeyBytes, true), // Convert private key to WIF format
address, // bitcoin address
messageHashBase58 // message in base58 format
);
// Convert signature to bytes
const signatureBytes = new Uint8Array(Buffer.from(signature, 'base64'));
console.log(`BIP322 Signature: ${signature}`);
console.log(`Signature bytes: ${Buffer.from(signatureBytes).toString('hex')}`);
// Send transaction
const result = await client.sendTransaction({
version: 0,
signatures: [signatureBytes],
message: messageObj,
});
console.log("Transaction result:", result);
return result;
} catch (error) {
console.error('Error details:', {
message: error.message,
cause: error.cause?.message,
stack: error.stack
});
throw error;
}
};
sendData();
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
// Add endpoint
app.post('/send-data', async (req, res) => {
try {
const result = await sendData();
res.json({ success: true, result });
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment