For the complete documentation index, see llms.txt. This page is also available as Markdown.

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

Actor
Role in this flow
What they hold

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:

  1. requestedMin is not above requestedMax. Otherwise the call reverts with InvalidRequestedRange.

  2. from, to and spender are canonical interoperable addresses, and from is on a satellite. Otherwise NonCanonicalInteroperableAddress or SenderNotOnSatellite.

  3. from resolves to an identity. A wallet whose link was revoked still resolves. Otherwise UnverifiedWallet.

  4. The caller is that identity, or holds AGENT in the asset's domain. Otherwise NotAuthorizedForWallet.

  5. The validity window is set, issuance is not paused for the chain, and the chain has a reconciliation window. Otherwise ValidityWindowNotSet, ValidationIssuancePaused or ReconciliationWindowNotSet.

  6. to is eligible: it is actively linked to an identity that holds a valid claim from a trusted Claim Issuer for every required topic. Otherwise UnverifiedWallet.

  7. The range is capped at what the wallet can still send, availableOf(from). requestedMin must still fit. Otherwise EmptyValidationRange.

  8. The range is capped at the smallest amount the RULE modules allow for this movement. requestedMin must still fit. Otherwise EmptyValidationRange. This check is skipped when both addresses belong to one identity.

  9. The final maximum is not zero. Otherwise ZeroValue.

  10. If a spender is named, every SPENDER module accepts it. Otherwise ValidationSpenderRefused.

  11. 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:

  1. The delivering gateway is trusted by the network. Otherwise ERC7786RecipientUnauthorizedGateway.

  2. The author of the message is the asset's peer on that chain. Otherwise SenderNotPeer.

  3. This gateway has not already delivered this message. Otherwise MessageAlreadyReceived.

  4. The gateway is the one the validation went out through. Otherwise GatewayNotPinned.

  5. The token is not paused. Otherwise EnforcedPause: the delivery reverts and can be made again.

  6. The validation was issued. Otherwise nothing is applied, the compliance emits ReplayedSettlement and the token pauses itself.

  7. The notification carries both addresses of the validation and comes from the sender's chain. Otherwise SettlementLegMismatch.

  8. The amount is inside the issued range. Otherwise SettlementOutOfBounds.

  9. The report of this validation was not already applied. Otherwise nothing is applied, the compliance emits ReplayedSettlement and 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:

The recipient is
On the token
Event

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) is Settled, and validationOf(validationId).executedAmount is 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 and Token.totalBridged() has decreased by it.

  • ModularCompliance.positionOf has moved by the executed amount between the two identities, unless they are the same.

  • ModularCompliance.pendingOutOf and pendingInOf no longer count this validation, and Token.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

Symptom
Cause
Fix

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)

The recipient completes its onboarding: 07, 05

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

Reverts with ChainNotOpen

The asset has no usable route to that chain (step 2, check 11)

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 ACTION key. The compliance is an external target for the identity.

  • Take validationId, the final range and expiry from TransferValidationIssued. 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). Pending means not settled yet, Expired means past its release time and not discarded, Settled means recorded.

  • A venue asks to be named as spender in 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.

Last updated