31. Transfer on a satellite
A transfer on a satellite moves tokens out of a wallet on a satellite chain to a recipient on the same chain, or to a recipient on the reference chain. It takes three steps: the reference chain authorizes the transfer by issuing a compliance validation, T-REX Lite executes it against that validation, and the satellite reports the execution so that the register records the change of ownership. A transfer the rules refuse receives no validation and never executes.
A transfer to a recipient on another satellite follows the same steps with two reports. It is covered in 34.
At a glance
Triggered by
Investor (sender), through its ONCHAINID. Or a Token Agent on its behalf
Actors
Investor (sender), Identity Owner, Investor (recipient), Venue or application (as spender), Platform
Contracts
ModularCompliance, compliance modules, Token, TREXRegistry, the ERC-7786 gateway of the route, T-REX Lite on the satellite and its compliance contract
Preconditions
The asset is open on the satellite, with its windows set (see 33); the sending wallet holds a bridged position (see 30); the recipient's address is linked to an identity that is eligible for the asset; issuance is not paused for the chain; for a transfer through a spender, the asset's spender policy accepts it (see 26)
Result
The executed amount has moved from the sender's bridged position to the recipient, and from the position of the sender's identity to the position of the recipient's identity
Actors and roles
Investor (sender)
Holds the position on the satellite and executes the transfer there, unless a spender does.
A balance on T-REX Lite. The key of its wallet on the satellite
Identity Owner
The sender in its capacity as controller of its ONCHAINID, which requests the validation on the reference chain.
An ACTION key of the identity the sending wallet is linked to
Investor (recipient)
Receives the tokens. Does not transact.
An address linked to an eligible identity
Venue or application
Executes the transfer on the satellite for the sender, when the validation names it as spender.
Acceptance by the asset's spender policy
Platform
Runs the pre-checks, relays the request, and follows the validation to its settlement.
Whatever keys the sender has authorized
Sequence
Step by step
Step 1. Confirm the transfer can be authorized
Who: Platform, on behalf of the sender
Call: Off-chain, using read calls on the reference chain
Before the call: The sender has chosen the recipient and the amount. The Platform encodes the sending wallet and the recipient's address as ERC-7930 interoperable addresses in canonical form, from and to. It chooses a range [requestedMin, requestedMax]: the intended amount, with a tolerance when the executed amount may differ, as on a venue.
What happens: The Platform reads Token.availableOf(from), the bridged position of the wallet less what earlier validations reserve, which must cover requestedMin. It reads TREXRegistry.isWalletVerified(to), which must be true. It reads ModularCompliance.isIssuancePaused(chainKey), which must be false, and Token.isChainOpen(chainKey), which must be true.
What changes: Nothing on-chain.
Step 2. Request the validation
Who: Identity Owner (ACTION key), through the ONCHAINID the sending wallet is linked to. Or a Token Agent (AGENT)
Call: ModularCompliance.requestTransferValidation(from, to, requestedMin, requestedMax, spender), called by the identity. spender is empty when the sender executes itself
Before the call: Step 1 passed.
What the contract checks:
requestedMinis not aboverequestedMax. Otherwise the call reverts withInvalidRequestedRange.from,toandspenderare canonical interoperable addresses, andfromis on a satellite. OtherwiseNonCanonicalInteroperableAddressorSenderNotOnSatellite.fromresolves to an identity. A wallet whose link was revoked still resolves. OtherwiseUnverifiedWallet.The caller is that identity, or holds
AGENTin the asset's domain. OtherwiseNotAuthorizedForWallet.The validity window is set, issuance is not paused for the chain, and the chain has a reconciliation window. Otherwise
ValidityWindowNotSet,ValidationIssuancePausedorReconciliationWindowNotSet.tois eligible: it is actively linked to an identity that holds a valid claim from a trusted Claim Issuer for every required topic. OtherwiseUnverifiedWallet.The range is capped at what the wallet can still send,
availableOf(from).requestedMinmust still fit. OtherwiseEmptyValidationRange.The range is capped at the smallest amount the
RULEmodules allow for this movement.requestedMinmust still fit. OtherwiseEmptyValidationRange. This check is skipped when both addresses belong to one identity.The final maximum is not zero. Otherwise
ZeroValue.If a spender is named, every
SPENDERmodule accepts it. OtherwiseValidationSpenderRefused.The chain is open on the token. Otherwise
ChainNotOpen.
What changes: The compliance takes the next validationId and records the validation with its final range, its expiry (now plus the validity window), its release time (expiry plus the reconciliation window) and the status Pending. It adds amountMax to the pending amounts of the two identities, which every rule counts from now on. The token reserves amountMax against the sending wallet and emits ReservedForValidation. The compliance emits TransferValidationIssued(validationId, from, to, spender, amountMin, amountMax, expiry, reconciliationWindow). The token records the gateway the validation goes out through, emits ValidationRoutePinned, sends the validation to its peer and emits ProtocolMessageSent. Nothing has moved yet.
Step 3. Execute on the satellite
Who: Investor (sender), from its wallet on the satellite. Or the spender named in the validation
Call: The ERC-20 transfer(to, amount) on T-REX Lite, by the sender. Or transferFrom(from, to, amount), by the spender. [[TBC: how the call names a recipient that is on the reference chain]]
Before the call: The validation has been delivered to T-REX Lite through the gateway and is stored in the compliance contract linked to it.
What the contract checks: T-REX Lite is a plain ERC-20 whose transfers are conditional. A transfer executes only if a stored validation matches it: the sender and the recipient are those of the validation, the caller is the sender or the named spender, the amount is inside [amountMin, amountMax], and the execution is strictly before expiry. The validation is consumed by the transfer and cannot be used again. A transfer with no matching validation reverts.
What changes: On the satellite, for a recipient on the same chain, the sender's balance decreases and the recipient's increases by the executed amount. For a recipient on the reference chain, the sender's balance is burned. T-REX Lite sends a settlement notification carrying the validationId, both addresses and the exact amount. The register is unchanged until that notification arrives.
Step 4. Settle on the reference chain
Who: The ERC-7786 gateway delivers the notification to the Token. No actor transacts
Call: Token.receiveMessage(receiveId, sender, payload), called by the gateway
Before the call: Step 3 executed, and the satellite's transaction is final for the messaging provider.
What the contract checks:
The delivering gateway is trusted by the network. Otherwise
ERC7786RecipientUnauthorizedGateway.The author of the message is the asset's peer on that chain. Otherwise
SenderNotPeer.This gateway has not already delivered this message. Otherwise
MessageAlreadyReceived.The gateway is the one the validation went out through. Otherwise
GatewayNotPinned.The token is not paused. Otherwise
EnforcedPause: the delivery reverts and can be made again.The validation was issued. Otherwise nothing is applied, the compliance emits
ReplayedSettlementand the token pauses itself.The notification carries both addresses of the validation and comes from the sender's chain. Otherwise
SettlementLegMismatch.The amount is inside the issued range. Otherwise
SettlementOutOfBounds.The report of this validation was not already applied. Otherwise nothing is applied, the compliance emits
ReplayedSettlementand the token pauses itself.
What changes: The compliance emits SettlementNotified. It releases the pending amounts of the two identities, and the token releases the reservation on the sending wallet with ReleasedFromValidation. The compliance moves the executed amount from the position of the sender's identity to the position of the recipient's identity, unless they are the same. The token updates its ledger:
On the same satellite
The bridged position of from decreases and the bridged position of to increases.
BridgedTransfer(fromKey, toKey, validationId, from, to, amount)
On the reference chain
The bridged position of from and the total bridged amount decrease. The free balance of to increases.
Transfer(0x0, to, amount) and SettledToNative(fromKey, to, validationId, fromWallet, amount)
The validation becomes Settled and the compliance emits ValidationSettled(validationId, chainKey, amount). The TRACKER modules are told. The token emits ProtocolMessageReceived.
State after the flow
ModularCompliance.statusOf(validationId)isSettled, andvalidationOf(validationId).executedAmountis the amount that moved.Token.bridgedBalanceOf(from)has decreased by the executed amount. For a recipient on the same satellite,Token.bridgedBalanceOf(to)has increased by it. For a recipient on the reference chain,Token.balanceOf(to)has increased by it andToken.totalBridged()has decreased by it.ModularCompliance.positionOfhas moved by the executed amount between the two identities, unless they are the same.ModularCompliance.pendingOutOfandpendingInOfno longer count this validation, andToken.reservedOf(from)no longer includes it.Token.totalSupply()is unchanged.The balances on T-REX Lite match the bridged positions on the register.
Failure modes
Reverts with SenderNotOnSatellite
from is an address on the reference chain (step 2, check 2)
A movement that starts on the reference chain does not use a validation. See Movement types
Reverts with NonCanonicalInteroperableAddress
An address is malformed or not in canonical form (step 2, check 2)
Encode the chain and the address in canonical ERC-7930 form
Reverts with UnverifiedWallet, naming from
The sending wallet is linked to no identity (step 2, check 3)
Link the wallet: 07
Reverts with NotAuthorizedForWallet
The caller is the wallet itself, a key of the identity, or another account. It is neither the identity nor an agent (step 2, check 4)
Have the identity make the call
Reverts with ValidityWindowNotSet or ReconciliationWindowNotSet
The Issuer has not set a window (step 2, check 5)
Reverts with ValidationIssuancePaused
Issuance is paused for the chain, by the Issuer or after a late reconciliation that breached a rule (step 2, check 5)
Wait for the Issuer to lift it: 36
Reverts with UnverifiedWallet, naming to
The recipient is not eligible: no link, a revoked link, or a missing, expired or revoked claim (step 2, check 6)
Reverts with EmptyValidationRange
The wallet cannot send requestedMin: its position is smaller, or earlier validations reserve it (step 2, check 7). Or the rules allow less than requestedMin (step 2, check 8)
Read availableOf(from). Lower requestedMin, or wait for earlier validations to settle or be discarded
Reverts with ZeroValue
Nothing is left to authorize (step 2, check 9)
Same
Reverts with ValidationSpenderRefused
The asset's spender policy does not accept the named spender (step 2, check 10)
The Issuer authorizes it: 26. Or the sender executes itself
The validation was issued for less than requestedMax
The compliance narrowed the range to what the wallet holds or the rules allow
Read amountMax in TransferValidationIssued. Execute within it
The transfer reverts on the satellite
No stored validation matches it: the validation is not delivered yet, has expired, was already consumed, or the amount is outside its range
Wait for delivery. After expiry, request a new validation
The validation expired without being executed and the wallet's available amount is still reduced
The reservation stays until the Validation Keeper discards the validation, after its release time
The transfer executed on the satellite and the register does not show it
The settlement notification is not delivered yet, or the token is paused (step 4, check 5)
Wait. A settlement is applied whenever it arrives
The delivery of the settlement reverts with SettlementLegMismatch or SettlementOutOfBounds
The notification does not match the validation (step 4, checks 7 and 8)
An anomaly of the satellite. The Issuer investigates: 36
The token paused itself
A settlement for an unknown validation, or one already applied, was delivered (step 4, checks 6 and 9)
Common misunderstandings
Wrong: "The satellite checks compliance when the transfer executes."
Right: The satellite checks nothing about the holder or the rules. It checks that a validation issued by the reference chain matches the transfer. Eligibility and compliance were evaluated on the reference chain, against the complete distribution of the asset, before the validation was issued.
Wrong: "The wallet on the satellite requests its own validation."
Right: The identity the wallet is linked to requests it, on the reference chain. A wallet on another chain cannot call the compliance, and authority over a holder's positions lives in its identity. An agent can also request a validation for a holder.
Wrong: "Once the transfer executed on the satellite, the recipient owns the tokens on the register."
Right: The register records the change of ownership when the settlement arrives. Between the two, the recipient holds a balance on T-REX Lite that it cannot move further: an onward transfer needs a new validation, and a validation is capped at the position the register records for the sending wallet.
Wrong: "A validation is for an exact amount."
Right: A validation carries a range. The satellite may execute any amount inside it, and the register treats the maximum as the amount that moves until the transfer settles. The settlement carries the exact amount.
Integration notes
Request the validation through the identity: a user operation or the execution queue, with an
ACTIONkey. The compliance is an external target for the identity.Take
validationId, the final range andexpiryfromTransferValidationIssued. The range may be narrower than requested.Execute well before
expiry. The satellite refuses an execution at or after it.Follow a validation with
ModularCompliance.statusOf(validationId).Pendingmeans not settled yet,Expiredmeans past its release time and not discarded,Settledmeans recorded.A venue asks to be named as
spenderin the validation. Whether it is accepted is decided at issuance, by the asset's spender policy.Between two wallets of one identity, the rules about distribution are not asked and nothing is reserved against the identity. The wallet's available amount and the spender policy still apply.
While a validation is
Pending, its maximum counts against the recipient's room under any cap and against the sender's available amount. Request ranges no wider than needed.A validation can be issued while the token is paused. Its settlement waits for the pause to be lifted.
Each party pays for the message its own transaction sends, directly or through a paymaster: the identity for the validation, on the reference chain, and the caller of the transfer for the settlement notification, on the satellite.
A wallet on a satellite sees T-REX Lite as an ordinary ERC-20 token. An integration needs no special transfer call, only a validation in place before the transfer.
Related flows
30 Delegate a position out to a satellite : how the position came to the satellite
34 Transfer between two satellites : the same flow with two reports
35 Discard or resolve a validation : when a validation is never executed
36 Handle a late reconciliation or a halt : when a settlement arrives late, or cannot be accounted for
26 Authorize spenders : the spender policy applied at issuance
10 Transfer between investors : the same movement on the reference chain
Last updated