Disclaimer: This code is provided as an example only and is not intended for production use. The author of this code and any parties involved in its distribution are not liable for any lost funds or damages arising from the use of this code. Users should conduct their own testing and due diligence before implementing or deploying this code in any environment.
To implement a "lock to mint" mechanism using sCrypt for minting BSV-20 (V2) tokens, the provided source code outlines a smart contract approach that integrates with the BSV-20 V2 standard. This method does not require an extended indexer and is compatible with the standard BSV-20 tokens, unlike the LRC-20 approach.
import { BSV20V2 } from 'scrypt-ord'
import {
Addr,
assert,
ByteString,
hash256,
int2ByteString,
method,
prop,
slice,
toByteString,
Utils,
} from 'scrypt-ts'
export class BSV20LockToMint extends BSV20V2 {
@prop(true)
supply: bigint
// Amount of sats to lock up in order to mint a single token.
@prop()
hodlRate: bigint
// Minimum deadline until you have to lock to mint new
// tokens.
@prop()
hodlDeadline: bigint
// Hodl lock script.
@prop()
lockupScript: ByteString
constructor(
id: ByteString,
sym: ByteString,
max: bigint,
dec: bigint,
supply: bigint,
hodlRate: bigint,
hodlDeadline: bigint,
lockupScript: ByteString
) {
super(id, sym, max, dec)
this.init(...arguments)
this.supply = supply
this.hodlRate = hodlRate
this.hodlDeadline = hodlDeadline
this.lockupScript = lockupScript
}
@method()
public mint(ordinalAddress: Addr, lockAddress: Addr, amount: bigint) {
let outputs = toByteString('')
let transferAmt = amount
if (this.supply > transferAmt) {
// If there are still tokens left, then update supply and
// build state output inscribed with leftover tokens.
this.supply -= transferAmt
outputs += this.buildStateOutputFT(this.supply)
} else {
// If not, then transfer all the remaining supply.
transferAmt = this.supply
}
// Build FT P2PKH output to dest paying specified amount of tokens.
outputs += BSV20V2.buildTransferOutput(
ordinalAddress,
this.id,
transferAmt
)
// Make sure satoshis are locked.
const lockupScriptFinal =
slice(this.lockupScript, 0n, 114n) +
lockAddress +
int2ByteString(this.hodlDeadline, 4n) +
slice(this.lockupScript, 138n)
outputs += Utils.buildOutput(
lockupScriptFinal,
transferAmt * this.hodlRate
)
// Build change output.
outputs += this.buildChangeOutput()
assert(hash256(outputs) == this.ctx.hashOutputs, 'hashOutputs mismatch')
}
}
For the seamless integration of ordinals functionality extends the BSV20V2
class from the scrypt-ord package.
supply
: Tracks the total supply of "unminted" tokens.hodlRate
: The amount of satoshis that must be locked to mint a single token.hodlDeadline
: The minimum deadline for locking satoshis to mint new tokens.lockupScript
: A locking script defining the conditions of the satoshi lockup. In our case, it is compiled from this contract.
Initializes the contract with parameters like token ID, symbol, maximum supply, decimals, current supply, hodl rate, hodl deadline, and the lockup script.
- Checks if tokens are available for minting and updates the supply.
- Constructs and enforces the transaction outputs, including:
- A state output indicating the remaining token supply.
- A transfer output for the minted tokens to the recipient.
- An output to lock the required satoshis according to the
hodlRate
.
- The
lockupScriptFinal
is crafted by combining parts of thelockupScript
with the lock address and thehodlDeadline
. - The satoshis are locked in an output locked by this script, ensuring that they remain locked until the specified deadline.
There have been instances where clients experience race conditions upon token minting, where a single instance of a contract, like the one described above, is deployed. This mainly happens due to many simultaneous contract calls via different network nodes.
This problem can be mitigated by splitting the entire minted supply into multiple contract instances. Suppose you mint a token X with a supply of 1000. You can simply mint the entire supply to a P2PKH and then split it into multiple outputs, each holding, say, 10 tokens. These outputs will each be instances of the aforementioned lock smart contract.
<3