Skip to content

Commit 1df9623

Browse files
authored
fix: fix parsing of PC when a inner transaction fails (#397)
* fix: properly parse inner txn pc when an error occurs * test: ensure it works even with a middle app call * chore: generate docs and fix lint error
1 parent 403a1a2 commit 1df9623

File tree

13 files changed

+1548
-13
lines changed

13 files changed

+1548
-13
lines changed

docs/code/classes/types_logic_error.LogicError.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Error.constructor
6262

6363
#### Defined in
6464

65-
[src/types/logic-error.ts:52](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L52)
65+
[src/types/logic-error.ts:56](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L56)
6666

6767
## Properties
6868

@@ -86,7 +86,7 @@ ___
8686

8787
#### Defined in
8888

89-
[src/types/logic-error.ts:40](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L40)
89+
[src/types/logic-error.ts:44](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L44)
9090

9191
___
9292

@@ -96,7 +96,7 @@ ___
9696

9797
#### Defined in
9898

99-
[src/types/logic-error.ts:42](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L42)
99+
[src/types/logic-error.ts:46](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L46)
100100

101101
___
102102

@@ -134,7 +134,7 @@ ___
134134

135135
#### Defined in
136136

137-
[src/types/logic-error.ts:41](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L41)
137+
[src/types/logic-error.ts:45](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L45)
138138

139139
___
140140

@@ -148,7 +148,7 @@ Error.stack
148148

149149
#### Defined in
150150

151-
[src/types/logic-error.ts:44](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L44)
151+
[src/types/logic-error.ts:48](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L48)
152152

153153
___
154154

@@ -158,7 +158,7 @@ ___
158158

159159
#### Defined in
160160

161-
[src/types/logic-error.ts:43](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L43)
161+
[src/types/logic-error.ts:47](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L47)
162162

163163
___
164164

@@ -258,4 +258,4 @@ The logic error details if any, or undefined
258258

259259
#### Defined in
260260

261-
[src/types/logic-error.ts:26](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L26)
261+
[src/types/logic-error.ts:28](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L28)

docs/code/interfaces/types_logic_error.LogicErrorDetails.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ The full error description
2626

2727
#### Defined in
2828

29-
[src/types/logic-error.ts:14](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L14)
29+
[src/types/logic-error.ts:16](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L16)
3030

3131
___
3232

@@ -38,7 +38,7 @@ The error message
3838

3939
#### Defined in
4040

41-
[src/types/logic-error.ts:12](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L12)
41+
[src/types/logic-error.ts:14](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L14)
4242

4343
___
4444

@@ -50,7 +50,7 @@ The program counter where the error was
5050

5151
#### Defined in
5252

53-
[src/types/logic-error.ts:10](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L10)
53+
[src/types/logic-error.ts:12](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L12)
5454

5555
___
5656

@@ -62,7 +62,7 @@ Any trace information included in the error
6262

6363
#### Defined in
6464

65-
[src/types/logic-error.ts:16](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L16)
65+
[src/types/logic-error.ts:18](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L18)
6666

6767
___
6868

@@ -74,4 +74,4 @@ The ID of the transaction with the logic error
7474

7575
#### Defined in
7676

77-
[src/types/logic-error.ts:8](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L8)
77+
[src/types/logic-error.ts:10](https://github.com/algorandfoundation/algokit-utils-ts/blob/main/src/types/logic-error.ts#L10)

src/types/app-factory-and-client.spec.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import * as algokit from '..'
55
import arc56Json from '../../tests/example-contracts/arc56_templates/artifacts/Templates.arc56_draft.json'
66
import largeAppArc56Json from '../../tests/example-contracts/extra-pages/large.arc56.json'
77
import smallAppArc56Json from '../../tests/example-contracts/extra-pages/small.arc56.json'
8+
import errorInnerAppArc56Json from '../../tests/example-contracts/inner_error/artifacts/InnerApp.arc56.json'
9+
import errorMiddleAppArc56Json from '../../tests/example-contracts/inner_error/artifacts/MiddleApp.arc56.json'
10+
import errorOuterAppArc56Json from '../../tests/example-contracts/inner_error/artifacts/OuterApp.arc56.json'
811
import { getTestingAppContract } from '../../tests/example-contracts/testing-app/contract'
912
import { algoKitLogCaptureFixture, algorandFixture } from '../testing'
1013
import { asJson } from '../util'
@@ -757,6 +760,36 @@ describe('ARC56: app-factory-and-app-client', () => {
757760
})
758761
}, 10_000)
759762

