@@ -22,6 +22,7 @@ import { Contract } from '../Contract.js';
2222import { DebugResults , debugTemplate } from '../debugging.js' ;
2323import {
2424 AddressType ,
25+ ContractUnlocker ,
2526 UnlockableUtxo ,
2627 Utxo ,
2728} from '../interfaces.js' ;
@@ -31,6 +32,7 @@ import {
3132 formatParametersForDebugging ,
3233 generateTemplateScenarioBytecode ,
3334 generateTemplateScenarioKeys ,
35+ generateTemplateScenarioParametersFunctionIndex ,
3436 generateTemplateScenarioParametersValues ,
3537 generateTemplateScenarioTransactionOutputLockingBytecode ,
3638 getHashTypeName ,
@@ -85,6 +87,35 @@ export const generateTemplateEntitiesP2SH = (
8587 encodedFunctionArgs : EncodedFunctionArgument [ ] ,
8688 inputIndex : number ,
8789) : WalletTemplate [ 'entities' ] => {
90+ const entities = {
91+ [ artifact . contractName + '_input' + inputIndex + '_parameters' ] : {
92+ description : 'Contract creation and function parameters' ,
93+ name : `${ artifact . contractName } (input #${ inputIndex } )` ,
94+ scripts : [
95+ artifact . contractName + '_lock' ,
96+ artifact . contractName + '_' + abiFunction . name + '_input' + inputIndex + '_unlock' ,
97+ ] ,
98+ variables : createWalletTemplateVariables ( artifact , abiFunction , encodedFunctionArgs ) ,
99+ } ,
100+ } ;
101+
102+ // function_index is a special variable that indicates the function to execute
103+ if ( artifact . abi . length > 1 ) {
104+ entities [ artifact . contractName + '_input' + inputIndex + '_parameters' ] . variables . function_index = {
105+ description : 'Script function index to execute' ,
106+ name : 'function_index' ,
107+ type : 'WalletData' ,
108+ } ;
109+ }
110+
111+ return entities ;
112+ } ;
113+
114+ const createWalletTemplateVariables = (
115+ artifact : Artifact ,
116+ abiFunction : AbiFunction ,
117+ encodedFunctionArgs : EncodedFunctionArgument [ ] ,
118+ ) : Record < string , WalletTemplateVariable > => {
88119 const functionParameters = Object . fromEntries < WalletTemplateVariable > (
89120 abiFunction . inputs . map ( ( input , index ) => ( [
90121 input . name ,
@@ -107,31 +138,7 @@ export const generateTemplateEntitiesP2SH = (
107138 ] ) ) ,
108139 ) ;
109140
110- const entities = {
111- [ artifact . contractName + '_input' + inputIndex + '_parameters' ] : {
112- description : 'Contract creation and function parameters' ,
113- name : `${ artifact . contractName } (input #${ inputIndex } )` ,
114- scripts : [
115- artifact . contractName + '_lock' ,
116- artifact . contractName + '_' + abiFunction . name + '_input' + inputIndex + '_unlock' ,
117- ] ,
118- variables : {
119- ...functionParameters ,
120- ...constructorParameters ,
121- } ,
122- } ,
123- } ;
124-
125- // function_index is a special variable that indicates the function to execute
126- if ( artifact . abi . length > 1 ) {
127- entities [ artifact . contractName + '_input' + inputIndex + '_parameters' ] . variables . function_index = {
128- description : 'Script function index to execute' ,
129- name : 'function_index' ,
130- type : 'WalletData' ,
131- } ;
132- }
133-
134- return entities ;
141+ return { ...functionParameters , ...constructorParameters } ;
135142} ;
136143
137144/**
@@ -303,14 +310,14 @@ const generateTemplateScenarioTransaction = (
303310 csTransaction : Transaction ,
304311 slotIndex : number ,
305312) : WalletTemplateScenario [ 'transaction' ] => {
306- const inputs = libauthTransaction . inputs . map ( ( input , index ) => {
307- const csInput = csTransaction . inputs [ index ] as Utxo ;
313+ const inputs = libauthTransaction . inputs . map ( ( input , inputIndex ) => {
314+ const csInput = csTransaction . inputs [ inputIndex ] as Utxo ;
308315
309316 return {
310317 outpointIndex : input . outpointIndex ,
311318 outpointTransactionHash : binToHex ( input . outpointTransactionHash ) ,
312319 sequenceNumber : input . sequenceNumber ,
313- unlockingBytecode : generateTemplateScenarioBytecode ( csInput , `p2pkh_placeholder_unlock_ ${ index } ` , `placeholder_key_ ${ index } ` , slotIndex === index ) ,
320+ unlockingBytecode : generateTemplateScenarioBytecode ( csInput , inputIndex , 'p2pkh_placeholder_unlock' , slotIndex === inputIndex ) ,
314321 } as WalletTemplateScenarioInput ;
315322 } ) ;
316323
@@ -335,10 +342,9 @@ const generateTemplateScenarioSourceOutputs = (
335342 csTransaction : Transaction ,
336343 slotIndex : number ,
337344) : Array < WalletTemplateScenarioOutput < true > > => {
338-
339- return csTransaction . inputs . map ( ( input , index ) => {
345+ return csTransaction . inputs . map ( ( input , inputIndex ) => {
340346 return {
341- lockingBytecode : generateTemplateScenarioBytecode ( input , `p2pkh_placeholder_lock_ ${ index } ` , `placeholder_key_ ${ index } ` , index === slotIndex ) ,
347+ lockingBytecode : generateTemplateScenarioBytecode ( input , inputIndex , 'p2pkh_placeholder_lock' , inputIndex === slotIndex ) ,
342348 valueSatoshis : Number ( input . satoshis ) ,
343349 token : serialiseTokenDetails ( input . token ) ,
344350 } ;
@@ -396,7 +402,7 @@ export const getLibauthTemplates = (
396402
397403 for ( const [ inputIndex , input ] of txn . inputs . entries ( ) ) {
398404 // If template exists on the input, it indicates this is a P2PKH (Pay to Public Key Hash) input
399- if ( input . unlocker ?. template ) {
405+ if ( 'template' in input . unlocker ) {
400406 // @ts -ignore TODO: Remove UtxoP2PKH type and only use UnlockableUtxo in Libaith Template generation
401407 input . template = input . unlocker ?. template ; // Added to support P2PKH inputs in buildTemplate
402408 Object . assign ( p2pkhEntities , generateTemplateEntitiesP2PKH ( inputIndex ) ) ;
@@ -406,7 +412,7 @@ export const getLibauthTemplates = (
406412 }
407413
408414 // If contract exists on the input, it indicates this is a contract input
409- if ( input . unlocker ?. contract ) {
415+ if ( 'contract' in input . unlocker ) {
410416 const contract = input . unlocker ?. contract ;
411417 const abiFunction = input . unlocker ?. abiFunction ;
412418
@@ -454,9 +460,8 @@ export const getLibauthTemplates = (
454460 const lockScriptName = Object . keys ( script ) . find ( scriptName => scriptName . includes ( '_lock' ) ) ;
455461 if ( lockScriptName ) {
456462 // Generate bytecodes for this contract input
457- const csInput = csTransaction . inputs [ inputIndex ] ;
458463 const unlockingBytecode = binToHex ( libauthTransaction . inputs [ inputIndex ] . unlockingBytecode ) ;
459- const lockingScriptParams = generateLockingScriptParams ( csInput . unlocker ! . contract ! , csInput , lockScriptName ) ;
464+ const lockingScriptParams = generateLockingScriptParams ( input . unlocker . contract , input , lockScriptName ) ;
460465
461466 // Assign a name to the unlocking bytecode so later it can be used to replace the bytecode/slot in scenarios
462467 unlockingBytecodeToLockingBytecodeParams [ unlockingBytecode ] = lockingScriptParams ;
@@ -525,7 +530,7 @@ export const getLibauthTemplates = (
525530
526531export const debugLibauthTemplate = ( template : WalletTemplate , transaction : TransactionBuilder ) : DebugResults => {
527532 const allArtifacts = transaction . inputs
528- . map ( input => input . unlocker ?. contract )
533+ . map ( input => 'contract' in input . unlocker ? input . unlocker . contract : undefined )
529534 . filter ( ( contract ) : contract is Contract => ! ! contract )
530535 . map ( contract => contract . artifact ) ;
531536
@@ -537,14 +542,19 @@ const generateLockingScriptParams = (
537542 csInput : UnlockableUtxo ,
538543 lockScriptName : string ,
539544) : WalletTemplateScenarioBytecode => {
540- if ( ! csInput . unlocker ?. contract ) return {
541- script : lockScriptName ,
542- } ;
545+ if ( ( 'template' in csInput . unlocker ) ) {
546+ return {
547+ script : lockScriptName ,
548+ } ;
549+ }
543550
544551 const constructorParamsEntries = contract . artifact . constructorInputs
545552 . map ( ( { name } , index ) => [
546553 name ,
547- addHexPrefixExceptEmpty ( binToHex ( csInput . unlocker ! . contract ! . encodedConstructorArgs [ index ] ) ) ,
554+ // TODO: For some reason, typescript forgets that the unlocker is a ContractUnlocker
555+ addHexPrefixExceptEmpty (
556+ binToHex ( ( csInput . unlocker as ContractUnlocker ) . contract . encodedConstructorArgs [ index ] ) ,
557+ ) ,
548558 ] ) ;
549559
550560 const constructorParams = Object . fromEntries ( constructorParamsEntries ) ;
@@ -556,3 +566,41 @@ const generateLockingScriptParams = (
556566 } ,
557567 } ;
558568} ;
569+
570+ export const generateUnlockingScriptParams = (
571+ csInput : UnlockableUtxo ,
572+ p2pkhScriptNameTemplate : string ,
573+ inputIndex : number ,
574+ ) : WalletTemplateScenarioBytecode => {
575+ if ( ( 'template' in csInput . unlocker ) ) {
576+ return {
577+ script : `${ p2pkhScriptNameTemplate } _${ inputIndex } ` ,
578+ overrides : {
579+ keys : {
580+ privateKeys : {
581+ [ `placeholder_key_${ inputIndex } ` ] : binToHex ( csInput . unlocker . template . privateKey ) ,
582+ } ,
583+ } ,
584+ } ,
585+ } ;
586+ }
587+
588+ const abiFunction = csInput . unlocker . abiFunction ;
589+ const contract = csInput . unlocker . contract ;
590+ const encodedFunctionArgs = encodeFunctionArguments ( abiFunction , csInput . unlocker . params ) ;
591+
592+ return {
593+ script : `${ csInput . unlocker . contract . name } _${ abiFunction . name } _input${ inputIndex } _unlock` ,
594+ overrides : {
595+ // encode values for the variables defined above in `entities` property
596+ bytecode : {
597+ ...generateTemplateScenarioParametersFunctionIndex ( abiFunction , contract . artifact . abi ) ,
598+ ...generateTemplateScenarioParametersValues ( abiFunction . inputs , encodedFunctionArgs ) ,
599+ ...generateTemplateScenarioParametersValues ( contract . artifact . constructorInputs , contract . encodedConstructorArgs ) ,
600+ } ,
601+ keys : {
602+ privateKeys : generateTemplateScenarioKeys ( abiFunction . inputs , encodedFunctionArgs ) ,
603+ } ,
604+ } ,
605+ } ;
606+ } ;
0 commit comments