Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .oxfmtrc.json

This file was deleted.

3 changes: 0 additions & 3 deletions .oxlintrc.json

This file was deleted.

11 changes: 4 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Changelog


## v0.3.2

[compare changes](https://github.com/agntn/chains/compare/v0.3.1...v0.3.2)
Expand Down Expand Up @@ -46,11 +45,11 @@
### 💅 Refactors

- Registry without import side effects ([#10](https://github.com/agntn/chains/pull/10))
- ⚠️ Canonical keys name the chain, not the ticker ([#12](https://github.com/agntn/chains/pull/12))
- ⚠️ Canonical keys name the chain, not the ticker ([#12](https://github.com/agntn/chains/pull/12))

#### ⚠️ Breaking Changes

- ⚠️ Canonical keys name the chain, not the ticker ([#12](https://github.com/agntn/chains/pull/12))
- ⚠️ Canonical keys name the chain, not the ticker ([#12](https://github.com/agntn/chains/pull/12))

### ❤️ Contributors

Expand Down Expand Up @@ -111,12 +110,11 @@

## v0.2.0


### 🚀 Enhancements

- Chains — blockchain data dictionary (18 chains, aliases, inter-lib bridges, address validation) ([2522db9](https://github.com/agntn/chains/commit/2522db9))
- Add Octra chain metadata ([550491a](https://github.com/agntn/chains/commit/550491a))
- ⚠️ Class registry, @agntn scope, CLI and agent extensions ([4137cb2](https://github.com/agntn/chains/commit/4137cb2))
- ⚠️ Class registry, @agntn scope, CLI and agent extensions ([4137cb2](https://github.com/agntn/chains/commit/4137cb2))
- Resolve chain display names from the registry ([9a9d59e](https://github.com/agntn/chains/commit/9a9d59e))
- MCP server over stdio with shared tool executors ([ec68c07](https://github.com/agntn/chains/commit/ec68c07))

Expand All @@ -132,9 +130,8 @@

#### ⚠️ Breaking Changes

- ⚠️ Class registry, @agntn scope, CLI and agent extensions ([4137cb2](https://github.com/agntn/chains/commit/4137cb2))
- ⚠️ Class registry, @agntn scope, CLI and agent extensions ([4137cb2](https://github.com/agntn/chains/commit/4137cb2))

### ❤️ Contributors

- Oritwoen ([@oritwoen](https://github.com/oritwoen))

7 changes: 7 additions & 0 deletions oxfmt.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import oxfmt from "@agntn/ox/oxfmt";
import { defineConfig } from "oxfmt";

export default defineConfig({
...oxfmt,
ignorePatterns: ["dist", "coverage", "AGENTS.md"],
});
8 changes: 8 additions & 0 deletions oxlint.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import oxlint from "@agntn/ox/oxlint";
import { defineConfig } from "oxlint";

export default defineConfig({
...oxlint,
rules: { ...oxlint.rules },
ignorePatterns: ["dist", "coverage"],
});
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@
"scripts": {
"build": "obuild",
"dev": "obuild --stub",
"fmt": "oxlint . --fix && oxfmt --write .",
"fmt:check": "oxlint . && oxfmt --check .",
"lint": "oxlint .",
"lint:fix": "oxlint . --fix",
"fmt": "pnpm build && oxlint . --fix && oxfmt --write .",
"fmt:check": "pnpm build && oxlint . && oxfmt --check .",
"lint": "pnpm build && oxlint .",
"lint:fix": "pnpm build && oxlint . --fix",
"test": "vitest run",
"test:watch": "vitest",
"typecheck": "tsc --noEmit && pnpm build && tsc --noEmit -p tsconfig.extensions.json",
Expand All @@ -57,12 +57,14 @@
"typebox": "1.3.15"
},
"devDependencies": {
"@agntn/ox": "0.1.0",
"@earendil-works/pi-coding-agent": "0.84.2",
"@types/node": "26.2.0",
"changelogen": "0.6.2",
"obuild": "0.4.38",
"oxfmt": "0.63.0",
"oxlint": "1.78.0",
"oxlint-tsgolint": "7.0.2001",
"typescript": "7.0.2",
"vitest": "4.1.10"
},
Expand Down
2 changes: 2 additions & 0 deletions packages/omp/extensions/chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ let toolOperationsPromise: Promise<typeof ChainsTools> | undefined;
* under NodeNext resolution, which a bare TypeScript-stripping runtime cannot
* resolve back to `.ts` files. Run `pnpm build` before loading the extension
* from a working tree.
*
* @returns {Promise<typeof ChainsTools>} The cached shared executor module.
*/
function loadToolOperations(): Promise<typeof ChainsTools> {
toolOperationsPromise ??= (
Expand Down
2 changes: 2 additions & 0 deletions packages/pi/extensions/chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ let toolOperationsPromise: Promise<typeof ChainsTools> | undefined;
* specifiers under NodeNext resolution, which a bare TypeScript-stripping runtime
* cannot resolve back to `.ts` files. Run `pnpm build` before loading the extension
* from a working tree.
*
* @returns {Promise<typeof ChainsTools>} The cached shared executor module.
*/
function loadToolOperations(): Promise<typeof ChainsTools> {
toolOperationsPromise ??= import(
Expand Down
86 changes: 84 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/chains/bitcoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ export class Bitcoin extends Chain {
* all. Decoding is the check the format needs, because a character-length
* window lets any 32-byte base58 key through and Solana's System Program is
* exactly that. The checksum stays unchecked: this is a format check.
*
* @param {string} address - Candidate Bitcoin address.
* @returns {string} The accepted address unchanged.
*/
override assertAddress(address: string): string {
const decoded = decodeBase58(address, 35);
Expand Down
35 changes: 28 additions & 7 deletions src/chains/cardano.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,39 @@ const SHELLEY_ADDRESS =
const STAKE_ADDRESS =
/^(stake1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{53}|STAKE1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{53})$/;

const BYRON_ENVELOPE_PREFIX = [0x82, 0xd8, 0x18, 0x58] as const;
const BYRON_PAYLOAD_PREFIX = [0x83, 0x58, 0x1c] as const;

function hasBytesAt(decoded: ArrayLike<number>, expected: readonly number[], offset = 0): boolean {
return expected.every((byte, index) => decoded[offset + index] === byte);
}

function cborUnsignedLength(head: number): number {
if (head <= 0x17) return 1;
if (head === 0x18) return 2;
if (head === 0x19) return 3;
if (head === 0x1a) return 5;
return 0;
}

/**
* The Byron envelope: array(2), tag(24), bytes opening as the three-item
* array with its 28-byte root, then a CRC head matching the bytes it
* claims. Attributes, type and the CRC value stay unparsed on purpose.
*
* @param {ArrayLike<number>} decoded - Candidate decoded Byron address bytes.
* @returns {boolean} Whether the bytes have the expected Byron CBOR envelope.
*/
function isByronEnvelope(decoded: Uint8Array): boolean {
if (decoded[0] !== 0x82 || decoded[1] !== 0xd8 || decoded[2] !== 0x18 || decoded[3] !== 0x58) {
return false;
}
function isByronEnvelope(decoded: ArrayLike<number>): boolean {
if (!hasBytesAt(decoded, BYRON_ENVELOPE_PREFIX)) return false;

const payloadLength = decoded[4] ?? 0;
if (payloadLength < 33) return false;
if (decoded[5] !== 0x83 || decoded[6] !== 0x58 || decoded[7] !== 0x1c) return false;
if (payloadLength < 33 || !hasBytesAt(decoded, BYRON_PAYLOAD_PREFIX, 5)) return false;

const head = decoded[5 + payloadLength];
if (head === undefined) return false;
const crcBytes = head <= 0x17 ? 1 : head === 0x18 ? 2 : head === 0x19 ? 3 : head === 0x1a ? 5 : 0;

const crcBytes = cborUnsignedLength(head);
return crcBytes > 0 && decoded.length === 5 + payloadLength + crcBytes;
}

Expand All @@ -44,6 +62,9 @@ export class Cardano extends Chain {
* A format check: the bech32 checksum and the Byron CRC stay unverified,
* and a Byron testnet address passes because its network hides in a CBOR
* attribute this check does not open.
*
* @param {string} address - Candidate Cardano address.
* @returns {string} The accepted address unchanged.
*/
override assertAddress(address: string): string {
const decoded = decodeBase58(address, 128);
Expand Down
3 changes: 3 additions & 0 deletions src/chains/ecash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export class Ecash extends Chain {
* upstream's ecashaddrjs. The checksum stays unchecked, so a prefixless
* Bitcoin Cash address passes. Legacy base58 stays out: it is byte-identical
* to a Bitcoin address.
*
* @param {string} address - Candidate eCash address.
* @returns {string} The accepted address unchanged.
*/
override assertAddress(address: string): string {
if (!CASHADDR_ADDRESS.test(address)) {
Expand Down
3 changes: 3 additions & 0 deletions src/chains/litecoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ export class Litecoin extends Chain {
* byte-identical to a Bitcoin `3...` address, so accepting it would make every
* such address identify as both chains. The checksum stays unchecked: this is
* a format check.
*
* @param {string} address - Candidate Litecoin address.
* @returns {string} The accepted address unchanged.
*/
override assertAddress(address: string): string {
const decoded = decodeBase58(address, 35);
Expand Down
3 changes: 3 additions & 0 deletions src/chains/octra.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export class Octra extends Chain {
/**
* The width is the whole format. A contract address is cut out of base58
* rather than encoded from a payload, so decoding it drops real contracts.
*
* @param {string} address - Candidate Octra address.
* @returns {string} The accepted address unchanged.
*/
override assertAddress(address: string): string {
if (!ADDRESS.test(address)) {
Expand Down
3 changes: 3 additions & 0 deletions src/chains/pepecoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export class Pepecoin extends Chain {
* Base58Check under 0x38 (`P...`) and 0x16 (`9...` or `A...`), 25 bytes, checksum
* unchecked. No bech32: the fork carries Dogecoin's timed-out segwit. 0x16 is
* Dogecoin's script version too, kept because Pepecoin has no other one.
*
* @param {string} address - Candidate Pepecoin address.
* @returns {string} The accepted address unchanged.
*/
override assertAddress(address: string): string {
const decoded = decodeBase58(address, 34);
Expand Down
Loading
Loading