1- import { Account , Application , Asset , BaseContract , Bytes , bytes , Contract , LocalState } from '@algorandfoundation/algorand-typescript'
1+ import {
2+ Account ,
3+ Application ,
4+ Asset ,
5+ BaseContract ,
6+ Bytes ,
7+ bytes ,
8+ Contract ,
9+ contract ,
10+ internal ,
11+ LocalState ,
12+ } from '@algorandfoundation/algorand-typescript'
213import { ABIMethod } from 'algosdk'
3- import { AbiMetadata , getAbiMetadata , getArc4Signature } from '../abi-metadata'
14+ import {
15+ AbiMetadata ,
16+ copyAbiMetadatas ,
17+ getArc4Signature ,
18+ getContractAbiMetadata ,
19+ getContractMethodAbiMetadata ,
20+ isContractProxy ,
21+ } from '../abi-metadata'
422import { BytesMap } from '../collections/custom-key-map'
23+ import { checkRoutingConditions } from '../context-helpers/context-util'
524import { lazyContext } from '../context-helpers/internal-context'
625import type { TypeInfo } from '../encoders'
726import { AccountCls } from '../impl/account'
@@ -21,6 +40,8 @@ import { getGenericTypeInfo } from '../runtime-helpers'
2140import { DeliberateAny , IConstructor } from '../typescript-helpers'
2241import { toBytes } from '../util'
2342
43+ type ContractOptionsParameter = Parameters < typeof contract > [ 0 ]
44+
2445type StateTotals = Pick < Application , 'globalNumBytes' | 'globalNumUint' | 'localNumBytes' | 'localNumUint' >
2546
2647interface States {
@@ -34,7 +55,7 @@ const isUint64GenericType = (typeInfo: TypeInfo | undefined) => {
3455 return typeInfo . genericArgs . some ( ( t ) => t . name . toLocaleLowerCase ( ) === 'uint64' )
3556}
3657
37- const extractStates = ( contract : BaseContract ) : States => {
58+ const extractStates = ( contract : BaseContract , contractOptions : ContractOptionsParameter | undefined ) : States => {
3859 const stateTotals = { globalNumBytes : 0 , globalNumUint : 0 , localNumBytes : 0 , localNumUint : 0 }
3960 const states = {
4061 globalStates : new BytesMap < GlobalStateCls < unknown > > ( ) ,
@@ -67,6 +88,12 @@ const extractStates = (contract: BaseContract): States => {
6788 stateTotals . localNumBytes += isLocalState && ! isUint64State ? 1 : 0
6889 }
6990 } )
91+
92+ stateTotals . globalNumUint = contractOptions ?. stateTotals ?. globalUints ?? stateTotals . globalNumUint
93+ stateTotals . globalNumBytes = contractOptions ?. stateTotals ?. globalBytes ?? stateTotals . globalNumBytes
94+ stateTotals . localNumUint = contractOptions ?. stateTotals ?. localUints ?? stateTotals . localNumUint
95+ stateTotals . localNumBytes = contractOptions ?. stateTotals ?. localBytes ?? stateTotals . localNumBytes
96+
7097 return states
7198}
7299
@@ -142,8 +169,8 @@ export class ContractContext {
142169 }
143170
144171 private getContractProxyHandler < T extends BaseContract > ( isArc4 : boolean ) : ProxyHandler < IConstructor < T > > {
145- const onConstructed = ( application : Application , instance : T ) => {
146- const states = extractStates ( instance )
172+ const onConstructed = ( application : Application , instance : T , conrtactOptions : ContractOptionsParameter | undefined ) => {
173+ const states = extractStates ( instance , conrtactOptions )
147174
148175 const applicationData = lazyContext . ledger . applicationDataMap . getOrFail ( application . id )
149176 applicationData . application = {
@@ -159,23 +186,33 @@ export class ContractContext {
159186 let t : T | undefined = undefined
160187 const application = lazyContext . any . application ( )
161188 const txn = lazyContext . any . txn . applicationCall ( { appId : application } )
189+ const appData = lazyContext . ledger . applicationDataMap . getOrFail ( application . id )
190+ appData . isCreating = true
162191 lazyContext . txn . ensureScope ( [ txn ] ) . execute ( ( ) => {
163192 t = new target ( ...args )
164193 } )
194+ appData . isCreating = hasCreateMethods ( t ! )
165195 const instance = new Proxy ( t ! , {
166196 get ( target , prop , receiver ) {
197+ if ( prop === isContractProxy ) {
198+ return true
199+ }
167200 const orig = Reflect . get ( target , prop , receiver )
168- const abiMetadata = getAbiMetadata ( target , prop as string )
201+ const abiMetadata = getContractMethodAbiMetadata ( target , prop as string )
169202 const isProgramMethod = prop === 'approvalProgram' || prop === 'clearStateProgram'
170203 const isAbiMethod = isArc4 && abiMetadata
171204 if ( isAbiMethod || isProgramMethod ) {
172205 return ( ...args : DeliberateAny [ ] ) : DeliberateAny => {
173206 const txns = ContractContext . createMethodCallTxns ( receiver , abiMetadata , ...args )
174207 return lazyContext . txn . ensureScope ( txns ) . execute ( ( ) => {
208+ if ( isAbiMethod ) {
209+ checkRoutingConditions ( application . id , abiMetadata )
210+ }
175211 const returnValue = ( orig as DeliberateAny ) . apply ( target , args )
176212 if ( ! isProgramMethod && isAbiMethod && returnValue !== undefined ) {
177213 ; ( txns . at ( - 1 ) as ApplicationTransaction ) . logArc4ReturnValue ( returnValue )
178214 }
215+ appData . isCreating = false
179216 return returnValue
180217 } )
181218 }
@@ -184,10 +221,22 @@ export class ContractContext {
184221 } ,
185222 } )
186223
187- onConstructed ( application , instance )
224+ onConstructed ( application , instance , getContractOptions ( t ! ) )
225+
226+ copyAbiMetadatas ( t ! , instance )
188227
189228 return instance
190229 } ,
191230 }
192231 }
193232}
233+
234+ const getContractOptions = ( contract : BaseContract ) : ContractOptionsParameter | undefined => {
235+ const contractClass = contract . constructor as DeliberateAny
236+ return contractClass [ internal . ContractOptionsSymbol ] as ContractOptionsParameter
237+ }
238+
239+ const hasCreateMethods = ( contract : BaseContract ) => {
240+ const metadatas = getContractAbiMetadata ( contract )
241+ return Object . values ( metadatas ) . some ( ( metadata ) => ( metadata . onCreate ?? 'disallow' ) !== 'disallow' )
242+ }
0 commit comments