Skip to content

Commit

Permalink
fix: Add missing native property on arc4 struct
Browse files Browse the repository at this point in the history
  • Loading branch information
tristanmenzel committed Feb 21, 2025
1 parent 099eb43 commit 69abdd7
Show file tree
Hide file tree
Showing 24 changed files with 1,471 additions and 283 deletions.
8 changes: 6 additions & 2 deletions packages/algo-ts/src/arc4/encoded-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,17 +463,21 @@ type StructConstraint = Record<string, ARC4Encoded>
/**
* The base type for arc4 structs
*/
class StructBase extends ARC4Encoded {
class StructBase<T> extends ARC4Encoded {
/** @hidden */
[TypeProperty] = 'arc4.Struct'

get native(): T {
throw new NoImplementation()
}
}

/**
* Type alias for the Struct constructor function
* @typeParam T The shape of the arc4 struct
*/
type StructConstructor = {
new <T extends Record<string, ARC4Encoded>>(initial: T): StructBase & Readonly<T> & { native: T }
new <T extends Record<string, ARC4Encoded>>(initial: T): StructBase<T> & Readonly<T>
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/awst_build/type-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ export class TypeResolver {
}
}

if (typeName.fullName === arc4StructBaseType.fullName) return arc4StructBaseType
if (typeName.fullName === ClusteredPrototype.fullName) {
return this.resolveClusteredPrototype(tsType, sourceLocation)
}
Expand Down Expand Up @@ -236,7 +237,6 @@ export class TypeResolver {
if (tsType.isClass()) {
if (typeName.fullName === arc4BaseContractType.fullName) return arc4BaseContractType
if (typeName.fullName === baseContractType.fullName) return baseContractType
if (typeName.fullName === arc4StructBaseType.fullName) return arc4StructBaseType
if (typeName.fullName === logicSigBaseType.fullName) return logicSigBaseType

const [baseType, ...rest] = tsType.getBaseTypes()?.map((t) => this.resolveType(t, sourceLocation)) ?? []
Expand Down Expand Up @@ -353,7 +353,7 @@ export class TypeResolver {
baseType: ARC4StructType,
sourceLocation: SourceLocation,
): ARC4StructType {
const ignoredProps = ['bytes', 'equals', Constants.constructorMethodName]
const ignoredProps = ['bytes', 'equals', 'native', Constants.constructorMethodName]
const fields: Record<string, ARC4EncodedType> = {}
for (const prop of tsType.getProperties()) {
if (isIn(prop.name, ignoredProps)) continue
Expand Down
4 changes: 4 additions & 0 deletions tests/approvals/arc4-struct.algo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,8 @@ class StructDemo extends Contract {
const v1_bytes = v1.bytes
return interpretAsArc4<Vector>(v1_bytes)
}

public toNative(v1: Vector) {
return v1.native
}
}
48 changes: 42 additions & 6 deletions tests/approvals/out/o1/arc4-struct/StructDemo.approval.teal
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,39 @@ main:
// tests/approvals/arc4-struct.algo.ts:9
// class StructDemo extends Contract {
txn NumAppArgs
bz main_bare_routing@9
pushbytess 0x89388ddd 0xef322d6d 0xcb81deb8 0xf79d6c46 // method "testVectorCreationAndEquality()void", method "addVectors((uint64,uint64),(uint64,uint64))(uint64,uint64)", method "implicitCastingAndSpreading((uint64,uint64))void", method "toAndFromBytes((uint64,uint64))(uint64,uint64)"
bz main_bare_routing@10
pushbytess 0x89388ddd 0xef322d6d 0xcb81deb8 0xf79d6c46 0x91915545 // method "testVectorCreationAndEquality()void", method "addVectors((uint64,uint64),(uint64,uint64))(uint64,uint64)", method "implicitCastingAndSpreading((uint64,uint64))void", method "toAndFromBytes((uint64,uint64))(uint64,uint64)", method "toNative((uint64,uint64))(uint64,uint64)"
txna ApplicationArgs 0
match main_testVectorCreationAndEquality_route@3 main_addVectors_route@4 main_implicitCastingAndSpreading_route@5 main_toAndFromBytes_route@6
match main_testVectorCreationAndEquality_route@3 main_addVectors_route@4 main_implicitCastingAndSpreading_route@5 main_toAndFromBytes_route@6 main_toNative_route@7

main_after_if_else@13:
main_after_if_else@14:
// tests/approvals/arc4-struct.algo.ts:9
// class StructDemo extends Contract {
intc_1 // 0
return

main_toNative_route@7:
// tests/approvals/arc4-struct.algo.ts:37
// public toNative(v1: Vector) {
txn OnCompletion
!
assert // OnCompletion is not NoOp
txn ApplicationID
assert // can only call when not creating
// tests/approvals/arc4-struct.algo.ts:9
// class StructDemo extends Contract {
txna ApplicationArgs 1
// tests/approvals/arc4-struct.algo.ts:37
// public toNative(v1: Vector) {
callsub toNative
concat
bytec_0 // 0x151f7c75
swap
concat
log
intc_0 // 1
return

main_toAndFromBytes_route@6:
// tests/approvals/arc4-struct.algo.ts:32
// public toAndFromBytes(v1: Vector): Vector {
Expand Down Expand Up @@ -89,11 +111,11 @@ main_testVectorCreationAndEquality_route@3:
intc_0 // 1
return

main_bare_routing@9:
main_bare_routing@10:
// tests/approvals/arc4-struct.algo.ts:9
// class StructDemo extends Contract {
txn OnCompletion
bnz main_after_if_else@13
bnz main_after_if_else@14
txn ApplicationID
!
assert // can only call when creating
Expand Down Expand Up @@ -179,3 +201,17 @@ implicitCastingAndSpreading:
==
assert
retsub


// tests/approvals/arc4-struct.algo.ts::StructDemo.toNative(v1: bytes) -> bytes, bytes:
toNative:
// tests/approvals/arc4-struct.algo.ts:37
// public toNative(v1: Vector) {
proto 1 2
// tests/approvals/arc4-struct.algo.ts:38
// return v1.native
frame_dig -1
extract 0 8 // on error: Index access is out of bounds
frame_dig -1
extract 8 8 // on error: Index access is out of bounds
retsub
48 changes: 47 additions & 1 deletion tests/approvals/out/o1/arc4-struct/StructDemo.arc32.json

Large diffs are not rendered by default.

67 changes: 52 additions & 15 deletions tests/approvals/out/o1/arc4-struct/StructDemo.arc56.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ subroutine tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__(
block@0: // L9
let tmp%0#0: uint64 = (txn NumAppArgs)
let tmp%1#0: bool = (!= tmp%0#0 0u)
goto tmp%1#0 ? block@1 : block@8
goto tmp%1#0 ? block@1 : block@9
block@1: // abi_routing_L9
let tmp%2#0: bytes = (txna ApplicationArgs 0)
switch tmp%2#0 {method "testVectorCreationAndEquality()void" => block@2, method "addVectors((uint64,uint64),(uint64,uint64))(uint64,uint64)" => block@3, method "implicitCastingAndSpreading((uint64,uint64))void" => block@4, method "toAndFromBytes((uint64,uint64))(uint64,uint64)" => block@5, * => block@6}
switch tmp%2#0 {method "testVectorCreationAndEquality()void" => block@2, method "addVectors((uint64,uint64),(uint64,uint64))(uint64,uint64)" => block@3, method "implicitCastingAndSpreading((uint64,uint64))void" => block@4, method "toAndFromBytes((uint64,uint64))(uint64,uint64)" => block@5, method "toNative((uint64,uint64))(uint64,uint64)" => block@6, * => block@7}
block@2: // testVectorCreationAndEquality_route_L10
let tmp%3#0: uint64 = (txn OnCompletion)
let tmp%4#0: bool = (== tmp%3#0 NoOp)
Expand Down Expand Up @@ -55,24 +55,40 @@ subroutine tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__(
let tmp%22#0: bytes = (concat 0x151f7c75 tmp%21#0)
(log tmp%22#0)
return 1u
block@6: // switch_case_default_L9
goto block@7
block@7: // switch_case_next_L9
goto block@12
block@8: // bare_routing_L9
block@6: // toNative_route_L37
let tmp%23#0: uint64 = (txn OnCompletion)
switch tmp%23#0 {0u => block@9, * => block@10}
block@9: // __algots__.defaultCreate_L9
let tmp%24#0: uint64 = (txn ApplicationID)
let tmp%25#0: bool = (== tmp%24#0 0u)
(assert tmp%25#0) // can only call when creating
let tmp%24#0: bool = (== tmp%23#0 NoOp)
(assert tmp%24#0) // OnCompletion is not NoOp
let tmp%25#0: uint64 = (txn ApplicationID)
let tmp%26#0: bool = (!= tmp%25#0 0u)
(assert tmp%26#0) // can only call when not creating
let reinterpret_bytes[16]%4#0: bytes[16] = (txna ApplicationArgs 1)
let (elements_to_encode%0#0: bytes[8], elements_to_encode%1#0: bytes[8]) = tests/approvals/arc4-struct.algo.ts::StructDemo.toNative(reinterpret_bytes[16]%4#0)
let current_tail_offset%0#0: uint64 = 16u
let encoded_tuple_buffer%0#0: bytes[0] = 0x
let encoded_tuple_buffer%1#0: bytes = (concat encoded_tuple_buffer%0#0 elements_to_encode%0#0)
let encoded_tuple_buffer%2#0: bytes = (concat encoded_tuple_buffer%1#0 elements_to_encode%1#0)
let tmp%27#0: bytes = (concat 0x151f7c75 encoded_tuple_buffer%2#0)
(log tmp%27#0)
return 1u
block@7: // switch_case_default_L9
goto block@8
block@8: // switch_case_next_L9
goto block@13
block@9: // bare_routing_L9
let tmp%28#0: uint64 = (txn OnCompletion)
switch tmp%28#0 {0u => block@10, * => block@11}
block@10: // __algots__.defaultCreate_L9
let tmp%29#0: uint64 = (txn ApplicationID)
let tmp%30#0: bool = (== tmp%29#0 0u)
(assert tmp%30#0) // can only call when creating
tests/approvals/arc4-struct.algo.ts::StructDemo.__algots__.defaultCreate()
return 1u
block@10: // switch_case_default_L9
goto block@11
block@11: // switch_case_next_L9
block@11: // switch_case_default_L9
goto block@12
block@12: // after_if_else_L9
block@12: // switch_case_next_L9
goto block@13
block@13: // after_if_else_L9
return 0u

subroutine tests/approvals/arc4-struct.algo.ts::StructDemo.testVectorCreationAndEquality() -> void:
Expand Down Expand Up @@ -159,6 +175,14 @@ subroutine tests/approvals/arc4-struct.algo.ts::StructDemo.toAndFromBytes(v1: by
let reinterpret_bytes[16]%0#0: bytes[16] = v1_bytes#0
return reinterpret_bytes[16]%0#0

subroutine tests/approvals/arc4-struct.algo.ts::StructDemo.toNative(v1: bytes[16]) -> <bytes[8], bytes[8]>:
block@0: // L37
let item0%0#0: bytes = (extract3 v1#0 0u 8u) // on error: Index access is out of bounds
let item1%0#0: bytes = (extract3 v1#0 8u 8u) // on error: Index access is out of bounds
let item0%1#0: bytes = (extract3 v1#0 0u 8u) // on error: Index access is out of bounds
let item1%1#0: bytes = (extract3 v1#0 8u 8u) // on error: Index access is out of bounds
return item0%0#0 item1%1#0

subroutine tests/approvals/arc4-struct.algo.ts::StructDemo.__algots__.defaultCreate() -> void:
block@0: // L9
return
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
main @algorandfoundation/algorand-typescript/arc4/index.d.ts::Contract.approvalProgram:
block@0: // L1
let tmp%0#1: uint64 = (txn NumAppArgs)
goto tmp%0#1 ? block@2 : block@9
goto tmp%0#1 ? block@2 : block@10
block@2: // abi_routing_L9
let tmp%2#0: bytes = (txna ApplicationArgs 0)
switch tmp%2#0 {method "testVectorCreationAndEquality()void" => block@3, method "addVectors((uint64,uint64),(uint64,uint64))(uint64,uint64)" => block@4, method "implicitCastingAndSpreading((uint64,uint64))void" => block@5, method "toAndFromBytes((uint64,uint64))(uint64,uint64)" => block@6, * => block@13}
switch tmp%2#0 {method "testVectorCreationAndEquality()void" => block@3, method "addVectors((uint64,uint64),(uint64,uint64))(uint64,uint64)" => block@4, method "implicitCastingAndSpreading((uint64,uint64))void" => block@5, method "toAndFromBytes((uint64,uint64))(uint64,uint64)" => block@6, method "toNative((uint64,uint64))(uint64,uint64)" => block@7, * => block@14}
block@3: // testVectorCreationAndEquality_route_L10
let tmp%3#0: uint64 = (txn OnCompletion)
let tmp%4#0: bool = (! tmp%3#0)
Expand All @@ -13,7 +13,7 @@ main @algorandfoundation/algorand-typescript/arc4/index.d.ts::Contract.approvalP
(assert tmp%5#0) // can only call when not creating
tests/approvals/arc4-struct.algo.ts::StructDemo.testVectorCreationAndEquality()
let tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#0: bool = 1u
goto block@14
goto block@15
block@4: // addVectors_route_L18
let tmp%7#0: uint64 = (txn OnCompletion)
let tmp%8#0: bool = (! tmp%7#0)
Expand All @@ -26,7 +26,7 @@ main @algorandfoundation/algorand-typescript/arc4/index.d.ts::Contract.approvalP
let tmp%12#0: bytes = (concat 0x151f7c75 tmp%11#0)
(log tmp%12#0)
let tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#1: bool = 1u
goto block@14
goto block@15
block@5: // implicitCastingAndSpreading_route_L25
let tmp%13#0: uint64 = (txn OnCompletion)
let tmp%14#0: bool = (! tmp%13#0)
Expand All @@ -36,7 +36,7 @@ main @algorandfoundation/algorand-typescript/arc4/index.d.ts::Contract.approvalP
let reinterpret_bytes[16]%2#0: bytes[16] = (txna ApplicationArgs 1)
tests/approvals/arc4-struct.algo.ts::StructDemo.implicitCastingAndSpreading(reinterpret_bytes[16]%2#0)
let tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#2: bool = 1u
goto block@14
goto block@15
block@6: // toAndFromBytes_route_L32
let tmp%17#0: uint64 = (txn OnCompletion)
let tmp%18#0: bool = (! tmp%17#0)
Expand All @@ -47,21 +47,34 @@ main @algorandfoundation/algorand-typescript/arc4/index.d.ts::Contract.approvalP
let tmp%22#0: bytes = (concat 0x151f7c75 v1#0)
(log tmp%22#0)
let tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#3: bool = 1u
goto block@14
block@9: // bare_routing_L9
goto block@15
block@7: // toNative_route_L37
let tmp%23#0: uint64 = (txn OnCompletion)
goto tmp%23#0 ? block@13 : block@10
block@10: // __algots__.defaultCreate_L9
let tmp%24#0: uint64 = (txn ApplicationID)
let tmp%25#0: bool = (! tmp%24#0)
(assert tmp%25#0) // can only call when creating
let tmp%24#0: bool = (! tmp%23#0)
(assert tmp%24#0) // OnCompletion is not NoOp
let tmp%25#0: uint64 = (txn ApplicationID)
(assert tmp%25#0) // can only call when not creating
let reinterpret_bytes[16]%4#0: bytes[16] = (txna ApplicationArgs 1)
let (elements_to_encode%0#0: bytes[8], elements_to_encode%1#0: bytes[8]) = tests/approvals/arc4-struct.algo.ts::StructDemo.toNative(reinterpret_bytes[16]%4#0)
let encoded_tuple_buffer%2#0: bytes = (concat elements_to_encode%0#0 elements_to_encode%1#0)
let tmp%27#0: bytes = (concat 0x151f7c75 encoded_tuple_buffer%2#0)
(log tmp%27#0)
let tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#4: bool = 1u
goto block@14
block@13: // after_if_else_L9
let tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#5: bool = 0u
goto block@14
block@14: // after_inlined_tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router___L1
let tmp%0#0: bool = φ(tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#0 <- block@3, tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#1 <- block@4, tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#2 <- block@5, tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#3 <- block@6, tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#4 <- block@10, tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#5 <- block@13)
goto block@15
block@10: // bare_routing_L9
let tmp%28#0: uint64 = (txn OnCompletion)
goto tmp%28#0 ? block@14 : block@11
block@11: // __algots__.defaultCreate_L9
let tmp%29#0: uint64 = (txn ApplicationID)
let tmp%30#0: bool = (! tmp%29#0)
(assert tmp%30#0) // can only call when creating
let tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#5: bool = 1u
goto block@15
block@14: // after_if_else_L9
let tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#6: bool = 0u
goto block@15
block@15: // after_inlined_tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router___L1
let tmp%0#0: bool = φ(tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#0 <- block@3, tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#1 <- block@4, tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#2 <- block@5, tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#3 <- block@6, tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#4 <- block@7, tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#5 <- block@11, tests/approvals/arc4-struct.algo.ts::StructDemo.__puya_arc4_router__%0#6 <- block@14)
return tmp%0#0

subroutine tests/approvals/arc4-struct.algo.ts::StructDemo.testVectorCreationAndEquality() -> void:
Expand Down Expand Up @@ -95,4 +108,10 @@ subroutine tests/approvals/arc4-struct.algo.ts::StructDemo.implicitCastingAndSpr
(assert tmp%4#0)
let tmp%5#0: bool = (== v3#0 v1#0)
(assert tmp%5#0)
return
return

subroutine tests/approvals/arc4-struct.algo.ts::StructDemo.toNative(v1: bytes[16]) -> <bytes[8], bytes[8]>:
block@0: // L37
let item0%0#0: bytes = ((extract 0 8) v1#0) // on error: Index access is out of bounds
let item1%1#0: bytes = ((extract 8 8) v1#0) // on error: Index access is out of bounds
return item0%0#0 item1%1#0
Loading

0 comments on commit 69abdd7

Please sign in to comment.