core

package
v0.5.1 Latest Latest
Warning

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

Go to latest
Published: Jul 17, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

This file exists solely to anchor the `go generate` directive that produces pkg/core/cbor_gen.go. The generator is the main package at pkg/core/gen/; it reads the type list there and emits tuple-mode CBOR codecs per ADR-009 §2.

Re-run whenever any target type's fields change:

go generate ./pkg/core/...

Index

Constants

View Source
const (
	// MaxBlockAge bounds how stale a finalized block may be and still be
	// signed/submitted (freshness cutoff on the signing path). It also anchors
	// the withdrawal validity window: a block older than MaxBlockAge is never
	// re-signed, so no fresh authorization can be minted past that point.
	MaxBlockAge = 7 * 24 * time.Hour

	// ExecutionMargin is the slack added on top of MaxBlockAge to cover the time
	// a fresh authorization needs to be signed, submitted, and confirmed on L1.
	// It bounds the per-attempt liveness budget on XRPL (see LedgerBudget).
	ExecutionMargin = 2 * time.Hour

	// WithdrawalValidityWindow is the total lifetime of a withdrawal
	// authorization measured from the source block's SealedAt. Any signed
	// digest is dead once SealedAt + WithdrawalValidityWindow has passed.
	WithdrawalValidityWindow = MaxBlockAge + ExecutionMargin
)

Withdrawal-authorization time bounds.

Every withdrawal digest signed by the custody quorum embeds a `deadline` (unix seconds) past which the authorization is void — on EVM/Solana it is a consensus-enforced execution check, on XRPL it caps `LastLedgerSequence`, and clearnet uses it to decide when a reverted/unbroadcast withdrawal may be safely re-credited. Because the deadline is a *digest input*, these values are compile-time constants: they cannot ride the config registry (ADR-017) without opening a digest-divergence window across a rolling restart. Changing them is therefore a coordinated binary upgrade, not a runtime config change.

The values are provisional pre-mainnet. They are defined ONCE here in the SDK (clearnet imports the SDK) so custody and clearnet cannot drift.

View Source
const (
	URIScheme      = "yellow"
	DefaultNetwork = "ynet"
)

URI scheme and default network for Yellow Network resources (ADR-007 §4).

View Source
const BLSPubKeyG2Len = 128

BLSPubKeyG2Len is the serialized length of a BN254 G2 pubkey (4×32 bytes).

View Source
const BloomByteLength = 256

Event bloom filter for per-block log filtering (data_layer.md §5.2). 2048-bit (256-byte) bloom with 3 hash functions, matching Ethereum's log bloom.

Only the length constant lives in the SDK — Block.EventBloom is [BloomByteLength]byte. The add/test helpers (BloomAdd, BloomTest, BlockEventBloom) stay in clearnet; they operate on clearnet-internal Events.

View Source
const DefaultIssuer = "custody"

Variables

View Source
var (
	ErrNonCanonicalOrder     = errors.New("block: entries not in canonical order")
	ErrNonConsecutiveNonce   = errors.New("block: same-account entries must have consecutive nonces")
	ErrEntriesDigestMismatch = errors.New("block: entries digest does not match header")
)

Block validation errors (extracted from clearnet block_params.go — used by Block entry/digest verification above).

View Source
var ValidTreasuries = []string{"emission"}

ValidTreasuries is the compile-time allowlist of protocol-treasury names (ADR-010 §1). Treasuries are consensus-critical state-machine inputs, not operator configuration: declaring them in the network manifest would diverge SMT roots across operators the first time distribution fires. The set is therefore hardcoded here. Adding a new treasury requires a follow-up ADR, an entry in this list, a registered minimum balance (ADR-010 §6), and an authorized ledger helper for its outbound flow (ADR-010 §3).

Functions

func BitmaskBitLen

func BitmaskBitLen(bm [32]byte) int

BitmaskBitLen returns the position of the highest set bit + 1 (0 if empty).

func BitmaskIsZero

func BitmaskIsZero(bm [32]byte) bool

BitmaskIsZero returns true if no bits are set in the bitmask.

func BitmaskOnesCount

func BitmaskOnesCount(bm [32]byte) int

BitmaskOnesCount returns the number of set bits in the bitmask.

func BitmaskToBigInt

func BitmaskToBigInt(bm [32]byte) *big.Int

BitmaskToBigInt returns a big.Int representing the bitmask. The resulting big.Int uses big-endian byte order, so the little-endian bitmask bytes are reversed.

func CanonicalSort

func CanonicalSort(anchor [32]byte, entries []BlockEntry)

CanonicalSort sorts entries in deterministic order (ADR-005 §2.3, data-structures.md §5.3.3). Primary: AccountID (= keccak256(URI)) by XOR distance from Anchor, ascending. Secondary: Nonce ascending within the same account.

func ComputeAccountID

func ComputeAccountID(uri string) [32]byte

ComputeAccountID derives the canonical 32-byte AccountID from an account URI or raw address (ADR-007 §4). The input is normalized to a canonical lowercase before hashing, so a caller that accidentally hands in a non-canonical form still produces the canonical AccountID. That covers two footguns at once:

  1. Non-URI heterogeneous protocol fields such as BlockEntry.Account (which may carry either a canonical URI for service/pool accounts or a raw user address for user-owned accounts). Non-URI input is auto-wrapped in UserURI() first.
  2. Mixed-case URI input (e.g. a URI produced by an external tool that didn't enforce the rule). Post-lowercasing eliminates the divergence before the hash is taken.

func ComputeEntriesDigest

func ComputeEntriesDigest(entries []BlockEntry) [32]byte

ComputeEntriesDigest computes the flat hash over all entry hashes (ADR-005 §2.2).

EntriesDigest = keccak256(EntryHash_1 || EntryHash_2 || ... || EntryHash_n)

func ComputeEntryHash

func ComputeEntryHash(e BlockEntry) [32]byte

ComputeEntryHash computes the hash of a single entry (ADR-005 §2.2).

EntryHash = keccak256(canonical-CBOR(BlockEntry))

The preimage is the cbor-gen tuple encoding of the entry struct (ADR-009 §4, CBOR migration plan §7 Wave 2b). `EntriesDigest` continues to be the flat keccak-concat of these per-entry hashes — only the per-entry preimage layout changed in Wave 2b.

func DecodePayload

func DecodePayload(entry BlockEntry) (interface{}, error)

DecodePayload decodes a BlockEntry's binary payload into the typed operation struct based on entry.Type. Returns one of:

*TransferOp, *SwapOp, *WithdrawalOp, *RepegOp,
*SessionCloseOp, *SessionChallengeOp

Returns an error for unknown entry types or malformed payloads.

func EncodeSessionChallengeOp

func EncodeSessionChallengeOp(op *SessionChallengeOp) []byte

EncodeSessionChallengeOp serializes a SessionChallengeOp.

func EncodeSessionCloseOp

func EncodeSessionCloseOp(op *SessionCloseOp) []byte

EncodeSessionCloseOp serializes a SessionCloseOp.

func First8Hex

func First8Hex(id NodeID) string

First8Hex returns the first 8 hex characters of id. Used to synthesize human-readable Slot labels when a peer did not supply one (docs/plans/logical_node.md §5.4).

func GetBitmaskBit

func GetBitmaskBit(bm [32]byte, i int) bool

GetBitmaskBit returns true if bit i is set in the bitmask.

func IsSwapTxID

func IsSwapTxID(txID string) bool

IsSwapTxID returns true if the TxID represents a swap handoff TransferOp.

func IsURI

func IsURI(s string) bool

IsURI returns true if the string looks like a yellow:// URI.

func IsValidTreasury

func IsValidTreasury(name string) bool

IsValidTreasury reports whether a treasury name is in the compile-time allowlist. A URI that parses as kind=`treasury` but whose name is absent from this list MUST be rejected by every account-materialization path (ADR-010 §1).

func MakeSwapTxID

func MakeSwapTxID(baseTxID string, assetOut AssetID, minAmountOut *big.Int) string

MakeSwapTxID creates the TransferOp TxID used for the user->pool swap handoff. TransferOp has no AssetOut field, so the pool cluster recovers the user-authorized output asset and slippage floor from this stable prefix after validating the sealed user block.

func NodeURI

func NodeURI(id NodeID) string

NodeURI returns the canonical URI for a validator node account.

yellow://ynet/node/<64-char lowercase hex nodeid>

func ParseURI

func ParseURI(uri string) (network, kind, path string, err error)

ParseURI splits a canonical URI into its components.

"yellow://ynet/pool/eth" → ("ynet", "pool", "eth", nil)

func PoolURI

func PoolURI(base string) string

PoolURI returns the canonical URI for a liquidity pool (ADR-007 §4). All pools are YELLOW-quoted (ADR-006), so the URI contains only the lowercase base asset. Example: yellow://ynet/pool/eth

func ServiceURI

func ServiceURI(kind, path string) string

ServiceURI returns the canonical URI for a named service.

yellow://ynet/<kind>/<path>

func SetBitmaskBit

func SetBitmaskBit(bm *[32]byte, i int)

SetBitmaskBit sets bit i (0-indexed, little-endian bit order) in a [32]byte bitmask. Bit i is stored at byte i/8, bit position i%8 within that byte.

func TreasuryURI

func TreasuryURI(name string) string

TreasuryURI returns the canonical URI for a protocol treasury (ADR-010 §1). The name is drawn from the compile-time ValidTreasuries allowlist. Initial set: `emission`. Example: yellow://ynet/treasury/emission.

func URIKind

func URIKind(uriOrAddress string) string

URIKind extracts the kind segment from a URI or address. For non-URI inputs (raw hex addresses), returns "user". Returns "" if parsing fails on an actual URI.

func URIToAddress

func URIToAddress(uri string) (common.Address, error)

URIToAddress maps a canonical yellow:// URI into the 20-byte address slot used by EIP-712 schemas that cannot carry a string recipient. The mapping is the first 20 bytes of keccak256(uri), paralleling the pool-anchor preimage rule while fitting the Transfer(address to, ...) type.

func UserURI

func UserURI(address string) string

UserURI returns the canonical URI for a user account.

yellow://ynet/user/0xd8da6bf26964af9d7eed9e03e53415d37aa96045

func ValidateAssetURI added in v0.5.0

func ValidateAssetURI(uri AssetURI) error

ValidateAssetURI checks only core-level asset URI shape. It does not inspect issuer-specific asset id structure.

func ValidateEntryOrder

func ValidateEntryOrder(anchor [32]byte, entries []BlockEntry) error

ValidateEntryOrder checks that entries are in canonical order (ADR-005 §2.3). Returns nil if ordering is valid.

func ValidateURI

func ValidateURI(uri string) error

ValidateURI enforces ADR-007 §4 URI conventions:

  1. The URI uses the yellow:// scheme.
  2. Parsing yields a non-empty network and kind.
  3. The network matches DefaultNetwork ("ynet") — multi-network support is a future extension; every URI in-flight today lives on ynet.
  4. The kind is one of the enumerated ADR-007 §3 values.
  5. Every URI component is lowercase (ADR-007 §4: "All URI components are lowercase").

Returns a descriptive error on the first violation; nil on success. Callers at system boundaries (gateway request parsing, store loads, manifest reads) should call ValidateURI on any URI they receive from an external source before trusting it. Internal constructors (UserURI, PoolURI, etc.) produce canonical URIs by construction and do not need re-validation at their call sites.

func WithdrawalDeadline added in v0.4.0

func WithdrawalDeadline(sealedAt int64) int64

WithdrawalDeadline returns the unix-second time bound for a withdrawal whose source block sealed at sealedAt (also unix seconds). This is the single value threaded into every chain's withdrawal digest and enforced on-chain.

Types

type AccountSnapshot

type AccountSnapshot struct {
	AccountID    [32]byte `json:"AccountID"`    // keccak256(Address)
	PrevBlockRef [32]byte `json:"PrevBlockRef"` // Account.LastBlockHash before this block (back-pointer)
	PostNonce    uint64   `json:"PostNonce"`    // Account.Nonce after all entries for this account
}

AccountSnapshot preserves per-account chain continuity within a Block (ADR-005 §2.4).

func (*AccountSnapshot) MarshalCBOR

func (t *AccountSnapshot) MarshalCBOR(w io.Writer) error

func (*AccountSnapshot) UnmarshalCBOR

func (t *AccountSnapshot) UnmarshalCBOR(r io.Reader) (err error)

type AccountType

type AccountType uint8

AccountType identifies the entity kind (ADR-007 §3).

const (
	AccountTypeUnknown  AccountType = 0x00 // Sentinel: URI kind not recognised (D-003, 2026-04-21).
	AccountTypeUser     AccountType = 0x01 // Externally owned
	AccountTypeNative   AccountType = 0x02 // On-cluster deterministic handlers (pools, vaults)
	AccountTypeVirtual  AccountType = 0x03 // Off-chain operator, NFT-identified
	AccountTypeContract AccountType = 0x04 // User-deployed bytecode (future)
)

func KindToAccountType

func KindToAccountType(kind string) (AccountType, error)

KindToAccountType maps a URI kind segment to its AccountType (ADR-007 §3). Returns an error on unknown kinds — this was previously a silent User-default which masked malformed URIs (D-003 resolution, 2026-04-21).

The returned AccountType on error is AccountTypeUnknown (0), so code that ignores the error still surfaces an obviously-bogus type rather than a plausible User account.

func (AccountType) String

func (t AccountType) String() string

String returns the human-readable name of the AccountType.

type AssetID

type AssetID string

AssetID is a unique identifier for a token (§2). Symbols (e.g. "USDT", "ETH") are mapped to L1 (ChainID, TokenAddress) pairs via the AssetResolver interface at runtime. TODO: Consider removing AssetID and using AssetURI for protocol asset identity once the issuer asset URI migration reaches transfers/swaps.

func ParseSwapTxID

func ParseSwapTxID(txID string) (baseTxID string, assetOut AssetID, minAmountOut *big.Int, ok bool)

ParseSwapTxID extracts the fields encoded by MakeSwapTxID.

type AssetTransfer

type AssetTransfer struct {
	Asset  AssetID
	Amount decimal.Decimal
}

AssetTransfer represents a single asset-amount pair in a multi-asset operation (§5.3.5).

func CanonicalAssetTransfers

func CanonicalAssetTransfers(in []AssetTransfer) ([]AssetTransfer, error)

CanonicalAssetTransfers validates, copies, sorts, and de-duplicates a TransferOp asset list.

func (*AssetTransfer) MarshalCBOR

func (t *AssetTransfer) MarshalCBOR(w io.Writer) error

func (*AssetTransfer) UnmarshalCBOR

func (t *AssetTransfer) UnmarshalCBOR(r io.Reader) (err error)

type AssetURI added in v0.5.0

type AssetURI string

AssetURI identifies an issuer-defined asset in protocol payloads.

Core treats the asset id as opaque issuer-owned data. Chain-specific structure such as family, chain id, and token address belongs outside core.

func NewAssetURI added in v0.5.0

func NewAssetURI(issuer, assetID string) (AssetURI, error)

NewAssetURI builds a canonical asset URI:

yellow://ynet/asset/<issuer>/<asset-id>

If issuer is empty, DefaultIssuer is used. The issuer is lowercased; the issuer-owned asset id is preserved as supplied.

type AssetURIParts added in v0.5.0

type AssetURIParts struct {
	Network string
	Issuer  string
	AssetID string
}

func ParseAssetURI added in v0.5.0

func ParseAssetURI(uri AssetURI) (AssetURIParts, error)

ParseAssetURI splits an asset URI into network, issuer, and issuer-owned asset id components.

type Attestation

type Attestation struct {
	ThresholdSig []byte   `json:"ThresholdSig"` // Aggregated BLS signature (G1 point)
	Bitmask      [32]byte `json:"Bitmask"`      // Bitmask indicating which validators signed (up to 256 bits, SS5.3).
	Validators   [][]byte `json:"Validators"`   // BLS public keys (G2) of signing validators — 128 bytes each once WS-A.2 lands.
}

Attestation holds the BLS threshold signature proving cluster consensus (ADR-005 §5.3). Embedded in every Block. Verified off-chain by clearing layer and custody layer.

§7 coordination: Validators is []BLSPubKey (variable-length byte slices) so entries can hold full 128-byte BN254 G2 public keys (WS-A.2). Legacy NodeID-only entries remain parseable as 32-byte slices; WS-A.2 populates real G2 keys from core.Slot.BLSPubKey.

func (*Attestation) MarshalCBOR

func (t *Attestation) MarshalCBOR(w io.Writer) error

func (*Attestation) UnmarshalCBOR

func (t *Attestation) UnmarshalCBOR(r io.Reader) (err error)

type Block

type Block struct {
	// --- Header (covered by BLS signature) ---
	Anchor        [32]byte              `json:"Anchor"`                  // AccountID of the first transaction (DHT center)
	SealedAt      int64                 `json:"SealedAt"`                // Unix timestamp when block was sealed
	Entries       []BlockEntry          `json:"Entries"`                 // Ordered operations (canonical sort, §2.3)
	StateRoot     [32]byte              `json:"StateRoot"`               // Flat SMT root after applying ALL entries in order
	EntriesDigest [32]byte              `json:"EntriesDigest"`           // Flat hash binding entries to BLS signature (§2.2)
	K             uint64                `json:"K"`                       // DQE-computed cluster size for aggregate VaR (§5.2). Semantic bound of 256; wire type widened to uint64 for cbor-gen compatibility.
	Attestation   Attestation           `json:"Attestation"`             // Single BLS threshold signature for the block (un-embedded so cbor-gen tuple emitter produces stable output)
	Accounts      []AccountSnapshot     `json:"Accounts"`                // Per-account chain continuity metadata
	EventBloom    [BloomByteLength]byte `json:"event_bloom,omitempty"`   // Per-block event bloom filter (data_layer.md §5.2)
	AggregateVaR  *big.Int              `json:"aggregate_var,omitempty"` // Advisory VaR projection; validators recompute (§6.6)
	SealReason    string                `json:"seal_reason,omitempty"`   // "idle" | "window" | "entries" | "value"
}

Block is an ordered batch of operations from accounts within a DHT neighborhood, attested by a single BLS threshold signature (ADR-005 §2).

func (*Block) Hash

func (b *Block) Hash() [32]byte

Hash returns keccak256(SigningMessage) — the block identifier (ADR-005 §2.1). After sealing, Account.LastBlockHash = Hash() for each account in Accounts.

Formula unchanged under Wave 2b; only the preimage layout moved from the 106-byte hand-rolled concat to canonical CBOR of `BlockHeader`.

func (*Block) MarshalCBOR

func (t *Block) MarshalCBOR(w io.Writer) error

func (*Block) SigningMessage

func (b *Block) SigningMessage() []byte

SigningMessage returns the canonical CBOR preimage covered by the BLS signature (ADR-009 §4, CBOR migration plan §7 Wave 2b).

Preimage shape: canonical CBOR of `BlockHeader{Anchor, SealedAt, StateRoot, EntriesDigest, K, Accounts}`. `Accounts` (per-account `PrevBlockRef` + `PostNonce`) is newly bound under the signature (Q6).

Byte output is frozen by goldens under `testdata/goldens/preimages/` (see `scripts/ci/check-preimage-goldens.sh`); any change to the field set or encoding rules trips the CI guard and requires a version-byte bump per ADR-009 §5.

func (*Block) UnmarshalCBOR

func (t *Block) UnmarshalCBOR(r io.Reader) (err error)

func (*Block) ValidateEntriesDigest

func (b *Block) ValidateEntriesDigest() error

ValidateEntriesDigest recomputes EntriesDigest and checks it matches the block header.

type BlockEntry

type BlockEntry struct {
	Type    EntryType `json:"Type"`    // Transfer | Swap | Withdrawal | Mint | Burn | Repeg (LP ops use Transfer per §8.3)
	Account string    `json:"Account"` // Account whose state is mutated
	Nonce   uint64    `json:"Nonce"`   // Account nonce consumed by this entry
	Payload []byte    `json:"Payload"` // Canonical CBOR of the typed op (§5.3)
}

BlockEntry is an individual operation within a Block (ADR-005 §2).

func (*BlockEntry) AccountID

func (e *BlockEntry) AccountID() [32]byte

AccountID returns keccak256(e.Account).

func (*BlockEntry) ConsumesNonce

func (e *BlockEntry) ConsumesNonce() bool

ConsumesNonce reports whether applying this entry advances the account nonce. Receipt-driven entries (OpMint deposit credits, OpBurn withdrawal-execution burns) leave the account nonce unchanged — the authoritative trigger is the custody-signed receipt, not a user-signed transaction. Used by block validation to compute the correct pre-block nonce from snap.PostNonce when verifying entry order.

func (*BlockEntry) DecodeBurnReceipt

func (e *BlockEntry) DecodeBurnReceipt() (*BurnReceipt, error)

DecodeBurnReceipt decodes the payload as a BurnReceipt (the on-block payload for OpBurn entries — the receipt IS the operation).

func (*BlockEntry) DecodeMintReceipt

func (e *BlockEntry) DecodeMintReceipt() (*MintReceipt, error)

DecodeMintReceipt decodes the payload as a MintReceipt (the on-block payload for OpMint entries — the receipt IS the operation).

func (*BlockEntry) DecodeOp

func (e *BlockEntry) DecodeOp() (interface{}, error)

DecodeOp decodes the entry payload into its typed operation struct. Returns one of *TransferOp, *SwapOp, *WithdrawalOp, *RepegOp, *SessionCloseOp, or *SessionChallengeOp.

func (*BlockEntry) DecodeRepegOp

func (e *BlockEntry) DecodeRepegOp() (*RepegOp, error)

DecodeRepegOp decodes the payload as a RepegOp. Returns an error if the entry type is not OpRepeg or the payload is malformed.

func (*BlockEntry) DecodeSwapOp

func (e *BlockEntry) DecodeSwapOp() (*SwapOp, error)

DecodeSwapOp decodes the payload as a SwapOp. Returns an error if the entry type is not OpSwap or the payload is malformed.

func (*BlockEntry) DecodeTransferOp

func (e *BlockEntry) DecodeTransferOp() (*TransferOp, error)

DecodeTransferOp decodes the payload as a TransferOp. Returns an error if the entry type is not OpTransfer or the payload is malformed.

func (*BlockEntry) DecodeWithdrawalOp

func (e *BlockEntry) DecodeWithdrawalOp() (*WithdrawalOp, error)

DecodeWithdrawalOp decodes the payload as a WithdrawalOp. Returns an error if the entry type is not OpWithdrawal or the payload is malformed.

func (*BlockEntry) Hash

func (e *BlockEntry) Hash() [32]byte

Hash returns keccak256(Type || Account || Nonce || Payload) for this entry.

func (*BlockEntry) IsSwap

func (e *BlockEntry) IsSwap() bool

IsSwap returns true if the entry type is OpSwap.

func (*BlockEntry) IsTransfer

func (e *BlockEntry) IsTransfer() bool

IsTransfer returns true if the entry type is OpTransfer.

func (*BlockEntry) IsWithdrawal

func (e *BlockEntry) IsWithdrawal() bool

IsWithdrawal returns true if the entry type is OpWithdrawal.

func (*BlockEntry) MarshalCBOR

func (t *BlockEntry) MarshalCBOR(w io.Writer) error

func (*BlockEntry) UnmarshalCBOR

func (t *BlockEntry) UnmarshalCBOR(r io.Reader) (err error)

type BlockEntryRef

type BlockEntryRef struct {
	BlockHash  [32]byte // keccak256(SigningMessage) of the sealed block
	EntryIndex uint64   // Position of the entry in Block.Entries (widened from uint16 for cbor-gen compat, Wave 2 pre)
}

BlockEntryRef identifies a specific entry within a sealed block. This is the composite key used throughout the escrow lifecycle: recording, challenge, finalization, and BurnReceipt handling.

func RefFromBlock

func RefFromBlock(block *Block, entryIndex uint64) BlockEntryRef

RefFromBlock creates a BlockEntryRef from a sealed block and entry index.

func (BlockEntryRef) Key

func (r BlockEntryRef) Key() string

Key returns a full-hex deduplication key for map lookups.

func (*BlockEntryRef) MarshalCBOR

func (t *BlockEntryRef) MarshalCBOR(w io.Writer) error

func (BlockEntryRef) String

func (r BlockEntryRef) String() string

String returns a compact hex:index representation for logging.

func (*BlockEntryRef) UnmarshalCBOR

func (t *BlockEntryRef) UnmarshalCBOR(r io.Reader) (err error)

type BlockHeader

type BlockHeader struct {
	Anchor        [32]byte          // AccountID of the first transaction (DHT center)
	SealedAt      int64             // Unix timestamp when block was sealed
	StateRoot     [32]byte          // Flat SMT root after applying ALL entries in order
	EntriesDigest [32]byte          // Flat hash binding entries to BLS signature (§2.2)
	K             uint64            // DQE-computed cluster size; semantic bound 256
	Accounts      []AccountSnapshot // Per-account chain continuity metadata (Q6)
}

BlockHeader is the signing-preimage projection of a sealed Block (docs/specs/protocol/data-structures.md §5.3). It pulls out the fields the BLS signature actually commits to — the six-tuple that becomes the canonical CBOR preimage now that Wave 2b has rewritten `Block.SigningMessage()` around the cbor-gen codec of this struct.

`Accounts` is newly included in the preimage (Q6 in the CBOR migration plan / ADR-009 §4) so per-account chain continuity (PrevBlockRef / PostNonce) commits under the BLS signature — closing the latent forgery surface where the legacy 106-byte preimage did not bind chain-continuity metadata. `K` is `uint64` on the Go side for cbor-gen compatibility (W2-pre widen); the semantic bound is still 256 (DQE cap).

Field order on this struct IS the wire encoding (cbor-gen tuple mode, ADR-009 §2). Append-only evolution: any insert/reorder/rename bumps the global schema-family version byte (ADR-009 §5).

func (*BlockHeader) MarshalCBOR

func (t *BlockHeader) MarshalCBOR(w io.Writer) error

func (*BlockHeader) UnmarshalCBOR

func (t *BlockHeader) UnmarshalCBOR(r io.Reader) (err error)

type BlockState

type BlockState uint8

BlockState represents the lifecycle phase of a pending block (ADR-005 §4.4).

const (
	BlockOpen    BlockState = iota // Proposer received first tx, block initialized
	BlockFilling                   // Accepting additional transactions
	BlockSealed                    // Sealed, BLS signing complete
)

type BurnReceipt

type BurnReceipt struct {
	WithdrawalID  [32]byte          // keccak256(accountId, blockHash, entryIndex, assetURI, amount, recipient, nonce)
	BlockEntryRef                   // Block hash + entry index of the escrow entry
	TxID          string            // Chain-native transaction/reference id (empty unless applicable)
	Signatures    [][]byte          // k-of-n provider ECDSA signatures over the receipt digest
	Status        WithdrawalOutcome // Terminal outcome: Executed, Expired, or failed with reason
}

BurnReceipt is returned by the custody layer after L1 execution of a withdrawal (ADR-005 §9.1, receipt-model amendment 2026-05-12). Provider ECDSA signatures (k-of-n against the configured custody signer directory — manifest custody.signers/threshold; future Registry-backed source) confirm the withdrawal was executed on-chain; the cluster validates the receipt and applies the second leg of the burn (DR 2010 / CR 1020).

func (*BurnReceipt) EncodePayload

func (v *BurnReceipt) EncodePayload() []byte

EncodePayload serializes a BurnReceipt into a BlockEntry payload.

func (*BurnReceipt) MarshalCBOR

func (t *BurnReceipt) MarshalCBOR(w io.Writer) error

func (*BurnReceipt) UnmarshalCBOR

func (t *BurnReceipt) UnmarshalCBOR(r io.Reader) (err error)

type DepositDestination added in v0.2.0

type DepositDestination struct {
	Account string
	Ref     [32]byte
}

DepositDestination identifies who a deposit credits. Account is the L1 / clearnet account; Ref is the opaque ADR-015 sub-account reference, carried alongside the account as side-data (a zero Ref means no sub-account). The reference is never interpreted on-chain — it is emitted so deposits are filterable per (Account, Ref); an observer folds it into the account URI. Chains without a reference channel (BTC) reject a non-zero Ref.

type DepositStatus

type DepositStatus int

DepositStatus is the tri-state result of VerifyDeposit, distinguishing a deposit that settled, one that is still in flight, and one that never landed (or was dropped/reorged out).

const (
	// DepositAbsent: no matching deposit transaction is on chain or in the
	// mempool (never broadcast, dropped, reorged out, or reverted/failed).
	DepositAbsent DepositStatus = iota
	// DepositPending: the deposit transaction is observed but not yet final —
	// in the mempool, or with fewer than the requested confirmations.
	DepositPending
	// DepositConfirmed: the deposit transaction is final to the requested depth.
	DepositConfirmed
)

func (DepositStatus) String

func (s DepositStatus) String() string

type EntryType

type EntryType uint8

EntryType identifies the kind of state operation in a BlockEntry (ADR-005 §5.3.5).

const (
	OpTransfer         EntryType = iota + 1 // SS5.3.5 — Transfer: debit sender, credit receiver (also LP operations per SS8.3)
	OpSwap                                  // SS8.1 — Swap: AMM execution result
	OpWithdrawal                            // SS7.3.1 — Withdrawal: fund lock for L1
	OpBurn                                  // ADR-005 §9.1 receipt-model — Withdrawal execution burn: DR 1020 / CR 2010 driven by a custody-signed BurnReceipt. Payload = canonical CBOR of the BurnReceipt.
	OpMint                                  // ADR-005 §9.1 receipt-model — Deposit credit: DR 1010 / CR 2010 driven by a custody-signed MintReceipt. Payload = canonical CBOR of the MintReceipt.
	OpRepeg                                 // SS8.1.2 — PriceScale adjustment
	OpSessionClose                          // service_sessions.md §4 — Cooperative or unilateral session close
	OpSessionChallenge                      // service_sessions.md §4 — Session dispute challenge
)

type FaucetReader

type FaucetReader interface {
	DripAmount(ctx context.Context) (*big.Int, error)
	Cooldown(ctx context.Context) (*big.Int, error)
	Owner(ctx context.Context) (common.Address, error)
	LastDrip(ctx context.Context, addr common.Address) (*big.Int, error)
}

FaucetReader provides read access to the testnet faucet's parameters.

type FaucetWriter

type FaucetWriter interface {
	Drip(ctx context.Context) error
	DripTo(ctx context.Context, recipient common.Address) error
}

FaucetWriter provides write access to the testnet faucet drip.

type FinalizedWithdrawal

type FinalizedWithdrawal struct {
	WithdrawalID [32]byte    `json:"WithdrawalID"`
	BlockHash    [32]byte    `json:"BlockHash"`
	EntryIndex   uint64      `json:"EntryIndex"`
	FinalizedAt  int64       `json:"FinalizedAt"`
	Attestation  Attestation `json:"Attestation"`
	Block        Block       `json:"Block"`
}

FinalizedWithdrawal is the positive clearing-layer finality object consumed by custody after the challenge window expires. Attestation signs SigningMessage(); Block is carried so custody providers can bind the ID to the exact withdrawal payload without maintaining clearing state.

func (*FinalizedWithdrawal) Header

func (*FinalizedWithdrawal) MarshalCBOR

func (t *FinalizedWithdrawal) MarshalCBOR(w io.Writer) error

func (*FinalizedWithdrawal) SigningMessage

func (fw *FinalizedWithdrawal) SigningMessage() []byte

SigningMessage returns the canonical CBOR preimage covered by the BLS finality signature (ADR-009 §4). It is not the same preimage as Block and excludes Attestation so the signature cannot be self-referential. Returns nil for a nil receiver so callers can distinguish "no message" from an all-zero preimage.

Preimage shape: canonical CBOR of FinalizedWithdrawalHeader{WithdrawalID, BlockHash, EntryIndex, FinalizedAt}. Frozen by the FinalizedWithdrawalHeader case in TestGoldens_Preimages; any change is a schema-family bump.

func (*FinalizedWithdrawal) UnmarshalCBOR

func (t *FinalizedWithdrawal) UnmarshalCBOR(r io.Reader) (err error)

type FinalizedWithdrawalHeader

type FinalizedWithdrawalHeader struct {
	WithdrawalID [32]byte
	BlockHash    [32]byte
	EntryIndex   uint64
	FinalizedAt  int64
}

FinalizedWithdrawalHeader is the deterministic preimage projection for a FinalizedWithdrawal. It intentionally excludes Attestation and Block while binding the block hash and entry location that custody must verify.

func (*FinalizedWithdrawalHeader) MarshalCBOR

func (t *FinalizedWithdrawalHeader) MarshalCBOR(w io.Writer) error

func (*FinalizedWithdrawalHeader) UnmarshalCBOR

func (t *FinalizedWithdrawalHeader) UnmarshalCBOR(r io.Reader) (err error)

type FraudEvidenceSubmitter

type FraudEvidenceSubmitter interface {
	SubmitWithdrawalFraudEvidence(ctx context.Context, evidence WithdrawalFraudEvidence) error
}

FraudEvidenceSubmitter provides write access to the on-chain Slasher.

type MintReceipt

type MintReceipt struct {
	TxID       string          // Issuer-defined transaction/event id
	Account    string          // Clearnet account URI to credit
	AssetURI   AssetURI        // Issuer asset URI
	Amount     decimal.Decimal // Deposit amount in protocol token units, must be > 0
	Signatures [][]byte        // k-of-n provider ECDSA signatures over the receipt digest
}

MintReceipt is issued by the custody layer after an L1 deposit confirms (ADR-005 §9.1, receipt-model amendment 2026-05-12). Provider ECDSA signatures (k-of-n against the configured custody signer directory — manifest custody.signers/threshold; future Registry-backed source) attest that the deposit landed and reached the configured confirmation depth; the cluster validates the receipt and credits the user account (DR 1010 / CR 2010).

Idempotency is keyed by (AssetURI, TxID) so a re-issued receipt cannot produce a second credit. Clearnet does not watch the chain — receipts are the only deposit ingress.

func (*MintReceipt) EncodePayload

func (v *MintReceipt) EncodePayload() []byte

EncodePayload serializes a MintReceipt into a BlockEntry payload.

func (*MintReceipt) MarshalCBOR

func (t *MintReceipt) MarshalCBOR(w io.Writer) error

func (*MintReceipt) UnmarshalCBOR

func (t *MintReceipt) UnmarshalCBOR(r io.Reader) (err error)

type NodeID

type NodeID [32]byte

NodeID is a 256-bit identity in the Kademlia space (§3.1). A Node MAY operate multiple NodeIDs, each with its own collateral and BLS key pair.

type RegistryReader

type RegistryReader interface {
	GetNodeByID(ctx context.Context, nodeID [32]byte) (*Slot, error)
	GetNodes(ctx context.Context, offset, limit *big.Int) ([]*Slot, error)
	TotalNodes(ctx context.Context) (*big.Int, error)
	GetActiveNodes(ctx context.Context, offset, limit *big.Int) ([]*Slot, error)
	ActiveCount(ctx context.Context) (uint32, error)
	FloorPrice(ctx context.Context) (*big.Int, error)
	GetNodeId(ctx context.Context, tokenId uint32) ([32]byte, error)
	UnbondingPeriod(ctx context.Context) (uint64, error)
}

RegistryReader provides read access to the L1 node registry.

Naming follows the on-chain `IRegistry` surface:

  • `TotalNodes` / `GetNodes` enumerate active + unbonding; active-only callers use `ActiveCount` plus `GetActiveNodes` (which filters `deactivatedAt == 0` on the Go side).
  • `FloorPrice` is the activation-time floor at the next cardinality.
  • `GetNodeId(tokenId)` resolves an NFT to the currently-locked nodeId.

type RegistryWriter

type RegistryWriter interface {
	Lock(ctx context.Context, blsPubkeyG1 [2]*big.Int, blsPubkeyG2 [4]*big.Int, popSignature [2]*big.Int, maxPrice *big.Int) (uint32, error)
	Unlock(ctx context.Context, tokenId uint32) error
	Release(ctx context.Context, tokenId uint32) error
	Fund(ctx context.Context, tokenId uint32, amount *big.Int) error
}

RegistryWriter provides write access to the L1 node registry.

`Lock` is a high-level onboarding helper: it calls `Registry.register`, which mints a NodeID NFT directly into Registry escrow and locks collateral. The `popSignature` parameter is accepted for source-compat but ignored on chain (ADR-008 2026-05-08: PoP verification moved to off-chain tooling).

type RepegOp

type RepegOp struct {
	PoolID        string   // Target pool
	OldPriceScale *big.Int // PriceScale before the repeg
	NewPriceScale *big.Int // PriceScale after the repeg
	OldVirtPrice  *big.Int // VirtualPrice before the repeg
	NewVirtPrice  *big.Int // VirtualPrice after the repeg
	Epoch         uint64   // Epoch number when the repeg occurred
	PriceEMA      *big.Int // Post-repeg PriceEMA (data_layer.md §4.2)
}

RepegOp is the payload for a PriceScale repegging block entry (SS8.1.2). Issued by the pool cluster after a profit-gated PriceScale adjustment.

func (*RepegOp) Decode

func (op *RepegOp) Decode(payload []byte) error

Decode deserializes a RepegOp from a block entry payload.

func (*RepegOp) Encode

func (op *RepegOp) Encode() []byte

Encode serializes the RepegOp into a block entry payload.

func (*RepegOp) MarshalCBOR

func (t *RepegOp) MarshalCBOR(w io.Writer) error

func (*RepegOp) UnmarshalCBOR

func (t *RepegOp) UnmarshalCBOR(r io.Reader) (err error)

type SessionChallengeOp

type SessionChallengeOp struct {
	SessionID       [32]byte // Session being challenged
	PreviousVersion uint64   // Version being replaced
	NewVersion      uint64   // Challenger's version (must be higher)
	NewDeadline     int64    // Unix timestamp when challenge window expires
}

SessionChallengeOp is the payload for a session dispute challenge (service_sessions.md §5.1).

func DecodeSessionChallengeOp

func DecodeSessionChallengeOp(data []byte) (*SessionChallengeOp, error)

DecodeSessionChallengeOp deserializes a SessionChallengeOp.

func (*SessionChallengeOp) Decode

func (op *SessionChallengeOp) Decode(payload []byte) error

Decode deserializes a SessionChallengeOp from a block entry payload.

func (*SessionChallengeOp) Encode

func (op *SessionChallengeOp) Encode() []byte

Encode serializes the SessionChallengeOp into a block entry payload.

func (*SessionChallengeOp) MarshalCBOR

func (t *SessionChallengeOp) MarshalCBOR(w io.Writer) error

func (*SessionChallengeOp) UnmarshalCBOR

func (t *SessionChallengeOp) UnmarshalCBOR(r io.Reader) (err error)

type SessionCloseOp

type SessionCloseOp struct {
	SessionID     [32]byte        // keccak256(userAccountID || serviceAccountID || nonce)
	Version       uint64          // Latest co-signed version
	UserAmount    decimal.Decimal // Final user allocation
	ServiceAmount decimal.Decimal // Final service allocation
	Cooperative   bool            // True if both parties signed
}

SessionCloseOp is the payload for a session close block entry (service_sessions.md §3.3). Emitted during cooperative or unilateral session settlement.

func DecodeSessionCloseOp

func DecodeSessionCloseOp(data []byte) (*SessionCloseOp, error)

DecodeSessionCloseOp deserializes a SessionCloseOp.

func (*SessionCloseOp) Decode

func (op *SessionCloseOp) Decode(payload []byte) error

Decode deserializes a SessionCloseOp from a block entry payload.

func (*SessionCloseOp) Encode

func (op *SessionCloseOp) Encode() []byte

Encode serializes the SessionCloseOp into a block entry payload.

func (*SessionCloseOp) MarshalCBOR

func (t *SessionCloseOp) MarshalCBOR(w io.Writer) error

func (*SessionCloseOp) UnmarshalCBOR

func (t *SessionCloseOp) UnmarshalCBOR(r io.Reader) (err error)

type SignerRotationFinalizer

type SignerRotationFinalizer interface {
	Pack(ctx context.Context, opID [32]byte, newSigners []string, newThreshold int) ([]byte, error)
	Validate(ctx context.Context, opID [32]byte, packed []byte, newSigners []string, newThreshold int) error
	Sign(ctx context.Context, packed []byte) ([]byte, error)
	Submit(ctx context.Context, packed []byte, signatures [][]byte) (string, error)
	VerifyRotation(ctx context.Context, newSigners []string, newThreshold int) (txID string, done bool, err error)
}

SignerRotationFinalizer rotates the vault's authorized signer set. It is the same build→sign→merge→submit→verify shape as VaultWithdrawalFinalizer, but the signed payload commits to the new signer set + threshold + the chain's local replay token (EVM signerNonce, XRPL account sequence, Solana program nonce) rather than a withdrawal. Signature collection (mesh) and submitter selection stay with the caller; the implementation owns the node's signer and the chain-specific authorization supplied at construction.

newSigners is the chain-native encoding of the incoming set — EVM/XRPL addresses, BTC 33-byte compressed pubkeys (hex), Solana ed25519 pubkeys (hex) — matching custody's RotationRequest. newThreshold is the new k-of-n quorum.

opID is the caller's unique identifier for this rotation operation (custody's RotationRequest.RequestID). In-place chains bind replay protection on-chain (EVM signerNonce, XRPL account sequence, Solana program nonce) and accept opID only to keep one uniform signature — they do not embed it in the packed payload. BTC has no on-chain op record: it embeds opID as an OP_RETURN marker in the sweep so an external watcher can attribute the swept transaction to this rotation. Pass a zero opID when the caller has no watcher to satisfy.

