Skip to content

chore: derive an agent wallet's address from its rules#1387

Merged
MicBun merged 1 commit into
mainfrom
feat/maa-precompiles
Jun 2, 2026
Merged

chore: derive an agent wallet's address from its rules#1387
MicBun merged 1 commit into
mainfrom
feat/maa-precompiles

Conversation

@MicBun
Copy link
Copy Markdown
Contributor

@MicBun MicBun commented Jun 1, 2026

resolves: https://github.com/truflation/website/issues/4035

What

Part 1 of the Modular Agent Addresses (MAA) rule store: the two pure tn_utils precompiles that derive a
deterministic agent-wallet address. Go only, no database, no consensus change.

Changes

  • compute_rules_hash(...)keccak256 of the canonical rule serialization (fee + allow-list, with a canonical
    dedup/sort and a version byte).
  • derive_maa_address(...) → low 20 bytes of keccak256(version ‖ restricted ‖ unrestricted ‖ rules_hash ‖ salt).
  • keccak256 is go-ethereum (Ethereum keccak), not NIST SHA3.
  • Golden-vector + determinism unit tests (maa_test.go).

Testing

  • go vet ./extensions/tn_utils/ — clean
  • go test ./extensions/tn_utils/ -run 'MAA|RulesHash|DeriveMAA' — pass

Notes

  • The SQL rule store that calls these precompiles is in a stacked follow-up PR.
  • A shared golden-vector fixture for cross-language SDK derivation will be added in a follow-up.

Summary by CodeRabbit

  • New Features
    • Added derive_maa_address and compute_rules_hash precompile functions to tn_utils for deterministic Modular Agent Address generation and rules hashing with automatic deduplication and canonical sorting.

@MicBun MicBun self-assigned this Jun 1, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces two deterministic cryptographic precompile functions (derive_maa_address and compute_rules_hash) to the tn_utils extension. Both functions compute deterministic outputs by canonicalizing their inputs, building frozen preimage structures, and hashing via Keccak-256. The changes include comprehensive test validation and precompile bundle registration.

Changes

MAA Precompile Implementation

Layer / File(s) Summary
Constants and foundational types
extensions/tn_utils/maa.go
Version byte constants for address and rules preimage layouts; helper struct for canonical allow-list entry representation carrying namespace, action, and optional body hash.
derive_maa_address precompile
extensions/tn_utils/maa.go
Precompile method wiring and core address derivation: validates restricted/unrestricted (20 bytes each) and rules_hash (32 bytes), concatenates canonical address preimage with optional salt, and returns low 20 bytes of Keccak-256 hash.
Utility encoding and parsing helpers
extensions/tn_utils/maa.go
Length-prefixed byte encoding (maaWriteLP8), base-10 fee_flat parsing constrained to 256 bits, and TEXT/TEXT[] type normalization for precompile input coercion.
compute_rules_hash precompile
extensions/tn_utils/maa.go
Precompile method wiring and core rules hash computation: validates fee mode, amounts, bridge, and allow-list array lengths; builds canonical rules preimage with deduplicated and bytewise-sorted (namespace, action) entries; returns Keccak-256 hash.
Test suite and validation
extensions/tn_utils/maa_test.go
Golden-vector tests for both functions, invariance tests (order-independence and deduplication for compute_rules_hash; salt/key/order sensitivity for derive_maa_address), and error handling validation for invalid input lengths and numeric constraints.
Precompile registration
extensions/tn_utils/precompiles.go
Registers deriveMAAAddressMethod and computeRulesHashMethod in the tn_utils precompile Methods list.

Sequence Diagrams

sequenceDiagram
  participant Handler as PrecompileHandler
  participant DeriveLogic as deriveMAAAddress
  participant Keccak256 as Keccak-256
  Handler->>DeriveLogic: restricted, unrestricted, rulesHash, salt
  DeriveLogic->>DeriveLogic: Validate lengths (20, 20, 32 bytes)
  DeriveLogic->>DeriveLogic: Concatenate version + inputs + salt
  DeriveLogic->>Keccak256: Hash address preimage
  Keccak256->>DeriveLogic: 32-byte digest
  DeriveLogic->>Handler: Return last 20 bytes as address
Loading
sequenceDiagram
  participant Handler as PrecompileHandler
  participant ComputeLogic as computeRulesHash
  participant Normalize as Type Normalizers
  participant Deduplicate as Deduplication & Sort
  participant Keccak256 as Keccak-256
  Handler->>ComputeLogic: fee_mode, fee_bps, fee_flat, bridge, namespaces, actions, body_hashes
  ComputeLogic->>Normalize: Coerce TEXT/TEXT[] inputs to native types
  Normalize->>ComputeLogic: Normalized values
  ComputeLogic->>ComputeLogic: Validate constraints (fee_mode, fee ranges, lengths match)
  ComputeLogic->>Deduplicate: Allow-list entries with (namespace, action, bodyHash)
  Deduplicate->>Deduplicate: Deduplicate by (namespace, action) pair
  Deduplicate->>Deduplicate: Sort bytewise by namespace then action
  Deduplicate->>ComputeLogic: Canonical sorted entries
  ComputeLogic->>ComputeLogic: Build rules preimage with version, fees, bridge, entries
  ComputeLogic->>Keccak256: Hash rules preimage
  Keccak256->>ComputeLogic: 32-byte digest
  ComputeLogic->>Handler: Return rules hash
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit hops through bytes and hashes bright,
Deriving addresses with Keccak's might,
Rules canonicalized, sorted with care,
Two precompiles woven with cryptographic flair! 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'chore: derive an agent wallet's address from its rules' partially relates to the changeset. It describes the key functionality (deriving addresses from rules), but uses 'chore' which typically indicates routine maintenance rather than feature implementation. The PR introduces two new deterministic MAA precompiles (compute_rules_hash and derive_maa_address) with supporting tests, which is more substantial than a chore.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/maa-precompiles

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.

@holdex
Copy link
Copy Markdown

holdex Bot commented Jun 1, 2026

Time Submission Status

Member Status Time Action Last Update
MicBun ✅ Submitted 4h Update time Jun 1, 2026, 9:33 PM

You can submit time with the command. Example:

@holdex pr submit-time 15m

See available commands to help comply with our Guidelines.

@MicBun MicBun changed the title feat(tn_utils): add maa address derivation precompiles chore: derive an agent wallet's address from its rules Jun 1, 2026
@MicBun
Copy link
Copy Markdown
Contributor Author

MicBun commented Jun 1, 2026

@holdex pr submit-time 4h

@MicBun MicBun requested a review from pr-time-tracker June 1, 2026 21:05
@MicBun MicBun enabled auto-merge (squash) June 1, 2026 21:07
@MicBun MicBun disabled auto-merge June 1, 2026 21:07
@MicBun MicBun marked this pull request as draft June 1, 2026 21:27
@MicBun MicBun marked this pull request as ready for review June 1, 2026 21:27
@MicBun MicBun enabled auto-merge (squash) June 1, 2026 21:28
@MicBun MicBun disabled auto-merge June 1, 2026 21:28
@MicBun
Copy link
Copy Markdown
Contributor Author

MicBun commented Jun 1, 2026

@coderabbitai approve

Copy link
Copy Markdown

@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: 1

🧹 Nitpick comments (3)
extensions/tn_utils/maa_test.go (3)

62-94: 💤 Low value

Optional: cover the duplicate-with-conflicting-body_hash case.

The dedup vector uses identical body_hash values for the duplicated (main, ob_place_order) key, so it proves dedup happens but not which entry survives when duplicates carry different bodies. A vector where the duplicate has a differing body_hash would pin down the canonical resolution rule.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extensions/tn_utils/maa_test.go` around lines 62 - 94, Test
TestComputeRulesHash_OrderIndependentAndDedup currently verifies deduplication
only when duplicated (namespace, action) entries share the same body_hash; add
an additional case that inserts a duplicate (e.g., same "main" +
"ob_place_order") with a different body_hash to assert which body wins the
canonicalization. Update the test to call computeRulesHash with the
conflicting-body duplicate (use repeatByte with a different value or nil vs
non-nil), compute the expected canonical hash (by constructing the canonical
single-entry input or by reordering inputs so the survivor is clear), and assert
bytes.Equal(base, conflicted) or compare against the explicit expected hash to
pin down the conflict-resolution rule for computeRulesHash.

161-170: 💤 Low value

Consider also asserting on a bad unrestricted length.

The test covers 19-byte restricted and 31-byte rules_hash, but not a wrong-length unrestricted, leaving that validation branch unexercised.

♻️ Optional addition
 	if _, err := deriveMAAAddress(good20, good20, repeatByte(0x33, 31), nil); err == nil {
 		t.Fatal("expected error for 31-byte rules_hash")
 	}
+	if _, err := deriveMAAAddress(good20, repeatByte(0x22, 21), good32, nil); err == nil {
+		t.Fatal("expected error for 21-byte unrestricted")
+	}
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extensions/tn_utils/maa_test.go` around lines 161 - 170, The test
TestDeriveMAAAddress_RejectsBadLengths misses exercising the invalid-length
branch for the unrestricted argument; add an assertion that calling
deriveMAAAddress with a wrong-length unrestricted slice (e.g., 21 bytes produced
by repeatByte) along with valid good20/good32 for restricted and rules_hash
returns an error. Update the test to call deriveMAAAddress(repeatByte(0x11, 21),
good20, good32, nil) and fail the test if err == nil so the unrestricted-length
validation in deriveMAAAddress is covered.

172-183: ⚡ Quick win

Add a test for mismatched allow-list array lengths.

computeRulesHash receives namespaces, actions, and body_hashes as parallel slices. The validation tests never exercise the case where these lengths differ, which is the most likely path to an index-out-of-range panic in the implementation. A test asserting an error (rather than a panic) for unequal lengths would guard that contract.

♻️ Suggested addition
 	if _, err := computeRulesHash("bps", 0, "0", "eth_truf",
 		[]string{"main"}, []string{"a"}, [][]byte{repeatByte(0x00, 31)}); err == nil {
 		t.Fatal("expected error for 31-byte body_hash")
 	}
+	// Mismatched parallel-array lengths must error, not panic.
+	if _, err := computeRulesHash("bps", 0, "0", "eth_truf",
+		[]string{"main", "main"}, []string{"a"}, [][]byte{nil}); err == nil {
+		t.Fatal("expected error for mismatched allow-list array lengths")
+	}
 }

Confirm how computeRulesHash handles unequal slice lengths today (error vs. panic) before adding the expectation:

#!/bin/bash
# Locate computeRulesHash and inspect its length validation / iteration over the parallel arrays.
ast-grep --pattern 'func computeRulesHash($$$) ($_, $_) {
  $$$
}'
rg -nP -C3 '\b(namespaces|actions|body_hashes)\b' --type=go -g '!*_test.go'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extensions/tn_utils/maa_test.go` around lines 172 - 183, The test suite lacks
a case where the parallel slices passed to computeRulesHash (namespaces,
actions, body_hashes) have mismatched lengths; add a unit test in
TestComputeRulesHash_Validation that calls computeRulesHash with differing
lengths (e.g., namespaces length 1, actions length 2, body_hashes length 1) and
assert it returns a non-nil error (or if computeRulesHash currently panics, wrap
the call in a recover/assert that a panic occurs); reference computeRulesHash to
locate validation logic and ensure the test covers the unequal-length path
rather than causing an index-out-of-range panic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@extensions/tn_utils/maa.go`:
- Around line 227-232: The dedup logic collapses entries by (namespace, action)
and silently overwrites differing body_hash values; update the loop that builds
dedup (using maaAllowEntry, namespaces, actions, bodyHashes and the dedup map)
to detect conflicts: compute key := namespace+"\x00"+action, and if dedup
already has an entry with the same key but a different bodyHash, reject by
returning an error (or propagate an appropriate error) from the caller (e.g.,
the compute_rules_hash path) instead of overwriting; alternatively, if the spec
treats body_hash as part of identity, include bodyHash in the dedup key to keep
both entries—choose one behavior and implement the corresponding
check/early-return or key change.

---

Nitpick comments:
In `@extensions/tn_utils/maa_test.go`:
- Around line 62-94: Test TestComputeRulesHash_OrderIndependentAndDedup
currently verifies deduplication only when duplicated (namespace, action)
entries share the same body_hash; add an additional case that inserts a
duplicate (e.g., same "main" + "ob_place_order") with a different body_hash to
assert which body wins the canonicalization. Update the test to call
computeRulesHash with the conflicting-body duplicate (use repeatByte with a
different value or nil vs non-nil), compute the expected canonical hash (by
constructing the canonical single-entry input or by reordering inputs so the
survivor is clear), and assert bytes.Equal(base, conflicted) or compare against
the explicit expected hash to pin down the conflict-resolution rule for
computeRulesHash.
- Around line 161-170: The test TestDeriveMAAAddress_RejectsBadLengths misses
exercising the invalid-length branch for the unrestricted argument; add an
assertion that calling deriveMAAAddress with a wrong-length unrestricted slice
(e.g., 21 bytes produced by repeatByte) along with valid good20/good32 for
restricted and rules_hash returns an error. Update the test to call
deriveMAAAddress(repeatByte(0x11, 21), good20, good32, nil) and fail the test if
err == nil so the unrestricted-length validation in deriveMAAAddress is covered.
- Around line 172-183: The test suite lacks a case where the parallel slices
passed to computeRulesHash (namespaces, actions, body_hashes) have mismatched
lengths; add a unit test in TestComputeRulesHash_Validation that calls
computeRulesHash with differing lengths (e.g., namespaces length 1, actions
length 2, body_hashes length 1) and assert it returns a non-nil error (or if
computeRulesHash currently panics, wrap the call in a recover/assert that a
panic occurs); reference computeRulesHash to locate validation logic and ensure
the test covers the unequal-length path rather than causing an
index-out-of-range panic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d12bc0fe-b8f3-482d-8c21-64f581728fae

📥 Commits

Reviewing files that changed from the base of the PR and between 1c418a2 and 3f16292.

📒 Files selected for processing (3)
  • extensions/tn_utils/maa.go
  • extensions/tn_utils/maa_test.go
  • extensions/tn_utils/precompiles.go

Comment thread extensions/tn_utils/maa.go
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

✅ Actions performed

Comments resolved. Approval is disabled; enable reviews.request_changes_workflow to allow explicit top-level @coderabbitai resolve or @coderabbitai approve commands.

@MicBun MicBun enabled auto-merge (squash) June 1, 2026 21:38
@MicBun MicBun disabled auto-merge June 1, 2026 21:58
@MicBun MicBun merged commit 0f26e52 into main Jun 2, 2026
15 checks passed
@MicBun MicBun deleted the feat/maa-precompiles branch June 2, 2026 02:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant