Building and reading scripts
An SVScript is a script, which is to say a list of chunks, each of which is either an opcode or a data push.
ScriptBuilder assembles one for us, and the SVScript constructors parse one from hex, ASM or the library’s
own string format. The language itself is described in the guide’s
Bitcoin Script page.
Building a script
Section titled “Building a script”Opcodes are constants on OpCodes. addData pushes bytes, and chooses the push opcode from their length.
final pubkeyHash = Uint8List.fromList(HEX.decode('94837d2d5d6106aa97db38957dcc294181ee91e9'));
final script = ScriptBuilder() .opCode(OpCodes.OP_DUP) .opCode(OpCodes.OP_HASH160) .addData(pubkeyHash) // picks the smallest push opcode for the length .opCode(OpCodes.OP_EQUALVERIFY) .opCode(OpCodes.OP_CHECKSIG) .build();Rendering it
Section titled “Rendering it”script.toHex(); // 76a91494837d2d5d6106aa97db38957dcc294181ee91e988acscript.toString(type: 'asm'); // OP_DUP OP_HASH160 94837d2d5d6106aa97db38957dcc294181ee91e9 OP_EQUALVERIFY OP_CHECKSIGscript.toString(); // OP_DUP OP_HASH160 20 0x94837d2d5d6106aa97db38957dcc294181ee91e9 OP_EQUALVERIFY OP_CHECKSIGtoString(type: 'asm') gives the ASM that most tools use. toString() gives the library’s own format, which
writes each push as <length> 0x<hex>. This is the format that SVScript.fromString reads, and the one that
UTXO maps use.
Parsing a script
Section titled “Parsing a script”final fromHex = SVScript.fromHex('76a91494837d2d5d6106aa97db38957dcc294181ee91e988ac');final fromAsm = SVScript.fromASM( 'OP_DUP OP_HASH160 94837d2d5d6106aa97db38957dcc294181ee91e9 OP_EQUALVERIFY OP_CHECKSIG');// The library's own format writes each push as "<length> 0x<hex>".final fromString = SVScript.fromString( 'OP_DUP OP_HASH160 20 0x94837d2d5d6106aa97db38957dcc294181ee91e9 OP_EQUALVERIFY OP_CHECKSIG');Numbers
Section titled “Numbers”number encodes an integer the way script arithmetic expects it: OP_0 to OP_16 and OP_1NEGATE for small
values, and a minimal little-endian push otherwise.
final script = ScriptBuilder() .number(5) // OP_5 .number(1000) // a minimal little-endian push: e803 .number(-1) // OP_1NEGATE .opTrue() // OP_1 .opFalse() // OP_0 .build();
script.toString(type: 'asm'); // OP_5 e803 -1 OP_1 0Large pushes
Section titled “Large pushes”final big = ScriptBuilder().addData(Uint8List(300)).build();big.chunks[0].opcodenum == OpCodes.OP_PUSHDATA2; // true: 300 bytes needs a 2-byte lengthReading a script
Section titled “Reading a script”chunks lists the parts of a script. A chunk is a data push when buf holds bytes. Otherwise opcodenum is the
opcode, and OpCodes.getOpCodeName gives us its name.
// script: 0 OP_RETURN 68656c6c6ffinal pushes = <String>[];for (final ScriptChunk chunk in script.chunks) { if (chunk.buf != null && chunk.buf!.isNotEmpty) { pushes.add(utf8.decode(chunk.buf!)); // a data push } else { OpCodes.getOpCodeName(chunk.opcodenum); // an opcode: OP_0, OP_RETURN }}// pushes: [hello]Modifying a script
Section titled “Modifying a script”ScriptBuilder.fromScript copies an existing script’s chunks, and the …AtIndex methods and insertData insert
at a given position. The original script is left unchanged.
// Let's prefix a P2PKH script with data, the shape P2PKHDataLockBuilder produces.final withData = ScriptBuilder.fromScript(p2pkh) .insertData(0, Uint8List.fromList(utf8.encode('note'))) .opCodeAtIndex(1, OpCodes.OP_DROP) .build();Recognising common shapes
Section titled “Recognising common shapes”ScriptPattern has static checks for the standard script types. For more detail, including the values inside a
script, we use script templates.
ScriptPattern.isP2PKH(p2pkh); // trueScriptPattern.isP2SH(p2pkh); // falseScriptPattern.isOpReturn(SVScript.fromHex('006a0568656c6c6f')); // truep2pkh.isPushOnly(); // falsePlease note that
SVScript.isScriptHashOut()is misnamed in 3.1.2. It tests for P2PKH. UseScriptPattern.isP2SHfor P2SH.