In-place chains (EVM, XRPL, Solana) mutate on-chain signer state at a fixed vault address. BTC has no in-place form: its P2WSH vault address is a function of the signer set, so rotation is a sweep of every old-vault UTXO into the newly-derived vault. The BTC implementation hides that behind the same interface via a vault store supplied at construction (it pivots to the new vault on confirmation); to callers all four chains rotate identically.

  • Pack returns the canonical bytes to be signed for this rotation.
  • Validate re-derives the trust-bound shape and asserts the packed bytes match — the Byzantine-packer defense; every node runs it before Sign.
  • Sign produces this node's signature over the packed bytes.
  • Submit merges the collected signatures against the live (outgoing) signer set and broadcasts the rotation. Idempotent against an already-applied rotation.
  • VerifyRotation reads canonical chain state to answer "is the set now the requested one?" — binary (done or not), the signal each node uses to close the dual-sign window and drop the outgoing key. It is keyed on the new signer set (not opID), so it stays a direct state read on every chain.

type Slot

type Slot struct {
	ID        NodeID `json:"id"`
	Label     string `json:"label"`
	BLSPubKey []byte `json:"bls_pubkey,omitempty"`

	// Registry position
	TokenID *big.Int `json:"-"`
	Index   uint64   `json:"-"` // widened from uint32 for cbor-gen compat (Wave 2 pre)

	// Economic weight + lifecycle
	Owner         string    `json:"-"` // EOA (hex) that owns the NFT per Registry.ownerOf(tokenId)
	Collateral    *big.Int  `json:"-"`
	ActivatedAt   uint64    `json:"-"`
	DeactivatedAt uint64    `json:"-"`
	State         SlotState `json:"-"`
	LastHeartbeat int64     `json:"-"`
	MissedBeats   uint64    `json:"-"` // widened from uint32 for cbor-gen compat (Wave 2 pre)
}

Slot is a logical node: one per NFT locked on Registry. Carries the slot's public identity (NodeID, Label, BLSPubKey) plus its Registry position and economic/lifecycle metadata.

type SlotState

type SlotState uint8

SlotState is the lifecycle state of a Registry slot (ADR-005 §3.3).

const (
	// SlotStateWarmup: slot is syncing state, not eligible to sign (§3.3).
	SlotStateWarmup SlotState = iota

	// SlotStateActive: slot is fully operational and may sign blocks.
	SlotStateActive

	// SlotStateUnbonding: slot has unregistered. Cannot sign new blocks but
	// remains in the Kademlia tree for the full UnbondingWindow so fraud
	// proofs may still be submitted against its collateral (ADR-005 §3.3).
	SlotStateUnbonding

	// SlotStateEvicted: slot has been fully removed from the Kademlia tree.
	SlotStateEvicted

	// SlotStateDisabled: slot missed heartbeats and is temporarily disabled (bitmask = 0).
	SlotStateDisabled
)

type SwapOp

type SwapOp struct {
	TxID      string          // Original transaction ID
	AssetIn   AssetID         // Input asset (what the user paid)
	AssetOut  AssetID         // Output asset (what the user receives)
	AmountIn  decimal.Decimal // Amount of input asset consumed
	AmountOut decimal.Decimal // Amount of output asset produced (after fee)
	PoolID    string          // Pool that executed the swap
	Fee       decimal.Decimal // Fee deducted (in output asset)
	FeeRate   uint64          // Dynamic fee rate applied (bps) — §5.3
	PriceEMA  decimal.Decimal // Post-swap EMA price (1e18 fixed-point, data_layer.md §4.2)
	SpotPrice decimal.Decimal // Post-swap spot price (1e18 fixed-point, data_layer.md §4.2)
}

