Skip to content
Open
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
20 changes: 15 additions & 5 deletions crates/nexum-macros/src/world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct Capability {
adapter: Option<&'static str>,
}

/// Every capability the macro recognizes, in emission order. Mirrors
/// Every capability the macro recognises, in emission order. Mirrors
/// the runtime's core registry plus the extension namespaces the
/// workspace ships (`nexum:intent/pool`, `shepherd:cow/cow-api`).
const KNOWN: &[Capability] = &[
Expand Down Expand Up @@ -114,9 +114,9 @@ pub fn manifest_capabilities(text: &str) -> Result<Vec<String>, String> {
.parse()
.map_err(|e| format!("module.toml is not valid TOML: {e}"))?;
let caps = value.get("capabilities").ok_or_else(|| {
"module.toml has no [capabilities] section; #[nexum_sdk::module] derives the module's \
WIT world from [capabilities].required/optional, so declare it (an empty `required = []` \
is valid)"
"module.toml has no [capabilities] section; the module/adapter macro derives the \
component's WIT world from [capabilities].required/optional, so declare it (an empty \
`required = []` is valid)"
.to_string()
})?;
let list = |key: &str| -> Result<Vec<String>, String> {
Expand Down Expand Up @@ -171,14 +171,24 @@ pub fn synthesize_venue(declared: &[String]) -> Result<ModuleWorld, String> {
// value-flow vocabulary they are expressed in) resolves against the
// same base package set every module world carries, in dependency
// order: a package precedes its dependants.
let packages = vec!["nexum-value-flow", "nexum-intent", "nexum-host"];
let mut packages = vec!["nexum-value-flow", "nexum-intent", "nexum-host"];
for cap in KNOWN {
if !declared.iter().any(|d| d == cap.name) {
continue;
}
if let Some(import) = cap.import {
writeln!(imports, " import {import};").expect("write to String");
}
// Accumulate any extra WIT packages a venue capability needs, exactly
// as `synthesize` does. All venue-permitted capabilities are
// packageless today, so this leaves the base set untouched; mirroring
// the loop keeps a future venue capability from silently failing to
// reach its package onto the resolve path.
for package in cap.packages {
if !packages.contains(package) {
packages.push(package);
}
}
}

let mut wit = String::from(
Expand Down
8 changes: 8 additions & 0 deletions crates/nexum-runtime/src/host/pool_router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,14 @@ impl PoolRouter {
/// caller before returning, so a caller feeding garbage exhausts its own
/// budget and is stopped at the gate on the next call rather than
/// re-invoking the adapter.
///
/// Charging is deliberately asymmetric across the two stages. Once the
/// guard admits the header the submission is charged before the adapter
/// call, so a forwarded submission spends one unit regardless of the
/// venue's outcome (the adapter did the work, and a transient venue
/// outage must not become a free retry loop). A derive-stage venue error
/// that is not a decode failure is the venue's fault, not the caller's,
/// so it is left uncharged and the caller may retry.
pub async fn submit(
&self,
caller: &str,
Expand Down
6 changes: 3 additions & 3 deletions crates/nexum-venue-test/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub struct GoldenHeader {
pub valid_until: Option<u64>,
/// Where the deal settles.
pub settlement: GoldenSettlement,
/// How the venue authorizes the intent.
/// How the venue authorises the intent.
pub authorisation: GoldenAuthScheme,
}

Expand Down Expand Up @@ -152,11 +152,11 @@ pub enum GoldenAuthScheme {
Eip712,
/// EIP-1271 contract signature.
Eip1271,
/// Pre-signed authorization at the settlement contract.
/// Pre-signed authorisation at the settlement contract.
Presign,
/// Venue-defined off-chain signature scheme.
OffchainSig,
/// No authorization travels with the body.
/// No authorisation travels with the body.
Unsigned,
}

Expand Down
2 changes: 1 addition & 1 deletion crates/nexum-venue-test/src/reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub enum ReferenceBody {
/// The reference venue's pure header derivation, the subject the
/// published goldens pin. Gives the amount as chain-1 native token,
/// wants (for v2) the same amount as an ERC-20 at the recipient
/// address, and authorizes via EIP-712.
/// address, and authorises via EIP-712.
pub fn derive_reference_header(body: Vec<u8>) -> Result<IntentHeader, VenueError> {
let (amount_wei, valid_until, wants) = match ReferenceBody::from_bytes(&body)? {
ReferenceBody::V1(quote) => (quote.amount_wei, None, Vec::new()),
Expand Down
10 changes: 5 additions & 5 deletions wit/nexum-intent/types.wit
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package nexum:intent@0.1.0;

/// The venue-neutral intent ontology: what a deal gives and wants, how the
/// venue authorizes it, and how its life at the venue is reported. Built on
/// venue authorises it, and how its life at the venue is reported. Built on
/// the nexum:value-flow vocabulary so a submission is described the same
/// way to strategy modules, venue adapters, and guard policy. The package
/// deliberately does not depend on nexum:host: embedding the host fault
Expand All @@ -16,20 +16,20 @@ package nexum:intent@0.1.0;
interface types {
use nexum:value-flow/types@0.1.0.{asset-amount, settlement};

/// How an intent is authorized at its venue.
/// How an intent is authorised at its venue.
variant auth-scheme {
/// An EIP-712 typed-data signature by host-held keys. The only
/// scheme that reaches the identity checkpoint at submit time.
eip712,
/// An EIP-1271 contract signature: consent happened on-chain when
/// the commitment was created, so the host signs nothing here.
eip1271,
/// A pre-signed authorization recorded at the settlement contract
/// A pre-signed authorisation recorded at the settlement contract
/// ahead of submission.
presign,
/// A venue-defined off-chain signature scheme.
offchain-sig,
/// No authorization travels with the body.
/// No authorisation travels with the body.
unsigned,
}

Expand All @@ -48,7 +48,7 @@ interface types {
valid-until: option<u64>,
/// Where the deal settles.
settlement: settlement,
/// How the venue authorizes the intent.
/// How the venue authorises the intent.
authorisation: auth-scheme,
}

Expand Down
13 changes: 12 additions & 1 deletion wit/nexum-value-flow/types.wit
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,12 @@ interface types {
/// tuple carries raw big-endian bytes: a 20-byte address, and for the
/// NFT cases a token id of arbitrary width.
variant asset {
/// The settlement domain's own gas token (ETH, BZZ, ...).
/// The settlement domain's own gas token (ETH, BZZ, ...). Only an
/// on-chain settlement carries a gas token, so `native-token` pairs
/// meaningfully with `settlement.evm-chain`; `native-token(offchain)`
/// is representable but intentionally invalid -- an off-chain domain
/// has no gas token -- so consumers MUST reject that pairing rather
/// than ascribe a meaning to it.
native-token(settlement),
/// An ERC-20 token: (chain id, 20-byte contract address).
erc20(tuple<u64, list<u8>>),
Expand All @@ -80,6 +85,12 @@ interface types {
/// most-significant byte first, with no fixed width; an empty list is
/// zero. Amounts are never negative -- direction lives in whichever
/// field holds the pair (a header's `gives` vs `wants`), not here.
///
/// The canonical wire form is minimal-length: no leading zero bytes, so
/// zero is the empty list and five is `[0x05]`, never `[0x00, 0x05]`.
/// Encoders MUST emit the minimal form; decoders MUST compare amounts by
/// integer value, not by byte equality, so a non-minimal encoding from a
/// lenient peer still compares equal to its canonical twin.
record asset-amount {
asset: asset,
amount: list<u8>,
Expand Down
Loading