Spaces:
Runtime error
Runtime error
sidebar_position: 2 | |
# How to Customize a Contract Tx | |
## Deployment Tx | |
### Default | |
For contract deployment, the default tx builder creates a transaction with the following structure: | |
* Inputs: | |
* [0β¦]: One or more [P2PKH](https://learnmeabitcoin.com/technical/p2pkh) inputs for paying transaction fees. | |
* Outputs: | |
* [0]: The output containing the contract. | |
* [1]: A P2PKH change output if needed. | |
Numbers in [] represent index, starting from 0. | |
 | |
### Customize | |
You can customize a contract's deployment tx builder by overriding its [buildDeployTransaction](../how-to-write-a-contract/built-ins#builddeploytransaction) method. An example is shown below. | |
```ts | |
class DemoContract extends SmartContract { | |
// ... | |
// customize the deployment tx by overriding `SmartContract.buildDeployTransaction` method | |
override async buildDeployTransaction(utxos: UTXO[], amount: number, | |
changeAddress?: bsv.Address | string): Promise<bsv.Transaction> { | |
const deployTx = new bsv.Transaction() | |
// add p2pkh inputs for paying tx fees | |
.from(utxos) | |
// add contract output | |
.addOutput(new bsv.Transaction.Output({ | |
script: this.lockingScript, | |
satoshis: amount, | |
})) | |
// add OP_RETURN output | |
.addData('Hello World') | |
if (changeAddress) { | |
deployTx.change(changeAddress); | |
if (this._provider) { | |
deployTx.feePerKb(await this.provider.getFeePerKb()) | |
} | |
} | |
return deployTx; | |
} | |
} | |
``` | |
You may visit the [full code](https://github.com/sCrypt-Inc/boilerplate/blob/f63c37038a03bc51267e816d9441969d3e1d2ece/src/contracts/auction.ts#L100-L127) for more details. | |
## Call Tx | |
### Default | |
For contract calls, the default tx builder creates a transaction with the following structure: | |
* Inputs | |
* [0]: The input that spends the contract UTXO. | |
* [1β¦]: Zero or more P2PKH inputs for paying transaction fees. | |
* Outputs | |
* [0β¦N-1]: One or more outputs, each containing a new contract instance (UTXO) if the contract is [stateful](../how-to-write-a-contract/stateful-contract). | |
* [N]: A P2PKH change output if needed. | |
 | |
### Customize | |
You can customize a tx builder for a public `@method` of your contract by calling `bindTxBuilder`. The first parameter is the public method name, and the second parameter is the customized tx builder. | |
```ts | |
// bind a customized tx builder for the public method `MyContract.unlock` | |
instance.bindTxBuilder("unlock", (current: T, options: MethodCallOptions<T>, ...args: any) => { | |
// the tx is NOT signed | |
const unsignedTx: bsv.Transaction = new bsv.Transaction() | |
// add contract input | |
.addInput(current.buildContractInput(options.fromUTXO)) | |
// add a p2pkh output | |
.addOutput(new bsv.Transaction.Output({ | |
script: bsv.Script.fromHex(Utils.buildPublicKeyHashScript(args[0])), | |
satoshis: args[1] | |
})) | |
// add change output | |
.change(options.changeAddress) | |
return Promise.resolve({ | |
tx: unsignedTx, | |
atInputIndex: 0, // the contract input's index | |
nexts: [] | |
}) | |
}) | |
``` | |
Note that the parameters of your customized tx builder consist of the following parts: | |
- `current` is the actual instance of the smart contract. | |
- `options` is of type [`MethodCallOptions`](../how-to-test-a-contract.md#methodcalloptions). | |
- `...args: any` is an argument list the same as the bound pubic `@method`. | |
## Notes | |
Please be aware that each of these tx builders should only create an **unsigned** transaction. If required, the transaction gets signed automatically in a later step prior to broadcasting. | |
Also, your customized tx must satisfy all of the called `@method`'s assertions. | |