hydrate

package
v0.64.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 19, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

README

Hydrate

Build hydratePayload bytes for HydrateProxy (hydrateExecute / hydrateExecuteAndSweep in trails-contracts) by resolving patch targets with abicalldata Selector and ByteRange instead of hand-counting calldata offsets.

This package depends on abicalldata for selector types and for building selectors with abicalldata.NewPath() (or abicalldata.NewRangeSelector for fixed offsets).

Usage

payload := v3.NewCallsPayload(...)

// Selector must resolve to exactly one range on the target call (same index as ForCall).
permitOwner := abicalldata.NewPath().
    CallData(0).
    ABI(trailsABI, "hydrateExecute").
    ArgBytesData("packedPayload").
    EncodedCallsPayload().
    EncodedCallData(0).
    ABI(erc2612ABI, "permit").
    ArgSlot("owner").
    AsSelector()

b := hydrate.NewBuilder(&payload)

if err := b.ForCall(0).DataAddress(permitOwner, hydrate.SourceSelf()); err != nil {
    return err
}

hydratePayload, err := b.Build()
if err != nil {
    return err
}
// nil/empty hydratePayload means "no hydration" (contract skips hydration).

calldata, err := hydrate.PackHydrateExecute(packedPayload, hydratePayload)

With sweep after execution:

calldata, err := hydrate.PackHydrateExecuteAndSweep(
    packedPayload,
    hydratePayload,
    sweepTarget,
    tokensToSweep,
    sweepNative,
)

If ABI parameters are unnamed, use index-based steps such as ArgSlotIndex / ArgBytesDataIndex on abicalldata.NewPath() (see the abicalldata README).

Call sections and ordering

  • Use ForCall(tindex) for each packed call you want to hydrate. Multiple methods on the same ForCall append commands to that call's section.
  • Build() emits sections in ascending tindex order, each as: [tindex byte][commands…][0x00]. That order matches how the proxy walks the stream while executing calls; sections must not be reordered arbitrarily.

Address sources

Data patches and CallTo / CallValue use a low nibble on the command byte; optional literals append 20 bytes when needed:

Helper Meaning at execution time
SourceSelf() address(this) (the proxy)
SourceMsgSender() msg.sender
SourceTxOrigin() tx.origin
SourceAddress(a) fixed a (encoded after the flag)

Selectors

Each Data* method requires an abicalldata.Selector that resolves to exactly one abicalldata.ByteRange, and that range's CallIndex must equal the ForCall index. The range's offset within that call's data becomes the patch offset (uint16); the builder checks that 20-byte (address) or 32-byte (uint256) replacements fit.

For unit tests or fixed layouts, abicalldata.NewRangeSelector(callIndex, offset, size) returns a selector backed by an explicit range.

When using a multi-step path into nested calldata, ABI context is cleared after any step that narrows the active range or switches to a new byte frame (including .Slice, .ArgBytesData, .ArgBytesDataIndex, .ArgBytesEncoded, .EncodedCallsPayload, .EncodedCallData). Call .ABI(contractABI, method) again before .ArgSlot, .ArgSlotIndex, .ArgBytesData, .ArgBytesDataIndex, or .ArgBytesEncoded on that frame.

Documentation

Index

Constants

View Source
const (
	TypeDataAddress        = 0x01
	TypeDataBalance        = 0x02
	TypeDataERC20Balance   = 0x03
	TypeDataERC20Allowance = 0x04
	TypeTo                 = 0x05
	TypeValue              = 0x06
)

Hydration op-type nibble (high bits of command flag byte). Must match HydrateProxy.sol.

View Source
const (
	DataSelf       = 0x00
	DataMsgSender  = 0x01
	DataTxOrigin   = 0x02
	DataAnyAddress = 0x03
)

Hydration address-source nibble (low bits of command flag byte).

Variables

View Source
var ABI abi.ABI

ABI is the parsed HydrateProxy contract ABI (from trails-contracts artifact).

Functions

func PackHydrateExecute

func PackHydrateExecute(packedPayload, hydratePayload []byte) ([]byte, error)

PackHydrateExecute ABI-encodes a call to HydrateProxy.hydrateExecute.

func PackHydrateExecuteAndSweep

func PackHydrateExecuteAndSweep(packedPayload, hydratePayload []byte, sweepTarget common.Address, tokensToSweep []common.Address, sweepNative bool) ([]byte, error)

PackHydrateExecuteAndSweep ABI-encodes hydrateExecuteAndSweep.

Types

type AddrSource

type AddrSource struct {
	// contains filtered or unexported fields
}

AddrSource selects how HydrateProxy resolves an address at execution time (low nibble of the command flag; literal addresses add 20 bytes after the flag).

func SourceAddress

func SourceAddress(a common.Address) AddrSource

func SourceMsgSender

func SourceMsgSender() AddrSource

func SourceSelf

func SourceSelf() AddrSource

func SourceTxOrigin

func SourceTxOrigin() AddrSource

type Builder

type Builder struct {
	// contains filtered or unexported fields
}

Builder constructs hydratePayload bytes for HydrateProxy using abicalldata.Selector (calldata selectors: ABI paths via abicalldata.NewPath().AsSelector() in app code, fixed ranges via abicalldata.NewRangeSelector, etc.) so call-data offsets are not hand-computed.

Sections are emitted in ascending call index order, which matches how HydrateProxy consumes the stream during sequential execution.

func NewBuilder

func NewBuilder(payload *v3.CallsPayload) *Builder

func (*Builder) Build

func (b *Builder) Build() ([]byte, error)

Build returns hydratePayload. An empty builder yields nil, which HydrateProxy treats as "no hydration".

func (*Builder) ForCall

func (b *Builder) ForCall(tindex int) *CallSection

ForCall begins or continues the hydrate section for packed call tindex.

type CallSection

type CallSection struct {
	// contains filtered or unexported fields
}

CallSection targets one packed call index; method calls append hydrate commands for that call.

func (*CallSection) CallTo

func (s *CallSection) CallTo(src AddrSource) error

CallTo sets decoded.calls[tindex].to to the address resolved from src at execution time.

func (*CallSection) CallValue

func (s *CallSection) CallValue(src AddrSource) error

CallValue sets decoded.calls[tindex].value to the native balance of the address resolved from src.

func (*CallSection) DataAddress

func (s *CallSection) DataAddress(sel abicalldata.Selector, src AddrSource) error

DataAddress patches calldata at sel with replaceAddress (20 bytes) using src as the hydrated address.

func (*CallSection) DataERC20Allowance

func (s *CallSection) DataERC20Allowance(sel abicalldata.Selector, owner AddrSource, token common.Address, spender AddrSource) error

DataERC20Allowance patches calldata at sel with IERC20(token).allowance(owner, spender) at execution time.

func (*CallSection) DataERC20Balance

func (s *CallSection) DataERC20Balance(sel abicalldata.Selector, token common.Address, holder AddrSource) error

DataERC20Balance patches calldata at sel with IERC20(token).balanceOf(holder) at execution time.

func (*CallSection) DataNativeBalance

func (s *CallSection) DataNativeBalance(sel abicalldata.Selector, src AddrSource) error

DataNativeBalance patches calldata at sel with replaceUint256 using the native balance of the address resolved from src at execution time.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL