Skip to main content

Messaging scheme

The Centrifuge Protocol routes messages between chains through its Gateway layer. To minimize cross-chain gas costs, all messages use a custom packed binary encoding rather than standard ABI encoding.

Encoding

Each message is a tightly packed byte sequence. The first byte is a uint8 that identifies the message type. All subsequent fields are packed in a fixed order with no padding or dynamic offset tables, using Solidity's abi.encodePacked. Fixed-width types occupy exactly their natural byte size (e.g. uint128 → 16 bytes, bytes32 → 32 bytes, bool → 1 byte).

This differs from standard ABI encoding, which zero-pads all values to 32-byte slots and prepends dynamic offset tables. For cross-chain messages that may be relayed through bridges with per-byte fees, the savings are significant.

Messages with variable-length payloads (UpdateRestriction, Request, RequestCallback, TrustedContractUpdate, and UntrustedContractUpdate) encode the payload length as a uint16 immediately before the payload bytes. The base message size does not include this variable portion.

All pool-scoped messages (from NotifyPool onwards) carry a poolId at byte offset 1.

Some messages include a extraGasLimit parameter, which lets the initiator reserve additional gas for the forwarded call on the destination chain.

Core messages

Pool-independent messages

These messages are not scoped to a specific pool.

ScheduleUpgrade

Schedules a contract upgrade for the given target.

OffsetSizeFieldType
01typeuint8 (code 1)
132targetbytes32

Total: 33 bytes

CancelUpgrade

Cancels a previously scheduled upgrade for the given target.

OffsetSizeFieldType
01typeuint8 (code 2)
132targetbytes32

Total: 33 bytes

RecoverTokens

Recovers tokens from a target contract, sending them to a specified recipient.

OffsetSizeFieldType
01typeuint8 (code 3)
132targetbytes32
3332tokenbytes32
6532tokenIduint256
9732tobytes32
12932amountuint256

Total: 161 bytes

RegisterAsset

Registers an asset with its identifier and decimal precision.

OffsetSizeFieldType
01typeuint8 (code 4)
116assetIduint128
171decimalsuint8

Total: 18 bytes

SetPoolAdapters

Sets the set of adapters for a pool, along with a confirmation threshold and a recovery index. The adapterList is variable-length; the 2-byte length field at offset 11 gives the number of entries.

OffsetSizeFieldType
01typeuint8 (code 5)
18poolIduint64
91thresholduint8
101recoveryIndexuint8
112lengthuint16
13N×32adapterListbytes32[]

Total: 13 + N×32 bytes


Pool-scoped messages

These messages carry a poolId at offset 1 and are routed to a specific pool.

NotifyPool

Notifies a remote chain that a pool exists.

OffsetSizeFieldType
01typeuint8 (code 6)
18poolIduint64

Total: 9 bytes

NotifyShareClass

Notifies a remote chain of a share class and its initial configuration.

OffsetSizeFieldType
01typeuint8 (code 7)
18poolIduint64
916scIdbytes16
25128namefixed 128-byte UTF-8 string
15332symbolbytes32 UTF-8
1851decimalsuint8
18632saltbytes32
21832hookbytes32

Total: 250 bytes

NotifyPricePoolPerShare

Publishes the pool-per-share price for a share class at a given timestamp.

OffsetSizeFieldType
01typeuint8 (code 8)
18poolIduint64
916scIdbytes16
2516priceuint128
418timestampuint64

Total: 49 bytes

NotifyPricePoolPerAsset

Publishes the pool-per-asset price for a specific asset in a share class.

OffsetSizeFieldType
01typeuint8 (code 9)
18poolIduint64
916scIdbytes16
2516assetIduint128
4116priceuint128
578timestampuint64

Total: 65 bytes

NotifyShareMetadata

Updates the name and symbol metadata for a share class on a remote chain.

OffsetSizeFieldType
01typeuint8 (code 10)
18poolIduint64
916scIdbytes16
25128namefixed 128-byte UTF-8 string
15332symbolbytes32 UTF-8

Total: 185 bytes

UpdateShareHook

Sets the hook contract address for a share class.

OffsetSizeFieldType
01typeuint8 (code 11)
18poolIduint64
916scIdbytes16
2532hookbytes32

Total: 57 bytes

InitiateTransferShares

Initiates a cross-chain share transfer from the originating chain. Carries separate gas limits for the local execution and the remote leg of the transfer.

OffsetSizeFieldType
01typeuint8 (code 12)
18poolIduint64
916scIdbytes16
252centrifugeIduint16
2732receiverbytes32
5916amountuint128
7516remoteExtraGasLimituint128
9116extraGasLimituint128

Total: 107 bytes

ExecuteTransferShares

Executes the receiving side of a cross-chain share transfer.

OffsetSizeFieldType
01typeuint8 (code 13)
18poolIduint64
916scIdbytes16
2532receiverbytes32
5716amountuint128
7316extraGasLimituint128

Total: 89 bytes

UpdateRestriction

Delivers a restriction update to a share class hook. The payload is a submessage encoded using UpdateRestrictionMessageLib (see UpdateRestriction submessages below).

OffsetSizeFieldType
01typeuint8 (code 14)
18poolIduint64
916scIdbytes16
2516extraGasLimituint128
412payloadLengthuint16
43payloadLengthpayloadbytes

Base: 43 bytes + payload

UpdateVault

Deploys, links, or unlinks a vault for a share class and asset. The kind field maps to VaultUpdateKind: 0 for DeployAndLink, 1 for Link, 2 for Unlink.

OffsetSizeFieldType
01typeuint8 (code 15)
18poolIduint64
916scIdbytes16
2516assetIduint128
4132vaultOrFactorybytes32
731kinduint8
7416extraGasLimituint128

Total: 90 bytes

UpdateBalanceSheetManager

Grants or revokes balance sheet management rights for a pool.

OffsetSizeFieldType
01typeuint8 (code 16)
18poolIduint64
932whobytes32
411canManagebool

Total: 42 bytes

UpdateGatewayManager

Grants or revokes gateway management rights for a pool.

OffsetSizeFieldType
01typeuint8 (code 17)
18poolIduint64
932whobytes32
411canManagebool

Total: 42 bytes

UpdateHoldingAmount

Updates the recorded holding amount for a share class and asset, including price and whether the update is an increase, a snapshot, or both.

OffsetSizeFieldType
01typeuint8 (code 18)
18poolIduint64
916scIdbytes16
2516assetIduint128
4116amountuint128
5716pricePoolPerAssetuint128
738timestampuint64
811isIncreasebool
821isSnapshotbool
838nonceuint64
9116extraGasLimituint128

Total: 107 bytes

UpdateShares

Records share issuance or revocation for a share class, with snapshot and ordering metadata.

OffsetSizeFieldType
01typeuint8 (code 19)
18poolIduint64
916scIdbytes16
2516sharesuint128
418timestampuint64
491isIssuancebool
501isSnapshotbool
518nonceuint64
5916extraGasLimituint128

Total: 75 bytes

SetMaxAssetPriceAge

Sets the maximum acceptable age of an asset price feed for a share class.

OffsetSizeFieldType
01typeuint8 (code 20)
18poolIduint64
916scIdbytes16
2516assetIduint128
418maxPriceAgeuint64

Total: 49 bytes

SetMaxSharePriceAge

Sets the maximum acceptable age of a share price feed for a share class.

OffsetSizeFieldType
01typeuint8 (code 21)
18poolIduint64
916scIdbytes16
258maxPriceAgeuint64

Total: 33 bytes

Request

Forwards an investor request (deposit, redeem, or cancel) from a spoke chain to the hub. The payload is a submessage encoded using RequestMessageLib (see Request submessages below).

OffsetSizeFieldType
01typeuint8 (code 22)
18poolIduint64
916scIdbytes16
2516assetIduint128
4116extraGasLimituint128
572payloadLengthuint16
59payloadLengthpayloadbytes

Base: 59 bytes + payload

RequestCallback

Returns the result of a processed investor request from the hub back to the spoke. The payload is a submessage encoded using RequestCallbackMessageLib (see RequestCallback submessages below).

OffsetSizeFieldType
01typeuint8 (code 23)
18poolIduint64
916scIdbytes16
2516assetIduint128
4116extraGasLimituint128
572payloadLengthuint16
59payloadLengthpayloadbytes

Base: 59 bytes + payload

SetRequestManager

Assigns a request manager contract for a pool on the remote chain.

OffsetSizeFieldType
01typeuint8 (code 24)
18poolIduint64
932managerbytes32

Total: 41 bytes

TrustedContractUpdate

Forwards an arbitrary call to a trusted contract on a remote chain. The payload is standard ABI-encoded calldata for the target contract. Because the call is forwarded without a sender check, the target must already trust all messages arriving via the protocol. See Extensibility via contract updates for details.

OffsetSizeFieldType
01typeuint8 (code 25)
18poolIduint64
916scIdbytes16
2532targetbytes32
5716extraGasLimituint128
732payloadLengthuint16
75payloadLengthpayloadbytes

Base: 75 bytes + payload

UntrustedContractUpdate

Forwards an arbitrary call to a contract on a remote chain, including a sender field so the target can verify the originator. This is appropriate for contracts that do not unconditionally trust all protocol messages. See Extensibility via contract updates for details.

