Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | 57x 57x 57x 57x 2x 2x 2x 2x 2x 2x 2x 57x 1x 1x 1x 1x 57x 2x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x | /* eslint-disable @typescript-eslint/no-unused-vars */
import { Beef, Transaction as BsvTransaction, SignActionResult, SignActionSpend } from '@bsv/sdk'
import { asBsvSdkScript, ScriptTemplateSABPPP, sdk } from "../../index.client"
import { PendingSignAction, WalletSigner } from "../WalletSigner"
import { processAction } from './createAction'
export async function signAction(signer: WalletSigner, auth: sdk.AuthId, vargs: sdk.ValidSignActionArgs)
: Promise<SignActionResult>
{
const prior = signer.pendingSignActions[vargs.reference]
Iif (!prior)
throw new sdk.WERR_NOT_IMPLEMENTED('recovery of out-of-session signAction reference data is not yet implemented.')
Iif (!prior.dcr.inputBeef)
throw new sdk.WERR_INTERNAL('prior.dcr.inputBeef must be valid')
prior.tx = await completeSignedTransaction(prior, vargs.spends, signer)
const sendWithResults = await processAction(prior, signer, auth, vargs)
const r: SignActionResult = {
txid: prior.tx.id('hex'),
tx: vargs.options.returnTXIDOnly ? undefined : makeAtomicBeef(prior.tx, prior.dcr.inputBeef),
sendWithResults
}
return r
}
export function makeAtomicBeef(tx: BsvTransaction, beef: number[] | Beef) : number[] {
if (Array.isArray(beef))
beef = Beef.fromBinary(beef)
beef.mergeTransaction(tx)
return beef.toBinaryAtomic(tx.id('hex'))
}
export async function completeSignedTransaction(
prior: PendingSignAction,
spends: Record<number, SignActionSpend>,
ninja: WalletSigner,
)
: Promise<BsvTransaction>
{
/////////////////////
// Insert the user provided unlocking scripts from "spends" arg
/////////////////////
for (const [key, spend] of Object.entries(spends)) {
const vin = Number(key)
const createInput = prior.args.inputs[vin]
const input = prior.tx.inputs[vin]
Iif (!createInput || !input || createInput.unlockingScript || !Number.isInteger(createInput.unlockingScriptLength))
throw new sdk.WERR_INVALID_PARAMETER('args', `spend does not correspond to prior input with valid unlockingScriptLength.`)
Iif (spend.unlockingScript.length / 2 > createInput.unlockingScriptLength!)
throw new sdk.WERR_INVALID_PARAMETER('args', `spend unlockingScript length ${spend.unlockingScript.length} exceeds expected length ${createInput.unlockingScriptLength}`)
input.unlockingScript = asBsvSdkScript(spend.unlockingScript)
Iif (spend.sequenceNumber !== undefined)
input.sequence = spend.sequenceNumber
}
const results = {
sdk: <SignActionResult>{}
}
/////////////////////
// Insert SABPPP unlock templates for dojo signed inputs
/////////////////////
for (const pdi of prior.pdi) {
const sabppp = new ScriptTemplateSABPPP({
derivationPrefix: pdi.derivationPrefix,
derivationSuffix: pdi.derivationSuffix,
keyDeriver: ninja.keyDeriver
})
const keys = ninja.getClientChangeKeyPair()
const lockerPrivKey = keys.privateKey
const unlockerPubKey = pdi.unlockerPubKey || keys.publicKey
const sourceSatoshis = pdi.sourceSatoshis
const lockingScript = asBsvSdkScript(pdi.lockingScript)
const unlockTemplate = sabppp.unlock(lockerPrivKey, unlockerPubKey, sourceSatoshis, lockingScript)
const input = prior.tx.inputs[pdi.vin]
input.unlockingScriptTemplate = unlockTemplate
}
/////////////////////
// Sign dojo signed inputs making transaction fully valid.
/////////////////////
await prior.tx.sign()
return prior.tx
}
|