SwapOp is the payload for a swap execution block entry (§7.1). Issued by the pool cluster after executing the AMM swap. Consumed by the user's cluster to credit the output asset.

func (*SwapOp) Decode

func (op *SwapOp) Decode(payload []byte) error

Decode deserializes a SwapOp from a block entry payload.

func (*SwapOp) Encode

func (op *SwapOp) Encode() []byte

Encode serializes the SwapOp into a block entry payload.

func (*SwapOp) MarshalCBOR

func (t *SwapOp) MarshalCBOR(w io.Writer) error

func (*SwapOp) UnmarshalCBOR

func (t *SwapOp) UnmarshalCBOR(r io.Reader) (err error)

type TokenReader

type TokenReader interface {
	BalanceOf(ctx context.Context, token string, account string) (*big.Int, error)
}

TokenReader provides read access to ERC-20 token balances. token is the token contract address (hex); account is the holder address (hex).

type TransferOp

type TransferOp struct {
	TxID   string          // Original transaction ID
	To     string          // Recipient address
	Assets []AssetTransfer // Assets transferred, sorted by AssetID (§7.2)
}

TransferOp is the payload for a transfer block entry (§5.3.5). Issued by the sender's cluster after debiting the sender. Consumed by the recipient's cluster to credit the recipient.

