Skip to content

chore: Update u5c to 0.18.1#97

Merged
scarmuega merged 1 commit intotxpipe:mainfrom
gonzalezzfelipe:chore/update-u5c
Mar 11, 2026
Merged

chore: Update u5c to 0.18.1#97
scarmuega merged 1 commit intotxpipe:mainfrom
gonzalezzfelipe:chore/update-u5c

Conversation

@gonzalezzfelipe
Copy link
Contributor

@gonzalezzfelipe gonzalezzfelipe commented Mar 2, 2026

Summary by CodeRabbit

  • New Features

    • Added convenience method for accessing UTXO coin values.
    • Transitioned authentication configuration to header-based format.
  • Bug Fixes

    • Improved minimum UTXO lovelace calculation with enhanced error handling for missing protocol parameters.
    • Simplified transaction submission logic.
    • Added timestamp support for block references.
  • Chores

    • Updated utxorpc and related dependencies to latest versions.

@coderabbitai
Copy link

coderabbitai bot commented Mar 2, 2026

📝 Walkthrough

Walkthrough

This PR bumps utxorpc dependencies in both balius-runtime and balius-sdk, refactors the transaction submit interface to accept wasm bytecode directly instead of file paths, replaces API key authentication with HTTP headers configuration, and adds a convenience coin() accessor method to the Utxo struct. Several test configurations are updated to align with the new authentication and wasm handling patterns.

Changes

Cohort / File(s) Summary
Dependency and Version Updates
balius-runtime/Cargo.toml, balius-sdk/Cargo.toml
Bumps utxorpc from 0.12.0 to 0.13.0 and utxorpc-spec from 0.16.0 to 0.18.1.
Runtime Block and Submit Refactoring
balius-runtime/src/lib.rs, balius-runtime/src/submit/u5c.rs
BlockRef construction now includes timestamp field; transaction submit simplified to pass single tx directly instead of batching in a vec.
SDK Utility Methods
balius-sdk/src/qol.rs, balius-sdk/src/txbuilder/dsl.rs
New coin() method added to extract coin value from Utxo; coins_per_utxo_byte now extracted from nested protocol parameter path with error handling.
API Configuration and Wasm Loading Refactoring
balius-runtime/tests/u5c-chainsync.rs, balius-runtime/tests/u5c-ledger.rs
API authentication changed from api_key string field to headers HashMap; register_worker now accepts wasm bytes (\&[u8]) instead of file path string.
Example and Test Updates
balius-runtime/tests/e2e.rs, examples/wallet/offchain/src/lib.rs
Runtime binding changed to immutable; coin value retrieval updated to use new coin() method instead of direct field access.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • scarmuega

Poem

🐰 Hopping through bytes and timestamps bright,
Headers dance where keys took flight,
Coins now bubble up with cheer,
Dependency's fresh and crystal clear!
Balius bounces to v0.13,
The finest protocol we've seen!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main objective: updating the utxorpc (u5c) dependency to version 0.18.1, which is the primary change across multiple manifest files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@balius-runtime/tests/u5c-chainsync.rs`:
- Around line 25-30: The test currently commits a real API key in the headers
assignment (the "api-key" entry and the commented api_key line); remove the
literal string and instead read the secret from an environment variable (e.g.,
std::env::var("UTXORPC_API_KEY")) when constructing headers, and fail the test
early or skip it with a clear message if the env var is not set; also delete the
commented hardcoded key and rotate the leaked key in your secret store.

In `@balius-runtime/tests/u5c-ledger.rs`:
- Around line 10-14: Replace the hardcoded API key in the test that constructs
ledgers::u5c::Ledger::new with environment-based injection: read the API key
from an env var (e.g. U5C_API_KEY) and set headers only if the variable is
present, and if not present either omit the header and run the test against a
public endpoint or early-skip the test (use a test skip/return) instead of
embedding secrets; update the Config.headers construction where headers:
Some(HashMap::from([...])) currently includes the literal key to conditionally
build headers from the env var or skip the test.

