Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there any support for custom scripts like Hash Time Lock Contracts? #81

Open
Mister-EA opened this issue Mar 25, 2024 · 1 comment
Open

Comments

@Mister-EA
Copy link

Hi,

I would like to use this library to implement a Hash Time Lock Contract (HTLC). Although I have been able to lock an amount of BTC to the HTLC through a P2WSH transaction using the library, I am struggling to create the transaction that unlocks it.

For context the HTLC script hex is : 6376a9147b0bbdf24f26e0b06609b74344842b31a540e6f088ac6704748b320ab1750014a322914d649da49325b44c915af682da7a7bd43a

which decodes to :

script                                   |  stack 
-----------------------------------------+--------
OP_IF                                    | 
OP_DUP                                   | 
OP_HASH160                               | 
7b0bbdf24f26e0b06609b74344842b31a540e6f0 | 
OP_EQUALVERIFY                           | 
OP_CHECKSIG                              | 
OP_ELSE                                  | 
748b320a                                 | 
OP_CHECKLOCKTIMEVERIFY                   | 
OP_DROP                                  | 
0                                        | 
a322914d649da49325b44c915af682da7a7bd43a | 

So as you can see the first branch OP_IF consists of a P2PKH script for the recipient to redeem the locked amount, and the OP_ELSE branch consists of P2WPKH script for the sender to reclaim the locked amount after lock time expiry (OP_CHECKLOCKTIMEVERIFY ).

I am having issues reclaiming the BTC from the sender account. To reclaim this BTC you need to provide in the witness:
<senderSignature> <senderPublicKey> 0 <htlcScriptAsRawData> .

The issue I have is that I don't know where to place this 0 value using the library. This value is important as it activates the OP_ELSE branch of the HTLC script and needs to be at the top of the stack during the witness script execution.

Signing an input seems to take care of placing the <senderSignature> and <senderPublicKey> values into the final witness stack, but I can't seem to find any functionality in the library to include other values, like the 0 value in the input script. I cannot include this 0 value in the witnessScript field of the input because that field needs to be the original htlcScript , whose hash will be compared against the hash in the scriptPubKey, so I don't see any place where I can add this value to the witness stack.

Is that something that is considered too advanced and which the current version of the library does not support?

This is my code for reference:

export function createReclaimPsbt(reclaimerAddress: string, reclaimerPubKey: string,  htlcAddress: string, htlcAmount: bigint, htlcTimeout: bigint,  htlcScript: Buffer, htlcOutput: UTXO, network: any) {
    const htlcScriptHash = sha256(htlcScript);
    const scriptPubKey = btc.Script.encode(["OP_0", htlcScriptHash]); // the scriptPubKey for the HTLC UTXO we want to reclaim


    const lockTime = Number(htlcTimeout) + 1;
    const tx = new btc.Transaction({
      allowUnknownOutputs: true,
      lockTime : lockTime,  // the HTLC output can be reclaimed after the timeout 
      version: 0,
    });

    // input
    tx.addInput({
      txid: htlcOutput.txid,
      index: htlcOutput.vout,
      witnessUtxo: {
        script: scriptPubKey ,
        amount: BigInt(htlcAmount),
      },
      witnessScript : htlcScript,
      sequence: 0xfffffffe, // non-final sequence number needed to enable locktime
      sighashType: btc.SigHash.ALL,
    });

    const fee = 300n; // set the miner fee amount
    const reclaimedAmount = BigInt(htlcAmount) - fee;

    tx.addOutputAddress(reclaimerAddress, reclaimedAmount, network);  
    const psbt = tx.toPSBT(0);
    const psbtHex = hex.encode(psbt);

    console.log("txHex = " + tx.hex);
    console.log("psbtHex = " + psbtHex);
    const psbtB64 = base64.encode(psbt);
    return psbtB64;  
}
@paulmillr
Copy link
Owner

Is that something that is considered too advanced

Yes. For now. We will be doing a deeper research into the feature in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants