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. | |