Skip to content

Feature: Expose the build_fee_block#37

Merged
sephynox merged 8 commits into
mainfrom
feat/expose-build-fee-block
Jul 23, 2026
Merged

Feature: Expose the build_fee_block#37
sephynox merged 8 commits into
mainfrom
feat/expose-build-fee-block

Conversation

@sephynox

@sephynox sephynox commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

Aligns fee payment DX across Rust, WASM, WASI, and Java with TS's generateFeeBlock model.

  • Any account can now pay a staple's fee via a fee-block factory on the transmit options
  • Building a fee block is now part of the public client API.
  • The WASI module exposes the fee primitives so hosts don't reimplement client logic.

Examples

Rust

// Simpler for most cases: storage pays, owner signs
let options = TransmitOptions::default().with_fee_block_from(&storage, &owner);
client.transmit(&blocks, options).await?;

// Self-signing payer: shortest form
let options = TransmitOptions::default().with_fee_signer(&payer);
client.transmit(&blocks, options).await?;

// More flexible: factory
let payer = Arc::clone(&payer);
let options = TransmitOptions {
	generate_fee_block: Some(Arc::new(move |client, staple, priority| {
		let payer = Arc::clone(&payer);
		Box::pin(async move { client.build_fee_block(&staple, &payer, &payer, &priority).await })
	})),
	..Default::default()
};
client.transmit(&blocks, options).await?;

Java

// Simpler for most cases: storage pays, owner signs
client.transmit(blocks, TransmitOptions.defaults().withFeeBlockFrom(storage, owner));

// Self-signing payer: shortest form
client.transmit(blocks, TransmitOptions.defaults().withFeeSigner(payer));

// More flexible: factory
TransmitOptions options = TransmitOptions.defaults()
	.withGenerateFeeBlock((feeClient, staple, priority) ->
		feeClient.buildFeeBlock(staple, payer, payer, priority));

client.transmit(blocks, options);

Breaking

  • TransmitOptions.fee_signer field removed

Note

Medium Risk
Breaking transmit-options API and changes how staples are assembled and published when fees are required; mistakes affect all client bindings but behavior is heavily covered by new fee E2E tests.

Overview
Breaking: TransmitOptions.fee_signer is removed. Fee payment during transmit/recover now goes through an optional generate_fee_block callback invoked with the temporary-round staple; common cases use with_fee_signer or with_fee_block_from (delegated signing, e.g. storage account pays while the owner signs).

The Rust client adds a public build_fee_block that builds/signs the fee block from staple votes, honors fee-token priority, and chains the payer after their tip in the staple or their ledger head so the payer need not be in the round. Factory failures surface FeeBlockFactory; missing factory when fees are required still yields FEE_REQUIRED.

WASI gains staple handles and fee helpers (keeta_fees_required, keeta_staple_fee_sends, keeta_staple_tip_for, keeta_base_token, keeta_vote_staple_new), replacing the single-vote keeta_fee_send path. Java mirrors TS-style TransmitOptions / GenerateFeeBlock; WASM adds setGenerateFeeBlock, buildFeeBlock, and preserves coded errors from JS factories instead of always mapping to FEE_BLOCK_FACTORY.

CI/Makefile pin cargo install cargo-audit --locked. Block testing adds random_ed25519_ref. Fee coverage expands across Rust E2E, Playwright (fee.spec.ts + dual fee-enforcing server), and the Java fee harness (self-pay, storage/delegated pay, typed FEE_REQUIRED).

Reviewed by Cursor Bugbot for commit 6e64761. Bugbot is set up for automated code reviews on this repo. Configure here.

@sephynox
sephynox requested review from Srayman, rkeene and wezrule July 23, 2026 21:56
@sephynox sephynox self-assigned this Jul 23, 2026
@sephynox sephynox added the enhancement New feature or request label Jul 23, 2026
#[derive(Clone, Copy)]
struct FeePayer<'a> {
account: &'a AccountRef,
signer: &'a AccountRef,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In the future we might want to see if it's possible to use the type system to enforce that only keyed accounts can be the signer as is done in the TypeScript SDK

Comment thread keetanetwork-client/tests/e2e.rs Outdated
Comment thread Makefile

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a29fdf8. Configure here.

Comment thread keetanetwork-client-wasm/src/options.rs Outdated
@sonarqubecloud

Copy link
Copy Markdown

@sephynox
sephynox merged commit e2a4ef7 into main Jul 23, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants