33 binToHex ,
44 decodeCashAddress ,
55 hexToBin ,
6+ Input ,
67 isHex ,
78 TransactionBch ,
89 utf8ToBin ,
@@ -30,10 +31,10 @@ import { Contract } from './Contract.js';
3031import { DebugResults , debugTemplate } from './debugging.js' ;
3132import {
3233 HashType ,
34+ isContractUnlocker ,
3335 isP2PKHUnlocker ,
3436 isStandardUnlockableUtxo ,
3537 isUnlockableUtxo ,
36- isUtxoP2PKH ,
3738 LibauthTokenDetails ,
3839 Output ,
3940 SignatureAlgorithm ,
@@ -43,11 +44,10 @@ import {
4344 Utxo ,
4445} from './interfaces.js' ;
4546import SignatureTemplate from './SignatureTemplate.js' ;
46- import { addressToLockScript , extendedStringify , zip } from './utils.js' ;
47+ import { addressToLockScript , extendedStringify , getSignatureAndPubkeyFromP2PKHInput , zip } from './utils.js' ;
4748import { TransactionBuilder } from './TransactionBuilder.js' ;
4849import { deflate } from 'pako' ;
4950
50-
5151/**
5252 * Generates template entities for P2PKH (Pay to Public Key Hash) placeholder scripts.
5353 *
@@ -61,16 +61,22 @@ export const generateTemplateEntitiesP2PKH = (
6161 const lockScriptName = `p2pkh_placeholder_lock_${ inputIndex } ` ;
6262 const unlockScriptName = `p2pkh_placeholder_unlock_${ inputIndex } ` ;
6363
64+ // TODO: Add descriptions
6465 return {
6566 [ `signer_${ inputIndex } ` ] : {
6667 scripts : [ lockScriptName , unlockScriptName ] ,
67- description : `placeholder_key_ ${ inputIndex } ` ,
68+ description : `P2PKH data for input ${ inputIndex } ` ,
6869 name : `P2PKH Signer (input #${ inputIndex } )` ,
6970 variables : {
70- [ `placeholder_key_${ inputIndex } ` ] : {
71+ [ `signature_${ inputIndex } ` ] : {
72+ description : '' ,
73+ name : `P2PKH Signature (input #${ inputIndex } )` ,
74+ type : 'WalletData' ,
75+ } ,
76+ [ `public_key_${ inputIndex } ` ] : {
7177 description : '' ,
72- name : `P2PKH Placeholder Key (input #${ inputIndex } )` ,
73- type : 'Key ' ,
78+ name : `P2PKH public key (input #${ inputIndex } )` ,
79+ type : 'WalletData ' ,
7480 } ,
7581 } ,
7682 } ,
@@ -152,30 +158,29 @@ const createWalletTemplateVariables = (
152158 *
153159 */
154160export const generateTemplateScriptsP2PKH = (
155- template : SignatureTemplate ,
156161 inputIndex : number ,
157162) : WalletTemplate [ 'scripts' ] => {
158163 const scripts : WalletTemplate [ 'scripts' ] = { } ;
159164 const lockScriptName = `p2pkh_placeholder_lock_${ inputIndex } ` ;
160165 const unlockScriptName = `p2pkh_placeholder_unlock_${ inputIndex } ` ;
161- const placeholderKeyName = `placeholder_key_${ inputIndex } ` ;
162166
163- const signatureAlgorithmName = getSignatureAlgorithmName ( template . getSignatureAlgorithm ( ) ) ;
164- const hashtypeName = getHashTypeName ( template . getHashType ( false ) ) ;
165- const signatureString = ` ${ placeholderKeyName } . ${ signatureAlgorithmName } . ${ hashtypeName } ` ;
167+ const signatureString = `signature_ ${ inputIndex } ` ;
168+ const publicKeyString = `public_key_ ${ inputIndex } ` ;
169+
166170 // add extra unlocking and locking script for P2PKH inputs spent alongside our contract
167171 // this is needed for correct cross-references in the template
168172 scripts [ unlockScriptName ] = {
173+ passes : [ `P2PKH_spend_input${ inputIndex } _evaluate` ] ,
169174 name : `P2PKH Unlock (input #${ inputIndex } )` ,
170175 script :
171- `<${ signatureString } >\n<${ placeholderKeyName } .public_key >` ,
176+ `<${ signatureString } >\n<${ publicKeyString } >` ,
172177 unlocks : lockScriptName ,
173178 } ;
174179 scripts [ lockScriptName ] = {
175180 lockingType : 'standard' ,
176181 name : `P2PKH Lock (input #${ inputIndex } )` ,
177182 script :
178- `OP_DUP\nOP_HASH160 <$(<${ placeholderKeyName } .public_key > OP_HASH160\n)> OP_EQUALVERIFY\nOP_CHECKSIG` ,
183+ `OP_DUP\nOP_HASH160 <$(<${ publicKeyString } > OP_HASH160\n)> OP_EQUALVERIFY\nOP_CHECKSIG` ,
179184 } ;
180185
181186 return scripts ;
@@ -275,6 +280,7 @@ export const generateTemplateScenarios = (
275280 const encodedConstructorArgs = contract . encodedConstructorArgs ;
276281 const scenarioIdentifier = `${ artifact . contractName } _${ abiFunction . name } _input${ inputIndex } _evaluate` ;
277282
283+ // TODO: Update scenario descriptions
278284 const scenarios = {
279285 // single scenario to spend out transaction under test given the CashScript parameters provided
280286 [ scenarioIdentifier ] : {
@@ -288,12 +294,13 @@ export const generateTemplateScenarios = (
288294 } ,
289295 currentBlockHeight : 2 ,
290296 currentBlockTime : Math . round ( + new Date ( ) / 1000 ) ,
297+ // TODO: remove usage of private keys in P2SH scenarios as well
291298 keys : {
292299 privateKeys : generateTemplateScenarioKeys ( abiFunction . inputs , encodedFunctionArgs ) ,
293300 } ,
294301 } ,
295302 transaction : generateTemplateScenarioTransaction ( contract , libauthTransaction , csTransaction , inputIndex ) ,
296- sourceOutputs : generateTemplateScenarioSourceOutputs ( csTransaction , inputIndex ) ,
303+ sourceOutputs : generateTemplateScenarioSourceOutputs ( csTransaction , libauthTransaction , inputIndex ) ,
297304 } ,
298305 } ;
299306
@@ -308,20 +315,53 @@ export const generateTemplateScenarios = (
308315 return scenarios ;
309316} ;
310317
318+ export const generateTemplateScenariosP2PKH = (
319+ libauthTransaction : TransactionBch ,
320+ csTransaction : TransactionType ,
321+ inputIndex : number ,
322+ ) : WalletTemplate [ 'scenarios' ] => {
323+ const scenarioIdentifier = `P2PKH_spend_input${ inputIndex } _evaluate` ;
324+
325+ const { signature, publicKey } = getSignatureAndPubkeyFromP2PKHInput ( libauthTransaction . inputs [ inputIndex ] ) ;
326+
327+ // TODO: Update scenario descriptions
328+ const scenarios = {
329+ // single scenario to spend out transaction under test given the CashScript parameters provided
330+ [ scenarioIdentifier ] : {
331+ name : `Evaluate P2PKH spend (input #${ inputIndex } )` ,
332+ description : 'An example evaluation where this script execution passes.' ,
333+ data : {
334+ // encode values for the variables defined above in `entities` property
335+ bytecode : {
336+ [ `signature_${ inputIndex } ` ] : `0x${ binToHex ( signature ) } ` ,
337+ [ `public_key_${ inputIndex } ` ] : `0x${ binToHex ( publicKey ) } ` ,
338+ } ,
339+ currentBlockHeight : 2 ,
340+ currentBlockTime : Math . round ( + new Date ( ) / 1000 ) ,
341+ } ,
342+ transaction : generateTemplateScenarioTransaction ( undefined , libauthTransaction , csTransaction , inputIndex ) ,
343+ sourceOutputs : generateTemplateScenarioSourceOutputs ( csTransaction , libauthTransaction , inputIndex ) ,
344+ } ,
345+ } ;
346+
347+ return scenarios ;
348+ } ;
349+
311350const generateTemplateScenarioTransaction = (
312- contract : Contract ,
351+ contract : Contract | undefined ,
313352 libauthTransaction : TransactionBch ,
314353 csTransaction : TransactionType ,
315354 slotIndex : number ,
316355) : WalletTemplateScenario [ 'transaction' ] => {
317356 const inputs = libauthTransaction . inputs . map ( ( input , inputIndex ) => {
318357 const csInput = csTransaction . inputs [ inputIndex ] as Utxo ;
358+ const libauthInput = libauthTransaction . inputs [ inputIndex ] ;
319359
320360 return {
321361 outpointIndex : input . outpointIndex ,
322362 outpointTransactionHash : binToHex ( input . outpointTransactionHash ) ,
323363 sequenceNumber : input . sequenceNumber ,
324- unlockingBytecode : generateTemplateScenarioBytecode ( csInput , inputIndex , 'p2pkh_placeholder_unlock' , slotIndex === inputIndex ) ,
364+ unlockingBytecode : generateTemplateScenarioBytecode ( csInput , libauthInput , inputIndex , 'p2pkh_placeholder_unlock' , slotIndex === inputIndex ) ,
325365 } as WalletTemplateScenarioInput ;
326366 } ) ;
327367
@@ -330,8 +370,16 @@ const generateTemplateScenarioTransaction = (
330370 const outputs = libauthTransaction . outputs . map ( ( output , index ) => {
331371 const csOutput = csTransaction . outputs [ index ] ;
332372
373+ if ( csOutput && contract ) {
374+ return {
375+ lockingBytecode : generateTemplateScenarioTransactionOutputLockingBytecode ( csOutput , contract ) ,
376+ token : serialiseTokenDetails ( output . token ) ,
377+ valueSatoshis : Number ( output . valueSatoshis ) ,
378+ } as WalletTemplateScenarioTransactionOutput ;
379+ }
380+
333381 return {
334- lockingBytecode : generateTemplateScenarioTransactionOutputLockingBytecode ( csOutput , contract ) ,
382+ lockingBytecode : ` ${ binToHex ( output . lockingBytecode ) } ` ,
335383 token : serialiseTokenDetails ( output . token ) ,
336384 valueSatoshis : Number ( output . valueSatoshis ) ,
337385 } as WalletTemplateScenarioTransactionOutput ;
@@ -344,11 +392,14 @@ const generateTemplateScenarioTransaction = (
344392
345393const generateTemplateScenarioSourceOutputs = (
346394 csTransaction : TransactionType ,
395+ libauthTransaction : TransactionBch ,
347396 slotIndex : number ,
348397) : Array < WalletTemplateScenarioOutput < true > > => {
349398 return csTransaction . inputs . map ( ( input , inputIndex ) => {
399+ const libauthInput = libauthTransaction . inputs [ inputIndex ] ;
400+
350401 return {
351- lockingBytecode : generateTemplateScenarioBytecode ( input , inputIndex , 'p2pkh_placeholder_lock' , inputIndex === slotIndex ) ,
402+ lockingBytecode : generateTemplateScenarioBytecode ( input , libauthInput , inputIndex , 'p2pkh_placeholder_lock' , inputIndex === slotIndex ) ,
352403 valueSatoshis : Number ( input . satoshis ) ,
353404 token : serialiseTokenDetails ( input . token ) ,
354405 } ;
@@ -409,18 +460,14 @@ export const getLibauthTemplates = (
409460
410461 // We can typecast this because we check that all inputs are standard unlockable at the top of this function
411462 for ( const [ inputIndex , input ] of ( txn . inputs as StandardUnlockableUtxo [ ] ) . entries ( ) ) {
412- // If template exists on the input, it indicates this is a P2PKH (Pay to Public Key Hash) input
413- if ( 'template' in input . unlocker ) {
414- // @ts -ignore TODO: Remove UtxoP2PKH type and only use UnlockableUtxo in Libauth Template generation
415- input . template = input . unlocker ?. template ; // Added to support P2PKH inputs in buildTemplate
463+ if ( isP2PKHUnlocker ( input . unlocker ) ) {
416464 Object . assign ( p2pkhEntities , generateTemplateEntitiesP2PKH ( inputIndex ) ) ;
417- Object . assign ( p2pkhScripts , generateTemplateScriptsP2PKH ( input . unlocker . template , inputIndex ) ) ;
418-
465+ Object . assign ( p2pkhScripts , generateTemplateScriptsP2PKH ( inputIndex ) ) ;
466+ Object . assign ( scenarios , generateTemplateScenariosP2PKH ( libauthTransaction , csTransaction , inputIndex ) ) ;
419467 continue ;
420468 }
421469
422- // If contract exists on the input, it indicates this is a contract input
423- if ( 'contract' in input . unlocker ) {
470+ if ( isContractUnlocker ( input . unlocker ) ) {
424471 const contract = input . unlocker ?. contract ;
425472 const abiFunction = input . unlocker ?. abiFunction ;
426473
@@ -537,7 +584,7 @@ export const getLibauthTemplates = (
537584
538585export const debugLibauthTemplate = ( template : WalletTemplate , transaction : TransactionBuilder ) : DebugResults => {
539586 const allArtifacts = transaction . inputs
540- . map ( input => 'contract' in input . unlocker ? input . unlocker . contract : undefined )
587+ . map ( input => isContractUnlocker ( input . unlocker ) ? input . unlocker . contract : undefined )
541588 . filter ( ( contract ) : contract is Contract => Boolean ( contract ) )
542589 . map ( contract => contract . artifact ) ;
543590
@@ -575,17 +622,19 @@ const generateLockingScriptParams = (
575622
576623export const generateUnlockingScriptParams = (
577624 csInput : StandardUnlockableUtxo ,
625+ libauthInput : Input ,
578626 p2pkhScriptNameTemplate : string ,
579627 inputIndex : number ,
580628) : WalletTemplateScenarioBytecode => {
581629 if ( isP2PKHUnlocker ( csInput . unlocker ) ) {
630+ const { signature, publicKey } = getSignatureAndPubkeyFromP2PKHInput ( libauthInput ) ;
631+
582632 return {
583633 script : `${ p2pkhScriptNameTemplate } _${ inputIndex } ` ,
584634 overrides : {
585- keys : {
586- privateKeys : {
587- [ `placeholder_key_${ inputIndex } ` ] : binToHex ( csInput . unlocker . template . privateKey ) ,
588- } ,
635+ bytecode : {
636+ [ `signature_${ inputIndex } ` ] : `0x${ binToHex ( signature ) } ` ,
637+ [ `public_key_${ inputIndex } ` ] : `0x${ binToHex ( publicKey ) } ` ,
589638 } ,
590639 } ,
591640 } ;
@@ -604,6 +653,7 @@ export const generateUnlockingScriptParams = (
604653 ...generateTemplateScenarioParametersValues ( abiFunction . inputs , encodedFunctionArgs ) ,
605654 ...generateTemplateScenarioParametersValues ( contract . artifact . constructorInputs , contract . encodedConstructorArgs ) ,
606655 } ,
656+ // TODO: remove usage of private keys in P2SH scenarios as well
607657 keys : {
608658 privateKeys : generateTemplateScenarioKeys ( abiFunction . inputs , encodedFunctionArgs ) ,
609659 } ,
@@ -745,29 +795,16 @@ export const generateTemplateScenarioKeys = (
745795
746796// Used for generating the locking / unlocking bytecode for source outputs and inputs
747797export const generateTemplateScenarioBytecode = (
748- input : Utxo , inputIndex : number , p2pkhScriptNameTemplate : string , insertSlot ?: boolean ,
798+ input : Utxo ,
799+ libauthInput : Input ,
800+ inputIndex : number ,
801+ p2pkhScriptNameTemplate : string ,
802+ insertSlot ?: boolean ,
749803) : WalletTemplateScenarioBytecode | [ 'slot' ] => {
750804 if ( insertSlot ) return [ 'slot' ] ;
751805
752- const p2pkhScriptName = `${ p2pkhScriptNameTemplate } _${ inputIndex } ` ;
753- const placeholderKeyName = `placeholder_key_${ inputIndex } ` ;
754-
755- // This is for P2PKH inputs in the old transaction builder (TODO: remove when we remove old transaction builder)
756- if ( isUtxoP2PKH ( input ) ) {
757- return {
758- script : p2pkhScriptName ,
759- overrides : {
760- keys : {
761- privateKeys : {
762- [ placeholderKeyName ] : binToHex ( input . template . privateKey ) ,
763- } ,
764- } ,
765- } ,
766- } ;
767- }
768-
769806 if ( isUnlockableUtxo ( input ) && isStandardUnlockableUtxo ( input ) ) {
770- return generateUnlockingScriptParams ( input , p2pkhScriptNameTemplate , inputIndex ) ;
807+ return generateUnlockingScriptParams ( input , libauthInput , p2pkhScriptNameTemplate , inputIndex ) ;
771808 }
772809
773810 // 'slot' means that we are currently evaluating this specific input,
0 commit comments