Skip to content

Commit

Permalink
Update lock btc to mint contract.
Browse files Browse the repository at this point in the history
  • Loading branch information
msinkec committed Dec 13, 2023
1 parent 4e1b845 commit 13ed995
Showing 1 changed file with 22 additions and 26 deletions.
48 changes: 22 additions & 26 deletions src/contracts/bsv20LockBtcToMint.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Hash } from 'crypto'
import { BSV20V2 } from 'scrypt-ord'
import {
Addr,
Expand All @@ -11,6 +10,7 @@ import {
int2ByteString,
method,
prop,
PubKey,
slice,
toByteString,
Utils,
Expand Down Expand Up @@ -38,14 +38,11 @@ export class Bsv20LockBtcToMint extends BSV20V2 {
@prop()
hodlDeadline: bigint

@prop()
btcHtlcScriptSuffix: ByteString

@prop()
targetDifficulty: bigint

@prop(true)
usedAddresses: HashedSet<Addr>
usedLockPubKeys: HashedSet<PubKey>

constructor(
id: ByteString,
Expand All @@ -55,37 +52,35 @@ export class Bsv20LockBtcToMint extends BSV20V2 {
supply: bigint,
hodlRate: bigint,
hodlDeadline: bigint,
btcHtlcScriptSuffix: ByteString,
targetDifficulty: bigint,
usedAddresses: HashedSet<Addr>
usedLockPubKeys: HashedSet<PubKey>
) {
super(id, sym, max, dec)
this.init(...arguments)

this.supply = supply
this.hodlRate = hodlRate
this.hodlDeadline = hodlDeadline
this.btcHtlcScriptSuffix = btcHtlcScriptSuffix
this.targetDifficulty = targetDifficulty
this.usedAddresses = usedAddresses
this.usedLockPubKeys = usedLockPubKeys
}

@method()
public mint(
ordinalAddress: Addr,
lockAddress: Addr,
lockPubKey: PubKey,
amount: bigint,
btcTx: ByteString,
merkleProof: MerkleProof,
headers: FixedArray<BlockHeader, typeof Bsv20LockBtcToMint.MIN_CONF>
) {
// Check lock address was not yet used. This is to avoid replay
// Check lock public key was not yet used. This is to avoid replay
// attacks where the same BTC tx would be used to mint multiple times.
assert(
!this.usedAddresses.has(lockAddress),
'lock address already used'
!this.usedLockPubKeys.has(lockPubKey),
'lock pub key already used'
)
this.usedAddresses.add(lockAddress)
this.usedLockPubKeys.add(lockPubKey)

let outputs = toByteString('')
let transferAmt = amount
Expand All @@ -101,7 +96,7 @@ export class Bsv20LockBtcToMint extends BSV20V2 {
}

// Check btc tx.
this.checkBtcTx(btcTx, lockAddress, transferAmt * this.hodlRate)
this.checkBtcTx(btcTx, lockPubKey, transferAmt * this.hodlRate)

// Calc merkle root.
const txID = hash256(btcTx)
Expand Down Expand Up @@ -153,9 +148,9 @@ export class Bsv20LockBtcToMint extends BSV20V2 {
}

@method()
checkBtcTx(btcTx: ByteString, lockAddress: Addr, amount: bigint): void {
checkBtcTx(btcTx: ByteString, lockPubKey: PubKey, amount: bigint): void {
// Most things should be the same as in BSV except the witness data and flag.
// - Check (first) output is a P2SH to a HTLC script with the specified lock address.
// - Check (first) output is a P2WSH to a time-lock script with the specified lock address.
// - Check (first) output amount is correct.

let idx = 4n
Expand Down Expand Up @@ -189,7 +184,7 @@ export class Bsv20LockBtcToMint extends BSV20V2 {
}

//// FIRST OUTPUT:
// Check first outputs amount is correct and that it's a P2SH to the correct HTLC script.
// Check first outputs amount is correct and that it's a P2WSH to the correct time-lock script.
const outLen = Bsv20LockBtcToMint.parseVarInt(btcTx, idx)
idx = outLen.newIdx
const outAmt = Utils.fromLEUnsigned(slice(btcTx, idx, idx + 8n))
Expand All @@ -199,15 +194,16 @@ export class Bsv20LockBtcToMint extends BSV20V2 {
idx = scriptLen.newIdx
const script = slice(btcTx, idx, idx + scriptLen.val)

const btcHtlcScriptFinal =
lockAddress +
// <nBlocksLocked> OP_CHECKSEQUENCEVERIFY OP_DROP <lockPubKey> OP_CHECKSIG
const witnessScript =
toByteString('04') +
int2ByteString(this.hodlDeadline, 4n) +
this.btcHtlcScriptSuffix
const expectedScript =
toByteString('a9') +
hash160(btcHtlcScriptFinal) +
toByteString('87')
assert(script == expectedScript, 'locking script invalid')
toByteString('b275') +
lockPubKey +
toByteString('ac')
const expectedP2WSHScript =
toByteString('a9') + hash160(witnessScript) + toByteString('87')
assert(script == expectedP2WSHScript, 'P2WSH script invalid')

// Data past this point is not relevant in our use-case.
}
Expand Down

0 comments on commit 13ed995

Please sign in to comment.