In `@balius-sdk/src/qol.rs`:
- Around line 291-293: The match arm in coin() that handles
utxorpc_spec::utxorpc::v1alpha::cardano::big_int::BigInt::Int currently does a
lossy cast (*z as u64) which wraps negatives; change it to attempt a fallible
conversion using u64::try_from(*z).ok() so negative or out-of-range i64 values
map to None instead of producing huge u64 balances, i.e. replace the direct cast
in the BigInt::Int arm with a try_from-based conversion and return that Option
result from coin().

In `@balius-sdk/src/txbuilder/dsl.rs`:
- Around line 349-351: The match arm for
utxorpc_spec::utxorpc::v1alpha::cardano::big_int::BigInt::Int(z) currently uses
a wrapping cast (*z as u64) which corrupts negative values for
coins_per_utxo_byte; replace that cast with u64::try_from(*z).ok() so negative
or out-of-range i64 values return None, and update the subsequent error handling
message that references coins_per_utxo_byte/min_lovelace to say the parameter is
invalid (not missing) when conversion fails; search for the match using
BigInt::Int and the code that computes min_lovelace/coins_per_utxo_byte to apply
this change.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99f0218 and ae7e62b.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • balius-runtime/Cargo.toml
  • balius-runtime/src/lib.rs
  • balius-runtime/src/submit/u5c.rs
  • balius-runtime/tests/e2e.rs
  • balius-runtime/tests/u5c-chainsync.rs
  • balius-runtime/tests/u5c-ledger.rs
  • balius-sdk/Cargo.toml
  • balius-sdk/src/qol.rs
  • balius-sdk/src/txbuilder/dsl.rs
  • examples/wallet/offchain/src/lib.rs

Comment on lines +25 to 30
headers: Some(HashMap::from([(
"api-key".to_string(),
"dmtr_utxorpc1wgnnj0qcfj32zxsz2uc8d4g7uclm2s2w".to_string(),
)])),
// api_key: "dmtr_utxorpc1wgnnj0qcfj32zxsz2uc8d4g7uclm2s2w".to_string(),
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Remove committed API key from test code.

Lines 25–30 expose a live credential (including in a comment). This is a security blocker; move it to environment/config secrets and rotate the leaked key.

