Skip to content

feat(precompiles): implement TIP-1099 keychain ABI changes - #7270

Open
decofe wants to merge 4 commits into
tip/1099from
centaur/implement-tip-1099-1787306475
Open

feat(precompiles): implement TIP-1099 keychain ABI changes#7270
decofe wants to merge 4 commits into
tip/1099from
centaur/implement-tip-1099-1787306475

Conversation

@decofe

@decofe decofe commented Aug 21, 2026

Copy link
Copy Markdown
Member

Depends on tempoxyz/tempo-std#139.

Fork-gates direct AccountKeychain authorization selectors at T11 and replaces nested-ABI setAllowedCalls with the TIP-1011 RLP schema. RLP input is charged another 50 gas per 32-byte word before decoding, on top of TIP-1100 input pricing.

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

⚠️ Changelog not found.

A changelog entry is required before merging. We've generated a suggested changelog based on your changes:

Preview
---
tempo-alloy: major
tempo-contracts: major
---

Added the T11 account-keychain ABI and switched allowed-call scopes to RLP encoding. Disabled legacy direct key-authorization calls at T11.

Add changelog to commit this to your branch.

@klkvr
klkvr force-pushed the centaur/implement-tip-1099-1787306475 branch from b30c73d to cda0149 Compare August 24, 2026 07:43
@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

📊 Tempo Precompiles Coverage

precompiles

Coverage: 6422/10631 lines (60.41%)

File details
File Lines Coverage
src/account_keychain/dispatch.rs 16/45 35.56%
src/account_keychain/mod.rs 310/927 33.44%
src/address_registry/dispatch.rs 21/27 77.78%
src/address_registry/mod.rs 50/60 83.33%
src/current_committee/dispatch.rs 0/9 0.00%
src/current_committee/mod.rs 0/18 0.00%
src/dispatch.rs 130/153 84.97%
src/error.rs 52/166 31.33%
src/ip_validation.rs 10/10 100.00%
src/lib.rs 129/146 88.36%
src/nonce/dispatch.rs 6/7 85.71%
src/nonce/mod.rs 44/58 75.86%
src/receive_policy_guard/dispatch.rs 0/12 0.00%
src/receive_policy_guard/mod.rs 0/139 0.00%
src/signature_verifier/dispatch.rs 15/23 65.22%
src/signature_verifier/mod.rs 13/55 23.64%
src/stablecoin_dex/dispatch.rs 59/71 83.10%
src/stablecoin_dex/mod.rs 972/1097 88.61%
src/stablecoin_dex/order/mod.rs 120/154 77.92%
src/stablecoin_dex/order/storage.rs 178/249 71.49%
src/stablecoin_dex/orderbook.rs 183/242 75.62%
src/storage/actions.rs 11/90 12.22%
src/storage/evm.rs 390/437 89.24%
src/storage/hashmap.rs 0/241 0.00%
src/storage/mod.rs 27/69 39.13%
src/storage/packing.rs 68/93 73.12%
src/storage/thread_local.rs 200/296 67.57%
src/storage/types/array.rs 0/72 0.00%
src/storage/types/bytes_like.rs 135/179 75.42%
src/storage/types/cache.rs 65/122 53.28%
src/storage/types/mapping.rs 27/48 56.25%
src/storage/types/mod.rs 47/71 66.20%
src/storage/types/primitives.rs 21/24 87.50%
src/storage/types/set.rs 28/192 14.58%
src/storage/types/slot.rs 80/101 79.21%
src/storage/types/vec.rs 103/261 39.46%
src/storage_credits/accounting.rs 79/92 85.87%
src/storage_credits/dispatch.rs 16/16 100.00%
src/storage_credits/mod.rs 138/193 71.50%
src/tip20/dispatch.rs 64/73 87.67%
src/tip20/mod.rs 657/801 82.02%
src/tip20/rewards.rs 242/260 93.08%
src/tip20/roles.rs 85/88 96.59%
src/tip20_channel_reserve/dispatch.rs 0/42 0.00%
src/tip20_channel_reserve/mod.rs 3/548 0.55%
src/tip20_factory/dispatch.rs 9/11 81.82%
src/tip20_factory/mod.rs 115/140 82.14%
src/tip403_registry/dispatch.rs 29/46 63.04%
src/tip403_registry/mod.rs 347/544 63.79%
src/tip_fee_manager/amm.rs 295/465 63.44%
src/tip_fee_manager/dispatch.rs 35/37 94.59%
src/tip_fee_manager/mod.rs 56/155 36.13%
src/validator_config/dispatch.rs 18/28 64.29%
src/validator_config/mod.rs 171/227 75.33%
src/validator_config_v2/dispatch.rs 30/33 90.91%
src/validator_config_v2/mod.rs 523/581 90.02%
src/zone_factory/dispatch.rs 0/15 0.00%
src/zone_factory/mod.rs 0/215 0.00%
src/zone_factory/portal.rs 0/57 0.00%

