ACINQ / bitcoin-kmp

Kotlin Multiplatform Bitcoin Library
Apache License 2.0
68 stars 15 forks source link

How do I use Redeem Script Hex for create PSBT to unlock P2SH? #125

Open rushmi0 opened 7 months ago

rushmi0 commented 7 months ago
val xpub = DeterministicWallet.ExtendedPublicKey.decode(
            "xpub6CEAyB6zF8bLzi1tNqg4zEfWSBBXtieA4hm3EstWsgSJCgMQS1UrfAFAZHYH1o7tfgFuNWzJhsDHg1EhoF4G5gzXUpQNkt1RzSTyFeAUv4S"
        ).second
        println(xpub)

        // สร้างธุรกรรม
        val unsignedTx = Transaction(
            version = 2,
            txIn = listOf(
                TxIn(
                    OutPoint(
                        TxId("c95039b1ce6152a20ecab1759e924c15e25f4d980673bd64c07a43d2fb501acb"),
                        0
                    ),
                    signatureScript = listOf(),
                    sequence = 0xfdffffff
                )
            ),
            txOut = listOf(
                TxOut(
                    12_000.toSatoshi(),
                    ByteVector("0014d85c2b71d0060b09c9886aeb815e50991dda124d")
                )
            ),
            lockTime = 1423787
        )
        val psbt = Psbt(unsignedTx)

        // ดึงข้อมูล public key, fingerprint, และ key path จาก xpub
        val publicKey = xpub.publicKey
        val fingerprint = xpub.parent
        val keyPath = xpub.path

        // สร้าง mapping ของ public key และ key path
        val pubkeyData = mapOf(
            publicKey to KeyPathWithMaster(fingerprint, keyPath)
        )

        // ระบุ redeem script
        val redeemScript = listOf(

        )

        // อัปเดต PSBT : https://github.com/ACINQ/bitcoin-kmp/blob/master/src%2FcommonMain%2Fkotlin%2Ffr%2Facinq%2Fbitcoin%2Fpsbt%2FPsbt.kt#L172-L172
        val firstPSBT = psbt.updateNonWitnessInput(
            inputTx = unsignedTx,
            outputIndex = 0,
            redeemScript = redeemScript,
            sighashType = 1,
            derivationPaths = pubkeyData
        )
rushmi0 commented 7 months ago
import fr.acinq.bitcoin.OP_CHECKLOCKTIMEVERIFY
import fr.acinq.bitcoin.OP_CHECKSIG
import fr.acinq.bitcoin.OP_DROP
import fr.acinq.bitcoin.OP_PUSHDATA
import win.notoshi.genesec.utils.ShiftTo.ByteArrayToHex
import win.notoshi.genesec.utils.ShiftTo.HexToByteArray
import win.notoshi.genesec.utils.ShiftTo.toByteArray
import java.nio.ByteBuffer
import java.nio.ByteOrder

class ScriptBuilder {

    // * https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki
    fun TimeLock(blockNumber: Int, publicKey: ByteArray): String {
        if (blockNumber < 0) {
            throw IllegalArgumentException("Block number must be non-negative")
        }

        // กำหนดค่าเริ่มต้นสำหรับ blockNumber ในรูปแบบ LITTLE ENDIAN 8 Bytes
        val LITTLE_ENDIAN: ByteBuffer =
            ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putInt(blockNumber)

        // ตรวจสอบและกำหนดค่าให้กับ nLockTime โดยตัด byte 0x00 ที่อยู่ด้านท้ายออก
        var nLockTime: ByteArray = LITTLE_ENDIAN.array()
        while (nLockTime.isNotEmpty() && nLockTime.last() == 0x00.toByte()) {
            nLockTime = nLockTime.dropLast(1).toByteArray()
        }

        /*
        * องค์ประกอบสคริปต์
        *
        *   [ < ขนาดหมายเลข Block, หมายเลข Block รูปแบบ LITTLE ENDIAN > ]
        * OP_CHECKLOCKTIMEVERIFY
        * OP_DROP
        *   [ < ขนาดของ Public key >, < Public key > ]
        * OP_CHECKSIG
        */
        val stack = listOf(
            OP_PUSHDATA(nLockTime).opCode.toByteArray(),
            nLockTime,
            OP_CHECKLOCKTIMEVERIFY.code.toByteArray(),
            OP_DROP.code.toByteArray(),
            OP_PUSHDATA(publicKey).opCode.toByteArray(),
            publicKey,
            OP_CHECKSIG.code.toByteArray()
        )

        return buildString {
            stack.forEach { element ->
                append(element.ByteArrayToHex())
            }
        }
    }

}

fun main() {
    val script = ScriptBuilder()
    val publicKey = "02a1d6c523ea4baa26127a55eee14adcee1b1419407e317654682c0759f431ecaf"
    val redeemScript = script.TimeLock(1423787, publicKey.HexToByteArray())
    println(redeemScript)
    // 03abb915b1752102a1d6c523ea4baa26127a55eee14adcee1b1419407e317654682c0759f431ecafac
    // 3JFVsdsib5mrvpZmid1jdTPa2KR1fXXgpz
}