Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
edc0bd3
Merge master (v0.21.3 release) back into develop
jdogresorg Oct 3, 2026
d232340
Regenerate CI tier timing block
jdogresorg Oct 4, 2026
64c5da8
test identity pin exports
jdogresorg Oct 4, 2026
35efe72
test first input key binding and reservations
jdogresorg Oct 4, 2026
2c413e6
sync trunk
jdogresorg Oct 4, 2026
b8e5a7d
sync trunk
jdogresorg Oct 4, 2026
1e1cb10
sync trunk
jdogresorg Oct 4, 2026
a9722e3
split identity pin test suites
jdogresorg Oct 4, 2026
c27311f
verify first input key unit coverage
jdogresorg Oct 4, 2026
92875bb
test validator value checks
jdogresorg Oct 4, 2026
ceadb67
Split validator test suites
jdogresorg Oct 4, 2026
53c6762
Make UTXO complexity test deterministic
jdogresorg Oct 4, 2026
2cfeb6d
Keep UTXO complexity test within structure limits
jdogresorg Oct 4, 2026
6f71a02
Merge: Keep UTXO complexity test within structure limits
jdogresorg Oct 4, 2026
bee8cbb
sync trunk
jdogresorg Oct 4, 2026
a05ba0a
sync trunk
jdogresorg Oct 4, 2026
945d901
fix: allow additive suite-title growth
jdogresorg Oct 5, 2026
bb1b1ec
test: exercise suite title compare CLI
jdogresorg Oct 5, 2026
71a69ae
Merge: sync trunk
jdogresorg Oct 5, 2026
6c699fb
Merge: test: exercise suite title compare CLI
jdogresorg Oct 5, 2026
e93f470
Merge: split identity pin test suites
jdogresorg Oct 5, 2026
c4aaf70
Merge: verify first input key unit coverage
jdogresorg Oct 5, 2026
5837cf3
sync trunk
jdogresorg Oct 5, 2026
56350c1
Confirm generated CI tier timing block
jdogresorg Oct 5, 2026
8b22769
Merge: Confirm generated CI tier timing block
jdogresorg Oct 5, 2026
f2d773e
Route encoder api env reads through the config module
jdogresorg Oct 5, 2026
cf092c2
Merge: Route encoder api env reads through the config module
jdogresorg Oct 5, 2026
c959f56
Exempt every spelling of the OpenRPC spec route from the key gate, ap…
jdogresorg Oct 6, 2026
280dbff
Cover a multi-chunk payload through one P2SH fund tx
jdogresorg Oct 6, 2026
8374509
sync trunk
jdogresorg Oct 6, 2026
2a55aa3
Add the CLA Assistant step to the encoder PR checklist
jdogresorg Oct 6, 2026
f515908
Merge: Add the CLA Assistant step to the encoder PR checklist
jdogresorg Oct 6, 2026
9c6c5ef
sync trunk
jdogresorg Oct 6, 2026
ffe475b
Merge: sync trunk
jdogresorg Oct 6, 2026
f5a17f9
Review round 2026-10-06: 4 review fixes in xchain-encoder
jdogresorg Oct 7, 2026
80a0a3d
Review round 2026-10-06: 3 review fixes in xchain-encoder
jdogresorg Oct 7, 2026
690139e
Clarify AGPL attribution term
jdogresorg Oct 7, 2026
b8535b6
Review round 2026-10-06, second pass: 1 review fix in xchain-encoder
jdogresorg Oct 7, 2026
3271718
Review round 2026-10-06, third pass: 1 review fix in xchain-encoder
jdogresorg Oct 7, 2026
4b0f7f9
Merge: Clarify AGPL attribution term
jdogresorg Oct 7, 2026
155b3a6
Review round 2026-10-06, fourth pass: 1 review fix in xchain-encoder
jdogresorg Oct 7, 2026
4c0486a
Route coin conformance through sibling guard
jdogresorg Oct 7, 2026
05b6195
Merge: Route coin conformance through sibling guard
jdogresorg Oct 7, 2026
d4ec74c
Add UTXO_TRACKER_PROFILE=remote fail-closed tracker profile
jdogresorg Oct 7, 2026
489a4bd
test: re-vendor action manifest settlement anchors
jdogresorg Oct 7, 2026
bb91b19
Refactor trackerless profile test layout
jdogresorg Oct 7, 2026
94d4aac
Answer node rejections from broadcast_tx as -32010 with the node code
jdogresorg Oct 7, 2026
68bd2ce
Consolidate tracker profile test coverage
jdogresorg Oct 7, 2026
7da12e9
Cover connector-to-controller node code propagation in broadcast_tx test
jdogresorg Oct 7, 2026
6253e0c
Split connector node code cases into their own suite
jdogresorg Oct 7, 2026
a8eb953
test: sync BET version 4 manifest
jdogresorg Oct 7, 2026
a487d84
test: pin published taproot envelope vectors
jdogresorg Oct 7, 2026
678b5f6
test: group taproot vector suite
jdogresorg Oct 7, 2026
c702060
test: place taproot vectors at declared path
jdogresorg Oct 7, 2026
88da5cd
Merge: Consolidate tracker profile test coverage
jdogresorg Oct 8, 2026
63f2577
Merge: Split connector node code cases into their own suite
jdogresorg Oct 8, 2026
7412bc7
sync trunk
jdogresorg Oct 8, 2026
690d39e
test: restore published vectors to nested suite
jdogresorg Oct 8, 2026
2610fd0
Fix encoder validator and cancel-envelope findings
jdogresorg Oct 8, 2026
a9315f8
sync trunk
jdogresorg Oct 8, 2026
b31479c
test: assert published envelope grammar
jdogresorg Oct 8, 2026
ca86144
Re-sync the coin registry from the canonical xchain-hub/src/coins
jdogresorg Oct 8, 2026
90ea857
sync trunk
jdogresorg Oct 8, 2026
5c2102b
test: exercise published Taproot envelope vectors
jdogresorg Oct 8, 2026
96deef4
test: split published vector assertions
jdogresorg Oct 8, 2026
e7db35c
test: resolve published vectors from sibling
jdogresorg Oct 8, 2026
165c3f8
Merge: test: resolve published vectors from sibling
jdogresorg Oct 8, 2026
3409cc5
Merge: test: re-vendor action manifest settlement anchors
jdogresorg Oct 8, 2026
decc58c
sync trunk
jdogresorg Oct 8, 2026
6ed1bb6
test: tolerate staged BET manifest landing
jdogresorg Oct 8, 2026
0aea6dd
test: enforce exact action manifest identity
jdogresorg Oct 8, 2026
a50ea4a
Merge BET format 4 lane work.
jdogresorg Oct 8, 2026
e48c5fe
Repin the vendored action manifest hash after the BET format 4 re-ven…
jdogresorg Oct 8, 2026
bcd62bb
fix: review round corrections
jdogresorg Oct 8, 2026
65fd444
Bound fragmented input selection at transaction cap
jdogresorg Oct 8, 2026
0b5c5e8
Refuse a capped unconfirmed selection with NO_CONFIRMED_UTXO
jdogresorg Oct 9, 2026
e157a82
Preserve the unconfirmed input cap contract
jdogresorg Oct 9, 2026
ba376c9
Defer capped selections containing mempool inputs
jdogresorg Oct 9, 2026
b04ab86
Archive orphaned encoder work as patch
jdogresorg Oct 9, 2026
a64f06e
Return retryable errors for capped dust selection
jdogresorg Oct 9, 2026
750e6f6
Sanitize archived patch subject
jdogresorg Oct 9, 2026
54440de
Sanitize archived patch references
jdogresorg Oct 9, 2026
327d6f6
Group capped selection tests under existing suite
jdogresorg Oct 9, 2026
46f6f61
Merge: Sanitize archived patch references
jdogresorg Oct 9, 2026
e327c8a
sync trunk
jdogresorg Oct 9, 2026
3f716c2
Nest capped selection tests
jdogresorg Oct 9, 2026
b6a2000
Clarify JSON-RPC error retry ownership
jdogresorg Oct 9, 2026
43c79f8
Merge: Clarify JSON-RPC error retry ownership
jdogresorg Oct 9, 2026
2906b0b
sync trunk
jdogresorg Oct 9, 2026
aafacf9
Preserve capped selection error contract
jdogresorg Oct 9, 2026
78273a3
Merge: Nest capped selection tests
jdogresorg Oct 9, 2026
b5e2293
Merge: Preserve capped selection error contract
jdogresorg Oct 9, 2026
495deec
Fix 4 review findings in xchain-encoder
jdogresorg Oct 9, 2026
ad10959
Sync the canonical action manifest
jdogresorg Oct 9, 2026
1c53085
Sync sibling checkout helper
jdogresorg Oct 9, 2026
bd03330
Merge: Sync sibling checkout helper
jdogresorg Oct 9, 2026
73ed42f
Set the repo git identity at session start and turn attribution off
jdogresorg Oct 10, 2026
2ccbe9b
Release v0.23.0
jdogresorg Oct 11, 2026
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
17 changes: 17 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"attribution": false,
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "git config user.name 'J-Dog' && git config user.email 'j-dog@j-dog.net' || true",
"timeout": 10,
"statusMessage": "Setting the repo git identity"
}
]
}
]
}
}
9 changes: 7 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,19 @@ ENCODER_API_PORT=3003
UTXO_TRACKER_URL=127.0.0.1
UTXO_TRACKER_API_PORT=3001

