11import { Account , Application , Asset , BaseContract , Bytes , bytes , Contract , internal } from '@algorandfoundation/algorand-typescript'
22import { getAbiMetadata } from '../abi-metadata'
3+ import { BytesMap } from '../collections/custom-key-map'
34import { lazyContext } from '../context-helpers/internal-context'
45import { AccountCls } from '../impl/account'
56import { ApplicationCls } from '../impl/application'
@@ -15,7 +16,7 @@ import {
1516} from '../impl/transactions'
1617import { getGenericTypeInfo } from '../runtime-helpers'
1718import { DeliberateAny } from '../typescript-helpers'
18- import { extractGenericTypeArgs } from '../util'
19+ import { asUint64Cls , extractGenericTypeArgs } from '../util'
1920
2021interface IConstructor < T > {
2122 new ( ...args : DeliberateAny [ ] ) : T
@@ -24,8 +25,8 @@ interface IConstructor<T> {
2425type StateTotals = Pick < Application , 'globalNumBytes' | 'globalNumUint' | 'localNumBytes' | 'localNumUint' >
2526
2627interface States {
27- globalStates : Map < bytes , internal . state . GlobalStateCls < unknown > >
28- localStates : Map < bytes , internal . state . LocalStateMapCls < unknown > >
28+ globalStates : BytesMap < internal . state . GlobalStateCls < unknown > >
29+ localStates : BytesMap < internal . state . LocalStateMapCls < unknown > >
2930 totals : StateTotals
3031}
3132
@@ -38,8 +39,8 @@ const isUint64GenericType = (typeName: string | undefined) => {
3839const extractStates = ( contract : BaseContract ) : States => {
3940 const stateTotals = { globalNumBytes : 0 , globalNumUint : 0 , localNumBytes : 0 , localNumUint : 0 }
4041 const states = {
41- globalStates : new Map < bytes , internal . state . GlobalStateCls < unknown > > ( ) ,
42- localStates : new Map < bytes , internal . state . LocalStateMapCls < unknown > > ( ) ,
42+ globalStates : new BytesMap < internal . state . GlobalStateCls < unknown > > ( ) ,
43+ localStates : new BytesMap < internal . state . LocalStateMapCls < unknown > > ( ) ,
4344 totals : stateTotals ,
4445 }
4546 Object . entries ( contract ) . forEach ( ( [ key , value ] ) => {
@@ -50,7 +51,7 @@ const extractStates = (contract: BaseContract): States => {
5051 if ( value . key === undefined ) value . key = Bytes ( key )
5152
5253 // capture state into the context
53- if ( isLocalState ) states . localStates . set ( value . key , value . map )
54+ if ( isLocalState ) states . localStates . set ( value . key , value )
5455 else states . globalStates . set ( value . key , value )
5556
5657 // populate state totals
@@ -64,23 +65,31 @@ const extractStates = (contract: BaseContract): States => {
6465 return states
6566}
6667
67- const extractArraysFromArgs = ( args : DeliberateAny [ ] ) => {
68+ const extractArraysFromArgs = ( app : Application , args : DeliberateAny [ ] ) => {
6869 const transactions : Transaction [ ] = [ ]
6970 const accounts : Account [ ] = [ ]
70- const apps : Application [ ] = [ ]
71+ const apps : Application [ ] = [ app ]
7172 const assets : Asset [ ] = [ ]
73+ const appArgs : bytes [ ] = [ ]
74+
75+ // TODO: replace `asUint64Cls(accounts.length).toBytes().asAlgoTs()` with `arc4.Uint8(account.length).toBytes().asAlgoTs()`
7276 for ( const arg of args ) {
7377 if ( isTransaction ( arg ) ) {
7478 transactions . push ( arg )
7579 } else if ( arg instanceof AccountCls ) {
80+ appArgs . push ( asUint64Cls ( accounts . length ) . toBytes ( ) . asAlgoTs ( ) )
7681 accounts . push ( arg as Account )
7782 } else if ( arg instanceof ApplicationCls ) {
83+ appArgs . push ( asUint64Cls ( apps . length ) . toBytes ( ) . asAlgoTs ( ) )
7884 apps . push ( arg as Application )
7985 } else if ( arg instanceof AssetCls ) {
86+ appArgs . push ( asUint64Cls ( assets . length ) . toBytes ( ) . asAlgoTs ( ) )
8087 assets . push ( arg as Asset )
8188 }
8289 }
83- return { accounts, apps, assets, transactions }
90+
91+ // TODO: use actual method selector in appArgs
92+ return { accounts, apps, assets, transactions, appArgs : [ Bytes ( 'method_selector' ) , ...appArgs ] }
8493}
8594
8695function isTransaction ( obj : unknown ) : obj is Transaction {
@@ -96,7 +105,6 @@ function isTransaction(obj: unknown): obj is Transaction {
96105
97106export class ContractContext {
98107 create < T extends BaseContract > ( type : IConstructor < T > , ...args : DeliberateAny [ ] ) : T {
99- Object . getPrototypeOf ( type )
100108 const proxy = new Proxy ( type , this . getContractProxyHandler < T > ( this . isArc4 ( type ) ) )
101109 return new proxy ( ...args )
102110 }
@@ -114,10 +122,12 @@ export class ContractContext {
114122 }
115123
116124 private getContractProxyHandler < T extends BaseContract > ( isArc4 : boolean ) : ProxyHandler < IConstructor < T > > {
117- const onConstructed = ( instance : BaseContract ) => {
125+ const onConstructed = ( instance : T ) => {
118126 const states = extractStates ( instance )
119127
120128 const application = lazyContext . any . application ( {
129+ globalStates : states . globalStates ,
130+ localStates : states . localStates ,
121131 ...states . totals ,
122132 } )
123133 lazyContext . ledger . addAppIdContractMap ( application . id , instance )
@@ -127,12 +137,13 @@ export class ContractContext {
127137 const instance = new Proxy ( new target ( ...args ) , {
128138 get ( target , prop , receiver ) {
129139 const orig = Reflect . get ( target , prop , receiver )
140+ const abiMetadata = getAbiMetadata ( target , prop as string )
130141 const isProgramMethod = prop === 'approvalProgram' || prop === 'clearStateProgram'
131- if ( isArc4 || isProgramMethod ) {
142+ const isAbiMethod = isArc4 && abiMetadata
143+ if ( isAbiMethod || isProgramMethod ) {
132144 return ( ...args : DeliberateAny [ ] ) : DeliberateAny => {
133145 const app = lazyContext . ledger . getApplicationForContract ( receiver )
134- const { transactions, ...appCallArgs } = extractArraysFromArgs ( args )
135- const abiMetadata = getAbiMetadata ( target , prop as string )
146+ const { transactions, ...appCallArgs } = extractArraysFromArgs ( app , args )
136147 const appTxn = lazyContext . any . txn . applicationCall ( {
137148 appId : app ,
138149 ...appCallArgs ,
@@ -142,7 +153,7 @@ export class ContractContext {
142153 const txns = [ ...( transactions ?? [ ] ) , appTxn ]
143154 return lazyContext . txn . ensureScope ( txns ) . execute ( ( ) => {
144155 const returnValue = ( orig as DeliberateAny ) . apply ( target , args )
145- if ( ! isProgramMethod && isArc4 && returnValue !== undefined ) {
156+ if ( ! isProgramMethod && isAbiMethod && returnValue !== undefined ) {
146157 appTxn . logArc4ReturnValue ( returnValue )
147158 }
148159 return returnValue
@@ -152,6 +163,7 @@ export class ContractContext {
152163 return orig
153164 } ,
154165 } )
166+
155167 onConstructed ( instance )
156168
157169 return instance
0 commit comments