🔐 Suggested fix
-    let chainsync_config = drivers::chainsync::Config {
+    let api_key = std::env::var("UTXORPC_API_KEY")
+        .expect("UTXORPC_API_KEY must be set for integration test");
+
+    let chainsync_config = drivers::chainsync::Config {
         endpoint_url: "https://mainnet.utxorpc-v0.demeter.run".to_string(),
         headers: Some(HashMap::from([(
             "api-key".to_string(),
-            "dmtr_utxorpc1wgnnj0qcfj32zxsz2uc8d4g7uclm2s2w".to_string(),
+            api_key,
         )])),
-        // api_key: "dmtr_utxorpc1wgnnj0qcfj32zxsz2uc8d4g7uclm2s2w".to_string(),
     };
🧰 Tools
🪛 Gitleaks (8.30.0)

[high] 29-29: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@balius-runtime/tests/u5c-chainsync.rs` around lines 25 - 30, The test
currently commits a real API key in the headers assignment (the "api-key" entry
and the commented api_key line); remove the literal string and instead read the
secret from an environment variable (e.g., std::env::var("UTXORPC_API_KEY"))
when constructing headers, and fail the test early or skip it with a clear
message if the env var is not set; also delete the commented hardcoded key and
rotate the leaked key in your secret store.

Comment on lines +10 to +14
let ledger = ledgers::u5c::Ledger::new(&ledgers::u5c::Config {
endpoint_url: "https://mainnet.utxorpc-v0.demeter.run".to_string(),
api_key: "dmtr_utxorpc1wgnnj0qcfj32zxsz2uc8d4g7uclm2s2w".to_string(),
headers: Some(HashMap::from([
("api-key".to_string(), "dmtr_utxorpc1wgnnj0qcfj32zxsz2uc8d4g7uclm2s2w".to_string()),
])),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Remove hardcoded API key from test source.

Line 13 embeds a real credential in plaintext. This is a secret-leak risk and should be replaced with environment-based injection (or test skip when missing).

🔐 Suggested fix
-    let ledger = ledgers::u5c::Ledger::new(&ledgers::u5c::Config {
+    let api_key = match std::env::var("UTXORPC_API_KEY") {
+        Ok(v) => v,
+        Err(_) => {
+            eprintln!("Skipping test: UTXORPC_API_KEY is not set");
+            return;
+        }
+    };
+
+    let ledger = ledgers::u5c::Ledger::new(&ledgers::u5c::Config {
         endpoint_url: "https://mainnet.utxorpc-v0.demeter.run".to_string(),
         headers: Some(HashMap::from([
-            ("api-key".to_string(), "dmtr_utxorpc1wgnnj0qcfj32zxsz2uc8d4g7uclm2s2w".to_string()),
+            ("api-key".to_string(), api_key),
         ])),
     })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let ledger = ledgers::u5c::Ledger::new(&ledgers::u5c::Config {
endpoint_url: "https://mainnet.utxorpc-v0.demeter.run".to_string(),
api_key: "dmtr_utxorpc1wgnnj0qcfj32zxsz2uc8d4g7uclm2s2w".to_string(),
headers: Some(HashMap::from([
("api-key".to_string(), "dmtr_utxorpc1wgnnj0qcfj32zxsz2uc8d4g7uclm2s2w".to_string()),
])),
let api_key = match std::env::var("UTXORPC_API_KEY") {
Ok(v) => v,
Err(_) => {
eprintln!("Skipping test: UTXORPC_API_KEY is not set");
return;
}
};
let ledger = ledgers::u5c::Ledger::new(&ledgers::u5c::Config {
endpoint_url: "https://mainnet.utxorpc-v0.demeter.run".to_string(),
headers: Some(HashMap::from([
("api-key".to_string(), api_key),
])),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@balius-runtime/tests/u5c-ledger.rs` around lines 10 - 14, Replace the
hardcoded API key in the test that constructs ledgers::u5c::Ledger::new with
environment-based injection: read the API key from an env var (e.g. U5C_API_KEY)
and set headers only if the variable is present, and if not present either omit
the header and run the test against a public endpoint or early-skip the test
(use a test skip/return) instead of embedding secrets; update the Config.headers
construction where headers: Some(HashMap::from([...])) currently includes the
literal key to conditionally build headers from the env var or skip the test.

Comment on lines +291 to +293
utxorpc_spec::utxorpc::v1alpha::cardano::big_int::BigInt::Int(z) => {
Some(*z as u64)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's find and examine the qol.rs file
find . -name "qol.rs" -type f

Repository: txpipe/balius

Length of output: 80


🏁 Script executed:

# Check the structure of the repository
git ls-files | head -20

Repository: txpipe/balius

Length of output: 552


🏁 Script executed:

# Search for the coin() method in the codebase
rg "fn coin" -A 15

Repository: txpipe/balius

Length of output: 843


🏁 Script executed:

# Look for the utxorpc-spec dependency version
fd "Cargo.toml" | xargs grep -l "utxorpc" 2>/dev/null

Repository: txpipe/balius

Length of output: 140


🏁 Script executed:

# Check the balius-sdk Cargo.toml for utxorpc-spec version
cat balius-sdk/Cargo.toml

Repository: txpipe/balius

Length of output: 892


🏁 Script executed:

# Search for BigInt type definition in the codebase
rg "enum BigInt" -A 10

Repository: txpipe/balius

Length of output: 39


🏁 Script executed:

# Also search for where BigInt is imported from
rg "BigInt::" | head -20

Repository: txpipe/balius

Length of output: 673


🏁 Script executed:

# Check how BigInt::Int is handled in dsl.rs
rg "BigInt::Int" -B 3 -A 3 balius-sdk/src/txbuilder/dsl.rs

Repository: txpipe/balius

Length of output: 347


🏁 Script executed:

# Let's also check the full context around the coin() method in qol.rs
cat -n balius-sdk/src/qol.rs | sed -n '280,300p'

Repository: txpipe/balius

Length of output: 750


🌐 Web query:

utxorpc-spec 0.18.1 Rust BigInt::Int type definition cardano

💡 Result:

In utxorpc-spec Rust crate v0.18.1, Cardano’s BigInt::Int is the Int(i64) variant of the generated enum:

pub enum BigInt {
    Int(i64),
    BigUInt(Bytes),
    BigNInt(Bytes),
}

So the BigInt::Int payload/type is i64. [1]


🏁 Script executed:

# Check the similar pattern in dsl.rs to see if it has the same issue
cat -n balius-sdk/src/txbuilder/dsl.rs | grep -B 5 -A 5 "BigInt::Int"

Repository: txpipe/balius

Length of output: 512


Fix lossy cast in coin() extraction.

Line 292 casts an i64 to u64 without bounds checking. Since BigInt::Int holds i64 values from utxorpc-spec 0.18.1, negative values will wrap to very large u64s, producing incorrect balances. Use u64::try_from(*z).ok() instead to properly handle out-of-range values.

💡 Suggested fix
 impl<D> Utxo<D> {
     pub fn coin(&self) -> u64 {
         self.utxo
             .coin
             .as_ref()
             .and_then(|x| {
                 x.big_int.as_ref().and_then(|y| match y {
                     utxorpc_spec::utxorpc::v1alpha::cardano::big_int::BigInt::Int(z) => {
-                        Some(*z as u64)
+                        u64::try_from(*z).ok()
                     }
                     _ => None,
                 })
             })
             .unwrap_or_default()
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
utxorpc_spec::utxorpc::v1alpha::cardano::big_int::BigInt::Int(z) => {
Some(*z as u64)
}
utxorpc_spec::utxorpc::v1alpha::cardano::big_int::BigInt::Int(z) => {
u64::try_from(*z).ok()
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@balius-sdk/src/qol.rs` around lines 291 - 293, The match arm in coin() that
handles utxorpc_spec::utxorpc::v1alpha::cardano::big_int::BigInt::Int currently
does a lossy cast (*z as u64) which wraps negatives; change it to attempt a
fallible conversion using u64::try_from(*z).ok() so negative or out-of-range i64
values map to None instead of producing huge u64 balances, i.e. replace the
direct cast in the BigInt::Int arm with a try_from-based conversion and return
that Option result from coin().

Comment on lines +349 to +351
utxorpc_spec::utxorpc::v1alpha::cardano::big_int::BigInt::Int(z) => {
Some(*z as u64)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's find the file and examine the specific lines
find . -name "dsl.rs" -path "*/txbuilder/*" | head -5

Repository: txpipe/balius

Length of output: 90


🏁 Script executed:

# Get a broader context around the lines in question
sed -n '340,365p' balius-sdk/src/txbuilder/dsl.rs

Repository: txpipe/balius

Length of output: 1016


🏁 Script executed:

# Search for all occurrences of coins_per_utxo_byte in the file
rg "coins_per_utxo_byte" balius-sdk/src/txbuilder/dsl.rs -A 5 -B 5

Repository: txpipe/balius

Length of output: 1026


🏁 Script executed:

# Let's check the type definition of BigInt::Int to confirm the type
rg "BigInt::Int" balius-sdk/src/txbuilder/dsl.rs -B 10 -A 10 | head -40

Repository: txpipe/balius

Length of output: 881


🏁 Script executed:

# Check if utxorpc-spec is in the dependencies
find . -name "Cargo.toml" -exec grep -l "utxorpc" {} \;

Repository: txpipe/balius

Length of output: 146


🏁 Script executed:

# Check the Cargo.toml for utxorpc-spec version
grep -A 10 "utxorpc" balius-sdk/Cargo.toml | head -20

Repository: txpipe/balius

Length of output: 521


🏁 Script executed:

# Check around lines 355-357 to see if there's a similar pattern
sed -n '355,365p' balius-sdk/src/txbuilder/dsl.rs

Repository: txpipe/balius

Length of output: 513


🏁 Script executed:

# Search for type definition of BigInt in the dependencies/source
rg "BigInt" balius-sdk/Cargo.lock -A 3 | head -30

Repository: txpipe/balius

Length of output: 118


🏁 Script executed:

# Check if there's a utxorpc-spec definition file in the repo
find . -path "*/utxorpc*" -name "*.rs" | head -10

Repository: txpipe/balius

Length of output: 39


🏁 Script executed:

# Look at the imports in dsl.rs to understand the full path
head -50 balius-sdk/src/txbuilder/dsl.rs | grep -E "use|import"

Repository: txpipe/balius

Length of output: 261


🏁 Script executed:

# Let's check for the second occurrence mentioned "Also applies to: 355-357"
# First get the full context around these lines
sed -n '349,365p' balius-sdk/src/txbuilder/dsl.rs

Repository: txpipe/balius

Length of output: 730


🏁 Script executed:

# Search for all similar patterns in the file that might have the same issue
rg "as u64" balius-sdk/src/txbuilder/dsl.rs -B 5 -A 2

Repository: txpipe/balius

Length of output: 986


🏁 Script executed:

# Check the struct/module definitions to understand the full picture
ast-grep --pattern 'BigInt::Int($_) => { $$$  }'

Repository: txpipe/balius

Length of output: 39


🌐 Web query:

utxorpc-spec 0.18.1 BigInt::Int type definition Cardano coins_per_utxo_byte

💡 Result:

In utxorpc-spec 0.18.1 (Rust bindings):

  • BigInt is an enum whose Int variant is defined as Int(i64) (with the other variants BigUInt(Bytes) and BigNInt(Bytes)). [1]
  • In Cardano protocol parameters (PParams), coins_per_utxo_byte is typed as Option<BigInt>. [2]

Implication: coins_per_utxo_byte may be represented as Some(BigInt::Int(<i64>)) when it fits in 64-bit signed range, otherwise via the big-(u)int byte variants. [1][2]

Sources: [1] [2]


🏁 Script executed:

# Let's check if there are other similar patterns with BigInt::Int casting
rg "BigInt::Int" balius-sdk/src/txbuilder/dsl.rs -B 3 -A 3

Repository: txpipe/balius

Length of output: 347


🏁 Script executed:

# Count all occurrences of "as u64" specifically after BigInt::Int
grep -n "as u64" balius-sdk/src/txbuilder/dsl.rs

Repository: txpipe/balius

Length of output: 272


🏁 Script executed:

# Let's look at the complete function to understand both locations
sed -n '330,375p' balius-sdk/src/txbuilder/dsl.rs

Repository: txpipe/balius

Length of output: 1667


🏁 Script executed:

# Search for other occurrences of BigInt in the codebase that might match the "Also applies to" claim
rg "BigInt::" balius-sdk/src/txbuilder/dsl.rs -n

Repository: txpipe/balius

Length of output: 150


🏁 Script executed:

# Check if there might be another function with similar pattern
rg "as u64" balius-sdk/src/txbuilder/ -B 5 -A 2

Repository: txpipe/balius

Length of output: 2380


🏁 Script executed:

# Verify the line numbers more carefully - check what's at lines 355-357
sed -n '354,358p' balius-sdk/src/txbuilder/dsl.rs | cat -n

Repository: txpipe/balius

Length of output: 330


Replace unsafe cast with proper validation for coins_per_utxo_byte.

Line 350 uses as u64 to cast an i64, which wraps negative values and corrupts min_lovelace calculation. Use u64::try_from(*z).ok() to reject negative/invalid values, and update the error message to reflect that the parameter is invalid rather than missing.

💡 Suggested fix
             .and_then(|x| {
                 x.big_int.as_ref().and_then(|y| match y {
                     utxorpc_spec::utxorpc::v1alpha::cardano::big_int::BigInt::Int(z) => {
-                        Some(*z as u64)
+                        u64::try_from(*z).ok()
                     }
                     _ => None,
                 })
             })
             .ok_or(BuildError::LedgerError(
-                "Missing coins_per_utxo_byte protocol parameter".to_string(),
+                "Invalid coins_per_utxo_byte protocol parameter".to_string(),
             ))?;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@balius-sdk/src/txbuilder/dsl.rs` around lines 349 - 351, The match arm for
utxorpc_spec::utxorpc::v1alpha::cardano::big_int::BigInt::Int(z) currently uses
a wrapping cast (*z as u64) which corrupts negative values for
coins_per_utxo_byte; replace that cast with u64::try_from(*z).ok() so negative
or out-of-range i64 values return None, and update the subsequent error handling
message that references coins_per_utxo_byte/min_lovelace to say the parameter is
invalid (not missing) when conversion fails; search for the match using
BigInt::Int and the code that computes min_lovelace/coins_per_utxo_byte to apply
this change.

@scarmuega scarmuega merged commit e9c8cd5 into txpipe:main Mar 11, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants