Documentation
¶
Index ¶
- Constants
- Variables
- func BuildSigValidatorsBitmap(signerTypes []ChannelSignerType) string
- func DecimalToInt256(amount decimal.Decimal, decimals uint8) (*big.Int, error)
- func DecimalToUint256(amount decimal.Decimal, decimals uint8) (*big.Int, error)
- func GenerateChannelMetadata(asset string) [32]byte
- func GenerateSessionKeyStateIDV1(userAddress, sessionKey string, version uint64) (string, error)
- func GetChannelSessionKeyAuthMetadataHashV1(userAddress string, version uint64, assets []string, expiresAt int64) (common.Hash, error)
- func GetEscrowChannelID(homeChannelID string, stateVersion uint64) (string, error)
- func GetHomeChannelID(node, user, asset string, nonce uint64, challengeDuration uint32, ...) (string, error)
- func GetReceiverTransactionID(fromAccount, receiverNewStateID string) (string, error)
- func GetSenderTransactionID(toAccount string, senderNewStateID string) (string, error)
- func GetStateID(userWallet, asset string, epoch, version uint64) string
- func GetStateTransitionHash(transition Transition) ([32]byte, error)
- func IsChannelSignerSupported(approvedSigValidators string, signerType ChannelSignerType) bool
- func IsValidHash(s string, requireLowercase bool) bool
- func NormalizeHexAddress(s string) (string, error)
- func PackChallengeState(state State, assetStore AssetStore) ([]byte, error)
- func PackChannelKeyStateV1(sessionKey string, metadataHash common.Hash) ([]byte, error)
- func PackState(state State, assetStore AssetStore) ([]byte, error)
- func SafeOffset(offset uint32) int
- func SessionKeyAuthTypehash() common.Hash
- func SignerValidatorsSupported(channelValidators string) bool
- func TransitionToIntent(transition Transition) uint8
- func ValidateChannelSessionKeyStateUserSigV1(state ChannelSessionKeyStateV1) error
- func ValidateChannelSessionKeyStateV1(state ChannelSessionKeyStateV1) error
- func ValidateDecimalPrecision(amount decimal.Decimal, maxDecimals uint8) error
- type Asset
- type AssetStore
- type BalanceEntry
- type Blockchain
- type BlockchainClient
- type BlockchainEvent
- type Channel
- type ChannelDefaultSigner
- type ChannelDefinition
- type ChannelHubEventHandler
- type ChannelHubEventHandlerStore
- type ChannelParticipant
- type ChannelSessionKeySignerV1
- type ChannelSessionKeyStateV1
- type ChannelSigValidator
- type ChannelSigner
- type ChannelSignerType
- type ChannelStatus
- type ChannelType
- type EscrowDepositChallengedEvent
- type EscrowDepositDataResponse
- type EscrowDepositFinalizedEvent
- type EscrowDepositInitiatedEvent
- type EscrowDepositsPurgedEvent
- type EscrowWithdrawalChallengedEvent
- type EscrowWithdrawalDataResponse
- type EscrowWithdrawalFinalizedEvent
- type EscrowWithdrawalInitiatedEvent
- type HomeChannelChallengedEvent
- type HomeChannelCheckpointedEvent
- type HomeChannelClosedEvent
- type HomeChannelCreatedEvent
- type HomeChannelDataResponse
- type HomeChannelMigratedEvent
- type Ledger
- type NodeBalanceUpdatedEvent
- type NodeConfig
- type OnChainChannelSnapshot
- type PaginationMetadata
- type PaginationParams
- type ReadOnlyChannelHub
- type State
- func (state *State) ApplyAcknowledgementTransition() (Transition, error)
- func (state *State) ApplyChannelCreation(channelDef ChannelDefinition, blockchainID uint64, ...) (string, error)
- func (state *State) ApplyCommitTransition(accountID string, amount decimal.Decimal) (Transition, error)
- func (state *State) ApplyEscrowDepositTransition(amount decimal.Decimal) (Transition, error)
- func (state *State) ApplyEscrowLockTransition(blockchainID uint64, tokenAddress string, amount decimal.Decimal) (Transition, error)
- func (state *State) ApplyEscrowWithdrawTransition(amount decimal.Decimal) (Transition, error)
- func (state *State) ApplyFinalizeTransition() (Transition, error)
- func (state *State) ApplyHomeDepositTransition(amount decimal.Decimal) (Transition, error)
- func (state *State) ApplyHomeWithdrawalTransition(amount decimal.Decimal) (Transition, error)
- func (state *State) ApplyMigrateTransition(amount decimal.Decimal) (Transition, error)
- func (state *State) ApplyMutualLockTransition(blockchainID uint64, tokenAddress string, amount decimal.Decimal) (Transition, error)
- func (state *State) ApplyReleaseTransition(accountID string, amount decimal.Decimal) (Transition, error)
- func (state *State) ApplyTransferReceiveTransition(sender string, amount decimal.Decimal, txID string) (Transition, error)
- func (state *State) ApplyTransferSendTransition(recipient string, amount decimal.Decimal) (Transition, error)
- func (state *State) IsFinal() bool
- func (state State) NextState() *State
- type StateAdvancer
- type StateAdvancerV1
- type StatePacker
- type StatePackerV1
- type Token
- type Transaction
- type TransactionType
- type Transition
- type TransitionType
- type ValidatorRegisteredEvent
- type VerifyChannelSessionKePermissionsV1
Constants ¶
const ( INTENT_OPERATE = 0 INTENT_CLOSE = 1 INTENT_DEPOSIT = 2 INTENT_WITHDRAW = 3 INTENT_INITIATE_ESCROW_DEPOSIT = 4 INTENT_FINALIZE_ESCROW_DEPOSIT = 5 INTENT_INITIATE_ESCROW_WITHDRAWAL = 6 INTENT_FINALIZE_ESCROW_WITHDRAWAL = 7 INTENT_INITIATE_MIGRATION = 8 INTENT_FINALIZE_MIGRATION = 9 )
const ( // ChannelHubVersion is the version of the ChannelHub contract that this code is compatible with. // This version is encoded as the first byte of the channelId to prevent replay attacks // across different ChannelHub deployments on the same chain. ChannelHubVersion uint8 = 1 // ChannelMinChallengeDuration and ChannelMaxChallengeDuration mirror the // ChannelHub challenge-duration bounds. ChannelMinChallengeDuration uint32 = 24 * 60 * 60 ChannelMaxChallengeDuration uint32 = 7 * 24 * 60 * 60 )
Variables ¶
var AllTransitionTypes = []TransitionType{ TransitionTypeVoid, TransitionTypeAcknowledgement, TransitionTypeHomeDeposit, TransitionTypeHomeWithdrawal, TransitionTypeEscrowDeposit, TransitionTypeEscrowWithdraw, TransitionTypeTransferSend, TransitionTypeTransferReceive, TransitionTypeCommit, TransitionTypeRelease, TransitionTypeMigrate, TransitionTypeEscrowLock, TransitionTypeMutualLock, TransitionTypeFinalize, }
AllTransitionTypes enumerates every defined transition. Kept beside the const block so adding a new transition here is the natural place to update consumers that iterate the full domain (metrics seeding, drift tests).
var ( ChannelSignerTypes = []ChannelSignerType{ ChannelSignerType_Default, ChannelSignerType_SessionKey, } )
var ErrTokenNotSupported = errors.New("token not supported")
ErrTokenNotSupported indicates a token address is not configured in the node asset store for the given blockchain. Callers can use errors.Is to distinguish this deterministic "not configured" condition from genuine store failures.
var HashRegex = regexp.MustCompile(`^0x[0-9a-fA-F]{64}$`)
HashRegex matches a 32-byte hash rendered as a 0x-prefixed hex string, the canonical form of channel IDs and app session IDs (both Keccak256 hashes). Case-insensitive, since callers may submit checksummed or lowercased hex.
var LowercaseHashRegex = regexp.MustCompile(`^0x[0-9a-f]{64}$`)
LowercaseHashRegex matches the strict lowercase canonical form of a 32-byte hash, rejecting checksummed or uppercase hex.
Functions ¶
func BuildSigValidatorsBitmap ¶
func BuildSigValidatorsBitmap(signerTypes []ChannelSignerType) string
BuildSigValidatorsBitmap constructs a hex string bitmap from a slice of ChannelSignerType. Each signer type sets a bit at its corresponding position in a 256-bit value.
func DecimalToInt256 ¶ added in v1.3.0
DecimalToInt256 scales amount to the token's smallest unit and rejects values outside the Solidity int256 range [-2^255, 2^255 - 1]. Use for net-flow fields that are ABI-encoded as int256 prior to signing or onchain submission.
func DecimalToUint256 ¶ added in v1.3.0
DecimalToUint256 scales amount to the token's smallest unit and rejects values outside the Solidity uint256 range [0, 2^256 - 1]. Use for allocation/balance fields that are ABI-encoded as uint256 prior to signing or onchain submission.
func GenerateChannelMetadata ¶
GenerateChannelMetadata creates metadata from an asset by taking the first 8 bytes of keccak256(asset) and padding the rest with zeros to make a 32-byte array.
func GenerateSessionKeyStateIDV1 ¶
GenerateSessionKeyStateIDV1 generates a deterministic ID from user_address, session_key, and version.
func GetChannelSessionKeyAuthMetadataHashV1 ¶
func GetChannelSessionKeyAuthMetadataHashV1(userAddress string, version uint64, assets []string, expiresAt int64) (common.Hash, error)
GetChannelSessionKeyAuthMetadataHashV1 hashes the session-key authorization metadata. user_address is bound into the hash; together with the session_key already in PackChannelKeyStateV1, this binds the signed payload to a single (wallet, session_key) pair so signatures cannot be replayed across wallets or session keys.
func GetEscrowChannelID ¶
GetEscrowChannelID derives an escrow-specific channel ID based on a home channel and state version. This matches the Solidity getEscrowId function which computes keccak256(abi.encode(channelId, version)).
func GetHomeChannelID ¶
func GetHomeChannelID(node, user, asset string, nonce uint64, challengeDuration uint32, approvedSigValidators string) (string, error)
GetHomeChannelID generates a unique identifier for a primary channel based on its definition. It uses the configured ChannelHubVersion to ensure compatibility with the deployed ChannelHub contract. The channelId includes version information to prevent replay attacks across different ChannelHub deployments.
func GetReceiverTransactionID ¶
GetReceiverTransactionID calculates and returns a unique transaction ID reference for actions initiated by node.
func GetSenderTransactionID ¶
GetSenderTransactionID calculates and returns a unique transaction ID reference for actions initiated by user.
func GetStateID ¶
GetStateID creates a unique hash representing a specific snapshot of a user's wallet and asset state.
func GetStateTransitionHash ¶
func GetStateTransitionHash(transition Transition) ([32]byte, error)
func IsChannelSignerSupported ¶
func IsChannelSignerSupported(approvedSigValidators string, signerType ChannelSignerType) bool
func IsValidHash ¶ added in v1.4.0
IsValidHash reports whether s is a well-formed 32-byte hash (see HashRegex). When requireLowercase is true, s must be in strict lowercase canonical form (see LowercaseHashRegex); otherwise checksummed and uppercase hex are accepted.
func NormalizeHexAddress ¶ added in v1.3.0
func PackChallengeState ¶
func PackChallengeState(state State, assetStore AssetStore) ([]byte, error)
PackChallengeState is a convenience function that creates a StatePackerV1 and packs the challenge state.
func PackChannelKeyStateV1 ¶
PackChannelKeyStateV1 packs the session key authorization payload for signing using ABI encoding.
func PackState ¶
func PackState(state State, assetStore AssetStore) ([]byte, error)
PackState is a convenience function that creates a StatePackerV1 and packs the state. For production use, create a StatePackerV1 instance and reuse it.
func SafeOffset ¶ added in v1.4.0
SafeOffset converts a uint32 pagination offset to a non-negative int suitable for GORM's Offset(). A raw int(offset) wraps to a negative value on a 32-bit target for large uint32s, which GORM treats as "no offset" and silently returns the first page. Clamping to MaxInt32 keeps the conversion safe even when a caller reaches the store without routing through PaginationParams.GetOffsetAndLimit.
func SessionKeyAuthTypehash ¶ added in v1.3.0
SessionKeyAuthTypehash returns the type hash prepended to the session key authorization payload. It matches the Solidity constant SESSION_KEY_AUTH_TYPEHASH and prevents unrelated abi.encode(address, bytes32) signatures from being reused as authorizations.
func SignerValidatorsSupported ¶
SignerValidatorsSupported checks that every bit in channelValidators is covered by the node's supported ChannelSignerTypes.
func TransitionToIntent ¶
func TransitionToIntent(transition Transition) uint8
func ValidateChannelSessionKeyStateUserSigV1 ¶ added in v1.4.0
func ValidateChannelSessionKeyStateUserSigV1(state ChannelSessionKeyStateV1) error
ValidateChannelSessionKeyStateUserSigV1 verifies only user_sig over the registration payload: user_sig must recover to state.UserAddress (wallet authorizes the change). This is the revocation path (submitted expires_at <= now): the session-key holder's session_key_sig is intentionally not required so a lost, unavailable, or malicious delegate cannot veto the wallet's revocation of its own delegation. session_key binds the packed bytes and user_address binds the metadata hash, so the signature authorizes exactly this revocation and cannot be replayed for another key, wallet, or version.
func ValidateChannelSessionKeyStateV1 ¶ added in v1.3.0
func ValidateChannelSessionKeyStateV1(state ChannelSessionKeyStateV1) error
ValidateChannelSessionKeyStateV1 verifies both signatures over the registration payload: user_sig must recover to state.UserAddress (wallet authorizes the delegation) and session_key_sig must recover to state.SessionKey (session-key holder proves possession). Both signatures sign the same PackChannelKeyStateV1(session_key, metadataHash) payload; session_key binds the packed bytes and user_address binds the metadata hash, so a signature minted for one (wallet, session_key) pair cannot be replayed for another. Used for activation, extension, and rotation (submitted expires_at > now); revocation uses ValidateChannelSessionKeyStateUserSigV1.
Types ¶
type Asset ¶
type Asset struct {
Name string `json:"name"` // Asset name
Decimals uint8 `json:"decimals"` // Number of decimal places at YN
Symbol string `json:"symbol"` // Asset symbol
SuggestedBlockchainID uint64 `json:"suggested_blockchain_id"` // Suggested blockchain network ID for this asset
Tokens []Token `json:"tokens"` // Supported tokens for the asset
}
Asset represents information about a supported asset
type AssetStore ¶
type AssetStore interface {
// GetAssetDecimals checks if an asset exists and returns its decimals in YN
GetAssetDecimals(asset string) (uint8, error)
// GetTokenDecimals returns the decimals for a token on a specific blockchain
GetTokenDecimals(blockchainID uint64, tokenAddress string) (uint8, error)
}
type BalanceEntry ¶
type BalanceEntry struct {
Asset string `json:"asset"` // Asset symbol
Balance decimal.Decimal `json:"balance"` // Balance amount
Enforced decimal.Decimal `json:"enforced"` // On-chain enforced balance
}
BalanceEntry represents a balance entry for an asset
type Blockchain ¶
type Blockchain struct {
Name string `json:"name"` // Blockchain name
ID uint64 `json:"id"` // Blockchain network ID
ChannelHubAddress string `json:"channel_hub_address"` // Address of the ChannelHub contract on this blockchain
BlockStep uint64 `json:"block_step"` // Number of blocks between each channel update
ConfirmationDelaySecs uint32 `json:"confirmation_delay_secs"` // Seconds to wait before processing an event (0 = immediate)
}
Blockchain represents information about a supported blockchain network
type BlockchainClient ¶
type BlockchainClient interface {
// Getters - Token Balance & Approval
GetTokenBalance(asset string, walletAddress string) (decimal.Decimal, error)
Approve(asset string, amount decimal.Decimal) (string, error)
// Getters - ChannelsHub
GetNodeBalance(token string) (decimal.Decimal, error)
GetOpenChannels(user string) ([]string, error)
GetHomeChannelData(homeChannelID string) (HomeChannelDataResponse, error)
GetEscrowDepositData(escrowChannelID string) (EscrowDepositDataResponse, error)
GetEscrowWithdrawalData(escrowChannelID string) (EscrowWithdrawalDataResponse, error)
// Node vault functions
Deposit(token string, amount decimal.Decimal) (string, error)
Withdraw(to, token string, amount decimal.Decimal) (string, error)
// Node lifecycle
EnsureSigValidatorRegistered(validatorID uint8, validatorAddress string, checkOnly bool) error
// Channel lifecycle
Create(def ChannelDefinition, initCCS State) (string, error)
MigrateChannelHere(def ChannelDefinition, candidate State) (string, error)
Checkpoint(candidate State) (string, error)
Challenge(candidate State, challengerSig []byte, challengerIdx ChannelParticipant) (string, error)
Close(candidate State) (string, error)
// Escrow deposit
InitiateEscrowDeposit(def ChannelDefinition, initCCS State) (string, error)
ChallengeEscrowDeposit(candidate State, challengerSig []byte, challengerIdx ChannelParticipant) (string, error)
FinalizeEscrowDeposit(candidate State) (string, error)
// Escrow withdrawal
InitiateEscrowWithdrawal(def ChannelDefinition, initCCS State) (string, error)
ChallengeEscrowWithdrawal(candidate State, challengerSig []byte, challengerIdx ChannelParticipant) (string, error)
FinalizeEscrowWithdrawal(candidate State) (string, error)
}
Client defines the interface for interacting with the ChannelsHub smart contract TODO: add context to all methods
type BlockchainEvent ¶
type BlockchainEvent struct {
ContractAddress string `json:"contract_address"`
BlockchainID uint64 `json:"blockchain_id"`
Name string `json:"name"`
BlockNumber uint64 `json:"block_number"`
TransactionHash string `json:"transaction_hash"`
LogIndex uint32 `json:"log_index"`
BlockHash string `json:"block_hash"`
}
type Channel ¶
type Channel struct {
ChannelID string `json:"channel_id"` // Unique identifier for the channel
UserWallet string `json:"user_wallet"` // User wallet address
Asset string `json:"asset"` // Asset symbol (e.g. USDC, ETH)
Type ChannelType `json:"type"` // Type of the channel (home, escrow)
BlockchainID uint64 `json:"blockchain_id"` // Unique identifier for the blockchain
TokenAddress string `json:"token_address"` // Address of the token used in the channel
ChallengeDuration uint32 `json:"challenge_duration"` // Challenge period for the channel in seconds
ChallengeExpiresAt *time.Time `json:"challenge_expires_at,omitempty"` // Timestamp when the challenge period elapses
Nonce uint64 `json:"nonce"` // Nonce for the channel
ApprovedSigValidators string `json:"approved_sig_validators"` // Bitmask representing approved signature validators for the channel
Status ChannelStatus `json:"status"` // Current status of the channel (void, open, challenged, closed)
StateVersion uint64 `json:"state_version"` // On-chain state version of the channel
}
Channel represents an on-chain channel
func NewChannel ¶
type ChannelDefaultSigner ¶
func NewChannelDefaultSigner ¶
func NewChannelDefaultSigner(signer sign.Signer) (*ChannelDefaultSigner, error)
func (*ChannelDefaultSigner) Sign ¶
func (s *ChannelDefaultSigner) Sign(data []byte) (sign.Signature, error)
func (*ChannelDefaultSigner) Type ¶
func (s *ChannelDefaultSigner) Type() ChannelSignerType
type ChannelDefinition ¶
type ChannelDefinition struct {
Nonce uint64 `json:"nonce"` // A unique number to prevent replay attacks
Challenge uint32 `json:"challenge"` // Challenge period for the channel in seconds
ApprovedSigValidators string `json:"approved_sig_validators"` // Bitmask representing approved signature validators for the channel
}
ChannelDefinition represents configuration for creating a channel
type ChannelHubEventHandler ¶
type ChannelHubEventHandler interface {
HandleNodeBalanceUpdated(context.Context, ChannelHubEventHandlerStore, *NodeBalanceUpdatedEvent) error
HandleHomeChannelCreated(context.Context, ChannelHubEventHandlerStore, *HomeChannelCreatedEvent) error
HandleHomeChannelMigrated(context.Context, ChannelHubEventHandlerStore, *HomeChannelMigratedEvent) error
HandleHomeChannelCheckpointed(ctx context.Context, tx ChannelHubEventHandlerStore, hub ReadOnlyChannelHub, event *HomeChannelCheckpointedEvent) error
HandleHomeChannelChallenged(ctx context.Context, tx ChannelHubEventHandlerStore, hub ReadOnlyChannelHub, event *HomeChannelChallengedEvent) error
HandleHomeChannelClosed(ctx context.Context, tx ChannelHubEventHandlerStore, hub ReadOnlyChannelHub, event *HomeChannelClosedEvent) error
HandleEscrowDepositInitiated(context.Context, ChannelHubEventHandlerStore, *EscrowDepositInitiatedEvent) error
HandleEscrowDepositChallenged(context.Context, ChannelHubEventHandlerStore, *EscrowDepositChallengedEvent) error
HandleEscrowDepositFinalized(context.Context, ChannelHubEventHandlerStore, *EscrowDepositFinalizedEvent) error
HandleEscrowDepositsPurged(context.Context, ChannelHubEventHandlerStore, *EscrowDepositsPurgedEvent) error
HandleEscrowWithdrawalInitiated(context.Context, ChannelHubEventHandlerStore, *EscrowWithdrawalInitiatedEvent) error
HandleEscrowWithdrawalChallenged(context.Context, ChannelHubEventHandlerStore, *EscrowWithdrawalChallengedEvent) error
HandleEscrowWithdrawalFinalized(context.Context, ChannelHubEventHandlerStore, *EscrowWithdrawalFinalizedEvent) error
}
ChannelHubEventHandler defines the off-chain reactions to ChannelHub blockchain events. Only the three home-channel guard-drop handlers (HandleHomeChannelChallenged, HandleHomeChannelCheckpointed, HandleHomeChannelClosed) take a ReadOnlyChannelHub: they are the entrypoints where a version-regression guard may drop an event whose outer transaction has nonetheless committed state on chain, and the on-chain refresh is required to converge the Node row with chain. Other handlers do not need the hub and so do not accept the parameter, keeping the interface narrow.
type ChannelHubEventHandlerStore ¶ added in v1.3.0
type ChannelHubEventHandlerStore interface {
// GetLastStateByChannelID retrieves the most recent state for a given channel.
// If signed is true, only returns states with both user and node signatures.
// Returns nil if no matching state exists.
GetLastStateByChannelID(channelID string, signed bool) (*State, error)
// GetLastUserState retrieves the most recent state for a user's asset across all
// channels and detached chain entries (HomeChannelID nil). Returns nil if no
// matching state exists. If signed is true, only fully co-signed states are returned.
GetLastUserState(wallet, asset string, signed bool) (*State, error)
// GetStateByChannelIDAndVersion retrieves a specific state version for a channel.
// Returns nil if the state with the specified version does not exist.
GetStateByChannelIDAndVersion(channelID string, version uint64) (*State, error)
// UpdateChannel persists changes to a channel's metadata (status, version, etc).
// The channel must already exist in the database.
UpdateChannel(channel Channel) error
// GetChannelByID retrieves a channel by its unique identifier.
// Returns nil if the channel does not exist.
GetChannelByID(channelID string) (*Channel, error)
// ScheduleCheckpoint schedules a checkpoint operation for a home channel state.
// This queues the state to be submitted on-chain to update the channel's on-chain state.
ScheduleCheckpoint(stateID string, chainID uint64) error
// ScheduleChallenge schedules a challengeChannel(...) submission on the channel's home
// blockchain using the provided state and a node-produced challenger signature.
ScheduleChallenge(stateID string, chainID uint64) error
// ScheduleInitiateEscrowDeposit schedules an initiate for an escrow deposit operation.
// This queues the state to be submitted on-chain to finalize an escrow deposit.
ScheduleInitiateEscrowDeposit(stateID string, chainID uint64) error
// ScheduleFinalizeEscrowDeposit schedules a finalize for an escrow deposit operation.
// This queues the state to be submitted on-chain to finalize an escrow deposit.
ScheduleFinalizeEscrowDeposit(stateID string, chainID uint64) error
// ScheduleFinalizeEscrowWithdrawal schedules a checkpoint for an escrow withdrawal operation.
// This queues the state to be submitted on-chain to finalize an escrow withdrawal.
ScheduleFinalizeEscrowWithdrawal(stateID string, chainID uint64) error
// SetNodeBalance upserts the on-chain liquidity for a given blockchain and asset.
SetNodeBalance(blockchainID uint64, asset string, value decimal.Decimal) error
// RefreshUserEnforcedBalance recomputes the locked balance from the user's open home channel on-chain state.
RefreshUserEnforcedBalance(wallet, asset string) error
// LockUserState acquires SELECT ... FOR UPDATE on the user's balance row so the
// caller's transaction serializes against concurrent RPC paths that already lock
// the same row before issuing receiver states. Postgres-only; SQLite is a no-op
// in tests.
LockUserState(wallet, asset string) (decimal.Decimal, error)
// LockUserStateForHomeChannel locks the balance row of the user owning channelID. On
// postgres it derives the lock key from the channel in SQL and returns the channel read
// under that lock; on non-postgres (sqlite in tests) the snapshot is taken before the lock
// for test compatibility. Event handlers must use this instead of a GetChannelByID +
// LockUserState pair, which reads channel status before the lock and races a concurrent
// submit_state finalization. Returns nil if the channel is absent.
LockUserStateForHomeChannel(channelID string) (*Channel, error)
// UpdateStateSigsIfMissing backfills the user and/or node signatures for a stored state
// when the corresponding column is currently NULL. Used to repair the local record after
// an on-chain event proves the state was enforced. Either signature may be empty to skip
// that side; existing values are never overwritten and the call is idempotent on event replay.
UpdateStateSigsIfMissing(channelID string, version uint64, userSig, nodeSig string) error
// HasSignedFinalize reports whether a node-signed Finalize state exists for the given
// home channel. Used to detect the post-Finalize lifecycle when the channel status
// has been temporarily overwritten by an on-chain challenge.
HasSignedFinalize(channelID string) (bool, error)
// SumNetTransitionAmountAfterVersion returns the net effect on the user's
// home-channel balance of transitions stored against channelID strictly above
// minVersion. Receiver credits (TransferReceive, Release) contribute positively;
// sender debits (TransferSend, Commit) contribute negatively. Other transition
// kinds are excluded. Used to compute the ChallengeRescue amount when a
// challenged channel is closed.
SumNetTransitionAmountAfterVersion(channelID string, minVersion uint64) (decimal.Decimal, error)
// StoreUserState persists a user state row. Used by the event handler to record a
// ChallengeRescue squash state derived from a closed challenged channel.
StoreUserState(state State, applicationID string) error
// RecordTransaction creates a transaction row linking state transitions. Used by the
// event handler to record the ChallengeRescue transaction associated with the squash.
RecordTransaction(tx Transaction, applicationID string) error
}
type ChannelParticipant ¶
type ChannelParticipant uint8
var ( ChannelParticipantUser ChannelParticipant = 0 ChannelParticipantNode ChannelParticipant = 1 )
type ChannelSessionKeySignerV1 ¶
func NewChannelSessionKeySignerV1 ¶
func NewChannelSessionKeySignerV1(signer sign.Signer, metadataHash, authSig string) (*ChannelSessionKeySignerV1, error)
func (*ChannelSessionKeySignerV1) Sign ¶
func (s *ChannelSessionKeySignerV1) Sign(data []byte) (sign.Signature, error)
func (*ChannelSessionKeySignerV1) Type ¶
func (s *ChannelSessionKeySignerV1) Type() ChannelSignerType
type ChannelSessionKeyStateV1 ¶
type ChannelSessionKeyStateV1 struct {
// ID Hash(user_address + session_key + version)
UserAddress string `json:"user_address"` // UserAddress is the user wallet address
SessionKey string `json:"session_key"` // SessionKey is the session key address for delegation
Version uint64 `json:"version"` // Version is the version of the session key format
Assets []string `json:"assets"` // Assets associated with this session key
ExpiresAt time.Time `json:"expires_at"` // Expiration time as unix timestamp of this session key
UserSig string `json:"user_sig"` // UserSig is the user's signature over the session key metadata to authorize the registration/update of the session key
SessionKeySig string `json:"session_key_sig"` // SessionKeySig is the session-key holder's signature proving possession of the key being registered.
}
ChannelSessionKeyStateV1 represents the state of a session key.
type ChannelSigValidator ¶
type ChannelSigValidator struct {
// contains filtered or unexported fields
}
func NewChannelSigValidator ¶
func NewChannelSigValidator(permissionsVerifier VerifyChannelSessionKePermissionsV1) *ChannelSigValidator
type ChannelSigner ¶
type ChannelSigner interface {
sign.Signer
Type() ChannelSignerType
}
type ChannelSignerType ¶
type ChannelSignerType uint8
const ( ChannelSignerType_Default ChannelSignerType = 0x00 ChannelSignerType_SessionKey ChannelSignerType = 0x01 )
func GetSignerType ¶
func GetSignerType(sig []byte) (ChannelSignerType, error)
func (ChannelSignerType) String ¶
func (t ChannelSignerType) String() string
type ChannelStatus ¶
type ChannelStatus uint8
var ( ChannelStatusVoid ChannelStatus = 0 ChannelStatusOpen ChannelStatus = 1 ChannelStatusChallenged ChannelStatus = 2 ChannelStatusClosing ChannelStatus = 3 // co-signed Finalize stored off-chain; on-chain close pending ChannelStatusClosed ChannelStatus = 4 )
func (*ChannelStatus) Scan ¶
func (s *ChannelStatus) Scan(src any) error
func (ChannelStatus) String ¶
func (s ChannelStatus) String() string
type ChannelType ¶
type ChannelType uint8
var ( ChannelTypeHome ChannelType = 1 ChannelTypeEscrow ChannelType = 2 )
type EscrowDepositChallengedEvent ¶
type EscrowDepositChallengedEvent channelChallengedEvent
EscrowDepositChallengedEvent represents the EscrowDepositChallenged event
type EscrowDepositDataResponse ¶
type EscrowDepositDataResponse struct {
EscrowChannelID string `json:"escrow_channel_id"`
Node string `json:"node"`
LastState State `json:"last_state"`
UnlockExpiry uint64 `json:"unlock_expiry"`
ChallengeExpiry uint64 `json:"challenge_expiry"`
}
EscrowDepositDataResponse represents the response from getEscrowDepositData
type EscrowDepositFinalizedEvent ¶
type EscrowDepositFinalizedEvent channelEvent
EscrowDepositFinalizedEvent represents the EscrowDepositFinalized event
type EscrowDepositInitiatedEvent ¶
type EscrowDepositInitiatedEvent channelEvent
EscrowDepositInitiatedEvent represents the EscrowDepositInitiated event
type EscrowDepositsPurgedEvent ¶ added in v1.3.0
type EscrowDepositsPurgedEvent struct {
// EscrowIDs holds the hex-encoded escrow IDs (== channel_id in the channels table) that were purged.
EscrowIDs []string `json:"escrow_ids"`
}
EscrowDepositsPurgedEvent represents the EscrowDepositsPurged event emitted when expired escrow deposits are finalized by the purge queue without a signed FINALIZE_ESCROW_DEPOSIT state.
type EscrowWithdrawalChallengedEvent ¶
type EscrowWithdrawalChallengedEvent channelChallengedEvent
EscrowWithdrawalChallengedEvent represents the EscrowWithdrawalChallenged event
type EscrowWithdrawalDataResponse ¶
type EscrowWithdrawalDataResponse struct {
EscrowChannelID string `json:"escrow_channel_id"`
Node string `json:"node"`
LastState State `json:"last_state"`
}
EscrowWithdrawalDataResponse represents the response from getEscrowWithdrawalData
type EscrowWithdrawalFinalizedEvent ¶
type EscrowWithdrawalFinalizedEvent channelEvent
EscrowWithdrawalFinalizedEvent represents the EscrowWithdrawalFinalized event
type EscrowWithdrawalInitiatedEvent ¶
type EscrowWithdrawalInitiatedEvent channelEvent
EscrowWithdrawalInitiatedEvent represents the EscrowWithdrawalInitiated event
type HomeChannelChallengedEvent ¶
type HomeChannelChallengedEvent channelChallengedEvent
HomeChannelChallengedEvent represents the Challenged event
type HomeChannelCheckpointedEvent ¶
type HomeChannelCheckpointedEvent channelEvent
HomeChannelCheckpointedEvent represents the Checkpointed event
type HomeChannelClosedEvent ¶
type HomeChannelClosedEvent channelEvent
HomeChannelClosedEvent represents the Closed event
type HomeChannelCreatedEvent ¶
type HomeChannelCreatedEvent channelEvent
HomeChannelCreatedEvent represents the ChannelCreated event
type HomeChannelDataResponse ¶
type HomeChannelDataResponse struct {
Definition ChannelDefinition `json:"definition"`
Node string `json:"node"`
LastState State `json:"last_state"`
ChallengeExpiry uint64 `json:"challenge_expiry"`
}
HomeChannelDataResponse represents the response from getHomeChannelData
type HomeChannelMigratedEvent ¶
type HomeChannelMigratedEvent channelEvent
HomeChannelMigratedEvent represents the ChannelMigrated event
type Ledger ¶
type Ledger struct {
TokenAddress string `json:"token_address"` // Address of the token used in this channel
BlockchainID uint64 `json:"blockchain_id"` // Unique identifier for the blockchain
UserBalance decimal.Decimal `json:"user_balance"` // User balance in the channel
UserNetFlow decimal.Decimal `json:"user_net_flow"` // User net flow in the channel
NodeBalance decimal.Decimal `json:"node_balance"` // Node balance in the channel
NodeNetFlow decimal.Decimal `json:"node_net_flow"` // Node net flow in the channel
}
Ledger represents ledger balances
func (Ledger) Validate ¶
Validate checks ledger invariants and ensures all four scaled values fit the Solidity ABI ranges used for signing and onchain calls. Balances must fit uint256 ([0, 2^256-1]); net flows must fit int256 ([-2^255, 2^255-1]). assetDecimals is the token's decimal exponent, used to scale decimal values to their smallest onchain units before the range check.
type NodeBalanceUpdatedEvent ¶ added in v1.3.0
type NodeBalanceUpdatedEvent struct {
BlockchainID uint64 `json:"blockchain_id"`
Asset string `json:"asset"`
Balance decimal.Decimal `json:"balance"`
}
NodeBalanceUpdatedEvent represents the NodeBalanceUpdated event
type NodeConfig ¶
type NodeConfig struct {
// NodeAddress is the Ethereum address of the nitronode operator
NodeAddress string
// NodeVersion is the software version of the nitronode instance
NodeVersion string
// SupportedSigValidators is the list of supported signature validator types
SupportedSigValidators []ChannelSignerType
// Blockchains is the list of supported blockchain networks
Blockchains []Blockchain
}
NodeConfig represents the configuration of a Nitronode instance. It includes the node's identity, version, and supported blockchain networks.
type OnChainChannelSnapshot ¶ added in v1.4.0
type OnChainChannelSnapshot struct {
Status ChannelStatus // mapped from on-chain ChannelStatus enum
StateVersion uint64 // from ChannelMeta.lastState.version
ChallengeExpiresAt *time.Time // nil if no active challenge (on-chain expiry is zero)
LastStateUserSig string // hex-encoded user signature for UpdateStateSigsIfMissing backfill; empty when chain has no sig populated
}
OnChainChannelSnapshot carries the authoritative on-chain channel snapshot returned by ReadOnlyChannelHub.FetchChannel and used to converge a Node row that has diverged from chain.
The snapshot reflects on-chain state at RPC-read time, not event-emit time: the contract may have advanced the channel through additional transitions between when the dropped event was emitted and when the refresh RPC ran. The Node row may therefore briefly skip an intermediate status it never observed, but it will always converge to a status the chain currently asserts.
type PaginationMetadata ¶
type PaginationMetadata struct {
Page uint32 `json:"page"` // Current page number
PerPage uint32 `json:"per_page"` // Number of items per page
TotalCount uint32 `json:"total_count"` // Total number of items
PageCount uint32 `json:"page_count"` // Total number of pages
}
PaginationMetadata contains pagination information for list responses.
type PaginationParams ¶
PaginationParams provides pagination configuration for getters
func (*PaginationParams) GetOffsetAndLimit ¶
func (p *PaginationParams) GetOffsetAndLimit(defaultLimit, maxLimit uint32) (offset, limit uint32)
GetOffsetAndLimit extracts offset and limit from pagination params with defaults and max limit enforcement. A limit of 0 is treated the same as an absent limit: the defaultLimit is used.
type ReadOnlyChannelHub ¶ added in v1.4.0
type ReadOnlyChannelHub interface {
// FetchChannel reads the authoritative on-chain channel snapshot for channelID
// and returns an OnChainChannelSnapshot ready to overwrite the Node's local
// row. The snapshot reflects on-chain state at RPC-read time, not
// event-emit time.
FetchChannel(ctx context.Context, channelID string) (*OnChainChannelSnapshot, error)
}
ReadOnlyChannelHub is a read-only view of the on-chain ChannelHub contract, used by event handlers to converge the Node row with chain after a guard drops an event. Each reactor binds a ReadOnlyChannelHub for its own chain and threads it into the handler methods that need an authoritative on-chain snapshot; no global multi-chain dispatcher is required.
type State ¶
type State struct {
ID string `json:"id"` // Deterministic ID (hash) of the state
Transition Transition `json:"transition"` // The transition that led to this state
Asset string `json:"asset"` // Asset type of the state
UserWallet string `json:"user_wallet"` // User wallet address
Epoch uint64 `json:"epoch"` // User Epoch Index
Version uint64 `json:"version"` // Version of the state
HomeChannelID *string `json:"home_channel_id,omitempty"` // Identifier for the home Channel ID
EscrowChannelID *string `json:"escrow_channel_id,omitempty"` // Identifier for the escrow Channel ID
HomeLedger Ledger `json:"home_ledger"` // User and node balances for the home channel
EscrowLedger *Ledger `json:"escrow_ledger,omitempty"` // User and node balances for the escrow channel
UserSig *string `json:"user_sig,omitempty"` // User signature for the state
NodeSig *string `json:"node_sig,omitempty"` // Node signature for the state
}
State represents the current state of the user stored on Node
func NewChallengeRescueState ¶ added in v1.3.0
func NewChallengeRescueState(prev State, closedChannelID string, amount decimal.Decimal) (*State, error)
NewChallengeRescueState constructs a ChallengeRescue state crediting amount to the user against closedChannelID. Placement depends on prev:
prev is in-channel (HomeChannelID != nil): the rescue opens a fresh epoch at (prev.Epoch+1, version=1) with a clean ledger seeded by amount. Used when no node-signed Finalize exists locally for the closed channel — the user's chain has not been advanced past prev yet. Version=1 (not 0) mirrors NextState()'s post-Finalize convention so version=0 stays reserved as the "no on-chain state materialised yet" sentinel.
prev is detached (HomeChannelID == nil): the rescue appends at (prev.Epoch, prev.Version+1), inheriting prev's ledger and adding amount on top. Used after a path-1 timeout close when a node-signed Finalize is on file: the sign-time NextState() has already advanced the user to a fresh epoch and post-Finalize receiver credits may already live there. Placing rescue at v=0 would collide on deterministic state ID; appending after the detached tip avoids that.
closedChannelID is the on-chain channel whose close triggers the rescue. It is recorded as the rescue's transition AccountID so the credit is traceable back to the settlement.
func NewVoidState ¶
func (*State) ApplyAcknowledgementTransition ¶
func (state *State) ApplyAcknowledgementTransition() (Transition, error)
func (*State) ApplyChannelCreation ¶
func (state *State) ApplyChannelCreation(channelDef ChannelDefinition, blockchainID uint64, tokenAddress, nodeAddress string) (string, error)
ApplyChannelCreation applies channel creation parameters to the state and returns the calculated home channel ID.
func (*State) ApplyCommitTransition ¶
func (*State) ApplyEscrowDepositTransition ¶
func (state *State) ApplyEscrowDepositTransition(amount decimal.Decimal) (Transition, error)
func (*State) ApplyEscrowLockTransition ¶
func (*State) ApplyEscrowWithdrawTransition ¶
func (state *State) ApplyEscrowWithdrawTransition(amount decimal.Decimal) (Transition, error)
func (*State) ApplyFinalizeTransition ¶
func (state *State) ApplyFinalizeTransition() (Transition, error)
This transition can also contain non-zero amount in case previous state had a non-zero user balance. Basically, amount in this transition means that user is withdrawing it from the channel as part of finalization.
func (*State) ApplyHomeDepositTransition ¶
func (state *State) ApplyHomeDepositTransition(amount decimal.Decimal) (Transition, error)
func (*State) ApplyHomeWithdrawalTransition ¶
func (state *State) ApplyHomeWithdrawalTransition(amount decimal.Decimal) (Transition, error)
func (*State) ApplyMigrateTransition ¶
func (state *State) ApplyMigrateTransition(amount decimal.Decimal) (Transition, error)
func (*State) ApplyMutualLockTransition ¶
func (*State) ApplyReleaseTransition ¶
func (*State) ApplyTransferReceiveTransition ¶
func (*State) ApplyTransferSendTransition ¶
type StateAdvancer ¶
StateAdvancer applies state transitions
type StateAdvancerV1 ¶
type StateAdvancerV1 struct {
// contains filtered or unexported fields
}
StateAdvancerV1 provides basic validation for state transitions
func NewStateAdvancerV1 ¶
func NewStateAdvancerV1(assetStore AssetStore) *StateAdvancerV1
NewStateAdvancerV1 creates a new simple transition validator
func (*StateAdvancerV1) ValidateAdvancement ¶
func (v *StateAdvancerV1) ValidateAdvancement(currentState, proposedState State) error
ValidateAdvancement validates that the proposed state is a valid advancement of the current state
NOTE: User signature is not validated here
TODO: Add shared JSON fixture suite consumed by both Go and TS test suites to guarantee validation parity
type StatePacker ¶
StatePacker serializes channel states
type StatePackerV1 ¶
type StatePackerV1 struct {
// contains filtered or unexported fields
}
func NewStatePackerV1 ¶
func NewStatePackerV1(assetStore AssetStore) *StatePackerV1
func (*StatePackerV1) PackChallengeState ¶
func (p *StatePackerV1) PackChallengeState(state State) ([]byte, error)
PackChallengeState encodes a state for challenge signature verification. This matches the Solidity contract's challenge validation:
challengerSigningData = abi.encodePacked(abi.encode(version, intent, metadata, homeLedger, nonHomeLedger), "challenge") message = abi.encode(channelId, challengerSigningData)
func (*StatePackerV1) PackState ¶
func (p *StatePackerV1) PackState(state State) ([]byte, error)
PackState encodes a channel ID and state into ABI-packed bytes for on-chain submission. This matches the Solidity contract's two-step encoding:
Step 1: signingData = abi.encode(version, intent, metadata, homeLedger, nonHomeLedger) Step 2: message = abi.encode(channelId, signingData)
type Token ¶
type Token struct {
Name string `json:"name"` // Token name
Symbol string `json:"symbol"` // Token symbol
Address string `json:"address"` // Token contract address
BlockchainID uint64 `json:"blockchain_id"` // Blockchain network ID
Decimals uint8 `json:"decimals"` // Number of decimal places
}
Token represents information about a supported token
type Transaction ¶
type Transaction struct {
ID string `json:"id"` // Unique transaction reference
Asset string `json:"asset"` // Asset symbol
TxType TransactionType `json:"tx_type"` // Transaction type
FromAccount string `json:"from_account"` // The account that sent the funds
ToAccount string `json:"to_account"` // The account that received the funds
SenderNewStateID *string `json:"sender_new_state_id,omitempty"` // The ID of the new sender's channel state
ReceiverNewStateID *string `json:"receiver_new_state_id,omitempty"` // The ID of the new receiver's channel state
Amount decimal.Decimal `json:"amount"` // Transaction amount
CreatedAt time.Time `json:"created_at"` // When the transaction was created
}
Transaction represents a transaction record
func NewTransaction ¶
func NewTransaction(id, asset string, txType TransactionType, fromAccount, toAccount string, senderNewStateID, receiverNewStateID *string, amount decimal.Decimal) *Transaction
NewTransaction creates a new instance of Transaction
func NewTransactionFromTransition ¶
func NewTransactionFromTransition(senderState *State, receiverState *State, transition Transition) (*Transaction, error)
NewTransactionFromTransition maps the transition type to the appropriate transaction type and returns a pointer to a Transaction.
type TransactionType ¶
type TransactionType uint8
TransactionType represents the type of transaction
const ( TransactionTypeHomeDeposit TransactionType = 10 TransactionTypeHomeWithdrawal TransactionType = 11 TransactionTypeEscrowDeposit TransactionType = 20 TransactionTypeEscrowWithdraw TransactionType = 21 TransactionTypeTransfer TransactionType = 30 TransactionTypeCommit TransactionType = 40 TransactionTypeRelease TransactionType = 41 TransactionTypeMigrate TransactionType = 100 TransactionTypeEscrowLock TransactionType = 110 TransactionTypeMutualLock TransactionType = 120 TransactionTypeFinalize = 200 // TransactionTypeChallengeRescue mirrors TransitionTypeChallengeRescue and records // the squashed credit produced when a challenged home channel is closed onchain. TransactionTypeChallengeRescue TransactionType = 201 )
func (TransactionType) String ¶
func (t TransactionType) String() string
String returns the human-readable name of the transaction type
type Transition ¶
type Transition struct {
Type TransitionType `json:"type"` // Type of state transition
TxID string `json:"tx_id"` // Transaction ID associated with the transition
AccountID string `json:"account_id"` // Account identifier (varies based on transition type)
Amount decimal.Decimal `json:"amount"` // Amount involved in the transition
}
Transition represents a state transition
func NewTransition ¶
func NewTransition(transitionType TransitionType, txID, accountID string, amount decimal.Decimal) *Transition
NewTransition creates a new state transition
func (Transition) Equal ¶
func (t1 Transition) Equal(t2 Transition) error
Equal checks if two transitions are equal
type TransitionType ¶
type TransitionType uint8
TransitionType represents the type of state transition
const ( TransitionTypeVoid = 0 // Void transition, used for the initial state with no activity TransitionTypeAcknowledgement TransitionType = 1 // Acknowledgement of a received transfer, used for the initial state when a transfer is received without an existing state TransitionTypeHomeDeposit TransitionType = 10 // AccountID: HomeChannelID TransitionTypeHomeWithdrawal TransitionType = 11 // AccountID: HomeChannelID TransitionTypeEscrowDeposit TransitionType = 20 // AccountID: EscrowChannelID TransitionTypeEscrowWithdraw TransitionType = 21 // AccountID: EscrowChannelID TransitionTypeTransferSend TransitionType = 30 // AccountID: Receiver's UserWallet TransitionTypeTransferReceive TransitionType = 31 // AccountID: Sender's UserWallet TransitionTypeCommit TransitionType = 40 // AccountID: AppSessionID TransitionTypeRelease TransitionType = 41 // AccountID: AppSessionID TransitionTypeMigrate TransitionType = 100 // AccountID: EscrowChannelID TransitionTypeEscrowLock TransitionType = 110 // AccountID: EscrowChannelID TransitionTypeMutualLock TransitionType = 120 // AccountID: EscrowChannelID TransitionTypeFinalize TransitionType = 200 // AccountID: HomeChannelID // TransitionTypeChallengeRescue is issued by the node when a challenged home channel // is closed onchain with a non-finalize transition. It squashes the sum of receiver // states accrued under the no-sign-while-challenged rule into a single credit on the // user's ledger, with AccountID set to the closed channel ID and HomeChannelID nil. // Only the node can produce this transition; it has no state-advancer validation rule. TransitionTypeChallengeRescue TransitionType = 201 // AccountID: closed HomeChannelID )
func (TransitionType) String ¶
func (t TransitionType) String() string
String returns the human-readable name of the transition type
type ValidatorRegisteredEvent ¶ added in v1.3.0
type ValidatorRegisteredEvent struct {
BlockchainID uint64 `json:"blockchain_id"`
ValidatorID uint8 `json:"validator_id"`
// Validator is the EIP-55 checksummed hex address of the registered validator contract.
// Always compare using strings.EqualFold or common.HexToAddress(ev.Validator).Hex()
// to avoid silent mismatches against lowercase or non-checksummed config values.
Validator string `json:"validator"`
BlockNumber uint64 `json:"block_number"` // block where the event was emitted; use as fromBlock on reconnect
}
ValidatorRegisteredEvent is emitted by ChannelHub when the node registers a new signature validator. Users should react to unexpected registrations by revoking ERC20 approvals granted to ChannelHub — see contracts/SECURITY.md for details.