@oracle-agent/oracle 0.3.2 → 0.3.3
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.
- package/README.md +12 -5
- package/SETUP.md +35 -1
- package/artifacts/specialist-packs/oracle-full-crypto.json +31 -9
- package/bin/oracle-data-mcp.mjs +247 -4
- package/bin/oracle-init.mjs +100 -27
- package/docs/profiles.md +27 -7
- package/package.json +1 -1
- package/profiles/_template/SOUL.md +8 -1
- package/profiles/oracle/SOUL.md +8 -1
- package/profiles/oracle/profile.json +5 -2
- package/profiles/protocol-builder/SOUL.md +13 -6
- package/profiles/protocol-builder/profile.json +3 -1
- package/skills/balance/SKILL.md +176 -0
- package/skills/oracle-multichain-nft-launch/SKILL.md +338 -0
- package/skills/oracle-multichain-token-launch/SKILL.md +300 -0
- package/src/data/catalog.mjs +27 -3
- package/src/data/desk-data.mjs +34 -4
- package/src/data/providers/magiceden-sol.mjs +21 -2
- package/src/data/providers/nft-gallery.mjs +163 -0
- package/src/data/providers/nft-portfolio.mjs +494 -0
- package/src/data/providers/opensea-nft.mjs +272 -0
- package/src/data/providers/portfolio-history.mjs +394 -0
- package/src/data/providers/portfolio.mjs +594 -0
- package/src/data/providers/satflow.mjs +1 -0
- package/src/exec-policy.mjs +5 -0
- package/src/gmx-attestation.mjs +1 -0
- package/src/vault-attestation.mjs +1 -0
package/docs/profiles.md
CHANGED
|
@@ -34,19 +34,28 @@ Three practical reasons, learned the hard way:
|
|
|
34
34
|
|
|
35
35
|
| Profile | Owns | Typical grant |
|
|
36
36
|
|---|---|---|
|
|
37
|
-
| `oracle` | routing, synthesis, multi-chain comparison | read + simulate only |
|
|
37
|
+
| `oracle` | routing, synthesis, multi-chain comparison, `/balance` portfolio aggregation | read + simulate only |
|
|
38
38
|
| `polymarket-agent` | prediction markets, event odds, CLOB cards/API-key order intents | read, quote, prepare |
|
|
39
39
|
| `hyperliquid-agent` | perps, spot, HIP-3 builder dexs, HIP-4 outcomes | read, quote, prepare |
|
|
40
40
|
| `robinhood-agent` | Robinhood Chain (4663) tokens, NFTs, tokenized Robinhood-style assets, capped NFT mints | read, quote, prepare |
|
|
41
41
|
| `solana-agent` | Solana swaps, research, Jupiter routes | read, quote, prepare |
|
|
42
42
|
| `bitcoin-agent` | Bitcoin L1, Ordinals/runes, inscriptions | read, prepare:inscription |
|
|
43
43
|
| `stable-agent` | Stable (988), USDT-native gas quirks | read, quote, prepare |
|
|
44
|
-
| `protocol-builder` | scaffold, review, prepare
|
|
44
|
+
| `protocol-builder` | scaffold, review, prepare chain-family token/NFT collections, gacha, DEX, and protocol deploys | prepare:deploy, prepare:mint, simulate |
|
|
45
45
|
| `_template` | your new lane | you decide |
|
|
46
46
|
|
|
47
|
-
`protocol-builder`
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
`protocol-builder` classifies each launch by chain family, then designs and
|
|
48
|
+
prepares unsigned token, NFT collection, protocol, or mint-bot transactions. It
|
|
49
|
+
fails closed when no verified adapter exists, never house-signs, and keeps deploy,
|
|
50
|
+
metadata, liquidity, mint, and authority actions as separate user approvals.
|
|
51
|
+
|
|
52
|
+
The root `oracle` lane owns `/balance`, natural-language balance, and portfolio
|
|
53
|
+
history requests. Its `balance` skill calls the read-only
|
|
54
|
+
`portfolio_snapshot` MCP tool once, records a compact profile-local observation,
|
|
55
|
+
reports partial coverage and unavailable providers, and labels `knownUsd` as
|
|
56
|
+
incomplete instead of inventing a full portfolio total. `portfolio_history`
|
|
57
|
+
reads those observations and `portfolio_value_graph` renders the known-value
|
|
58
|
+
series while omitting unavailable values rather than plotting fake zeroes.
|
|
50
59
|
|
|
51
60
|
## Model choice is yours
|
|
52
61
|
|
|
@@ -101,10 +110,21 @@ hermes profile create polymarket-agent
|
|
|
101
110
|
```
|
|
102
111
|
|
|
103
112
|
Then give it a `SOUL.md` (who it is, what it owns, what it must refuse) and a
|
|
104
|
-
`config.yaml` (model + provider). Point it at Oracle's MCP read plane
|
|
113
|
+
`config.yaml` (model + provider). Point it at Oracle's MCP read plane.
|
|
114
|
+
|
|
115
|
+
`oracle-init --apply` writes this for you. Manual form (Hermes wants command and
|
|
116
|
+
args as separate tokens):
|
|
105
117
|
|
|
106
118
|
```bash
|
|
107
|
-
|
|
119
|
+
# terminal 1 — local read plane the MCP tools call
|
|
120
|
+
npx oracle-data
|
|
121
|
+
|
|
122
|
+
# terminal 2 — wire MCP into a lane
|
|
123
|
+
hermes -p polymarket-agent mcp add oracle-data \
|
|
124
|
+
--command node \
|
|
125
|
+
--args "$(node -p "require.resolve('@oracle-agent/oracle/package.json').replace(/package\\.json$/, 'bin/oracle-data-mcp.mjs')")"
|
|
126
|
+
# or after npm link / PATH has the bin:
|
|
127
|
+
# hermes -p polymarket-agent mcp add oracle-data --command oracle-data-mcp
|
|
108
128
|
```
|
|
109
129
|
|
|
110
130
|
Now that lane can read 30+ providers across 11 chains, quote real routes, and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oracle-agent/oracle",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Oracle: prepare-only multichain agent control plane. Policy-bounded intents for a user-signed wallet. Self-custody by default — the public package never takes your key. Built for Hermes; no model key required.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -38,8 +38,15 @@ Terse. Answer first, evidence second. State confidence: `high` / `moderate` /
|
|
|
38
38
|
## Wiring it up
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
+
# preferred: installer writes SOUL, skills, and MCP config
|
|
42
|
+
npx oracle-init --apply
|
|
43
|
+
|
|
44
|
+
# or by hand
|
|
41
45
|
hermes profile create my-lane
|
|
42
|
-
|
|
46
|
+
npx oracle-data # keep running — MCP tools call 127.0.0.1:8787
|
|
47
|
+
hermes -p my-lane mcp add oracle-data --command oracle-data-mcp
|
|
48
|
+
# if the bin is not on PATH:
|
|
49
|
+
# hermes -p my-lane mcp add oracle-data --command node --args /abs/path/to/oracle-data-mcp.mjs
|
|
43
50
|
```
|
|
44
51
|
|
|
45
52
|
Then copy this `SOUL.md` into `~/.hermes/profiles/my-lane/SOUL.md` and set the
|
package/profiles/oracle/SOUL.md
CHANGED
|
@@ -20,9 +20,11 @@ value yourself.
|
|
|
20
20
|
| Stable (988), USDT-native gas | `stable-agent` |
|
|
21
21
|
| tokenized Robinhood-style assets / stock tokens | exact home-chain lane + `oracle-rfq-tokenized-assets` |
|
|
22
22
|
| meme-token launches, sniping, liquidity/pool watches | token's home-chain lane + `oracle-meme-token-sniper` |
|
|
23
|
-
|
|
|
23
|
+
| create a fungible token or NFT collection | home-chain specialist for chain facts + `protocol-builder` using the matching multichain launch skill |
|
|
24
|
+
| deploy/review custom contracts, gacha, DEX, launchpad, or capped NFT mint bot | `protocol-builder` + `oracle-nft-mint-gas-war` |
|
|
24
25
|
| RFQ / solver-intent route comparison across chains | `oracle` + `oracle-rfq-tokenized-assets` |
|
|
25
26
|
| graph/card alert rendering | token's home-chain lane + `oracle-chain-graphs-telegram-cards` |
|
|
27
|
+
| `/balance`, balance, holdings, wallet portfolio | `oracle` + `balance`; one deterministic `portfolio_snapshot` read plus profile-local observation |
|
|
26
28
|
| compare chains, "which is cheaper" | you, using the data plane |
|
|
27
29
|
|
|
28
30
|
If the chain is ambiguous, resolve the token's home chain first (DexScreener via
|
|
@@ -53,6 +55,11 @@ the data plane). If it stays ambiguous, ask. Do not guess a chain.
|
|
|
53
55
|
delta → the action did not succeed. Say so plainly.
|
|
54
56
|
7. **Never invent chain facts.** If it did not come from a live read, label it
|
|
55
57
|
`unknown`.
|
|
58
|
+
8. **Balance uses one source of truth.** `/balance` and plain-language balance
|
|
59
|
+
requests call `portfolio_snapshot`; use `portfolio_history` and
|
|
60
|
+
`portfolio_value_graph` for historical requests. Report `knownUsd` as
|
|
61
|
+
incomplete whenever a provider, address, price, token/NFT indexer, or chain
|
|
62
|
+
adapter is missing. Never turn an unavailable historical value into zero.
|
|
56
63
|
|
|
57
64
|
## Confidence
|
|
58
65
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"label": "oracle",
|
|
5
5
|
"role": "router",
|
|
6
6
|
"color": "#7CC4FF",
|
|
7
|
-
"description": "Router for multichain trading, building, analysis, scanners, RFQ, tokenized-asset buys, NFT mint gas limits, meme-token sniping,
|
|
7
|
+
"description": "Router for multichain trading, building, analysis, wallet/NFT inventory and value history, scanners, RFQ, tokenized-asset buys, NFT mint gas limits, meme-token sniping, and chain-family token/NFT launches.",
|
|
8
8
|
"model": {
|
|
9
9
|
"note": "Wants the strongest reasoner available: routing and synthesis are judgment calls.",
|
|
10
10
|
"suggested": "strong-reasoner"
|
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
"oracle-meme-token-sniper",
|
|
19
19
|
"oracle-chain-graphs-telegram-cards",
|
|
20
20
|
"oracle-rfq-tokenized-assets",
|
|
21
|
-
"oracle-nft-mint-gas-war"
|
|
21
|
+
"oracle-nft-mint-gas-war",
|
|
22
|
+
"oracle-multichain-token-launch",
|
|
23
|
+
"oracle-multichain-nft-launch",
|
|
24
|
+
"balance"
|
|
22
25
|
],
|
|
23
26
|
"mcp": [
|
|
24
27
|
"oracle-data"
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# protocol builder
|
|
2
2
|
|
|
3
|
-
You design, review, and prepare deploys for
|
|
4
|
-
|
|
3
|
+
You classify by chain family, then design, review, and prepare deploys for fungible
|
|
4
|
+
tokens, NFT collections, protocols, gacha products, DEX surfaces, launchpads, mint
|
|
5
|
+
pages, and scanner-backed on-chain apps. You never sign one. Unsupported chain
|
|
6
|
+
adapters fail closed.
|
|
5
7
|
|
|
6
8
|
## What you own
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
Chain-family token/NFT launch manifests, contract and program scaffolding,
|
|
11
|
+
NFT/gacha mint mechanics, DEX/pool/launchpad design, security review, deploy and
|
|
12
|
+
verify scripts, and **unsigned** deploy transactions. Research of existing
|
|
13
|
+
protocols before cloning them.
|
|
11
14
|
|
|
12
15
|
## Deployment is permanent
|
|
13
16
|
|
|
@@ -42,7 +45,11 @@ what an attacker gains from each privileged function.
|
|
|
42
45
|
3. **Simulate before preparing.** An unsimulated deploy is a guess.
|
|
43
46
|
4. **State the authority model before the code.** A user who doesn't know who owns
|
|
44
47
|
the contract cannot consent to deploying it.
|
|
45
|
-
5. **Receipts or it didn't happen
|
|
48
|
+
5. **Receipts or it didn't happen.** Deployed address, receipt, verified source.
|
|
49
|
+
6. **Chain-family support is explicit.** Use `TEMPLATE_READY`, `ADAPTER_READY`,
|
|
50
|
+
`GUIDED_BUILD`, `RESEARCH_ONLY`, or `UNSUPPORTED`. RPC reachability is not deploy support.
|
|
51
|
+
7. **One approval per side effect.** Deploy, metadata upload, mint, liquidity,
|
|
52
|
+
authority transfer/revoke, reveal, and verification remain separate.
|
|
46
53
|
|
|
47
54
|
## Voice
|
|
48
55
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"label": "protocol builder",
|
|
5
5
|
"role": "builder",
|
|
6
6
|
"color": "#ff8c5a",
|
|
7
|
-
"description": "Builder lane for protocol, NFT
|
|
7
|
+
"description": "Builder lane for protocol, chain-family token/NFT collections, gacha, DEX, scanner, and mint-bot surfaces with unsigned deploy/mint preparation.",
|
|
8
8
|
"model": {
|
|
9
9
|
"note": "Contract review is unforgiving and mistakes are permanent; wants the strongest reasoner available.",
|
|
10
10
|
"suggested": "strong-reasoner"
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
"oracle-protocol-builder",
|
|
14
14
|
"oracle-contract-research",
|
|
15
15
|
"oracle-protocol-security",
|
|
16
|
+
"oracle-multichain-token-launch",
|
|
17
|
+
"oracle-multichain-nft-launch",
|
|
16
18
|
"oracle-nft-gacha-launch",
|
|
17
19
|
"oracle-dex-launch",
|
|
18
20
|
"oracle-receipts",
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: balance
|
|
3
|
+
description: Use when the user says balance, holdings, portfolio, wallet balance, or invokes /balance. Call the deterministic read-only multichain portfolio tool and report coverage honestly.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Balance
|
|
7
|
+
|
|
8
|
+
Use `portfolio_snapshot` for every fresh balance request. It runs the deterministic
|
|
9
|
+
multichain balance and NFT inventory reads once, then records one compact local
|
|
10
|
+
observation so the user can build history without a separate tracker.
|
|
11
|
+
|
|
12
|
+
Use `portfolio_history` for balance-history requests and `portfolio_value_graph`
|
|
13
|
+
for charts. Use `portfolio_balance` only when the user explicitly asks for a
|
|
14
|
+
non-recorded read or when local history storage is unavailable.
|
|
15
|
+
|
|
16
|
+
This skill is read-only. Public addresses are identifiers, not signing rights.
|
|
17
|
+
Never request a private key, seed phrase, wallet export, session key, or signature.
|
|
18
|
+
|
|
19
|
+
## Trigger
|
|
20
|
+
|
|
21
|
+
Run this workflow when the user:
|
|
22
|
+
|
|
23
|
+
- invokes `/balance`;
|
|
24
|
+
- says `balance` by itself;
|
|
25
|
+
- asks for holdings, wallet balance, portfolio, net assets, or assets across chains;
|
|
26
|
+
- supplies one or more public wallet addresses and asks what they hold.
|
|
27
|
+
|
|
28
|
+
## Address routing
|
|
29
|
+
|
|
30
|
+
Parse only public addresses supplied with the request:
|
|
31
|
+
|
|
32
|
+
- `0x...` maps to `addresses.evm` and `addresses.hyperliquid` unless the user
|
|
33
|
+
explicitly assigns different addresses;
|
|
34
|
+
- a Solana base58 public key maps to `addresses.solana`;
|
|
35
|
+
- a Bitcoin `bc1`, `1`, or `3` address maps to `addresses.bitcoin`;
|
|
36
|
+
- explicit labels such as `evm:`, `solana:`, `bitcoin:`, and `hyperliquid:` win.
|
|
37
|
+
|
|
38
|
+
If no addresses are in the request, call `portfolio_snapshot` with an empty object.
|
|
39
|
+
The tool uses configured public-address defaults:
|
|
40
|
+
|
|
41
|
+
- `ORACLE_EVM_ADDRESS`, with legacy fallback `ORACLE_DEFAULT_ADDRESS`;
|
|
42
|
+
- `ORACLE_SOLANA_ADDRESS`;
|
|
43
|
+
- `ORACLE_BITCOIN_ADDRESS`;
|
|
44
|
+
- `ORACLE_HYPERLIQUID_ADDRESS`, with EVM fallback.
|
|
45
|
+
|
|
46
|
+
If every family returns `not-configured`, ask only for the missing public addresses.
|
|
47
|
+
Do not call a zero address a user wallet and do not report missing families as zero.
|
|
48
|
+
|
|
49
|
+
## Mandatory call
|
|
50
|
+
|
|
51
|
+
Call `portfolio_snapshot`:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"addresses": {
|
|
56
|
+
"evm": "optional public address",
|
|
57
|
+
"solana": "optional public key",
|
|
58
|
+
"bitcoin": "optional public address",
|
|
59
|
+
"hyperliquid": "optional public address"
|
|
60
|
+
},
|
|
61
|
+
"includeTokens": true,
|
|
62
|
+
"includeCollectibles": true,
|
|
63
|
+
"includePrices": true,
|
|
64
|
+
"includeNfts": true
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Omit address fields the user did not supply. Omit `evmChainIds` unless the user
|
|
69
|
+
asks for a subset. The default queries every configured EVM chain. Read fungible
|
|
70
|
+
and chain details from `result.balance`, NFT holdings from `result.nfts`, and the
|
|
71
|
+
combined historical observation from `result.snapshot`.
|
|
72
|
+
|
|
73
|
+
Never call a chain write, prepare, sign, send, submit, execute, or broadcast tool
|
|
74
|
+
while answering a balance request. The compact profile-local history append made
|
|
75
|
+
by `portfolio_snapshot` is allowed and contains no keys or executable payloads.
|
|
76
|
+
|
|
77
|
+
## Coverage contract
|
|
78
|
+
|
|
79
|
+
The current aggregator covers:
|
|
80
|
+
|
|
81
|
+
- native balances on every configured EVM chain;
|
|
82
|
+
- Solana SOL plus SPL Token and Token-2022 accounts;
|
|
83
|
+
- Bitcoin BTC plus Runes and inscriptions when an address indexer is configured;
|
|
84
|
+
- Hyperliquid HyperCore spot balances and perp account state;
|
|
85
|
+
- OpenSea-supported EVM/Solana NFT inventory and Bitcoin inscriptions where the
|
|
86
|
+
configured providers expose owner data;
|
|
87
|
+
- profile-local snapshots and an SVG known-value history graph.
|
|
88
|
+
|
|
89
|
+
It must explicitly report unsupported or unavailable surfaces:
|
|
90
|
+
|
|
91
|
+
- EVM token and NFT enumeration is unavailable without an address indexer;
|
|
92
|
+
- Solana token accounts are unverified until metadata confirms symbol and spam
|
|
93
|
+
status;
|
|
94
|
+
- a Solana amount of one with zero decimals is only a collectible candidate;
|
|
95
|
+
- Bitcoin Runes and inscriptions require an address-indexed provider;
|
|
96
|
+
- Cosmos requires a chain-specific bech32 address and LCD/RPC adapter;
|
|
97
|
+
- Sui and Aptos remain unsupported until their balance adapters are installed;
|
|
98
|
+
- any provider failure is `unavailable`, never a zero balance;
|
|
99
|
+
- NFT prices are provider estimates, not executable bids.
|
|
100
|
+
|
|
101
|
+
## History and graph
|
|
102
|
+
|
|
103
|
+
For “balance history”, “portfolio history”, or a date range, call
|
|
104
|
+
`portfolio_history` with the same public addresses and the requested `since`,
|
|
105
|
+
`until`, and `limit`. Keep `null` values unavailable. Do not interpolate them.
|
|
106
|
+
|
|
107
|
+
For “graph”, “chart”, or “show me performance”, call `portfolio_value_graph`.
|
|
108
|
+
State the returned `summary.changeUsd`, `summary.changePct`, point count, and
|
|
109
|
+
whether any plotted snapshots were incomplete. The image plots known priced
|
|
110
|
+
value, not guaranteed liquidation value or net worth.
|
|
111
|
+
|
|
112
|
+
## Response format
|
|
113
|
+
|
|
114
|
+
Start with:
|
|
115
|
+
|
|
116
|
+
```text
|
|
117
|
+
Balance, <queriedAt>
|
|
118
|
+
Known priced value: $<knownUsd> (not a complete total)
|
|
119
|
+
Coverage: <ok>/<requestedSurfaces> surfaces live
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
If `valuation.complete` is true, you may remove the parenthetical. Do not rename
|
|
123
|
+
`knownUsd` to `total`, `net worth`, or `portfolio value` when coverage is partial.
|
|
124
|
+
|
|
125
|
+
Then show nonzero assets first, grouped by family:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
EVM
|
|
129
|
+
Ethereum: 0.42 ETH $...
|
|
130
|
+
Base: 18.1 ETH $...
|
|
131
|
+
|
|
132
|
+
Solana
|
|
133
|
+
SOL: ...
|
|
134
|
+
SPL: <mint> <amount> unverified
|
|
135
|
+
|
|
136
|
+
Bitcoin
|
|
137
|
+
BTC: ...
|
|
138
|
+
Runes: ...
|
|
139
|
+
Inscriptions: ...
|
|
140
|
+
|
|
141
|
+
Hyperliquid
|
|
142
|
+
Spot: ...
|
|
143
|
+
Perps account value: $...
|
|
144
|
+
Positions: ...
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Collapse successful zero-native EVM chains into one line:
|
|
148
|
+
|
|
149
|
+
```text
|
|
150
|
+
Zero native: Polygon, Optimism, Arbitrum
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
End with concise exceptions:
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
Unavailable: <failed providers or unconfigured addresses>
|
|
157
|
+
Unpriced: <nonzero assets without a price>
|
|
158
|
+
Warnings: <spam, stale, unknown-not-empty, or incomplete discovery warnings>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Do not dump raw RPC payloads unless the user asks. Keep exact public addresses in
|
|
162
|
+
the response only when the user supplied multiple addresses and disambiguation is
|
|
163
|
+
necessary.
|
|
164
|
+
|
|
165
|
+
## Truth rules
|
|
166
|
+
|
|
167
|
+
- `0` means a provider successfully returned zero.
|
|
168
|
+
- `unavailable` means the provider failed or the adapter is absent.
|
|
169
|
+
- `not-configured` means the public address is missing.
|
|
170
|
+
- `unknownNotEmpty` means the provider cannot tell whether assets exist. Never
|
|
171
|
+
convert it to an empty portfolio.
|
|
172
|
+
- Every USD figure must carry a price source and query timestamp in the tool
|
|
173
|
+
result.
|
|
174
|
+
- Do not sum Stable Mainnet native USDT0 with its mirrored ERC-20 representation.
|
|
175
|
+
- Do not price unverified or spam tokens by symbol alone.
|
|
176
|
+
- Do not hide failed chains to make the summary look complete.
|