# Optional: "remote" makes the tracker mandatory and fails closed. A missing
# URL or port, an unreachable tracker, or a missing, halted, stale or not-ready
# sync state each refuse with a typed error. Default keeps the lenient behaviour.
# UTXO_TRACKER_PROFILE=remote

# Optional: cap fee-rate estimates at this sat/kB ceiling.
# MAX_FEE_RATE_KB=200000

# Optional: relative fee-rate ceiling as a multiple of the node's
# estimatesmartfee(1) estimate (default 100). Caps caller-supplied fee/feePerKb
# so a hostile request cannot drain inputs into miner fee. Set to 0 to disable
# (not recommended; a fixed 100x burn backstop still applies when
# MAX_FEE_RATE_KB is unset); an unset/unparseable value keeps the default.
# (not recommended; a fixed 100x burn backstop still applies whatever this
# or MAX_FEE_RATE_KB says); an unset/unparseable value keeps the default.
# MAX_FEE_RATE_MULTIPLIER=100

# Optional: ceiling (base units) on the extra fee a transaction spending
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.23.0] - 2026-10-11

### Added
- Added the remote tracker profile that fails closed.
- Answered node rejections from broadcast_tx as error -32010 with the node code.

### Changed
- Bounded fragmented input selection at the transaction cap and refused capped unconfirmed selections.
- Rounded fees up and shared one caller fee-rate cap with a node-anchored burn backstop.