func NewSingleAssetTransferOp

func NewSingleAssetTransferOp(txID, to string, asset AssetID, amount decimal.Decimal) *TransferOp

NewSingleAssetTransferOp creates a TransferOp with a single asset (common case).

func (*TransferOp) Decode

func (op *TransferOp) Decode(payload []byte) error

Decode deserializes a TransferOp from a block entry payload.

func (*TransferOp) Encode

func (op *TransferOp) Encode() []byte

Encode serializes the TransferOp into a block entry payload (canonical CBOR, ADR-009 §4).

func (*TransferOp) MarshalCBOR

func (t *TransferOp) MarshalCBOR(w io.Writer) error

func (*TransferOp) UnmarshalCBOR

func (t *TransferOp) UnmarshalCBOR(r io.Reader) (err error)

type VaultDepositor

type VaultDepositor interface {
	SubmitDeposit(ctx context.Context, assetAddress string, amount decimal.Decimal, dest DepositDestination) (string, error)
	// VerifyDeposit reports whether the deposit identified by txID (returned by
	// SubmitDeposit) is present and final on chain — a pure read for replay/audit.
	// minConf is the confirmation depth required for DepositConfirmed; chains
	// with no numeric depth (Solana) map it onto a commitment level instead.
	VerifyDeposit(ctx context.Context, txID string, minConf uint64) (DepositStatus, error)
}