contracts

Coverage: 1/202 lines (0.50%)

File details
File Lines Coverage
src/lib.rs 1/1 100.00%
src/precompiles/receive_policy_guard.rs 0/78 0.00%
src/precompiles/storage_credits.rs 0/7 0.00%
src/precompiles/tip20.rs 0/50 0.00%
src/precompiles/tip20_channel_reserve.rs 0/27 0.00%
src/precompiles/tip403_registry.rs 0/9 0.00%
src/precompiles/validator_config_v2.rs 0/3 0.00%
src/precompiles/zone_factory.rs 0/27 0.00%

Total: 6423/10833 lines (59.29%)

📦 Download full HTML report

@legion2002

Copy link
Copy Markdown
Contributor

cyclops audit fast

legion2002
legion2002 previously approved these changes Aug 24, 2026

@legion2002 legion2002 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm, pending CI

@tempoxyz-bot tempoxyz-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

👁️ Cyclops Review

This change fork-gates direct AccountKeychain authorization selectors at T11 and replaces nested-ABI setAllowedCalls with RLP. One verified gas-pricing issue is annotated inline; one additional issue cannot be placed inline because its root-cause line is outside this PR's diff.

⚠️ [ISSUE] Non-direct calls bypass mandatory input-gas accounting

Severity: Low
File: crates/precompiles/src/lib.rs:254

tempo_precompile! rejects DELEGATECALL and CALLCODE before creating StorageCtx or invoking the implementation-level input charge, so the rejection consumes zero precompile gas regardless of input size. A T4 call with 33 input bytes and 11 gas returns DelegateCallNotAllowed instead of halting out of gas for the required 12-gas charge; at T11 it skips 60 gas.

Recommended Fix: Charge input_cost(spec, input.data.len()) before the non-direct-call return, halt out of gas when insufficient, and report the charged gas on DelegateCallNotAllowed. Add T4 and T11 regression tests.

Reviewer Callouts
  • Pricing consistency: key_authorization charges 7,000 gas per target and selector plus 5,000 per recipient, while T11 setAllowedCalls charges only about 57, 17.5, and 52 gas respectively for the same work.
  • T11 Solidity coverage: tips/verify/foundry.toml:23 excludes AccountKeychainTest and AccountKeychainInvariantTest, leaving the new T11 surface without the existing Solidity invariant coverage.
  • Storage-credit coverage: Tests in crates/node/tests/it/storage_credits.rs:110 and crates/node/tests/it/tempo_transaction/local.rs:1535 were pinned to T10 even though key authorization becomes the only T11 provisioning route and disables TIP-1060 storage credits during keychain writes.
  • SDK compatibility: crates/alloy/src/provider/keychain.rs:371 always emits the T11-only selector, so the helper reverts on pre-T11 networks and has no legacy counterpart.

call: setAllowedCallsCall,
) -> Result<()> {
if !self.storage.spec().is_t3() {
self.storage.deduct_gas(rlp_input_cost(call.scopes.len()))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚨 [SECURITY] RLP pricing omits per-element validation work

The T11 path charges 80 gas per 32-byte input word, then runs unmetered HashSet inserts in validate_call_scopes and validate_selector_rules. A minimal selector rule occupies only 7 RLP bytes, costing about 17.5 gas per forced insertion. End-to-end measurements put this path at roughly 0.27–0.50 Ggas/s instead of TIP-1099's 1 Ggas/s target, and it is about 27% cheaper per selector validation than the ABI path it replaces. A duplicate final selector forces the complete validation pass and reverts before any storage write.

Recommended Fix:
Charge a per-scope, per-selector, and per-recipient surcharge before validation, or reprice the per-word surcharge from end-to-end decode-and-validation benchmarks. Add a large duplicate-tail regression test that asserts the intended gas charge.

@klkvr
klkvr force-pushed the centaur/implement-tip-1099-1787306475 branch from 96c6c9a to a0599d6 Compare August 25, 2026 07:53
@klkvr
klkvr force-pushed the centaur/implement-tip-1099-1787306475 branch from a0599d6 to 49b6975 Compare August 25, 2026 11:26
legion2002
legion2002 previously approved these changes Aug 25, 2026
@klkvr
klkvr force-pushed the centaur/implement-tip-1099-1787306475 branch from 49b6975 to 52b08d0 Compare August 25, 2026 13:09
key_id: Address,
scopes: Vec<CallScope>,
) -> Result<()> {
if !self.storage.spec().is_t3() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

it is a bit odd this is called reached by rlp path when we can assume t3 is active since it will always be t11+

let mut encoded_scopes = call.scopes.as_ref();
let scopes = Vec::<RlpCallScope>::decode(&mut encoded_scopes)
.map_err(|_| AccountKeychainError::invalid_call_scope())?;
if !encoded_scopes.is_empty() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

does the rlp decoder not require it to be consumed?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

guess not but can switch to decode_exact IIUC

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.

5 participants