-
Notifications
You must be signed in to change notification settings - Fork 18
/
decodeOutput.ts
97 lines (84 loc) · 2.75 KB
/
decodeOutput.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import { ContractPromise } from '@polkadot/api-contract'
import { ContractExecResult } from '@polkadot/types/interfaces'
import { AnyJson, TypeDef } from '@polkadot/types/types'
import { getAbiMessage } from './getAbiMessage'
/**
* Helper types & functions
* SOURCE: https://github.com/paritytech/contracts-ui (GPL-3.0-only)
*/
type ContractResultErr = {
Err: AnyJson
}
interface ContractResultOk {
Ok: AnyJson
}
function isErr(o: ContractResultErr | ContractResultOk | AnyJson): o is ContractResultErr {
return typeof o === 'object' && o !== null && 'Err' in o
}
function isOk(o: ContractResultErr | ContractResultOk | AnyJson): o is ContractResultOk {
return typeof o === 'object' && o !== null && 'Ok' in o
}
function getReturnTypeName(type: TypeDef | null | undefined) {
return type?.lookupName || type?.type || ''
}
/**
* Decodes & unwraps outputs and errors of a given result, contract, and method.
* Parsed error message can be found in `decodedOutput` if `isError` is true.
* SOURCE: https://github.com/paritytech/contracts-ui (GPL-3.0-only)
*/
export function decodeOutput(
{ result }: Pick<ContractExecResult, 'result' | 'debugMessage'>,
contract: ContractPromise,
method: string,
): {
output: any
decodedOutput: string
isError: boolean
} {
let output
let decodedOutput = ''
let isError = true
if (result.isOk) {
const flags = result.asOk.flags.toHuman()
isError = flags.includes('Revert')
const abiMessage = getAbiMessage(contract, method)
const returnType = abiMessage.returnType
const returnTypeName = getReturnTypeName(returnType)
const registry = contract.abi.registry
const r = returnType
? registry.createTypeUnsafe(returnTypeName, [result.asOk.data]).toHuman()
: '()'
output = isOk(r) ? r.Ok : isErr(r) ? r.Err : r
const errorText = isErr(output)
? typeof output.Err === 'object'
? JSON.stringify(output.Err, null, 2)
: output.Err?.toString() ?? 'Error'
: output !== 'Ok'
? output?.toString() || 'Error'
: 'Error'
const okText = isOk(r)
? typeof output === 'object'
? JSON.stringify(output, null, '\t')
: output?.toString() ?? '()'
: JSON.stringify(output, null, '\t') ?? '()'
decodedOutput = isError ? errorText : okText
} else if (result.isErr) {
output = result.toHuman()
let errorText
if (
isErr(output) &&
typeof output.Err === 'object' &&
Object.keys(output.Err || {}).length &&
typeof Object.values(output.Err || {})[0] === 'string'
) {
const [errorKey, errorValue] = Object.entries(output.Err || {})[0]
errorText = `${errorKey}${errorValue}`
}
decodedOutput = errorText || 'Error'
}
return {
output,
decodedOutput,
isError,
}
}