OffsetSizeFieldType
01typeuint8 (code 26)
18poolIduint64
916scIdbytes16
2532targetbytes32
5732senderbytes32
8916extraGasLimituint128
1052payloadLengthuint16
107payloadLengthpayloadbytes

Base: 107 bytes + payload


Submessages

Several core messages carry an inner payload that is itself a packed submessage. Each submessage library follows the same convention as MessageLib: a 1-byte type prefix followed by packed fields.

The submessage encoding scheme is not enforced by the core protocol. The following schema is used by the hook and vault implementations included in the protocol periphery code, but alternative submessage schemes may also be used by integrators.

UpdateRestriction submessages

Encoded by UpdateRestrictionMessageLib and carried inside UpdateRestriction.payload. The UpdateRestrictionType enum governs the submessage kind.

Member (code 1)

Adds or extends a user's membership in a restricted share class, valid until the given timestamp.

OffsetSizeFieldType
01typeuint8 (code 1)
132userbytes32
338validUntiluint64

Total: 41 bytes

Freeze (code 2)

Freezes a user's ability to transfer shares in a restricted share class.

OffsetSizeFieldType
01typeuint8 (code 2)
132userbytes32

Total: 33 bytes

Unfreeze (code 3)

Reverses a freeze on a user's share transfers.

OffsetSizeFieldType
01typeuint8 (code 3)
132userbytes32

Total: 33 bytes


Request submessages

Encoded by RequestMessageLib and carried inside Request.payload. The RequestType enum governs the submessage kind.

DepositRequest (code 1)

Requests a deposit of amount assets on behalf of investor.

OffsetSizeFieldType
01typeuint8 (code 1)
132investorbytes32
3316amountuint128

Total: 49 bytes

RedeemRequest (code 2)

Requests a redemption of amount shares on behalf of investor.

OffsetSizeFieldType
01typeuint8 (code 2)
132investorbytes32
3316amountuint128

Total: 49 bytes

CancelDepositRequest (code 3)

Cancels an outstanding deposit request for investor.

OffsetSizeFieldType
01typeuint8 (code 3)
132investorbytes32

Total: 33 bytes

CancelRedeemRequest (code 4)

Cancels an outstanding redeem request for investor.

OffsetSizeFieldType
01typeuint8 (code 4)
132investorbytes32

Total: 33 bytes


RequestCallback submessages

Encoded by RequestCallbackMessageLib and carried inside RequestCallback.payload. The RequestCallbackType enum governs the submessage kind. These messages flow from the hub back to spoke chains to report the outcome of processed requests.

ApprovedDeposits (code 1)

Reports that a batch of deposits has been approved at a given price.

OffsetSizeFieldType
01typeuint8 (code 1)
116assetAmountuint128
1716pricePoolPerAssetuint128

Total: 33 bytes

IssuedShares (code 2)

Reports that shares have been issued at a given price.

OffsetSizeFieldType
01typeuint8 (code 2)
116shareAmountuint128
1716pricePoolPerShareuint128

Total: 33 bytes

RevokedShares (code 3)

Reports that shares have been revoked, returning both asset and share amounts at the given price.

OffsetSizeFieldType
01typeuint8 (code 3)
116assetAmountuint128
1716shareAmountuint128
3316pricePoolPerShareuint128

Total: 49 bytes

FulfilledDepositRequest (code 4)

Notifies an investor that their deposit request has been fulfilled, including any cancelled portion.

OffsetSizeFieldType
01typeuint8 (code 4)
132investorbytes32
3316fulfilledAssetAmountuint128
4916fulfilledShareAmountuint128
6516cancelledAssetAmountuint128

Total: 81 bytes

FulfilledRedeemRequest (code 5)

Notifies an investor that their redeem request has been fulfilled, including any cancelled portion.

OffsetSizeFieldType
01typeuint8 (code 5)
132investorbytes32
3316fulfilledAssetAmountuint128
4916fulfilledShareAmountuint128
6516cancelledShareAmountuint128

Total: 81 bytes


Extensibility via contract updates

TrustedContractUpdate and UntrustedContractUpdate provide a general-purpose escape hatch for sending arbitrary cross-chain calls without adding a new message type to MessageLib. Both carry a payload of standard ABI-encoded calldata, including the 4-byte function selector. The receiving chain's Gateway forwards the call by invoking the target contract with that payload directly.

The two variants serve opposite directions and trust levels:

  • TrustedContractUpdate flows hub to spoke. It is initiated by a pool's hub manager through the Hub contract, so the receiving spoke can trust that any message of this type was authorized at the hub level. No sender field is included, and the target contract is expected to accept calls from the Gateway without additional verification.

  • UntrustedContractUpdate flows spoke to hub. It can be triggered by anyone on a spoke chain, so the hub-side target cannot assume the caller is authorized. The sender field carries the originating address so the target contract can apply its own access control checks.