@stellar-expert/ui-framework 1.12.0 → 1.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -11,6 +11,11 @@ import {Amount} from '../asset/amount'
|
|
|
11
11
|
import {CopyToClipboard} from '../interaction/copy-to-clipboard'
|
|
12
12
|
import {ScVal} from '../contract/sc-val'
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* @param {{}} effect
|
|
16
|
+
* @return {JSX.Element}
|
|
17
|
+
* @constructor
|
|
18
|
+
*/
|
|
14
19
|
export function EffectDescription({effect}) {
|
|
15
20
|
switch (effect.type) {
|
|
16
21
|
case 'accountCreated':
|
|
@@ -223,6 +228,9 @@ export function EffectDescription({effect}) {
|
|
|
223
228
|
</>
|
|
224
229
|
case 'contractDataRemoved':
|
|
225
230
|
return <>Contract <AccountAddress account={effect.owner}/> removed data <ScVal value={effect.key}/></>
|
|
231
|
+
case 'contractError':
|
|
232
|
+
return <>Execution error {effect.code ? effect.code + ': ' : ''}"{effect.details[0]}"{' '}
|
|
233
|
+
<code>{JSON.stringify(effect.details.slice(1))}</code> in <AccountAddress account={effect.contract}/></>
|
|
226
234
|
case 'feeCharged':
|
|
227
235
|
return <><Amount asset="XLM" amount={effect.charged} adjust/> fee charged from <AccountAddress account={effect.source}/> (
|
|
228
236
|
bid <Amount asset="XLM" amount={effect.bid} adjust/>)</>
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import {EffectDescription} from './effect-description'
|
|
3
|
+
import SorobanTxMetricsView from './soroban-tx-metrics-view'
|
|
3
4
|
import './op-effects.scss'
|
|
4
5
|
|
|
5
6
|
export function OpEffectsView({effects}) {
|
|
7
|
+
if (!effects.length)
|
|
8
|
+
return <div className="op-effects">
|
|
9
|
+
<div className="dimmed">(no effects)</div>
|
|
10
|
+
</div>
|
|
6
11
|
return <div className="op-effects">
|
|
7
|
-
{
|
|
8
|
-
|
|
9
|
-
|
|
12
|
+
{effects.map((e, i) => {
|
|
13
|
+
if (e.type === 'contractMetrics')
|
|
14
|
+
return null
|
|
15
|
+
return <div key={i}>
|
|
16
|
+
<i className={e.type === 'contractError' ? 'icon-warning' : 'icon-puzzle'}/> <EffectDescription effect={e}/>
|
|
17
|
+
</div>
|
|
18
|
+
})}
|
|
19
|
+
<SorobanTxMetricsView metrics={effects.find(e => e.type === 'contractMetrics')}/>
|
|
10
20
|
</div>
|
|
11
21
|
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {formatWithPrecision} from '@stellar-expert/formatter'
|
|
2
|
+
|
|
3
|
+
export default function SorobanTxMetricsView({metrics}) {
|
|
4
|
+
if (!metrics)
|
|
5
|
+
return null
|
|
6
|
+
return <div className="text-tiny row micro-space text-monospace">
|
|
7
|
+
{Object.entries(parseMetrics(metrics)).map(([key, value])=><div key={key} className="column column-33">
|
|
8
|
+
<span className="dimmed">{key}: </span>{value}
|
|
9
|
+
</div>)}
|
|
10
|
+
</div>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function parseMetrics(metrics) {
|
|
14
|
+
const res = {}
|
|
15
|
+
for (const [key, value] of Object.entries(metrics)) {
|
|
16
|
+
switch (key) {
|
|
17
|
+
case 'cpu_insn':
|
|
18
|
+
res['CPU instructions'] = formatWithPrecision(value, 0)
|
|
19
|
+
break
|
|
20
|
+
case 'emit_event':
|
|
21
|
+
if (value > 0) {
|
|
22
|
+
res['Emitted events'] = value.toString()
|
|
23
|
+
}
|
|
24
|
+
break
|
|
25
|
+
case 'emit_event_byte':
|
|
26
|
+
if (value > 0) {
|
|
27
|
+
res['Emitted events'] += ' ' + formatBytes(value)
|
|
28
|
+
}
|
|
29
|
+
break
|
|
30
|
+
case 'invoke_time_nsecs':
|
|
31
|
+
res['Invoke time'] = formatWithPrecision(value / 1000, 3) + 'µs'
|
|
32
|
+
break
|
|
33
|
+
case 'mem_byte':
|
|
34
|
+
res['Memory utilization'] = formatBytes(value)
|
|
35
|
+
break
|
|
36
|
+
case 'read_code_byte':
|
|
37
|
+
if (value > 0) {
|
|
38
|
+
res['Code read'] = formatBytes(value)
|
|
39
|
+
}
|
|
40
|
+
break
|
|
41
|
+
case 'write_code_byte':
|
|
42
|
+
if (value > 0) {
|
|
43
|
+
res['Code write'] = formatBytes(value)
|
|
44
|
+
}
|
|
45
|
+
break
|
|
46
|
+
case 'ledger_read_byte':
|
|
47
|
+
if (value > 0) {
|
|
48
|
+
res['Ledger read'] = formatBytes(value)
|
|
49
|
+
}
|
|
50
|
+
break
|
|
51
|
+
case 'ledger_write_byte':
|
|
52
|
+
if (value > 0) {
|
|
53
|
+
res['Ledger write'] = formatBytes(value)
|
|
54
|
+
}
|
|
55
|
+
break
|
|
56
|
+
case 'read_data_byte':
|
|
57
|
+
if (value > 0) {
|
|
58
|
+
res['Data read'] = formatBytes(value)
|
|
59
|
+
}
|
|
60
|
+
break
|
|
61
|
+
case 'write_data_byte':
|
|
62
|
+
if (value > 0) {
|
|
63
|
+
res['Data write'] = formatBytes(value)
|
|
64
|
+
}
|
|
65
|
+
break
|
|
66
|
+
case 'read_key_byte':
|
|
67
|
+
if (value > 0) {
|
|
68
|
+
res['Key read'] = formatBytes(value)
|
|
69
|
+
}
|
|
70
|
+
break
|
|
71
|
+
case 'write_key_byte':
|
|
72
|
+
if (value > 0) {
|
|
73
|
+
res['Key write'] = formatBytes(value)
|
|
74
|
+
}
|
|
75
|
+
break
|
|
76
|
+
case 'read_entry':
|
|
77
|
+
if (value > 0) {
|
|
78
|
+
res['Entries read'] = value
|
|
79
|
+
}
|
|
80
|
+
break
|
|
81
|
+
case 'write_entry':
|
|
82
|
+
if (value > 0) {
|
|
83
|
+
res['Entries write'] = value
|
|
84
|
+
}
|
|
85
|
+
break
|
|
86
|
+
case 'max_emit_event_byte':
|
|
87
|
+
case 'max_rw_code_byte':
|
|
88
|
+
case 'max_rw_data_byte':
|
|
89
|
+
case 'max_rw_key_byte': //ignore these metrics
|
|
90
|
+
break
|
|
91
|
+
case 'type':
|
|
92
|
+
case 'source':
|
|
93
|
+
case 'contract': //ignore other effect params
|
|
94
|
+
break
|
|
95
|
+
default:
|
|
96
|
+
console.log('Unsupported metric: ' + key)
|
|
97
|
+
break
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return res
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function formatBytes(value) {
|
|
104
|
+
return formatWithPrecision(value, 3) + 'B'
|
|
105
|
+
}
|
package/package.json
CHANGED
|
@@ -39,10 +39,12 @@ import TxMatcher from './tx-matcher'
|
|
|
39
39
|
* @param {TxFiltersContext} [context] - Filters applied to transactions search
|
|
40
40
|
* @param {String} [createdAt] - Ledger execution timestamp
|
|
41
41
|
* @param {Boolean} [skipUnrelated] - Ledger execution timestamp
|
|
42
|
+
* @param {Number} [protocol] – Specific Stellar protocol version for the executed transaction
|
|
42
43
|
* @return {ParsedTxDetails}
|
|
43
44
|
*/
|
|
44
|
-
export function parseTxDetails({network, txEnvelope, result, meta, id, context, createdAt, skipUnrelated}) {
|
|
45
|
-
const
|
|
45
|
+
export function parseTxDetails({network, txEnvelope, result, meta, id, context, createdAt, skipUnrelated, protocol}) {
|
|
46
|
+
const parsedTx = parseTxOperationsMeta({network, tx: txEnvelope, meta, result, protocol, processSystemEvents: true})
|
|
47
|
+
const {tx, effects, operations, isEphemeral, failed} = parsedTx
|
|
46
48
|
const txHash = tx.hash().toString('hex')
|
|
47
49
|
const txMatcher = new TxMatcher(context, skipUnrelated)
|
|
48
50
|
let parsedOps = OperationDescriptor.parseOperations(operations, txHash, isEphemeral, !isEphemeral && !failed)
|
package/tx/tx-operations-list.js
CHANGED
|
@@ -94,7 +94,7 @@ export const TxOperationsList = React.memo(function TxOperationsList({
|
|
|
94
94
|
return <div>
|
|
95
95
|
{!compact && showEffects !== false &&
|
|
96
96
|
<div className="tx-effects-toggle">
|
|
97
|
-
<Spoiler micro active expanded={effectsExpanded} showLess="Hide operation
|
|
97
|
+
<Spoiler micro active expanded={effectsExpanded} showLess="Hide operation details" showMore="Show operation details"
|
|
98
98
|
onChange={toggleEffects} style={{margin: '0.2em'}}/>
|
|
99
99
|
</div>}
|
|
100
100
|
<div className="condensed">
|