Skip to content

Commit f935d48

Browse files
committed
Fix #131
1 parent 0b50d60 commit f935d48

1 file changed

Lines changed: 96 additions & 0 deletions

File tree

docs/advanced/How to only sign p2pkh inputs.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,102 @@ console.log(tx.inputs[2].script.toASM()); // Should contain signature and pubkey
8686
const 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

91187
By 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

Comments
 (0)