Documentation
¶
Overview ¶
Package xrpl implements the XRP Ledger custody vault via Peersyst/xrpl-go: a depositor that sends tagged Payments, and a multi-sign withdrawal finalizer over a SignerList-configured vault account. Both take a sign.Signer; neither holds persistence or a mesh.
Index ¶
- Constants
- func BuildAmount(ctx context.Context, assets blockchain.AssetResolver, op *core.WithdrawalOp) (types.CurrencyAmount, error)
- func CanonicalJSON(flatTx transaction.FlatTransaction) ([]byte, error)
- func ValidateCanonical(ctx context.Context, assets blockchain.AssetResolver, ...) error
- type AssetResolver
- type AssetResolverConfig
- type Depositor
- type Identity
- type LedgerState
- type LedgerStateResolver
- type LedgerTicketProvider
- type RotationFinalizer
- func (f *RotationFinalizer) LiveQuorum(_ context.Context) (int, error)
- func (f *RotationFinalizer) Pack(ctx context.Context, _ [32]byte, newSigners []string, newThreshold int) ([]byte, error)
- func (f *RotationFinalizer) SetLedgerStateResolver(fn LedgerStateResolver)
- func (f *RotationFinalizer) SetStandaloneLedgerMode(v bool)
- func (f *RotationFinalizer) SetThresholdResolver(fn func(context.Context) (int, error))
- func (f *RotationFinalizer) Sign(ctx context.Context, packed []byte) ([]byte, error)
- func (f *RotationFinalizer) Submit(_ context.Context, _ []byte, signatures [][]byte) (string, error)
- func (f *RotationFinalizer) Validate(ctx context.Context, _ [32]byte, packed []byte, newSigners []string, ...) error
- func (f *RotationFinalizer) VerifyRotation(_ context.Context, newSigners []string, newThreshold int) (string, bool, error)
- type TicketProvider
- type WithdrawalFinalizer
- func (f *WithdrawalFinalizer) LiveQuorum(_ context.Context) (int, error)
- func (f *WithdrawalFinalizer) Pack(ctx context.Context, op *core.WithdrawalOp, withdrawalID [32]byte, ...) ([]byte, error)
- func (f *WithdrawalFinalizer) SetLedgerStateResolver(fn LedgerStateResolver)
- func (f *WithdrawalFinalizer) SetStandaloneLedgerMode(v bool)
- func (f *WithdrawalFinalizer) SetThresholdResolver(fn func(context.Context) (int, error))
- func (f *WithdrawalFinalizer) Sign(ctx context.Context, packed []byte) ([]byte, error)
- func (f *WithdrawalFinalizer) Submit(_ context.Context, _ []byte, signatures [][]byte) (string, error)
- func (f *WithdrawalFinalizer) Validate(ctx context.Context, packed []byte, op *core.WithdrawalOp, ...) error
- func (f *WithdrawalFinalizer) VerifyExecution(ctx context.Context, withdrawalID [32]byte) (string, bool, error)
Constants ¶
const ( // LedgerBudget is the number of ledgers of headroom the builder targets when // setting LastLedgerSequence (~2min at ~4s/ledger). LedgerBudget = uint32(30) // MaxLedgerBudget is the upper bound a follower accepts on (LLS - current): // slack over LedgerBudget for the ledgers that close between build and // validation, still far under the deadline. MaxLedgerBudget = uint32(120) )
LastLedgerSequence budget. XRPL has no per-tx timestamp expiry, so a signed-but-unbroadcast Payment would live as a standing bearer claim. Every canonical withdrawal instead carries a LastLedgerSequence: rippled drops the tx once the network passes that ledger, so each blob dies at the ledger level.
The critical correctness property: the budget is per-attempt and small — derived from ExecutionMargin, NOT the full validity window — so every blob a retry can produce dies before SealedAt + MaxBlockAge + margin = deadline. A full-window budget would let a blob signed near the freshness cutoff outlive clearnet's re-credit and double-spend.
Variables ¶
This section is empty.
Functions ¶
func BuildAmount ¶
func BuildAmount(ctx context.Context, assets blockchain.AssetResolver, op *core.WithdrawalOp) (types.CurrencyAmount, error)
BuildAmount converts a WithdrawalOp into an XRPL CurrencyAmount.
func CanonicalJSON ¶
func CanonicalJSON(flatTx transaction.FlatTransaction) ([]byte, error)
CanonicalJSON encodes a FlatTransaction with sorted keys.
func ValidateCanonical ¶
func ValidateCanonical(ctx context.Context, assets blockchain.AssetResolver, flat transaction.FlatTransaction, op *core.WithdrawalOp, withdrawalID [32]byte, vault string, policy llsPolicy) error
ValidateCanonical asserts the canonical flatTx matches the op and that its LastLedgerSequence falls inside the follower's expiry band.
Types ¶
type AssetResolver ¶ added in v0.5.0
type AssetResolver struct {
// contains filtered or unexported fields
}
func NewAssetResolver ¶ added in v0.5.0
func NewAssetResolver(cfg AssetResolverConfig) *AssetResolver
func (*AssetResolver) AssetDecimals ¶ added in v0.5.0
func (*AssetResolver) ValidateAssetAddress ¶ added in v0.5.0
func (r *AssetResolver) ValidateAssetAddress(_ context.Context, assetAddress string) error
type AssetResolverConfig ¶ added in v0.5.0
type Depositor ¶
type Depositor struct {
// contains filtered or unexported fields
}
Depositor sends a Payment from the depositor's account (the key the sign.Signer holds) to the vault, crediting a clearnet account via a `ynet-account` memo (a 20-byte account followed by a 32-byte ADR-015 reference). It implements core.VaultDepositor. Native XRP and issued currencies ("CUR.rIssuer") are both supported.
func NewDepositor ¶
func NewDepositor(rpcURL, vaultAddress string, signer sign.Signer, assets blockchain.AssetResolver) (*Depositor, error)
NewDepositor builds the XRPL depositor against the rippled JSON-RPC at rpcURL.
func (*Depositor) DepositorAddress ¶
DepositorAddress returns the depositor's classic r-address.
func (*Depositor) SubmitDeposit ¶
func (d *Depositor) SubmitDeposit(ctx context.Context, assetAddress string, amount decimal.Decimal, dest core.DepositDestination) (string, error)
SubmitDeposit sends amount of assetAddress to the vault, crediting dest.Account via a `ynet-account` memo carrying the 20-byte account and the 32-byte ADR-015 dest.Ref. assetAddress is "" for native or "CUR.rIssuer" for an issued currency.
func (*Depositor) VerifyDeposit ¶
func (d *Depositor) VerifyDeposit(_ context.Context, txID string, _ uint64) (core.DepositStatus, error)
VerifyDeposit reports the on-chain status of the deposit txID. XRPL finality is binary — a validated transaction cannot be reorged — so minConf is not a depth here: a validated tx is DepositConfirmed, one found but not yet validated is DepositPending, and an unknown hash (never submitted, or dropped before validation) is DepositAbsent.
type LedgerState ¶ added in v0.4.0
LedgerState is a snapshot of the network's current validated ledger: its index and close time (as a unix timestamp). Used to set and to bound a withdrawal's LastLedgerSequence against its deadline.
type LedgerStateResolver ¶ added in v0.4.0
type LedgerStateResolver func(ctx context.Context) (LedgerState, error)
LedgerStateResolver reads the current validated LedgerState. Injectable so followers/tests can supply a deterministic snapshot instead of a live RPC.
type LedgerTicketProvider ¶
type LedgerTicketProvider struct {
// contains filtered or unexported fields
}
LedgerTicketProvider is a TicketProvider that hands out Tickets already provisioned on the vault account, read live from the ledger via account_objects. It does not create Tickets (that needs signing authority over the vault, which the caller orchestrates); it surfaces the ones that exist.
TicketFor returns the lowest available TicketSequence and is stateless: it does not reserve the Ticket it returns, so two concurrent withdrawals can be handed the same one (the second submit then fails tefNO_TICKET). Callers that run withdrawals concurrently must layer their own reservation/pool on top — this is the simple single-flight building block.
func NewLedgerTicketProvider ¶
func NewLedgerTicketProvider(rpcURL, vaultAddress string) (*LedgerTicketProvider, error)
NewLedgerTicketProvider builds a provider reading Tickets owned by vaultAddress over the JSON-RPC at rpcURL.
type RotationFinalizer ¶
type RotationFinalizer struct {
// contains filtered or unexported fields
}
RotationFinalizer rotates the vault account's SignerList via a multi-signed SignerListSet — the rotation analogue of WithdrawalFinalizer. It owns the node's signer; the quorum's blobs are merged off-mesh by the caller. It implements core.SignerRotationFinalizer.
Replay defense is the vault account's own Sequence (autofilled into the SignerListSet), so there is no separate nonce: a given Sequence applies once.
func NewRotationFinalizer ¶
func NewRotationFinalizer(rpcURL, vaultAddress string, threshold int, signer sign.Signer) (*RotationFinalizer, error)
NewRotationFinalizer builds the XRPL rotation finalizer. threshold is the current SignerQuorum (used to size the multi-sign fee and trim the quorum); signer is one of the current SignerList members.
func (*RotationFinalizer) LiveQuorum ¶ added in v0.2.0
func (f *RotationFinalizer) LiveQuorum(_ context.Context) (int, error)
LiveQuorum returns the vault's current on-chain SignerQuorum. Callers wire it as the ThresholdResolver (and reuse it for the ceremony collect count) so a quorum-raising rotation sizes the fee and quorum against live state rather than the boot-time threshold.
func (*RotationFinalizer) Pack ¶
func (f *RotationFinalizer) Pack(ctx context.Context, _ [32]byte, newSigners []string, newThreshold int) ([]byte, error)
Pack builds the autofilled multi-sign SignerListSet installing newSigners / newThreshold (each member weight 1), returning its sorted-key JSON. opID is ignored: XRPL binds rotation replay to the account Sequence (autofilled here), so the operation identity is not embedded in the payload.
func (*RotationFinalizer) SetLedgerStateResolver ¶ added in v0.4.0
func (f *RotationFinalizer) SetLedgerStateResolver(fn LedgerStateResolver)
SetLedgerStateResolver overrides the current-ledger resolver used to set and bound LastLedgerSequence. Optional; unset uses a live-RPC resolver.
func (*RotationFinalizer) SetStandaloneLedgerMode ¶ added in v0.4.0
func (f *RotationFinalizer) SetStandaloneLedgerMode(v bool)
SetStandaloneLedgerMode toggles standalone-rippled behavior: LastLedgerSequence is omitted on build and required-absent on validate. TEST-ONLY.
func (*RotationFinalizer) SetThresholdResolver ¶ added in v0.2.0
func (f *RotationFinalizer) SetThresholdResolver(fn func(context.Context) (int, error))
SetThresholdResolver installs a hook that resolves the live SignerQuorum used to size the fee autofill. Optional; unset uses the static construction-time threshold.
func (*RotationFinalizer) Sign ¶
Sign multi-signs the packed SignerListSet and returns this node's blob.
func (*RotationFinalizer) Submit ¶
func (f *RotationFinalizer) Submit(_ context.Context, _ []byte, signatures [][]byte) (string, error)
Submit combines the collected multi-sign blobs (trimmed to the current quorum) and broadcasts the SignerListSet, returning the txID.
func (*RotationFinalizer) Validate ¶
func (f *RotationFinalizer) Validate(ctx context.Context, _ [32]byte, packed []byte, newSigners []string, newThreshold int) error
Validate asserts the packed SignerListSet rotates to exactly the requested set and that its LastLedgerSequence is inside the follower's ledger band.
func (*RotationFinalizer) VerifyRotation ¶
func (f *RotationFinalizer) VerifyRotation(_ context.Context, newSigners []string, newThreshold int) (string, bool, error)
VerifyRotation reads the vault's on-chain SignerList and reports whether it now holds exactly newSigners with SignerQuorum == newThreshold. Binary: no txID is recoverable from the SignerList object, so an empty txID is returned with done=true.
type TicketProvider ¶
type TicketProvider interface {
TicketFor(ctx context.Context, withdrawalID [32]byte) (uint32, error)
}
TicketProvider supplies the Ticket sequence that authorizes a withdrawal. Custody backs this with its ticket pool/store; tests and simpler clients back it with a fixed or create-then-return ticket.
type WithdrawalFinalizer ¶
type WithdrawalFinalizer struct {
// contains filtered or unexported fields
}
WithdrawalFinalizer is the XRPL multi-sign vault withdrawal path. It owns the node's signer and a TicketProvider; the quorum's blobs are merged off-mesh by the caller. It implements core.VaultWithdrawalFinalizer.
func NewWithdrawalFinalizer ¶
func NewWithdrawalFinalizer(rpcURL, vaultAddress string, threshold int, signer sign.Signer, tickets TicketProvider, assets blockchain.AssetResolver) (*WithdrawalFinalizer, error)
NewWithdrawalFinalizer builds the XRPL vault finalizer. threshold is the SignerQuorum; tickets authorizes each withdrawal's TicketSequence.
func (*WithdrawalFinalizer) LiveQuorum ¶ added in v0.2.0
func (f *WithdrawalFinalizer) LiveQuorum(_ context.Context) (int, error)
LiveQuorum returns the vault's current on-chain SignerQuorum. Callers wire it as the ThresholdResolver (and reuse it for the ceremony collect count) so a quorum-raising rotation sizes the fee and quorum against live state rather than the boot-time threshold.
func (*WithdrawalFinalizer) Pack ¶
func (f *WithdrawalFinalizer) Pack(ctx context.Context, op *core.WithdrawalOp, withdrawalID [32]byte, deadline int64) ([]byte, error)
Pack binds a Ticket and builds the autofilled multi-sign Payment, returning its sorted-key JSON. It sets LastLedgerSequence to current + a per-attempt budget clamped so the tx's estimated close is at or before the deadline ; if too little budget remains it fails and the withdrawal parks.
func (*WithdrawalFinalizer) SetLedgerStateResolver ¶ added in v0.4.0
func (f *WithdrawalFinalizer) SetLedgerStateResolver(fn LedgerStateResolver)
SetLedgerStateResolver overrides the current-ledger resolver used to set and bound LastLedgerSequence. Optional; unset uses a live-RPC resolver.
func (*WithdrawalFinalizer) SetStandaloneLedgerMode ¶ added in v0.4.0
func (f *WithdrawalFinalizer) SetStandaloneLedgerMode(v bool)
SetStandaloneLedgerMode toggles standalone-rippled behavior: LastLedgerSequence is omitted on build and required-absent on validate. TEST-ONLY — enabling it in production removes XRPL withdrawal expiry.
func (*WithdrawalFinalizer) SetThresholdResolver ¶ added in v0.2.0
func (f *WithdrawalFinalizer) SetThresholdResolver(fn func(context.Context) (int, error))
SetThresholdResolver installs a hook that resolves the live SignerQuorum used to size the fee autofill (see resolveThreshold). Optional; callers that leave it unset get the static threshold passed at construction.
func (*WithdrawalFinalizer) Sign ¶
Sign multi-signs the packed Payment and returns this node's blob.
func (*WithdrawalFinalizer) Submit ¶
func (f *WithdrawalFinalizer) Submit(_ context.Context, _ []byte, signatures [][]byte) (string, error)
Submit combines the collected multi-sign blobs (trimmed to the quorum) and broadcasts the result, returning the txID.
func (*WithdrawalFinalizer) Validate ¶
func (f *WithdrawalFinalizer) Validate(ctx context.Context, packed []byte, op *core.WithdrawalOp, withdrawalID [32]byte, deadline int64) error
Validate re-derives the trust-bound shape from the op and asserts the packed flatTx matches, including that LastLedgerSequence is inside this follower's deadline-bound expiry band.
func (*WithdrawalFinalizer) VerifyExecution ¶
func (f *WithdrawalFinalizer) VerifyExecution(ctx context.Context, withdrawalID [32]byte) (string, bool, error)
VerifyExecution scans the vault's recent account_tx for a Payment whose InvoiceID equals the withdrawalID, returning its txID + true.