@@ -86,6 +86,102 @@ console.log(tx.inputs[2].script.toASM()); // Should contain signature and pubkey
8686const finalizedTx = tx .build ();
8787```
8888
89+ ### 6. Partially Signing
90+
91+ when signer does not contain all private keys, it is used and multiple parties are required to perform signature authorization.
92+
93+ ``` ts
94+ const p2pkh = new P2PKH (Addr (ownerAddress .toByteString ()))
95+
96+ // Signer who unlocks / signs P2PKH UTXO.
97+ const ownerSigner = getNewSigner (ownerPrivkey )
98+
99+ // Signer who pays fee.
100+ // For simplicity here, we just again use the same default signer, but it
101+ // could be any other signer.
102+ const feeSigner = getDefaultSigner ()
103+
104+ // Connect the signer.
105+ await p2pkh .connect (feeSigner )
106+
107+ // Deploy the P2PKH contract.
108+ await p2pkh .deploy (1 )
109+
110+ const tx = new bsv .Transaction ()
111+
112+ // Get UTXOs for for the signer, who will pay the fee.
113+ const address = await feeSigner .getDefaultAddress ()
114+
115+ const utxos = await feeSigner .listUnspent (address )
116+
117+ // Spend retrieved UTXOs to pay the transaction fee. Any change will
118+ // be returned to the fee signers address.
119+ tx .from (utxos ).change (address )
120+
121+ // Bind custom call tx builder. It adds a single input, which will call
122+ // our deployed smart contracts "unlock" method. Additionally, it adds an
123+ // unspendable OP_RETURN output.
124+ p2pkh .bindTxBuilder (
125+ ' unlock' ,
126+ async (
127+ current : P2PKH ,
128+ options : MethodCallOptions < P2PKH >
129+ ): Promise <ContractTransaction > => {
130+ const inputLen = tx .inputs .length
131+ tx .addInput (current .buildContractInput ()).addOutput (
132+ new bsv .Transaction .Output ({
133+ script: bsv .Script .fromASM (' OP_FALSE OP_RETURN 0101' ),
134+ satoshis: 0 ,
135+ })
136+ )
137+
138+ return {
139+ tx: tx ,
140+ /** The input index of previous contract UTXO to spend in the method calling tx */
141+ atInputIndex: inputLen ,
142+ nexts: [],
143+ }
144+ }
145+ )
146+
147+ // // Construct the call tx locally (notice the "pratiallySigned" flag).
148+ // // Use the ANYONECANPAY_SINGLE sighash flag to sign the first input.
149+ const sigHashType = bsv .crypto .Signature .ANYONECANPAY_SINGLE
150+
151+ await p2pkh .connect (ownerSigner )
152+
153+ const call = async () => {
154+ const { tx : callTx } = await p2pkh .methods .unlock (
155+ // pass signature, the first parameter, to `unlock`
156+ // after the signer signs the transaction, the signatures are returned in `SignatureResponse[]`
157+ // you need to find the signature or signatures you want in the return through the public key or address
158+ // here we use `myPublicKey` to find the signature because we signed the transaction with `myPrivateKey` before
159+ (sigResps ) =>
160+ findSig (sigResps , ownerPrivkey .publicKey , sigHashType ),
161+ // pass public key, the second parameter, to `unlock`
162+ PubKey (ownerPrivkey .publicKey .toByteString ()),
163+ // method call options
164+ {
165+ // tell the signer to use the private key corresponding to `myPublicKey` to sign this transaction
166+ // that is using `myPrivateKey` to sign the transaction
167+ pubKeyOrAddrToSign: {
168+ pubKeyOrAddr: ownerPrivkey .publicKey ,
169+ sigHashType: sigHashType ,
170+ },
171+ partiallySigned: true ,
172+ autoPayFee: false ,
173+ } as MethodCallOptions <P2PKH >
174+ )
175+
176+ // Finally, sign the newly added inputs and broadcast the modified transaction.
177+ // Notice, that if the main singer wouldn't use the ANYONECANPAY_SINGLE sighash flag,
178+ // Then the call to the "unlock" method (first input) wouldn't successfully evaluate anymore.
179+ await feeSigner .signAndsendTransaction (callTx , { address })
180+ }
181+
182+ await expect (call ()).to .be .not .rejected
183+ ```
184+
89185## Conclusion
90186
91187By following these steps, your transaction sign only P2PKH inputs using the ** ` Signer ` ** class in sCrypt. If you encounter any issues or have specific requirements,
0 commit comments