763+
test('ARC56 error messages from inner app error', async () => {
764+
const innerFactory = localnet.algorand.client.getAppFactory({
765+
// @ts-expect-error TODO: Fix this
766+
appSpec: errorInnerAppArc56Json,
767+
defaultSender: localnet.context.testAccount.addr,
768+
})
769+
770+
const { appClient: innerClient } = await innerFactory.deploy({ createParams: { method: 'createApplication' } })
771+
772+
const middleFactory = localnet.algorand.client.getAppFactory({
773+
// @ts-expect-error TODO: Fix this
774+
appSpec: errorMiddleAppArc56Json,
775+
defaultSender: localnet.context.testAccount.addr,
776+
})
777+
778+
const { appClient: middleClient } = await middleFactory.deploy({ createParams: { method: 'createApplication' } })
779+
780+
const outerFactory = localnet.algorand.client.getAppFactory({
781+
// @ts-expect-error TODO: Fix this
782+
appSpec: errorOuterAppArc56Json,
783+
defaultSender: localnet.context.testAccount.addr,
784+
})
785+
786+
const { appClient: outerClient } = await outerFactory.deploy({ createParams: { method: 'createApplication' } })
787+
788+
await expect(
789+
outerClient.send.call({ method: 'callMiddle', args: [middleClient.appId, innerClient.appId], extraFee: algokit.microAlgos(2000) }),
790+
).rejects.toThrow('custom error message')
791+
})
792+
760793
test('ARC56 error messages with dynamic template vars (cblock offset)', async () => {
761794
const { appClient } = await factory.deploy({
762795
createParams: {

src/types/logic-error.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
const LOGIC_ERROR = /transaction ([A-Z0-9]+): logic eval error: (.*). Details: .*pc=([0-9]+).*/
2+
// inner tx 0 failed: logic eval error: err opcode executed. Details: app=6248, pc=29, opcodes=tx
3+
const INNER_LOGIC_ERROR = /inner tx (\d+) failed:.*?pc=([0-9]+)/
24

35
/**
46
* Details about a smart contract logic error
@@ -26,13 +28,15 @@ export class LogicError extends Error {
2628
static parseLogicError(error: any): LogicErrorDetails | undefined {
2729
const errorMessage = error.message
2830
const res = LOGIC_ERROR.exec(errorMessage)
31+
const innerRes = INNER_LOGIC_ERROR.exec(errorMessage)
32+
2933
if (res === null || res.length <= 3) return undefined
3034

3135
return {
3236
txId: res[1],
3337
msg: res[2],
3438
desc: errorMessage,
35-
pc: parseInt(res[3] ? res[3] : '0'),
39+
pc: parseInt(innerRes?.[2] ?? res[3] ?? '0'),
3640
traces: error.traces,
3741
} as LogicErrorDetails
3842
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
artifacts/*
2+
!artifacts/*.arc56.json
3+
!artifacts/*.approval.teal
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#pragma version 10
2+
intcblock 1
3+
4+
// This TEAL was generated by TEALScript v0.106.3
5+
// https://github.com/algorandfoundation/TEALScript
6+
7+
// This contract is compliant with and/or implements the following ARCs: [ ARC4 ]
8+
9+
// The following ten lines of TEAL handle initial program flow
10+
// This pattern is used to make it easy for anyone to parse the start of the program and determine if a specific action is allowed
11+
// Here, action refers to the OnComplete in combination with whether the app is being created or called
12+
// Every possible action for this contract is represented in the switch statement
13+
// If the action is not implemented in the contract, its respective branch will be "*NOT_IMPLEMENTED" which just contains "err"
14+
txn ApplicationID
15+
!
16+
pushint 6
17+
*
18+
txn OnCompletion
19+
+
20+
switch *call_NoOp *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *create_NoOp *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED *NOT_IMPLEMENTED
21+
22+
*NOT_IMPLEMENTED:
23+
// The requested action is not implemented in this contract. Are you using the correct OnComplete? Did you set your app ID?
24+
err
25+
26+
// throwError()void
27+
*abi_route_throwError:
28+
// execute throwError()void
29+
callsub throwError
30+
intc 0 // 1
31+
return
32+
33+
// throwError(): void
34+
throwError:
35+
proto 0 0
36+
37+
// custom error message
38+
err
39+
retsub
40+
41+
*abi_route_createApplication:
42+
intc 0 // 1
43+
return
44+
45+
*create_NoOp:
46+
pushbytes 0xb8447b36 // method "createApplication()void"
47+
txna ApplicationArgs 0
48+
match *abi_route_createApplication
49+
50+
// this contract does not implement the given ABI method for create NoOp
51+
err
52+
53+
*call_NoOp:
54+
pushbytes 0x3d870d87 // method "throwError()void"
55+
txna ApplicationArgs 0
56+
match *abi_route_throwError
57+
58+
// this contract does not implement the given ABI method for call NoOp
59+
err

0 commit comments

Comments
 (0)