1- import { Address , concatArrays , decodeMsgpack , hash } from '@algorandfoundation/algokit-common'
1+ import { Address , Addressable , concatArrays , decodeMsgpack , hash } from '@algorandfoundation/algokit-common'
22import { MultisigAccount } from './multisig'
3- import { TransactionSigner } from './signer'
3+ import { AddressWithDelegatedLsigSigner , TransactionSigner } from './signer'
44import { LogicSignature , MultisigSignature , SignedTransaction , encodeSignedTransaction } from './transactions/signed-transaction'
55import { Transaction } from './transactions/transaction'
66import { logicSignatureCodec } from './transactions/signed-transaction-meta'
@@ -9,43 +9,118 @@ const PROGRAM_TAG = new TextEncoder().encode('Program')
99const MSIG_PROGRAM_TAG = new TextEncoder ( ) . encode ( 'MsigProgram' )
1010const SIGN_PROGRAM_DATA_PREFIX = new TextEncoder ( ) . encode ( 'ProgData' )
1111
12- /** Function for signing logic signatures for delegation */
13- export type DelegatedLsigSigner = ( lsig : LogicSigAccount , msig ?: MultisigAccount ) => Promise < Uint8Array >
12+ /** Function for signing logic signatures for delegation
13+ * @param lsig - The logic signature that is being signed for delegation
14+ * @param msig - Optional multisig account that should be set when a public key is signing as a subsigner of a multisig
15+ * @returns The address of the delegator
16+ * */
17+ export type DelegatedLsigSigner = (
18+ lsig : LogicSigAccount ,
19+ msig ?: MultisigAccount ,
20+ ) => Promise < { addr : Address } & ( { sig ?: Uint8Array } | { lmsig ?: MultisigSignature } ) >
1421
1522/** Function for signing program data for a logic signature */
16- export type ProgramDataSigner = ( data : Uint8Array , lsig : LogicSigAccount ) => Promise < Uint8Array >
23+ export type ProgramDataSigner = ( data : Uint8Array , lsig : LogicSig ) => Promise < Uint8Array >
1724
18- export class LogicSigAccount {
25+ export class LogicSig implements Addressable {
1926 logic : Uint8Array
2027 args : Uint8Array [ ]
28+ protected _addr : Address
29+
30+ constructor ( program : Uint8Array , programArgs ?: Array < Uint8Array > ) {
31+ this . logic = program
32+ this . args = programArgs ?. map ( ( arg ) => new Uint8Array ( arg ) ) ?? [ ]
33+ this . _addr = this . address ( )
34+ const toBeSigned = concatArrays ( PROGRAM_TAG , this . logic )
35+ const h = hash ( toBeSigned )
36+ this . _addr = new Address ( h )
37+ }
38+
39+ static fromSignature ( signature : LogicSignature ) : LogicSig {
40+ return new LogicSig ( signature . logic , signature . args || [ ] )
41+ }
42+
43+ static fromBytes ( encodedLsig : Uint8Array ) : LogicSig {
44+ const decoded = decodeMsgpack ( encodedLsig )
45+ const lsigSignature = logicSignatureCodec . decode ( decoded , 'msgpack' )
46+ return LogicSig . fromSignature ( lsigSignature )
47+ }
48+
49+ address ( ) : Address {
50+ return this . _addr
51+ }
52+
53+ get addr ( ) : Address {
54+ return this . _addr
55+ }
56+
57+ bytesToSignForDelegation ( msig ?: MultisigAccount ) : Uint8Array {
58+ if ( msig ) {
59+ return concatArrays ( MSIG_PROGRAM_TAG , msig . addr . publicKey , this . logic )
60+ } else {
61+ return concatArrays ( PROGRAM_TAG , this . logic )
62+ }
63+ }
64+
65+ signProgramData ( data : Uint8Array , signer : ProgramDataSigner ) : Promise < Uint8Array > {
66+ return signer ( data , this )
67+ }
68+
69+ programDataToSign ( data : Uint8Array ) : Uint8Array {
70+ return concatArrays ( SIGN_PROGRAM_DATA_PREFIX , this . address ( ) . publicKey , data )
71+ }
72+
73+ account ( ) : LogicSigAccount {
74+ return new LogicSigAccount ( this . logic , this . args )
75+ }
76+
77+ delegatedAccount ( delegator : Address ) : LogicSigAccount {
78+ return new LogicSigAccount ( this . logic , this . args , delegator )
79+ }
80+ }
81+
82+ export class LogicSigAccount extends LogicSig {
2183 sig ?: Uint8Array
2284 msig ?: MultisigSignature
2385 lmsig ?: MultisigSignature
2486
25- static fromSignature ( signature : LogicSignature ) : LogicSigAccount {
26- const lsigAccount = new LogicSigAccount ( signature . logic , signature . args || [ ] )
27- lsigAccount . sig = signature . sig
28- lsigAccount . msig = signature . msig
29- lsigAccount . lmsig = signature . lmsig
87+ static fromSignature ( signature : LogicSignature , delegator ?: Address ) : LogicSigAccount {
88+ if ( signature . lmsig || signature . msig ) {
89+ const msigAddr = MultisigAccount . fromSignature ( ( signature . lmsig || signature . msig ) ! ) . addr
90+
91+ if ( delegator && ! msigAddr . equals ( delegator ) ) {
92+ throw new Error ( 'Provided delegator address does not match multisig address' )
93+ }
94+
95+ const lsig = new LogicSigAccount ( signature . logic , signature . args || [ ] , msigAddr )
96+ lsig . lmsig = signature . lmsig
97+ lsig . msig = signature . msig
98+ return lsig
99+ }
100+
101+ const lsigAccount = new LogicSigAccount ( signature . logic , signature . args || [ ] , delegator )
102+
103+ if ( signature . sig && delegator === undefined ) {
104+ throw new Error ( 'Delegated address must be provided when logic sig has a signature' )
105+ }
106+
107+ if ( signature . sig ) {
108+ lsigAccount . sig = signature . sig
109+ return lsigAccount
110+ }
111+
30112 return lsigAccount
31113 }
32114
33- static fromBytes ( encodedLsig : Uint8Array ) : LogicSigAccount {
115+ static fromBytes ( encodedLsig : Uint8Array , delegator ?: Address ) : LogicSigAccount {
34116 const decoded = decodeMsgpack ( encodedLsig )
35117 const lsigSignature = logicSignatureCodec . decode ( decoded , 'msgpack' )
36- return LogicSigAccount . fromSignature ( lsigSignature )
118+ return LogicSigAccount . fromSignature ( lsigSignature , delegator )
37119 }
38120
39- constructor ( program : Uint8Array , programArgs ?: Array < Uint8Array > | null ) {
40- if ( programArgs && ( ! Array . isArray ( programArgs ) || ! programArgs . every ( ( arg ) => arg . constructor === Uint8Array ) ) ) {
41- throw new TypeError ( 'Invalid arguments' )
42- }
43-
44- let args : Uint8Array [ ] = [ ]
45- if ( programArgs != null ) args = programArgs . map ( ( arg ) => new Uint8Array ( arg ) )
46-
47- this . logic = program
48- this . args = args
121+ constructor ( program : Uint8Array , programArgs ?: Array < Uint8Array > | null , delegator ?: Address ) {
122+ super ( program , programArgs ?? undefined )
123+ this . _addr = delegator ?? this . _addr
49124 }
50125
51126 get signer ( ) : TransactionSigner {
@@ -59,60 +134,32 @@ export class LogicSigAccount {
59134 lsig : { logic : this . logic , args : this . args , msig : this . msig , lmsig : this . lmsig , sig : this . sig } ,
60135 }
61136
137+ if ( ! stxn . txn . sender . equals ( this . addr ) ) {
138+ stxn . authAddress = this . addr
139+ }
140+
62141 signedTxns . push ( encodeSignedTransaction ( stxn ) )
63142 }
64143
65144 return signedTxns
66145 }
67146 }
68147
69- get addr ( ) : Address {
70- return this . address ( )
71- }
72-
73- /**
74- * Compute hash of the logic sig program (that is the same as escrow account address) as string address
75- * @returns String representation of the address
76- */
77- address ( ) : Address {
78- const toBeSigned = concatArrays ( PROGRAM_TAG , this . logic )
79- const h = hash ( toBeSigned )
80- return new Address ( h )
81- }
82-
83- async delegate ( signer : DelegatedLsigSigner ) {
84- this . sig = await signer ( this )
85- }
86-
87- async delegateMultisig ( msig : MultisigAccount ) {
88- if ( this . lmsig == undefined ) {
89- this . lmsig = {
90- subsigs : [ ] ,
91- version : msig . params . version ,
92- threshold : msig . params . threshold ,
93- }
94- }
95- for ( const addrWithSigner of msig . subSigners ) {
96- const { lsigSigner, addr } = addrWithSigner
97- const signature = await lsigSigner ( this , msig )
148+ async signForDelegation ( delegator : AddressWithDelegatedLsigSigner ) {
149+ const result = await delegator . lsigSigner ( this )
98150
99- this . lmsig . subsigs . push ( { publicKey : addr . publicKey , sig : signature } )
151+ if ( ! result . addr . equals ( this . _addr ) ) {
152+ throw new Error (
153+ `Delagator address from signer does not match expected delegator address. Expected: ${ this . _addr . toString ( ) } , got: ${ result . addr . toString ( ) } ` ,
154+ )
100155 }
101- }
102156
103- bytesToSignForDelegation ( msig ?: MultisigAccount ) : Uint8Array {
104- if ( msig ) {
105- return concatArrays ( MSIG_PROGRAM_TAG , msig . addr . publicKey , this . logic )
157+ if ( 'sig' in result && result . sig ) {
158+ this . sig = result . sig
159+ } else if ( 'lmsig' in result && result . lmsig ) {
160+ this . lmsig = result . lmsig
106161 } else {
107- return concatArrays ( PROGRAM_TAG , this . logic )
162+ throw new Error ( 'Delegated lsig signer must return either a sig or lmsig' )
108163 }
109164 }
110-
111- signProgramData ( data : Uint8Array , signer : ProgramDataSigner ) : Promise < Uint8Array > {
112- return signer ( data , this )
113- }
114-
115- programDataToSign ( data : Uint8Array ) : Uint8Array {
116- return concatArrays ( SIGN_PROGRAM_DATA_PREFIX , this . address ( ) . publicKey , data )
117- }
118165}
0 commit comments