3434 ]
3535 )
3636_CreateValues = typing .Literal ["allow" , "require" , "disallow" ]
37+ _ResourceEncoding = typing .Literal ["index" , "value" ]
38+ _Direction = typing .Literal ["input" , "output" ]
3739ARC4_METADATA_ATTR = "arc4_metadata"
3840
3941
@@ -51,6 +53,7 @@ class MethodMetadata:
5153 create : _CreateValues
5254 allow_actions : Sequence [_AllowActions ]
5355 arc4_signature : str | None = None
56+ resource_encoding : _ResourceEncoding = "value"
5457
5558 @property
5659 def is_create (self ) -> bool :
@@ -145,6 +148,7 @@ def abimethod( # noqa: PLR0913
145148 name : str | None = None ,
146149 create : _CreateValues = "disallow" ,
147150 allow_actions : Sequence [_AllowActions ] = ("NoOp" ,),
151+ resource_encoding : _ResourceEncoding = "value" ,
148152 readonly : bool = False ,
149153 default_args : Mapping [str , str | object ] | None = None ,
150154) -> Callable [[Callable [_P , _R ]], Callable [_P , _R ]] | Callable [_P , _R ]:
@@ -160,13 +164,15 @@ def abimethod( # noqa: PLR0913
160164 allow_actions = allow_actions ,
161165 readonly = readonly ,
162166 default_args = default_args ,
167+ resource_encoding = resource_encoding ,
163168 )
164169
165170 arc4_name = name or fn .__name__
166171 metadata = MethodMetadata (
167172 create = create ,
168173 allow_actions = allow_actions ,
169- arc4_signature = _generate_arc4_signature_from_fn (fn , arc4_name ),
174+ arc4_signature = _generate_arc4_signature_from_fn (fn , arc4_name , resource_encoding ),
175+ resource_encoding = resource_encoding ,
170176 )
171177 set_arc4_metadata (fn , metadata )
172178
@@ -187,6 +193,7 @@ def wrapper(*args: _P.args, **kwargs: _P.kwargs) -> _R:
187193 arc4_signature = metadata .arc4_signature ,
188194 args = ordered_args ,
189195 allow_actions = allow_actions ,
196+ resource_encoding = metadata .resource_encoding ,
190197 )
191198 with context .txn ._maybe_implicit_txn_group (txns ):
192199 check_routing_conditions (app_id , metadata )
@@ -204,6 +211,7 @@ def create_abimethod_txns(
204211 arc4_signature : str ,
205212 args : Sequence [object ],
206213 allow_actions : Sequence [_AllowActions ],
214+ resource_encoding : _ResourceEncoding ,
207215) -> list [algopy .gtxn .TransactionBase ]:
208216 contract_app = lazy_context .ledger .get_app (app_id )
209217 txn_fields = get_active_txn_fields (contract_app , allow_actions )
@@ -215,6 +223,7 @@ def create_abimethod_txns(
215223 method_selector = method_selector ,
216224 sender = txn_fields ["sender" ],
217225 app = contract_app ,
226+ resource_encoding = resource_encoding ,
218227 )
219228 txn_fields .setdefault ("accounts" , txn_arrays .accounts )
220229 txn_fields .setdefault ("assets" , txn_arrays .assets )
@@ -273,11 +282,12 @@ class _TxnArrays:
273282 app_args : list [algopy .Bytes ]
274283
275284
276- def _extract_arrays_from_args (
285+ def _extract_arrays_from_args ( # noqa: PLR0912
277286 args : Sequence [object ],
278287 method_selector : algopy .Bytes ,
279288 app : algopy .Application ,
280289 sender : algopy .Account ,
290+ resource_encoding : _ResourceEncoding ,
281291) -> _TxnArrays :
282292 from _algopy_testing .serialize import native_to_arc4
283293
@@ -291,14 +301,23 @@ def _extract_arrays_from_args(
291301 case _algopy_testing .gtxn .TransactionBase () as txn :
292302 txns .append (txn )
293303 case _algopy_testing .Account () as acc :
294- app_args .append (_algopy_testing .arc4 .UInt8 (len (accounts )))
295- accounts .append (acc )
304+ if resource_encoding == "index" :
305+ app_args .append (_algopy_testing .arc4 .UInt8 (len (accounts )))
306+ accounts .append (acc )
307+ else :
308+ app_args .append (native_to_arc4 (acc ))
296309 case _algopy_testing .Asset () as asset :
297- app_args .append (_algopy_testing .arc4 .UInt8 (len (assets )))
298- assets .append (asset )
310+ if resource_encoding == "index" :
311+ app_args .append (_algopy_testing .arc4 .UInt8 (len (assets )))
312+ assets .append (asset )
313+ else :
314+ app_args .append (native_to_arc4 (asset .id ))
299315 case _algopy_testing .Application () as arg_app :
300- app_args .append (_algopy_testing .arc4 .UInt8 (len (apps )))
301- apps .append (arg_app )
316+ if resource_encoding == "index" :
317+ app_args .append (_algopy_testing .arc4 .UInt8 (len (apps )))
318+ apps .append (arg_app )
319+ else :
320+ app_args .append (native_to_arc4 (arg_app .id ))
302321 case _ as maybe_native :
303322 app_args .append (native_to_arc4 (maybe_native ))
304323 if len (app_args ) > 15 :
@@ -313,18 +332,29 @@ def _extract_arrays_from_args(
313332 )
314333
315334
316- def _generate_arc4_signature_from_fn (fn : typing .Callable [_P , _R ], arc4_name : str ) -> str :
335+ def _generate_arc4_signature_from_fn (
336+ fn : typing .Callable [_P , _R ], arc4_name : str , resource_encoding : _ResourceEncoding
337+ ) -> str :
317338 annotations = inspect .get_annotations (fn , eval_str = True ).copy ()
318- returns = algosdk .abi .Returns (_type_to_arc4 (annotations .pop ("return" )))
339+ returns = algosdk .abi .Returns (
340+ _type_to_arc4 (annotations .pop ("return" ), resource_encoding , "output" )
341+ )
319342 method = algosdk .abi .Method (
320343 name = arc4_name ,
321- args = [algosdk .abi .Argument (_type_to_arc4 (a )) for a in annotations .values ()],
344+ args = [
345+ algosdk .abi .Argument (_type_to_arc4 (a , resource_encoding , "input" ))
346+ for a in annotations .values ()
347+ ],
322348 returns = returns ,
323349 )
324350 return method .get_signature ()
325351
326352
327- def _type_to_arc4 (annotation : types .GenericAlias | type | None ) -> str : # noqa: PLR0911, PLR0912
353+ def _type_to_arc4 ( # noqa: PLR0912 PLR0911
354+ annotation : types .GenericAlias | type | None ,
355+ resource_encoding : _ResourceEncoding ,
356+ direction : _Direction ,
357+ ) -> str :
328358 from _algopy_testing .arc4 import _ABIEncoded
329359 from _algopy_testing .gtxn import Transaction , TransactionBase
330360 from _algopy_testing .models import Account , Application , Asset
@@ -340,7 +370,9 @@ def _type_to_arc4(annotation: types.GenericAlias | type | None) -> str: # noqa:
340370 return "void"
341371
342372 if isinstance (annotation , types .GenericAlias ) and typing .get_origin (annotation ) is tuple :
343- tuple_args = [_type_to_arc4 (a ) for a in typing .get_args (annotation )]
373+ tuple_args = [
374+ _type_to_arc4 (a , resource_encoding , direction ) for a in typing .get_args (annotation )
375+ ]
344376 return f"({ ',' .join (tuple_args )} )"
345377
346378 if not isinstance (annotation , type ):
@@ -350,11 +382,11 @@ def _type_to_arc4(annotation: types.GenericAlias | type | None) -> str: # noqa:
350382 annotation , Struct
351383 ):
352384 tuple_fields = list (inspect .get_annotations (annotation ).values ())
353- tuple_args = [_type_to_arc4 (a ) for a in tuple_fields ]
385+ tuple_args = [_type_to_arc4 (a , resource_encoding , direction ) for a in tuple_fields ]
354386 return f"({ ',' .join (tuple_args )} )"
355387
356388 if issubclass (annotation , Array | FixedArray | ImmutableArray | ImmutableFixedArray ):
357- return f"{ _type_to_arc4 (annotation ._element_type )} []"
389+ return f"{ _type_to_arc4 (annotation ._element_type , resource_encoding , direction )} []"
358390 # arc4 types
359391 if issubclass (annotation , _ABIEncoded ):
360392 return annotation ._type_info .arc4_name
@@ -365,11 +397,17 @@ def _type_to_arc4(annotation: types.GenericAlias | type | None) -> str: # noqa:
365397 return annotation .type_enum .txn_name
366398 # reference types
367399 if issubclass (annotation , Account ):
368- return "account"
400+ if resource_encoding == "index" and direction == "input" :
401+ return "account"
402+ return "address"
369403 if issubclass (annotation , Asset ):
370- return "asset"
404+ if resource_encoding == "index" and direction == "input" :
405+ return "asset"
406+ return "uint64"
371407 if issubclass (annotation , Application ):
372- return "application"
408+ if resource_encoding == "index" and direction == "input" :
409+ return "application"
410+ return "uint64"
373411 # native types
374412 if issubclass (annotation , UInt64 ):
375413 return "uint64"
0 commit comments