### Fixed
- Returned retryable errors for capped dust selection and deferred capped selections that contain mempool inputs.
- Mirrored exact PSBT fee totals past 2^53 from the SDK copy.

## [0.21.0] - 2026-09-29

### Added
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ CI is the smoke + unit gate. Before opening a PR:
2. Update `CHANGELOG.md` with a terse entry for your change.
3. Make sure `git status` is clean apart from intended changes (no `node_modules/`, no editor leftovers, no `.env`).
4. Open the PR with a clear title and a description of what changed and why.
5. Agree to the Contributor License Agreement when the CLA Assistant bot links it on your first PR. The bot records your signature once for every XChain Platform repository, and its `license/cla` check must pass before the PR can merge.

For non-security bugs, open an issue at <https://github.com/XChain-Platform/xchain-encoder/issues/new>. For security bugs, see [`SECURITY.md`](./SECURITY.md).

Expand Down
6 changes: 4 additions & 2 deletions NOTICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ For commercial licensing, contact **legal@dankest.llc**.

## Attribution

Any redistribution or modification of this software must retain the following
attribution, per the AGPL and the project's trademark policy:
As an additional term under section 7(b) of the GNU Affero General Public
License v3.0, any redistribution or modification of this software must preserve
the following author attribution in its source and in the Appropriate Legal
Notices displayed by any work containing it:

> Based on XChain Platform by Dankest, LLC - https://dankest.llc

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ PSBT encoding service for the XChain Platform. Takes an ACTION string, a set of
- **Two-transaction P2SH/P2WSH**: automatic tx1 (fund) -> tx2 (spend/reveal) orchestration with marker OP_RETURN
- **UTXO selection**: largest-first selection, duplicate removal, optional unconfirmed filtering, automatic change output
- **Fee estimation**: byte-accurate transaction size estimation per format via `TxSizeEstimator`; dust floor enforcement
- **Fee rate caps**: caller-supplied `fee`/`feePerKb` is capped at `MAX_FEE_RATE_MULTIPLIER` x the node's own fee estimate (default 100x), so a hostile or buggy request cannot drain inputs into miner fee; `MAX_FEE_RATE_KB` adds an optional absolute cap. The envelope cancel (`create_envelope_cancel_tx`) applies the same caps, and both anchor on the node's relayfee when it has no fee estimate
- **Fee rate caps**: caller-supplied `fee`/`feePerKb` is capped at `MAX_FEE_RATE_MULTIPLIER` x the node's own fee estimate (default 100x), so a hostile or buggy request cannot drain inputs into miner fee; `MAX_FEE_RATE_KB` adds an optional absolute cap, and a fixed 100x burn backstop holds even when either cap is looser or disabled. The envelope cancel (`create_envelope_cancel_tx`) applies the same caps, and both anchor on the node's relayfee when it has no fee estimate
- **Input validation**: centralized parameter validation (`validator.js`) with typed errors for all 15 `createTransaction` parameters
- **Multi-chain support**: Bitcoin, Litecoin, and Dogecoin today on mainnet, testnet, and regtest (9 network configs)
- **Replace-By-Fee**: optional RBF signaling via sequence number
Expand Down Expand Up @@ -77,12 +77,12 @@ npm run api
| `NODE_USER` | Yes | (none) | RPC username |
| `NODE_PASSWORD` | Yes | (none) | RPC password |
| `ENCODER_API_PORT` | No | `3000` | JSON-RPC API port |
| `NODE_RPC_TIMEOUT` | No | `30000` | Coin-node RPC call timeout in milliseconds |
| `NODE_RPC_TIMEOUT` | No | `30000` | Coin-node RPC call timeout in milliseconds; must be a positive integer, and an empty or invalid value falls back to `30000` with a warning |
| `UTXO_TRACKER_URL` | No | (none) | xchain-utxo-tracker service host |
| `UTXO_TRACKER_API_PORT` | No | (none) | xchain-utxo-tracker service port |
| `UTXO_TRACKER_MAX_LAG_BLOCKS` | No | `2` | Max blocks the utxo-tracker's reported sync lag may be before `create_tx` refuses to select UTXOs from it. `GET /status` publishes the effective value as `tracker_max_lag_blocks`, so a status board can rank lag against the other unready causes without mirroring a constant it cannot see (the tracker's own `SYNCED_THRESHOLD` is looser and is not this gate) |
| `MAX_FEE_RATE_KB` | No | Uncapped | Absolute maximum fee rate in sat/kB |
| `MAX_FEE_RATE_MULTIPLIER` | No | `100` | Caps caller-supplied fee/feePerKb at this multiple of the node's fee estimate (`0` disables this cap; with `MAX_FEE_RATE_KB` also unset, a fixed 100x burn backstop still clamps feePerKb and refuses an explicit fee) |
| `MAX_FEE_RATE_MULTIPLIER` | No | `100` | Caps caller-supplied fee/feePerKb at this multiple of the node's fee estimate (`0` disables this cap). Whatever this and `MAX_FEE_RATE_KB` are set to, a fixed 100x burn backstop still clamps feePerKb and refuses an explicit fee, so a value above `100` loosens nothing past 100x |
| `MAX_CPFP_UPLIFT_SAT` | No | `10000000` | Most a transaction spending unconfirmed inputs may add to its fee so the whole mempool package reaches the target rate (`0` disables package-aware sizing) |
| `FEE_NO_ESTIMATE_RELAY_MULTIPLIER` | No | `10` | Multiple of the node's relay floor charged on a non-mainnet chain when `estimatesmartfee` has no data. Raise it where miners ignore the documented rate (`100` gives 0.1 DOGE/kB). Mainnet is unaffected |
| `DUST_AMOUNT` | No | Coin default | Floor in base units on every value output the encoder authors (funding legs, data outputs, change). Only raises the floor: the coin's consensus dust threshold and its relay-policy soft-dust floor (Dogecoin: 0.01 DOGE, below which each output adds the whole limit to the required relay fee) already apply |
Expand Down
1 change: 1 addition & 0 deletions bin/ci-full.sh
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ ci_tier_deferred() {
# >>> ci-tier timer (generated block; re-run the tier wirer to update) >>>
run_tier() {
ci_tier_deferred "$1" && return 0 # ci-tier guard (generated)
if [ "${CI_TIER:-full}" = "fast" ] && [ -n "${FAILED:-}" ]; then echo; echo "ci:full ===== $1 NOT RUN (a push stops at its first red tier, its verdict already red; the full sweep runs it) ====="; return 0; fi # ci-tier stop (generated)
local name="$1"; shift
local __ci_tier_t0=$SECONDS
echo; echo "ci:full ===== $name ====="
Expand Down
10 changes: 5 additions & 5 deletions bin/pins/at1-identity.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"capturedAt": "2026-10-01T05:39:07.006Z",
"capturedAt": "2026-10-09T19:55:43.652Z",
"coins": {
"src/coins/BTC.js": "92f1e7d143f844886700f40deb53cb02bb7c6c270ab4bb837488f5d8535629b6",
"src/coins/LTC.js": "d7cf410caea44a18c3c5cac07ab7f47507af8680ec3cbbec4f54ab8cd09fc0b9",
"src/coins/DOGE.js": "3b1aac3d95ca96fd6a7f53c4af169e4e845effb77d00058473bda4d4786e397b",
"src/coins/BTC.js": "182baf5173e3846b94a5edc1ae15913a54fb266addfc45a3cf9a013bd9ec16c6",
"src/coins/LTC.js": "6155195bfa5fdfeab77dec3802ce67b5cc47a77695e81a4a5545d980e4c421dd",
"src/coins/DOGE.js": "4659b45fb7a5c959ce2777ab9d5e7c193f3515f03cdd8cd23bb6b9c4d012fc11",
"src/coins/index.js": "08b678d934fa647d3c7d14dc5ccdaeb86722ee32a3662de69e4a31cd7b09234c",
"src/coins/consensus_pin.js": "342bf7af224a19ea0a98ff9cfb2c9a70b3fd5be75de7ecef2db05936f82baa63"
},
Expand All @@ -13,7 +13,7 @@
"src/observability/index.js": "6d29637dc3a815d896076642823393866e4f74a68b59dc363ff1cd828aff422a",
"src/observability/logShipper.js": "fbb1e5b3f01229417117c718da24ee2d62fefd9740adbbec2a4e941a67dbd027",
"src/observability/metrics.js": "b29a0f2855e0dc4d8d97dde22c36daa6ab0408391945eda1b47b47398c0cd261",
"test/fixtures/action-manifest.json": "e4b386bf166203f65d0cd8a246bc0820a2518ed570ab2112367169dd8a5c1e69",
"test/fixtures/action-manifest.json": "2be99c8a8adbcfbeb9d545e8dc42663323cdb15351a39373ccd38fabf48e58ff",
"test/fixtures/roundtrip-conformance.json": "d9963ac7c35bdcfab99595fec040d7791d73119cb62fef20db136f8ea56236ed",
"test/fixtures/utxo-record-conformance.json": "ca9051b2dcacbcdded68d53089eea4b6a2ba0d498d1ee14eb95342ab0f7da5ff",
"tools/release/release-signing-fingerprint.txt": "a216bc460bc978da7011d8ed0a0e203d87f97d3bd14ef6c79283a05bb263d1db",
Expand Down
Loading
Loading