@pioneer-platform/pioneer-discovery 10.0.8 → 10.2.0
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/.turbo/turbo-build.log +4 -5
- package/CHANGELOG.md +10 -0
- package/ENDPOINTS.md +350 -0
- package/HANDOFF-coingecko-mapping-coverage.md +113 -0
- package/baseline.json +366 -0
- package/lib/assets-native.json +494 -0
- package/lib/assets-top500.json +70119 -0
- package/lib/chains.json +10104 -0
- package/lib/coingecko-mapping.json +9001 -7914
- package/lib/data.d.ts +5 -1
- package/lib/data.js +14 -2
- package/lib/descriptors/cosmos-msgs.json +328 -0
- package/lib/descriptors/evm-descriptors.json +97086 -0
- package/lib/descriptors/evm-signed-blobs.json +4557 -0
- package/lib/descriptors/solana-programs.json +9 -0
- package/lib/descriptors/universal-selectors.json +4035 -0
- package/lib/generatedAssetData.json +10314 -56627
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +9 -0
- package/lib/signatures/cosmos-signatures.json +40 -0
- package/lib/signatures/manifest.json +72 -0
- package/lib/signatures/token-signatures.json +8742 -0
- package/lib/solana-programs.json +194 -0
- package/lib/types/assets.d.ts +52 -0
- package/lib/types/assets.js +12 -0
- package/lib/types/chains.d.ts +51 -0
- package/lib/types/chains.js +12 -0
- package/lib/types/dapps.d.ts +38 -0
- package/lib/types/dapps.js +8 -0
- package/lib/types/descriptors.d.ts +134 -0
- package/lib/types/descriptors.js +17 -0
- package/lib/types/index.d.ts +6 -0
- package/lib/types/index.js +5 -0
- package/lib/types/profiles.d.ts +38 -0
- package/lib/types/profiles.js +86 -0
- package/package.json +53 -2
- package/critical-icon-results.json +0 -164
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
|
|
2
|
+
> @pioneer-platform/pioneer-discovery@10.1.0 build /Users/highlander/WebstormProjects/keepkey-stack/projects/pioneer/modules/pioneer/pioneer-discovery
|
|
3
|
+
> tsc -p . && cp src/*.json lib/ 2>/dev/null || true && mkdir -p lib/descriptors && cp src/descriptors/*.json lib/descriptors/ 2>/dev/null || true && mkdir -p lib/signatures && cp src/signatures/*.json lib/signatures/ 2>/dev/null || true
|
|
4
|
+
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @pioneer-platform/pioneer-discovery
|
|
2
2
|
|
|
3
|
+
## 10.0.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 5df7310: Add Solana program registry (`src/solana-programs.json`) with 23 canonical programs: System, SPL Token, SPL Token 2022, Associated Token Account, Memo v1/v2, Compute Budget, Stake, Vote, Address Lookup Table, Jupiter Aggregator v6, Raydium AMM v4 / CPMM / CLMM, Orca Whirlpool, Phoenix v1, Metaplex Token Metadata / Core / Auction House, Magic Eden v2, Tensor Swap, Marinade, Drift v2.
|
|
8
|
+
|
|
9
|
+
Each entry declares how to extract its instruction discriminator (Anchor 8-byte sighash, SPL 1-byte tag, System 4-byte LE u32, or `none`). Full instruction schemas are included for System transfer/createAccount/allocate, SPL Token transfer/transferChecked/approve/mintTo/burn/close, Token-2022 mirrors, ATA create/createIdempotent/recoverNested, and Compute Budget. Anchor-based DeFi and NFT programs declare name + category only for now; discriminators to be added in follow-ups alongside test fixtures.
|
|
10
|
+
|
|
11
|
+
Consumers: KeepKey Vault's clear-signing review UI reads this registry to render human-readable instruction summaries for Solana transactions; firmware-side Insight metadata binding will reuse the same id → program mapping once on-device v0 support lands.
|
|
12
|
+
|
|
3
13
|
## 10.0.8
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
package/ENDPOINTS.md
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# Pioneer Discovery API — Endpoint Reference
|
|
2
|
+
|
|
3
|
+
Base URL: `http://localhost:9001` (local) or production deployment
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd modules/pioneer/pioneer-discovery
|
|
9
|
+
|
|
10
|
+
# Serve locally (zero dependencies, Node.js only)
|
|
11
|
+
pnpm run serve
|
|
12
|
+
|
|
13
|
+
# Or with custom port
|
|
14
|
+
node scripts/serve.mjs --port 8080
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Data Pipeline
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
ledger-asset-dapps/ ──┐
|
|
21
|
+
├── import-ledger-descriptors.js ──→ evm-descriptors.json (800 contracts, 2957 selectors)
|
|
22
|
+
THORChain/Maya routers ┘
|
|
23
|
+
4byte.directory standards ──→ import-4byte-selectors.js ──→ universal-selectors.json (462 selectors)
|
|
24
|
+
manual curation ──→ ──→ cosmos-msgs.json (28 msg types)
|
|
25
|
+
|
|
26
|
+
sign-all.mjs (INSIGHT_MNEMONIC)
|
|
27
|
+
│
|
|
28
|
+
┌──────────────┼──────────────┐
|
|
29
|
+
▼ ▼ ▼
|
|
30
|
+
evm-signed- token- cosmos-
|
|
31
|
+
blobs.json signatures.json signatures.json
|
|
32
|
+
(2933 blobs) (8730 sigs) (28 sigs)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Re-sign after data changes:**
|
|
36
|
+
```bash
|
|
37
|
+
INSIGHT_MNEMONIC="..." node scripts/sign-all.mjs # ~82 seconds, 11,691 signatures
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Endpoints
|
|
43
|
+
|
|
44
|
+
### Health & Meta
|
|
45
|
+
|
|
46
|
+
| Method | Path | Description |
|
|
47
|
+
|--------|------|-------------|
|
|
48
|
+
| GET | `/api/v2/health` | Service health + aggregate stats |
|
|
49
|
+
| GET | `/api/v2/manifest` | Signing verification manifest (public key, formats) |
|
|
50
|
+
| GET | `/api/v2/descriptors/stats` | Detailed registry statistics |
|
|
51
|
+
|
|
52
|
+
**`GET /api/v2/health`**
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"online": true,
|
|
56
|
+
"service": "pioneer-discovery",
|
|
57
|
+
"stats": {
|
|
58
|
+
"evmDescriptors": { "totalContracts": 800, "totalSelectors": 2957 },
|
|
59
|
+
"evmSignedBlobs": { "totalBlobs": 2933, "verified": 2933 },
|
|
60
|
+
"tokenSignatures": { "totalSigned": 8730, "verified": 8730 },
|
|
61
|
+
"cosmosMsgs": { "totalMsgTypes": 28 },
|
|
62
|
+
"assets": { "total": 29923, "native": 36, "top500": 8730 },
|
|
63
|
+
"chains": 711
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**`GET /api/v2/manifest`** — everything a client needs to verify signed blobs:
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"success": true,
|
|
72
|
+
"data": {
|
|
73
|
+
"version": 1,
|
|
74
|
+
"publicKey": "0218621d9c14473458713bd3e672e53480aa7032ca9b67356395e88709bb45226a",
|
|
75
|
+
"publicKeyBytes": [2, 24, 98, ...],
|
|
76
|
+
"derivationPath": "m/13'/44358944'/1285410994'/2003068762'/1451542600'",
|
|
77
|
+
"blobFormats": { ... },
|
|
78
|
+
"verification": "All blobs: SHA256(payload) → secp256k1 verify(sig, digest, publicKey)"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
### EVM Descriptors (Clear-Signing)
|
|
86
|
+
|
|
87
|
+
| Method | Path | Description |
|
|
88
|
+
|--------|------|-------------|
|
|
89
|
+
| GET | `/api/v2/descriptors/lookup/:networkId/:contractAddress/:selector` | **Primary** — look up method + signed blob |
|
|
90
|
+
| GET | `/api/v2/descriptors/contract/:networkId/:contractAddress` | Full contract descriptor |
|
|
91
|
+
| GET | `/api/v2/descriptors/dapp/:dappSlug` | All contracts for a dApp |
|
|
92
|
+
| GET | `/api/v2/descriptors/chain/:networkId?page=0&limit=50` | List contracts on a chain |
|
|
93
|
+
|
|
94
|
+
**`GET /api/v2/descriptors/lookup/eip155:1/0xd37bbe5744d730a1d98d8dc97c42f0ca46ad7146/0x1fece7b4`**
|
|
95
|
+
|
|
96
|
+
This is the main clear-signing endpoint. Returns method info + pre-signed blob:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"success": true,
|
|
101
|
+
"data": {
|
|
102
|
+
"networkId": "eip155:1",
|
|
103
|
+
"chainId": 1,
|
|
104
|
+
"contractAddress": "0xd37bbe5744d730a1d98d8dc97c42f0ca46ad7146",
|
|
105
|
+
"contractName": "THORChain_Router",
|
|
106
|
+
"dappName": "THORChain",
|
|
107
|
+
"dappSlug": "thorchain",
|
|
108
|
+
"selector": "0x1fece7b4",
|
|
109
|
+
"method": "deposit",
|
|
110
|
+
"plugin": "THORChain",
|
|
111
|
+
"erc20OfInterest": ["asset"],
|
|
112
|
+
"parser": null,
|
|
113
|
+
"signedBlob": "AQAAAAEAz3u+V0TXMKHZjY3JfELwykattRQAAR/s57QAAAA...==",
|
|
114
|
+
"source": "keepkey"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Fallback behavior:** If the contract isn't in the descriptor registry, the endpoint automatically falls back to the universal selector index and returns `{ source: "universal-selector" }`.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
### Universal Selectors
|
|
124
|
+
|
|
125
|
+
| Method | Path | Description |
|
|
126
|
+
|--------|------|-------------|
|
|
127
|
+
| GET | `/api/v2/selectors/:selector` | Look up function signature by 4-byte selector |
|
|
128
|
+
|
|
129
|
+
**`GET /api/v2/selectors/0xa9059cbb`**
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"success": true,
|
|
133
|
+
"data": [{
|
|
134
|
+
"signature": "transfer(address,uint256)",
|
|
135
|
+
"methodName": "transfer",
|
|
136
|
+
"argTypes": ["address", "uint256"],
|
|
137
|
+
"argNames": ["to", "amount"],
|
|
138
|
+
"standard": "ERC-20"
|
|
139
|
+
}]
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Covers: ERC-20, ERC-721, ERC-1155, ERC-4626, Uniswap V2/V3, WETH, Multicall, governance, staking, THORChain/Maya routers, + 417 selectors extracted from Ledger descriptors.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
### Cosmos Message Types
|
|
148
|
+
|
|
149
|
+
| Method | Path | Description |
|
|
150
|
+
|--------|------|-------------|
|
|
151
|
+
| GET | `/api/v2/cosmos/msgs` | All known msg types with signed blobs |
|
|
152
|
+
| GET | `/api/v2/cosmos/msgs/:typeUrl` | Specific msg type |
|
|
153
|
+
|
|
154
|
+
**`GET /api/v2/cosmos/msgs`** — returns 28 msg types across:
|
|
155
|
+
- **Cosmos SDK:** MsgSend, MsgDelegate, MsgUndelegate, MsgVote, IBC Transfer, etc.
|
|
156
|
+
- **THORChain:** MsgDeposit, MsgSend
|
|
157
|
+
- **MayaChain:** MsgDeposit, MsgSend
|
|
158
|
+
- **Osmosis:** MsgSwapExactAmountIn, MsgJoinPool, MsgExitPool, MsgLockTokens, etc.
|
|
159
|
+
|
|
160
|
+
Each entry includes `signedBlob` (base64) for on-device verification.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
### Token Signatures
|
|
165
|
+
|
|
166
|
+
| Method | Path | Description |
|
|
167
|
+
|--------|------|-------------|
|
|
168
|
+
| GET | `/api/v2/tokens/signature/:caip` | Signed metadata for a single token |
|
|
169
|
+
| POST | `/api/v2/tokens/signatures` | Batch lookup (up to 500) |
|
|
170
|
+
|
|
171
|
+
**`GET /api/v2/tokens/signature/eip155%3A1%2Fslip44%3A60`**
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"success": true,
|
|
175
|
+
"caip": "eip155:1/slip44:60",
|
|
176
|
+
"signedBlob": "ARAIZWlwMTU1OjEDRVRIEgVFdGhlcmV1bWb..."
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**`POST /api/v2/tokens/signatures`**
|
|
181
|
+
```json
|
|
182
|
+
// Request
|
|
183
|
+
{ "caips": ["eip155:1/slip44:60", "bip122:000000000019d6689c085ae165831e93/slip44:0"] }
|
|
184
|
+
|
|
185
|
+
// Response
|
|
186
|
+
{ "success": true, "data": { "eip155:1/slip44:60": "ARAIZWl...", "bip122:...": "ARAIYWJ..." } }
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
8,730 tokens signed (36 native + top CoinGecko tokens).
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
### Chains
|
|
194
|
+
|
|
195
|
+
| Method | Path | Description |
|
|
196
|
+
|--------|------|-------------|
|
|
197
|
+
| GET | `/api/v2/chains` | All 711 chains |
|
|
198
|
+
| GET | `/api/v2/chains/:chainId` | Chain by CAIP-2 ID |
|
|
199
|
+
|
|
200
|
+
**`GET /api/v2/chains/eip155%3A1`**
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"success": true,
|
|
204
|
+
"data": {
|
|
205
|
+
"chainId": "eip155:1",
|
|
206
|
+
"name": "Ethereum",
|
|
207
|
+
"evmChainId": 1,
|
|
208
|
+
"slip44": 60,
|
|
209
|
+
"isEVM": true,
|
|
210
|
+
"nativeCurrency": { "symbol": "ETH", "name": "Ethereum", "decimals": 18 },
|
|
211
|
+
"explorer": "https://etherscan.io",
|
|
212
|
+
"thorchainId": "ETH",
|
|
213
|
+
"mayachainId": "ETH",
|
|
214
|
+
"ledgerChainName": "ethereum",
|
|
215
|
+
"knownAssetCount": 11095
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
### Assets
|
|
223
|
+
|
|
224
|
+
| Method | Path | Description |
|
|
225
|
+
|--------|------|-------------|
|
|
226
|
+
| GET | `/api/v2/assets/native` | 36 native gas tokens |
|
|
227
|
+
| GET | `/api/v2/assets/top500` | 8,730 top tokens |
|
|
228
|
+
| GET | `/api/v2/assets/:caip` | Single asset by CAIP |
|
|
229
|
+
| GET | `/api/v2/search?q=usdc&limit=50` | Search by symbol/name |
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
### Bulk Exports
|
|
234
|
+
|
|
235
|
+
For clients that want to sync everything locally and do lookups client-side:
|
|
236
|
+
|
|
237
|
+
| Method | Path | Size | Description |
|
|
238
|
+
|--------|------|------|-------------|
|
|
239
|
+
| GET | `/api/v2/bulk/evm-signed-blobs` | 0.7 MB | All 2,933 EVM signed blobs |
|
|
240
|
+
| GET | `/api/v2/bulk/evm-descriptors` | 2.7 MB | All 800 contracts raw |
|
|
241
|
+
| GET | `/api/v2/bulk/token-signatures` | 2.0 MB | All 8,730 token sigs |
|
|
242
|
+
| GET | `/api/v2/bulk/universal-selectors` | 77 KB | All 462 selectors |
|
|
243
|
+
| GET | `/api/v2/bulk/cosmos-msgs` | 9 KB | All 28 cosmos msg types |
|
|
244
|
+
| GET | `/api/v2/bulk/chains` | 223 KB | All 711 chains |
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Verification
|
|
249
|
+
|
|
250
|
+
All signed blobs follow the same verification pattern:
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
blob = base64decode(signedBlob)
|
|
254
|
+
payload = blob[0 .. blob.length - 65]
|
|
255
|
+
sig = blob[blob.length - 65 .. blob.length - 1] // 64 bytes (r + s)
|
|
256
|
+
recovery = blob[blob.length - 1] // 27 or 28
|
|
257
|
+
|
|
258
|
+
digest = SHA256(payload)
|
|
259
|
+
valid = secp256k1_verify(sig, digest, publicKey)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Public key** (compressed, 33 bytes):
|
|
263
|
+
```
|
|
264
|
+
0218621d9c14473458713bd3e672e53480aa7032ca9b67356395e88709bb45226a
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Fetch once from `GET /api/v2/manifest` and cache.
|
|
268
|
+
|
|
269
|
+
### Blob Formats
|
|
270
|
+
|
|
271
|
+
**EVM selector blob** (from `serializeMetadata` in pioneer-insight):
|
|
272
|
+
```
|
|
273
|
+
version(1) + chainId(4 BE) + contractAddress(20) + selector(4) + txHash(32) +
|
|
274
|
+
methodNameLen(2 BE) + methodName(var) + numArgs(1) + [args...] +
|
|
275
|
+
classification(1) + timestamp(4 BE) + keyId(1) + sig(64) + recovery(1)
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Token blob:**
|
|
279
|
+
```
|
|
280
|
+
version(1) + type(1: 0x10=native, 0x11=token) + chainIdLen(1) + chainId(var) +
|
|
281
|
+
contractAddr(0 or 20) + symbolLen(1) + symbol(var) + decimals(1) +
|
|
282
|
+
nameLen(2 BE) + name(var) + timestamp(4 BE) + keyId(1) + sig(64) + recovery(1)
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**Cosmos msg blob:**
|
|
286
|
+
```
|
|
287
|
+
version(1) + type(1: 0x20) + typeUrlLen(2 BE) + typeUrl(var) +
|
|
288
|
+
nameLen(1) + name(var) + numChains(1) + [chainIdLen(1) + chainId(var)]... +
|
|
289
|
+
numFields(1) + [fieldNameLen(1) + fieldName(var) + displayAs(1)]... +
|
|
290
|
+
timestamp(4 BE) + keyId(1) + sig(64) + recovery(1)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Integration Example (KeepKey Vault)
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
// 1. Fetch manifest once at startup
|
|
299
|
+
const { data: manifest } = await fetch('/api/v2/manifest').then(r => r.json());
|
|
300
|
+
const pubkey = new Uint8Array(manifest.publicKeyBytes);
|
|
301
|
+
|
|
302
|
+
// 2. Before signing an EVM tx, look up the descriptor
|
|
303
|
+
const { data } = await fetch(
|
|
304
|
+
`/api/v2/descriptors/lookup/eip155:1/${contractAddress}/${calldata.slice(0, 10)}`
|
|
305
|
+
).then(r => r.json());
|
|
306
|
+
|
|
307
|
+
if (data.signedBlob) {
|
|
308
|
+
// 3. Send signed blob to KeepKey firmware for on-device display
|
|
309
|
+
const blob = Uint8Array.from(atob(data.signedBlob), c => c.charCodeAt(0));
|
|
310
|
+
// firmware verifies blob internally using embedded public key
|
|
311
|
+
await wallet.ethSignTx({ ..., metadata: blob });
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// 4. Token identity verification
|
|
315
|
+
const { signedBlob } = await fetch(
|
|
316
|
+
`/api/v2/tokens/signature/${encodeURIComponent(tokenCaip)}`
|
|
317
|
+
).then(r => r.json());
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Data Sources
|
|
323
|
+
|
|
324
|
+
| Source | Data | Count |
|
|
325
|
+
|--------|------|-------|
|
|
326
|
+
| [ledger-asset-dapps](https://github.com/LedgerHQ/ledger-asset-dapps) | EVM contract selectors + parsers | 794 contracts |
|
|
327
|
+
| KeepKey custom | THORChain + Maya routers | 6 contracts |
|
|
328
|
+
| Hardcoded standards | ERC-20/721/1155/4626, Uniswap, governance | 45 selectors |
|
|
329
|
+
| Extracted from Ledger | Method names from imported descriptors | 417 selectors |
|
|
330
|
+
| CoinGecko mapping | Token metadata (symbol, decimals) | 8,730 tokens |
|
|
331
|
+
| Manual curation | Cosmos SDK, THORChain, Maya, Osmosis msgs | 28 msg types |
|
|
332
|
+
|
|
333
|
+
## Scripts
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
# Import Ledger descriptors (requires local clone of ledger-asset-dapps)
|
|
337
|
+
node scripts/import-ledger-descriptors.js --ledger-path /path/to/ledger-asset-dapps
|
|
338
|
+
|
|
339
|
+
# Build universal selector index
|
|
340
|
+
node scripts/import-4byte-selectors.js
|
|
341
|
+
|
|
342
|
+
# Sign everything (requires INSIGHT_MNEMONIC)
|
|
343
|
+
INSIGHT_MNEMONIC="..." node scripts/sign-all.mjs
|
|
344
|
+
|
|
345
|
+
# Full pipeline
|
|
346
|
+
node scripts/import-ledger-descriptors.js && node scripts/import-4byte-selectors.js && pnpm run sign
|
|
347
|
+
|
|
348
|
+
# Serve locally
|
|
349
|
+
pnpm run serve
|
|
350
|
+
```
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Handoff — `coingecko-mapping.json` is stale and symbol-matched (Solana/TRON/TON 0% covered)
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-06-15
|
|
4
|
+
**From:** keepkey-website-v7 (GEO/SEO asset-page work)
|
|
5
|
+
**To:** pioneer-discovery maintainers
|
|
6
|
+
**Severity:** High — blocks using the CoinGecko mapping as a logical-asset / trust key, and silently omits the chains KeepKey markets most.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## TL;DR
|
|
11
|
+
|
|
12
|
+
`src/coingecko-mapping.json` (CAIP → CoinGecko coin id) is **7 months stale** and was built by **symbol+name string matching with no contract addresses**. As a result:
|
|
13
|
+
|
|
14
|
+
- **Solana: 0 of 5,023 assets mapped. TRON: 0/3. TON: 0/1. XRPL token: 0/1.** Every real Solana token — USDT, USDC, BONK, JUP, WIF, JTO, PYTH, RAY — is unmapped, with the correct mint addresses sitting right there in `generatedAssetData.json`.
|
|
15
|
+
- Because matching is by symbol, the mapping **cannot be a trust signal**: a typosquat ("Tenter USD T", symbol `USDT`) is indistinguishable from real Tether, and real `WIF` (mint `EKpQGSJtjMFqKZ…`) is indistinguishable from `HAMSTER WIF HAT`.
|
|
16
|
+
|
|
17
|
+
These are the exact chains the marketing/GEO copy leads with ("Solana, TON, TRON"). Any consumer that uses CoinGecko-mapping membership to group multi-chain deployments and filter scams (which is keepkey.com's planned asset-page model) would **drop the entire Solana ecosystem** and **fail to separate real from scam** on it.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Evidence (reproducible)
|
|
22
|
+
|
|
23
|
+
Coverage by CAIP namespace, measured against the published package + current mapping:
|
|
24
|
+
|
|
25
|
+
| Namespace | Total assets | Mapped | Coverage |
|
|
26
|
+
|---|---:|---:|---:|
|
|
27
|
+
| eip155 (EVM) | 24,877 | 9,197 | 37% |
|
|
28
|
+
| **solana** | **5,023** | **0** | **0%** |
|
|
29
|
+
| cosmos | 9 | 4 | 44% |
|
|
30
|
+
| bip122 (BTC family) | 7 | 5 | 71% |
|
|
31
|
+
| **tron** | **3** | **0** | **0%** |
|
|
32
|
+
| **ton** | **1** | **0** | **0%** |
|
|
33
|
+
| ripple | 1 | 1 | 100% |
|
|
34
|
+
| binance / xrpl | 2 | 0 | 0% |
|
|
35
|
+
|
|
36
|
+
By token standard: `token:` (Solana SPL) **0 / 5,021**; `erc20` 34%; `bep20` 43%; `slip44` (natives) 76%.
|
|
37
|
+
|
|
38
|
+
Major Solana tokens present in `assetData` but unmapped (real mints):
|
|
39
|
+
```
|
|
40
|
+
USDT Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB (real Tether mint)
|
|
41
|
+
USDC EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v (real Circle mint)
|
|
42
|
+
BONK DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263
|
|
43
|
+
JUP JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN
|
|
44
|
+
WIF EKpQGSJtjMFqKZ… (real dogwifhat — alongside scams "HAMSTER WIF HAT", "Wif SecondChance")
|
|
45
|
+
JTO, PYTH, RAY, WEN, POPCAT … all unmapped
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Root cause 1 — Stale (never regenerated after Solana/TRON/TON were added)
|
|
51
|
+
|
|
52
|
+
`scripts/.coingecko-mapping-stats.json`:
|
|
53
|
+
```
|
|
54
|
+
startTime: 2025-11-01T03:18:17Z totalAssets: 14167 mapped: 10168 (71.77%)
|
|
55
|
+
solana entries in unmapped list: 0 ← Solana assets did not exist in the registry yet
|
|
56
|
+
```
|
|
57
|
+
- `src/coingecko-mapping.json` mtime: **2026-01-16**
|
|
58
|
+
- `src/generatedAssetData.json` mtime: **2026-06-07**, now **29,923** assets
|
|
59
|
+
|
|
60
|
+
~15,700 assets (Solana/TRON/TON SPL + new EVM tokens) were added to the registry **after** the mapping was last generated. The mapping has never caught up.
|
|
61
|
+
|
|
62
|
+
## Root cause 2 — Symbol+name matching, no contract addresses
|
|
63
|
+
|
|
64
|
+
`scripts/generate-coingecko-mapping.js` calls `GET /coins/list` (returns only `{id, symbol, name}`) and matches via `findBestMatch()` on `symbol` then `name` string equality/substring (lines 43–96). It never looks at contract/mint addresses. Consequences:
|
|
65
|
+
- Ambiguous by construction: any symbol with multiple CoinGecko coins falls back to "first match" (line 95) — wrong for scams and bridged variants.
|
|
66
|
+
- Cannot verify a specific deployment is the *real* one, so the mapping is unsafe as a scam filter even where it has coverage.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Recommended fix
|
|
71
|
+
|
|
72
|
+
### 1. (Immediate) Regenerate against the current `generatedAssetData.json`
|
|
73
|
+
A re-run today would symbol-match the Solana majors and lift coverage off 0% — a stopgap. But do **not** stop here; symbol matching will also map scams. Pair with #2.
|
|
74
|
+
|
|
75
|
+
### 2. (Correct fix) Match by contract address via `include_platform=true`
|
|
76
|
+
Use `GET /coins/list?include_platform=true`, which returns per-coin `platforms`:
|
|
77
|
+
```json
|
|
78
|
+
{ "id":"tether","symbol":"usdt","name":"Tether",
|
|
79
|
+
"platforms":{ "ethereum":"0xdac17f95…","solana":"Es9vMFrzaCERm…","binance-smart-chain":"0x55d39833…","tron":"TR7NHqje…" } }
|
|
80
|
+
```
|
|
81
|
+
Build a reverse index `(platform, lowercasedAddress) → coinId`, then for each CAIP derive `(platform, address)` and look it up. This is **exact and scam-proof**: real Solana USDC (`EPjFWdd5…`) maps to `usd-coin`; the typosquat doesn't map to anything.
|
|
82
|
+
|
|
83
|
+
Needs a CAIP-namespace → CoinGecko-platform-id table, e.g.:
|
|
84
|
+
```
|
|
85
|
+
eip155:1→ethereum eip155:56→binance-smart-chain eip155:8453→base eip155:137→polygon-pos
|
|
86
|
+
eip155:42161→arbitrum-one solana:5eykt4…→solana tron:…→tron ton:…→the-open-network
|
|
87
|
+
```
|
|
88
|
+
- Keep symbol+name only as a **fallback for natives** (`slip44`), which have no contract and already map well (76%).
|
|
89
|
+
- `include_platform=true` is a heavier payload / stricter rate limit — may need a CoinGecko API key (Demo/Pro). Flag for the team.
|
|
90
|
+
|
|
91
|
+
### 3. Stop it going stale — add a guard
|
|
92
|
+
Regenerate the mapping whenever `generatedAssetData.json` changes, or add a CI check in `validate-baseline.js` that fails when `mappedCount / assetCount` drops below a threshold, or when any whole namespace present in `assetData` has 0% coverage. The current 0%-Solana state should have failed a gate.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Decisions needed from the pioneer team
|
|
97
|
+
1. CoinGecko **API tier / key** for `include_platform=true` (rate limits). Pro vs Demo?
|
|
98
|
+
2. Canonical handling of **bridged vs native** variants (CoinGecko gives them distinct ids: `tether` vs `bridged-usdt`). Map to the true id per contract (correct), or collapse bridged into the parent for display? (Consumer-side concern, but affects what id you store.)
|
|
99
|
+
3. Authoritative **platform-id table** for all chains in the registry (above is a starter; 711 distinct chainIds exist — most are dust, but confirm the ~20 real ones).
|
|
100
|
+
4. Republish cadence + version so consumers (keepkey.com pinned `^10.0.8`) can rely on coverage.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Why this matters to keepkey.com specifically
|
|
105
|
+
The new asset-page model keys logical-asset grouping and scam-filtering on CoinGecko-mapping membership. With Solana at 0%, "exclude unmapped" would erase KeepKey's flagship-marketed Solana support (USDT/USDC/BONK/JUP/WIF/…) from the site, while "include unmapped" would let Solana scams through. Neither is acceptable until the mapping covers Solana/TRON/TON by contract address. **This handoff is the upstream unblock for that work.**
|
|
106
|
+
|
|
107
|
+
## Reproduce
|
|
108
|
+
From any project with the package installed:
|
|
109
|
+
```
|
|
110
|
+
node -e 'const m=require("@pioneer-platform/pioneer-discovery");const cg=m.coingeckoMapping,{assetData}=m;
|
|
111
|
+
const ns=id=>id.split(":")[0];const b={};for(const id in assetData){const n=ns(id);(b[n]=b[n]||{t:0,m:0});b[n].t++;if(cg[id])b[n].m++;}
|
|
112
|
+
console.log(Object.entries(b).map(([k,o])=>`${k}: ${o.m}/${o.t}`).join("\n"))'
|
|
113
|
+
```
|