From a question raised on #461: why does order.rs declare pub type U256? Target: cow-venue (L3). Wire format is free to change: nothing has been released to production.
Problem
cow-venue/src/order.rs declares two aliases that shadow well-known alloy primitives with raw byte arrays:
pub type Address = [u8; 20];
pub type U256 = [u8; 32];
U256 in an Ethereum Rust codebase means alloy_primitives::U256, a numeric type with arithmetic, ordering and parsing. This one is a byte array with none of that, so sell_amount: U256 reads as a number that can be operated on and is not. The collision is live inside this same crate: assembly.rs's doctest writes sellAmount: U256::from(1_000u64), which is alloy's U256 in that scope, so one identifier names two different types in two files. Address shadows alloy_primitives::Address identically.
Why the apparent justifications do not hold
- no_std. Self-imposed rather than required: every target here is
wasm32-wasip2, which has full std, and nexum-sdk is already a std crate. It is also hollow, because the default body slice pulls videre-sdk then nexum-sdk, which is std, so the linked artefact carries std regardless. #![no_std] constrains only this crate's own source.
- borsh.
alloy_primitives::U256 is ruint::Uint<256, 4>, and ruint (1.18.0 in the lock) ships a borsh feature. alloy-primitives exposes no passthrough for it, so enable it by declaring ruint directly with features = ["borsh"] and letting cargo unify.
- A dependency-light body slice. Illusory.
nexum-sdk depends on alloy-primitives and alloy-provider non-optionally, and body = ["dep:borsh", "dep:videre-sdk"] reaches nexum-sdk through videre-sdk. alloy-primitives is therefore already unconditionally in the body slice's graph, so marking it optional = true in this crate's manifest saves nothing.
Proposal
- Replace
pub type Address and pub type U256 with alloy_primitives::{Address, U256} in order.rs and its dependents.
- Enable borsh for ruint with a direct
ruint = { version = "1", default-features = false, features = ["borsh"] } dependency.
- Drop the
to_be_bytes / from_be_bytes hops in assembly.rs that exist only to cross the alias boundary.
- Regenerate
tests/vectors/cow-header-goldens.json if the encoding moves. No body-version bump and no #[borsh(with = ...)] byte-preserving adapter is needed: nothing is released, so the wire format may change freely. Doing this before a release is what makes it cheap.
While here
Two things this exposes, worth settling rather than carrying:
alloy-primitives being optional = true in this crate is meaningless given the transitive path above. Either drop the optionality or document what it actually gates.
#![cfg_attr(not(any(test, feature = "adapter")), no_std)] buys nothing while the crate's own dependencies are std. Decide whether cow-venue is genuinely meant to be no_std-portable, in which case the std dependency chain is the defect, or drop the attribute.
Acceptance criteria
- No type alias in cow-venue shadows an alloy primitive name.
- Amounts and addresses are
alloy_primitives::U256 and alloy_primitives::Address, borsh-encodable through ruint's feature.
- Goldens regenerated and the codec round-trips.
Problem
cow-venue/src/order.rsdeclares two aliases that shadow well-known alloy primitives with raw byte arrays:U256in an Ethereum Rust codebase meansalloy_primitives::U256, a numeric type with arithmetic, ordering and parsing. This one is a byte array with none of that, sosell_amount: U256reads as a number that can be operated on and is not. The collision is live inside this same crate:assembly.rs's doctest writessellAmount: U256::from(1_000u64), which is alloy'sU256in that scope, so one identifier names two different types in two files.Addressshadowsalloy_primitives::Addressidentically.Why the apparent justifications do not hold
wasm32-wasip2, which has full std, andnexum-sdkis already a std crate. It is also hollow, because the defaultbodyslice pullsvidere-sdkthennexum-sdk, which is std, so the linked artefact carries std regardless.#![no_std]constrains only this crate's own source.alloy_primitives::U256isruint::Uint<256, 4>, and ruint (1.18.0 in the lock) ships aborshfeature.alloy-primitivesexposes no passthrough for it, so enable it by declaringruintdirectly withfeatures = ["borsh"]and letting cargo unify.nexum-sdkdepends onalloy-primitivesandalloy-providernon-optionally, andbody = ["dep:borsh", "dep:videre-sdk"]reachesnexum-sdkthroughvidere-sdk.alloy-primitivesis therefore already unconditionally in the body slice's graph, so marking itoptional = truein this crate's manifest saves nothing.Proposal
pub type Addressandpub type U256withalloy_primitives::{Address, U256}inorder.rsand its dependents.ruint = { version = "1", default-features = false, features = ["borsh"] }dependency.to_be_bytes/from_be_byteshops inassembly.rsthat exist only to cross the alias boundary.tests/vectors/cow-header-goldens.jsonif the encoding moves. No body-version bump and no#[borsh(with = ...)]byte-preserving adapter is needed: nothing is released, so the wire format may change freely. Doing this before a release is what makes it cheap.While here
Two things this exposes, worth settling rather than carrying:
alloy-primitivesbeingoptional = truein this crate is meaningless given the transitive path above. Either drop the optionality or document what it actually gates.#![cfg_attr(not(any(test, feature = "adapter")), no_std)]buys nothing while the crate's own dependencies are std. Decide whether cow-venue is genuinely meant to be no_std-portable, in which case the std dependency chain is the defect, or drop the attribute.Acceptance criteria
alloy_primitives::U256andalloy_primitives::Address, borsh-encodable through ruint's feature.