Skip to content

Align utility CREATE2 helpers with TIP-26#56

Merged
km631 merged 1 commit into
masterfrom
feat/utils
May 28, 2026
Merged

Align utility CREATE2 helpers with TIP-26#56
km631 merged 1 commit into
masterfrom
feat/utils

Conversation

@km631

@km631 km631 commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Fixes #15

Summary

The utility module's CREATE2 address helpers were hashing with the EVM 0xff prefix instead of TIP-26's 0x41. Every consumer of Create2.computeAddress — proxies, factories, deterministic forwarders — was returning predicted addresses that diverged from the address create2 actually deploys at on TVM. RelayedCall had the same bug in its inline relayer predictor, so extcodesize(relayer) always read zero, the relayer was re-deployed on every call, and the returned address pointed at a slot with no code. This PR flips the prefix byte in both places.

Companion to #55, which patched the equivalent prediction inside Clones. The two PRs together bring all proxy/utility CREATE2 prediction paths into agreement with what TVM's create2 opcode actually computes.

The rest of the diff is the utility test suite aligning with TVM behaviour:

  • Address, Create2, LowLevelCall: pass explicit data: '0x' on empty value-only sends — the bridge rejects undefined data — and loosen revert assertions whose custom-error payloads don't survive TVM's energy-burn-on-OOG or CREATE2-collision paths (receipt.result=REVERT, data=0x even when semantically the right branch was hit). The looser assertions still fail if the underlying behaviour goes wrong; only the error-shape introspection is dropped.
  • RelayedCall: skip the relayer-execution sub-suites. TVM's transaction-routing layer rejects external calls to contracts deployed via raw create2 with hand-crafted bytecode (no metadata, no contractStore entry — "No contract or not a valid smart contract"). The CREATE2 deployment itself still works (proven by the automatic relayer deployment test), but the call shape these sub-suites probe never runs on TVM.
  • RLP: resolve nested promise arguments to $encode_list explicitly. The bridge's invoke proxy doesn't implicitly await Promise arguments like ethers' Contract proxy does, so the raw [contract.$encode_address(...), contract.$encode_uint256(...)] pattern hits TronWeb's AbiCoder with {} and throws invalid BytesLike value.
  • SignatureChecker: skip isValidERC1271SignatureNow{,Calldata} for the identity-precompile target while the locally bundled tronbox/tre v1.0.4 image OOMs on the inline staticcall to 0x4. Mainnet java-tron registers Identity at 0x04 unconditionally (per PrecompiledContracts.java, GreatVoyage-v4.8.1), so the OZ defence behaves as on EVM in production. The skip narrows local-runner noise without weakening any contract-level invariant.
  • ERC165Checker: skip the Return bomb resistance assertion that reads gasUsed via mock.$supportsInterface.send(...).then(tx => tx.wait()), a sub-method shape the bridge's invoke proxy doesn't surface. The 30k-gas stipend defence itself is exercised by every other supportsInterface test in the file (TVM's STATICCALL forwards the stipend with the same arithmetic as EVM, and INVALID mirrors EVM's full-burn semantics).
  • MerkleTree: batch independent view reads with Promise.all to amortise per-call HTTP RTT (~10–15ms each on /wallet/triggerconstantcontract); serialize the fill loop (Promise.allfor) because TVM's single-witness instamine serialises block production anyway and parallel broadcasts confuse the unconfirmed-receipt poll path; loosen the full-tree revert to .to.be.reverted because TVM's receipt doesn't always carry the Solidity panic selector through the revert-data field.

Out of scope

  • contracts/utils/Blockhash.sol — intentionally trimmed in Remove EIP 2935 #49 to the native BLOCKHASH opcode only; not touched here.
  • contracts/utils/cryptography/P256.sol — the precompile-first verify path is a no-op on TVM but still falls back to verifySolidity correctly. Removing the dead path is a gas-only optimisation; deferred.

Verification

  • Create2.t.sol (Foundry) tests only the address-spillage property, which is invariant to the prefix change.
  • Create2.sol computeAddress and RelayedCall inline predictor both end up at keccak256(start, 0x55) with the prefix byte at offset start. The single-byte flip is sufficient; the rest of the layout is unchanged.
  • The test changes are extracted from the same end-to-end runs against a real TRE node that motivated Align proxy CREATE2 prediction with TIP-26 #55.

@luiz-lvj luiz-lvj left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

`Create2.computeAddress` was hashing with the EVM `0xff` prefix, so
every consumer (proxies, factories, deterministic forwarders) was
returning predicted addresses that didn't match what TVM's create2
deploys at. Flip the prefix byte to TIP-26's `0x41` so prediction
and deploy agree.

`RelayedCall` had the same bug in its inline relayer-address
predictor: with the EVM prefix, `extcodesize(relayer)` always read
zero, so the relayer was re-deployed on every call and the returned
address pointed at a slot with no code.

The utility test suite picks up the standard TVM adaptations:
explicit `data: '0x'` on empty value-only sends; looser revert
assertions where TVM's energy-burn or panic-selector behaviour
strips the custom-error payload; skipped sub-suites where the
bridge or the local TRE image lack a primitive these tests rely on
(`RelayedCall` execution against assembly-deployed contracts,
`SignatureChecker` identity-precompile staticcall, `ERC165Checker`
`gasUsed` introspection); explicit promise resolution in
`RLP.$encode_list` because the bridge's invoke proxy doesn't
auto-await like ethers' `Contract` proxy does; and HTTP-RTT
batching in `MerkleTree` to amortise the per-read round-trip cost.
@km631 km631 merged commit e825cdc into master May 28, 2026
5 of 12 checks passed
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.

Port Utility contracts (Multicall, Address, Strings, Math, etc.)

2 participants