Add full Chain 138 integration: 8 steps, chain spec, app-ethereum config, docs

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-02-12 15:57:08 -08:00
parent 17020ba236
commit bee1d29d55
33 changed files with 1444 additions and 1 deletions

View File

@@ -0,0 +1,19 @@
# Step 3 — Create coin module
For Chain 138 we **extend the Ethereum family** in ledger-live (no new coin-module). Use:
**Note:** `network-explorer.ts` uses Blockscout REST v2 API (`GET /api/v2/addresses/{address}/transactions`) with `next_page_params` pagination. Do not use Etherscan-style `module=account&action=txlist` — Blockscout uses a different API.
- **config.chain138.ts** — Chain 138 RPC and explorer config; plug into Ethereum family config or currency config.
- **network-explorer.ts** — Example network layer (getLastBlock, getBalance, getTransactionCount, getAddressTransactions). Adapt to the Ethereum coin-modules network/bridge API (e.g. wrap in the same interface as other EVM chains).
If Ledger requests a **dedicated** coin-module, create `libs/coin-modules/coin-defi_oracle_meta/` with:
- `bridge/` — sync, buildTransaction, signOperation, broadcast, getFeesForTransaction, getTransactionStatus
- `logic/` — core logic (no bridge imports)
- `network/` — this explorer + RPC wrapper
- `signer/` — Step 4 getAddress + sign
- `types/` — bridge, signer, errors
- `config.ts`, `index.ts`
Dependency rule: `logic``network` only; `bridge``logic`, `network`, `signer`.

View File

@@ -0,0 +1,28 @@
/**
* Step 3 — Create coin module (config for Ethereum family + Chain 138)
* Target: ledger-live libs/coin-modules (or extend libs/ledger-live-common/src/families/ethereum)
*
* For Chain 138 we extend the Ethereum family. This config is used by the bridge/network.
*/
export const CHAIN_ID = 138 as const;
export const RPC_URLS = [
"https://rpc-http-pub.d-bis.org",
"https://rpc.d-bis.org",
"https://rpc2.d-bis.org",
"https://rpc.public-0138.defi-oracle.io",
"https://rpc.defi-oracle.io",
] as const;
export const EXPLORER_BASE = "https://explorer.d-bis.org" as const;
export const chain138Config = {
chainId: CHAIN_ID,
rpcUrls: RPC_URLS,
explorer: {
address: `${EXPLORER_BASE}/address/$address`,
tx: `${EXPLORER_BASE}/tx/$hash`,
token: `${EXPLORER_BASE}/token/$contractAddress?a=$address`,
},
} as const;

View File

@@ -0,0 +1,75 @@
/**
* Step 3 — Coin module: network layer (explorer/RPC wrapper)
* Target: ledger-live libs/coin-modules/coin-ethereum (or coin-defi_oracle_meta) src/network/
*
* Wraps Chain 138 RPC and Blockscout for sync, history, fees. Use in bridge.
*/
const RPC_URL = "https://rpc-http-pub.d-bis.org";
const EXPLORER_API = "https://explorer.d-bis.org/api";
export async function getLastBlock(): Promise<number> {
const res = await fetch(RPC_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_blockNumber", params: [] }),
});
const data = await res.json();
return parseInt(data.result, 16);
}
export async function getBalance(address: string): Promise<string> {
const res = await fetch(RPC_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "eth_getBalance",
params: [address, "latest"],
}),
});
const data = await res.json();
return data.result ?? "0x0";
}
export async function getTransactionCount(address: string): Promise<number> {
const res = await fetch(RPC_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "eth_getTransactionCount",
params: [address, "latest"],
}),
});
const data = await res.json();
return parseInt(data.result ?? "0x0", 16);
}
/**
* Explorer: get transactions for address.
* Blockscout REST v2: GET /api/v2/addresses/{address_hash}/transactions
* Response: { items: Tx[], next_page_params?: { block_number, index, items_count } }
*/
const EXPLORER_API_V2 = "https://explorer.d-bis.org/api/v2";
export async function getAddressTransactions(
address: string,
params?: { block_number?: number; index?: number; items_count?: number }
): Promise<{ items: unknown[]; next_page_params?: { block_number: number; index: number; items_count: number } }> {
let url = `${EXPLORER_API_V2}/addresses/${encodeURIComponent(address)}/transactions`;
if (params?.block_number != null && params?.index != null && params?.items_count != null) {
url += `?block_number=${params.block_number}&index=${params.index}&items_count=${params.items_count}`;
}
const res = await fetch(url);
if (!res.ok) return { items: [] };
const data = await res.json();
return {
items: data.items ?? [],
next_page_params: data.next_page_params,
};
}
export { RPC_URL, EXPLORER_API, EXPLORER_API_V2 };