VaultDepositor moves funds into the L1 vault. The implementation owns the depositor's signing identity (a sign.Signer supplied at construction) and executes the deposit on its chain: a contract call (EVM), a funding tx to a derived address (BTC), or a memo-tagged Payment (XRPL). It expects a chain-local asset address/key, protocol-unit amount, and crediting destination. An empty assetAddress denotes the native asset at this API boundary; chain implementations normalize it to their protocol native marker.

type VaultWithdrawalFinalizer

type VaultWithdrawalFinalizer interface {
	Pack(ctx context.Context, op *WithdrawalOp, withdrawalID [32]byte, deadline int64) ([]byte, error)
	Validate(ctx context.Context, packed []byte, op *WithdrawalOp, withdrawalID [32]byte, deadline int64) error
	Sign(ctx context.Context, packed []byte) ([]byte, error)
	Submit(ctx context.Context, packed []byte, signatures [][]byte) (string, error)
	VerifyExecution(ctx context.Context, withdrawalID [32]byte) (txID string, executed bool, err error)
}

VaultWithdrawalFinalizer turns an authorized withdrawal into an on-chain release, as a sequence each custody node runs over a caller-orchestrated quorum. The implementation owns the node's signer and the chain-specific authorization (vault address, signer set, fee policy, ticket source) supplied at construction.

  • Pack returns the canonical bytes to be signed for this withdrawal.
  • Validate re-derives the trust-bound shape from the op and asserts the packed bytes match — the defense against a Byzantine packer; every node runs it before Sign.
  • Sign produces this node's signature over the packed bytes.
  • Submit merges the packed bytes with the collected quorum signatures into a submittable artifact and broadcasts it. It filters the signatures against the live on-chain signer set and is idempotent against a withdrawal a peer has already executed.
  • VerifyExecution reads canonical chain state to answer "already executed?" for the retry/finalize loop.

deadline (unix seconds) is threaded into Pack/Validate: it is a digest input on every chain, so the packed bytes — and thus the signature — bind it. Sign/Submit are unchanged; the packed body already carries it.

type WithdrawalFraudEvidence

type WithdrawalFraudEvidence struct {
	ChallengedObject []byte
	AnchorHeader     []byte
	AnchorSignature  []byte
	EntryIndex       uint64
	SMTProof         [][32]byte
	SMTBitmask       *big.Int
	BalanceKey       [32]byte
	ProvenBalance    *big.Int
}

WithdrawalFraudEvidence is the frozen two-object Slasher evidence shape (protocol/security.md §11): challenged signed withdrawal Block bytes plus the immediate pre-withdrawal signed header and one balance SMT proof.

type WithdrawalOp

type WithdrawalOp struct {
	AssetURI      AssetURI        // Issuer asset URI — needed for ledger finalization and custody routing
	Amount        decimal.Decimal // Withdrawal amount in token units
	Recipient     string          // L1 recipient address (chain-native format)
	UserSignature []byte          // User's ECDSA authorization of the withdrawal
}

WithdrawalOp is the payload for a withdrawal block entry (SS7.3.1). Issued by the user's cluster after locking funds for L1 withdrawal. Delivered to the custody layer after the clearing-side challenge window.

Removed fields (now in block header or derived at vault level):

  • WithdrawalID: derived at vault level as keccak256(accountId, blockHash, entryIndex, assetURI, recipient, amount, nonce)
  • Nonce: in BlockEntry.Nonce
  • K: in Block.K
  • SignedAt: in Block.SealedAt
  • SignerNodeIDs: recoverable from Block.Attestation.Bitmask + cluster lookup

func (*WithdrawalOp) Decode

func (op *WithdrawalOp) Decode(payload []byte) error

Decode deserializes a WithdrawalOp from a block entry payload.

func (*WithdrawalOp) Encode

func (op *WithdrawalOp) Encode() []byte

Encode serializes the WithdrawalOp into a block entry payload.

func (*WithdrawalOp) MarshalCBOR

func (t *WithdrawalOp) MarshalCBOR(w io.Writer) error

func (*WithdrawalOp) UnmarshalCBOR

func (t *WithdrawalOp) UnmarshalCBOR(r io.Reader) (err error)

type WithdrawalOutcome added in v0.4.0

type WithdrawalOutcome uint8

WithdrawalOutcome is the terminal status of a withdrawal, carried in a BurnReceipt. It lets clearnet tell a withdrawal that executed on L1 (settle the burn) apart from one that did not leave the vault (authorize a safe re-credit, with an empty TxID). The status byte is bound into the receipt digest, so a quorum cannot be tricked into swapping one outcome for another.

const (
	// WithdrawalExecuted means the withdrawal was executed on the target chain;
	// TxID is set and the clearing layer settles the burn.
	WithdrawalExecuted WithdrawalOutcome = 1
	// WithdrawalExpired means the authorization passed its deadline unspent and
	// can never execute (time-bound expiry); the clearing layer may re-credit.
	WithdrawalExpired WithdrawalOutcome = 2
	// WithdrawalInvalidFormat means the withdrawal has not passed custody's
	// input validation (e.g. malformed address, or other pre-flight rejection);
	WithdrawalInvalidFormat WithdrawalOutcome = 3
	// WithdrawalUnauthorized means the withdrawal is signed by one or more
	// unauthorized signers
	WithdrawalUnauthorized WithdrawalOutcome = 4
	// WithdrawalInvalidDecimals means the withdrawal amount cannot be represented
	// in the target chain's base units.
	// TODO: Replace this status with explicit remainder semantics once
	// BurnReceipt carries the unexecuted amount.
	WithdrawalInvalidDecimals WithdrawalOutcome = 5
)

Directories

Path Synopsis
Package main is the cbor-gen driver for pkg/core.
Package main is the cbor-gen driver for pkg/core.

Jump to

Keyboard shortcuts

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