@synapsecns/contracts-core
contain the Solidity contracts used within the Synapse Interchain Network messaging system.
Usage
These contracts can be installed with:
npm i @synapsecns/contracts-core
Please refer to our usage guide or examples
Directory Structure
root ├── contracts: Contains core contracts │ ├── base: Base contracts of the protocol │ ├── client: Client contracts for callers of the messaging system. │ ├── events: Event types │ ├── hubs: Hubs │ ├── inbox: Inbox contracts │ ├── interfaces: Interfaces │ ├── libs: Library contracts │ ├── Manager: Manager contracts ├── deployments: Non-devnet deployments of the contracts ├── lib: Git-module based dependencies ├── script: Scripts for deploying + interacting with contracts ├── test: Test contracts
Running a devnet
To run a devnet, you can run make devnet-up
and make devnet-deploy
from this directory. This will start a local devnet and deploy the contracts to it. RPC endpoints for debugging etc will be availabe at http://localhost:9001/rpc/[chain_id]
.
By default, the PingPongClient.sol
is deployed, so you can interact with it with cast. For instance, to send a ping from chain 42 to chain 44:
cast send 0x521F44132489CDD54c9ceC8167CfC377CbAEa351 --rpc-url http://localhost:9001/rpc/42 --private-key 0x526db1890baf94e82162f17f25ad769eb7f981272d8d99c527ea1af443c2d0cc "doPing(uint32,address,uint16)" 44 0x521F44132489CDD54c9ceC8167CfC377CbAEa351 1
Now, to make sure it work, you can pull up scribe by going to http://localhost:9002/graphiql and querying the logs for chain 44:
{
logs(chain_id: 44, page: 1){
topics
block_number
contract_address
}
}
If everything went well, you will see topic 0x0a72872b9cfe43d6c13b13553f28d4879e427f3b456545649fd0761fdcbe0311
in the logs, which is the topic for the PingPongClient
's Pong
event.
Contents
AgentSecured
Inherits: MessagingBase, IAgentSecured
Base contract for messaging contracts that are secured by the agent manager.
AgentSecured
relies on AgentManager
to provide the following functionality:
- Keep track of agents and their statuses.
- Pass agent-signed statements that were verified by the agent manager.
- These statements are considered valid indefinitely, unless the agent is disputed.
- Disputes are opened and resolved by the agent manager.
AgentSecured
implementation should never use statements signed by agents that are disputed.
State Variables
agentManager
Returns the address of the local AgentManager contract, which is treated as the "source of truth" for agent statuses.
address public immutable agentManager;
inbox
Returns the address of the local Inbox contract, which is treated as the "source of truth" for agent-signed statements.
Inbox passes verified agent statements to IAgentSecured
contract.
address public immutable inbox;
_disputes
mapping(uint32 => DisputeStatus) internal _disputes;
__GAP
gap for upgrade safety
uint256[49] private __GAP;
Functions
onlyAgentManager
modifier onlyAgentManager();
onlyInbox
modifier onlyInbox();
constructor
constructor(string memory version_, uint32 synapseDomain_, address agentManager_, address inbox_)
MessagingBase(version_, synapseDomain_);
openDispute
Local AgentManager should call this function to indicate that a dispute between a Guard and a Notary has been opened.
function openDispute(uint32 guardIndex, uint32 notaryIndex) external onlyAgentManager;
Parameters
Name | Type | Description |
---|---|---|
guardIndex | uint32 | Index of the Guard in the Agent Merkle Tree |
notaryIndex | uint32 | Index of the Notary in the Agent Merkle Tree |
resolveDispute
Local AgentManager should call this function to indicate that a dispute has been resolved due to one of the agents being slashed.
rivalIndex
will be ZERO, if the slashed agent was not in the Dispute.
function resolveDispute(uint32 slashedIndex, uint32 rivalIndex) external onlyAgentManager;
Parameters
Name | Type | Description |
---|---|---|
slashedIndex | uint32 | Index of the slashed agent in the Agent Merkle Tree |
rivalIndex | uint32 | Index of the their Dispute Rival in the Agent Merkle Tree |
agentStatus
Returns (flag, domain, index) for a given agent. See Structures.sol for details.
Will return AgentFlag.Fraudulent for agents that have been proven to commit fraud, but their status is not updated to Slashed yet.
function agentStatus(address agent) external view returns (AgentStatus memory);
Parameters
Name | Type | Description |
---|---|---|
agent | address | Agent address |
Returns
Name | Type | Description |
---|---|---|
<none> | AgentStatus | Status for the given agent: (flag, domain, index). |
getAgent
Returns agent address and their current status for a given agent index.
Will return empty values if agent with given index doesn't exist.
function getAgent(uint256 index) external view returns (address agent, AgentStatus memory status);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Agent index in the Agent Merkle Tree |
Returns
Name | Type | Description |
---|---|---|
agent | address | Agent address |
status | AgentStatus | Status for the given agent: (flag, domain, index) |
latestDisputeStatus
Returns (flag, openedAt, resolvedAt) that describes the latest status of the latest dispute for an agent with a given index.
Will return empty values if agent with given index doesn't exist.
function latestDisputeStatus(uint32 agentIndex) external view returns (DisputeStatus memory);
Parameters
Name | Type | Description |
---|---|---|
agentIndex | uint32 | Agent index in the Agent Merkle Tree |
Returns
Name | Type | Description |
---|---|---|
<none> | DisputeStatus | Latest dispute status for the given agent: (flag, openedAt, resolvedAt) |
_agentStatus
Returns status of the given agent: (flag, domain, index).
function _agentStatus(address agent) internal view returns (AgentStatus memory);
_getAgent
Returns agent and their status for a given agent index. Returns zero values for non existing indexes.
function _getAgent(uint256 index) internal view returns (address agent, AgentStatus memory status);
_notaryDisputeExists
Checks if a Dispute exists for the given Notary. This function returns true, if
Notary is in ongoing Dispute, or if Dispute was resolved not in Notary's favor.
In both cases we can't trust Notary's data.
Note: Agent-Secured contracts can trust Notary data only if both _notaryDisputeExists
and
_notaryDisputeTimeout
return false.
function _notaryDisputeExists(uint32 notaryIndex) internal view returns (bool);
_notaryDisputeTimeout
Checks if a Notary recently won a Dispute and is still in the "post-dispute" timeout period.
In this period we still can't trust Notary's data, though we can optimistically assume that
that the data will be correct after the timeout (assuming no new Disputes are opened).
Note: Agent-Secured contracts can trust Notary data only if both _notaryDisputeExists
and
_notaryDisputeTimeout
return false.
function _notaryDisputeTimeout(uint32 notaryIndex) internal view returns (bool);
MessagingBase
Inherits: MultiCallable, Versioned, Ownable2StepUpgradeable
Base contract for all messaging contracts.
- Provides context on the local chain's domain.
- Provides ownership functionality.
- Will be providing pausing functionality when it is implemented.
State Variables
localDomain
Domain of the local chain, set once upon contract creation
uint32 public immutable localDomain;
synapseDomain
uint32 public immutable synapseDomain;
__GAP
gap for upgrade safety
uint256[50] private __GAP;
Functions
constructor
constructor(string memory version_, uint32 synapseDomain_) Versioned(version_);
renounceOwnership
Should be impossible to renounce ownership; we override OpenZeppelin OwnableUpgradeable's implementation of renounceOwnership to make it a no-op
function renounceOwnership() public override onlyOwner;
MultiCallable
Collection of Multicall utilities. Fork of Multicall3: https://github.com/mds1/multicall/blob/master/src/Multicall3.sol
Functions
multicall
Aggregates a few calls to this contract into one multicall without modifying msg.sender
.
function multicall(Call[] calldata calls) external returns (Result[] memory callResults);
Structs
Call
struct Call {
bool allowFailure;
bytes callData;
}
Result
struct Result {
bool success;
bytes returnData;
}
Versioned
Version getter for contracts. Doesn't use any storage slots, meaning it will never cause any troubles with the upgradeable contracts. For instance, this contract can be added or removed from the inheritance chain without shifting the storage layout.
State Variables
_length
Length of the "version string"
uint256 private immutable _length;
_data
Bytes representation of the "version string". Strings with length over 32 are not supported!
bytes32 private immutable _data;
Functions
constructor
constructor(string memory version_);
version
function version() external view returns (string memory versionString);
Structs
_ShortString
Struct that is mimicking the storage layout of a string with 32 bytes or less. Length is limited by 32, so the whole string payload takes two memory words:
struct _ShortString {
uint256 length;
bytes32 data;
}
Contents
BaseClient
Inherits: MessageRecipient
*Implementation of IMessageRecipient interface, to be used as the recipient of base messages passed by the Destination contract. BaseClient could be used as a backbone for cross-chain apps:
- A single BaseClient contract per chain (aka trusted sender)
- Only BaseClient instances from other chains are able to send messages to this contract
- BaseClient enforces a common optimistic period for all types of messages Note: BaseClient is forever stateless, meaning it can be potentially used as a parent for the upgradeable contract without worrying about storage collision.*
Functions
constructor
constructor(address origin_, address destination_) MessageRecipient(origin_, destination_);
optimisticPeriod
Period of time since the root was submitted to Destination. Once this period is over, root can be used for proving and executing a message though this Client.
function optimisticPeriod() public view virtual returns (uint32);
trustedSender
Address of the trusted sender on the destination chain. The trusted sender will be able to:
- Send messages to this contract from other chains.
- Receive messages from this contract on other chains.
function trustedSender(uint32 destination) public view virtual returns (bytes32);
_receiveBaseMessageUnsafe
*Child contracts should implement the logic for receiving a Base Message in an "unsafe way". Following checks HAVE been performed:
- receiveBaseMessage() was called by Destination (i.e. this is a legit base message).
- Nonce is not zero.
- Message sender on origin chain is not a zero address.
- Proof maturity is not zero. Following checks HAVE NOT been performed (thus "unsafe"):
- Message sender on origin chain could be anything non-zero at this point.
- Proof maturity could be anything non-zero at this point.*
function _receiveBaseMessageUnsafe(
uint32 origin_,
uint32 nonce,
bytes32 sender,
uint256 proofMaturity,
uint32 version,
bytes memory content
) internal override;
_receiveBaseMessage
*Child contracts should implement the logic for receiving a Base Message. Following checks HAVE been performed:
- receiveBaseMessage() was called by Destination (i.e. this is a legit base message).
- Nonce is not zero.
- Message sender on origin chain is a trusted sender (and is not zero).
- Optimistic period for the message have passed (and is not zero).*
function _receiveBaseMessage(uint32 origin_, uint32 nonce, uint32 version, bytes memory content) internal virtual;
_sendBaseMessage
*Sends a message to given destination chain. Full msg.value
is used to pay for the message tips.
_getMinimumTipsValue()
could be used to calculate the minimum required tips value, and should be also
exposed as a public view function to estimate the tips value before sending a message off-chain.
This function is not exposed in BaseClient, as the message encoding is implemented by the child contract.
Will revert if the trusted sender is not set for the destination domain.*
function _sendBaseMessage(uint32 destination_, uint256 tipsValue, MessageRequest memory request, bytes memory content)
internal
returns (uint32 messageNonce, bytes32 messageHash);
Parameters
Name | Type | Description |
---|---|---|
destination_ | uint32 | Domain of the destination chain |
tipsValue | uint256 | Tips to be paid for sending the message |
request | MessageRequest | Encoded message execution request on destination chain |
content | bytes | The message content |
MessageRecipient
Inherits: IMessageRecipient
State Variables
origin
Local chain Origin: used for sending messages
address public immutable origin;
destination
Local chain Destination: used for receiving messages
address public immutable destination;
Functions
constructor
constructor(address origin_, address destination_);
receiveBaseMessage
Message recipient needs to implement this function in order to receive cross-chain messages.
Message recipient needs to ensure that merkle proof for the message is at least as old as the optimistic period that the recipient is using. Note: as this point it is checked that the "message optimistic period" has passed, however the period value itself could be anything, and thus could differ from the one that the recipient would like to enforce.
function receiveBaseMessage(
uint32 origin_,
uint32 nonce,
bytes32 sender,
uint256 proofMaturity,
uint32 version,
bytes memory content
) external payable;
Parameters
Name | Type | Description |
---|---|---|
origin_ | uint32 | |
nonce | uint32 | Message nonce on the origin domain |
sender | bytes32 | Sender address on origin chain |
proofMaturity | uint256 | Message's merkle proof age in seconds |
version | uint32 | Message version specified by sender |
content | bytes | Raw bytes content of message |
_receiveBaseMessageUnsafe
*Child contracts should implement the logic for receiving a Base Message in an "unsafe way". Following checks HAVE been performed:
- receiveBaseMessage() was called by Destination (i.e. this is a legit base message).
- Nonce is not zero.
- Message sender on origin chain is not a zero address.
- Proof maturity is not zero. Following checks HAVE NOT been performed (thus "unsafe"):
- Message sender on origin chain could be anything non-zero at this point.
- Proof maturity could be anything non-zero at this point.*
function _receiveBaseMessageUnsafe(
uint32 origin_,
uint32 nonce,
bytes32 sender,
uint256 proofMaturity,
uint32 version,
bytes memory content
) internal virtual;
_sendBaseMessage
Sends a message to given destination chain. Full msg.value
is used to pay for the message tips.
_getMinimumTipsValue()
could be used to calculate the minimum required tips value, and should be also
exposed as a public view function to estimate the tips value before sending a message off-chain.
This function is not exposed in MessageRecipient, as the message encoding is implemented by the child contract.
function _sendBaseMessage(
uint32 destination_,
bytes32 recipient,
uint32 optimisticPeriod,
uint256 tipsValue,
MessageRequest memory request,
bytes memory content
) internal returns (uint32 messageNonce, bytes32 messageHash);
Parameters
Name | Type | Description |
---|---|---|
destination_ | uint32 | Domain of the destination chain |
recipient | bytes32 | Address of the recipient on destination chain |
optimisticPeriod | uint32 | Optimistic period for the message |
tipsValue | uint256 | Tips to be paid for sending the message |
request | MessageRequest | Message execution request on destination chain |
content | bytes | The message content |
_getMinimumTipsValue
Returns the minimum tips value for sending a message to given destination chain.
function _getMinimumTipsValue(uint32 destination_, MessageRequest memory request, uint256 contentLength)
internal
view
returns (uint256 tipsValue);
Parameters
Name | Type | Description |
---|---|---|
destination_ | uint32 | Domain of the destination chain |
request | MessageRequest | Message execution request on destination chain |
contentLength | uint256 | Length of the message content |
_encodeRequest
Encodes a message execution request into format that Origin contract is using.
function _encodeRequest(MessageRequest memory request) internal pure returns (uint256 paddedRequest);
Parameters
Name | Type | Description |
---|---|---|
request | MessageRequest | Message execution request on destination chain |
Returns
Name | Type | Description |
---|---|---|
paddedRequest | uint256 | Encoded request |
Structs
MessageRequest
struct MessageRequest {
uint96 gasDrop;
uint64 gasLimit;
uint32 version;
}
PingPongClient
Inherits: MessageRecipient
State Variables
random
uint256 public random;
pingsSent
Amount of "Ping" messages sent.
uint256 public pingsSent;
pingsReceived
Amount of "Ping" messages received. Every received Ping message leads to sending a Pong message back to initial sender.
uint256 public pingsReceived;
pongsReceived
Amount of "Pong" messages received.
When all messages are delivered, should be equal to pingsSent
uint256 public pongsReceived;
Functions
constructor
constructor(address origin_, address destination_) MessageRecipient(origin_, destination_);
doPings
function doPings(uint16 pingCount, uint32 destination_, address recipient, uint16 counter) external;
doPing
Send a Ping message to destination chain.
Upon receiving a Ping, a Pong message will be sent back.
If counter > 0
, this process will be repeated when the Pong message is received.
function doPing(uint32 destination_, address recipient, uint16 counter) external;
Parameters
Name | Type | Description |
---|---|---|
destination_ | uint32 | Chain to send Ping message to |
recipient | address | Recipient of Ping message |
counter | uint16 | Additional amount of Ping-Pong rounds to conclude |
nextOptimisticPeriod
function nextOptimisticPeriod() public view returns (uint32 period);
_receiveBaseMessageUnsafe
*Child contracts should implement the logic for receiving a Base Message in an "unsafe way". Following checks HAVE been performed:
- receiveBaseMessage() was called by Destination (i.e. this is a legit base message).
- Nonce is not zero.
- Message sender on origin chain is not a zero address.
- Proof maturity is not zero. Following checks HAVE NOT been performed (thus "unsafe"):
- Message sender on origin chain could be anything non-zero at this point.
- Proof maturity could be anything non-zero at this point.*
function _receiveBaseMessageUnsafe(uint32 origin_, uint32, bytes32 sender, uint256, uint32, bytes memory content)
internal
override;
_optimisticPeriod
Returns a random optimistic period value from 0 to 59 seconds.
function _optimisticPeriod() internal returns (uint32 period);
_sendMessage
Send a "Ping" or "Pong" message.
function _sendMessage(uint32 destination_, bytes32 recipient, PingPongMessage memory message) internal;
Parameters
Name | Type | Description |
---|---|---|
destination_ | uint32 | Domain of destination chain |
recipient | bytes32 | Message recipient on destination chain |
message | PingPongMessage | Ping-pong message |
_ping
Initiate a new Ping-Pong round.
function _ping(uint32 destination_, bytes32 recipient, uint16 counter) internal;
_pong
Send a Pong message back.
function _pong(uint32 destination_, bytes32 recipient, PingPongMessage memory message) internal;
Events
PingSent
Emitted when a Ping message is sent. Triggered externally, or by receveing a Pong message with instructions to do more pings.
event PingSent(uint256 pingId);
PingReceived
Emitted when a Ping message is received. Will always send a Pong message back.
event PingReceived(uint256 pingId);
PongSent
Emitted when a Pong message is sent. Triggered whenever a Ping message is received.
event PongSent(uint256 pingId);
PongReceived
Emitted when a Pong message is received. Will initiate a new Ping, if the counter in the message is non-zero.
event PongReceived(uint256 pingId);
Structs
PingPongMessage
struct PingPongMessage {
uint256 pingId;
bool isPing;
uint16 counter;
}
TestClient
Inherits: MessageRecipient
Functions
constructor
constructor(address origin_, address destination_) MessageRecipient(origin_, destination_);
sendMessage
function sendMessage(
uint32 destination_,
address recipientAddress,
uint32 optimisticPeriod,
uint64 gasLimit,
uint32 version,
bytes memory content
) external payable;
_receiveBaseMessageUnsafe
*Child contracts should implement the logic for receiving a Base Message in an "unsafe way". Following checks HAVE been performed:
- receiveBaseMessage() was called by Destination (i.e. this is a legit base message).
- Nonce is not zero.
- Message sender on origin chain is not a zero address.
- Proof maturity is not zero. Following checks HAVE NOT been performed (thus "unsafe"):
- Message sender on origin chain could be anything non-zero at this point.
- Proof maturity could be anything non-zero at this point.*
function _receiveBaseMessageUnsafe(
uint32 origin_,
uint32 nonce,
bytes32 sender,
uint256 proofMaturity,
uint32 version,
bytes memory content
) internal override;
Events
MessageReceived
event MessageReceived(
uint32 origin, uint32 nonce, bytes32 sender, uint256 proofMaturity, uint32 version, bytes content
);
MessageSent
event MessageSent(uint32 destination, uint32 nonce, bytes32 sender, bytes32 recipient, bytes content);
Contents
- AgentManagerEvents
- DestinationEvents
- ExecutionHubEvents
- GasOracleEvents
- InboxEvents
- OriginEvents
- SnapshotHubEvents
- StateHubEvents
- StatementInboxEvents
- SummitEvents
AgentManagerEvents
Events
DisputeOpened
Emitted whenever a Dispute is opened between two agents. This happens when a Guard submits
their report for the Notary-signed statement to StatementInbox
.
event DisputeOpened(uint256 disputeIndex, uint32 guardIndex, uint32 notaryIndex);
DisputeResolved
Emitted whenever a Dispute is resolved. This happens when an Agent who was in Dispute is slashed. Note: this won't be emitted, if an Agent was slashed without being in Dispute.
event DisputeResolved(uint256 disputeIndex, uint32 slashedIndex, uint32 rivalIndex, address fraudProver);
RootUpdated
Emitted whenever the root of the Agent Merkle Tree is updated.
event RootUpdated(bytes32 newRoot);
AgentRootProposed
Emitted after the contract owner proposes a new agent root to resolve the stuck chain.
event AgentRootProposed(bytes32 newRoot);
ProposedAgentRootCancelled
Emitted after the contract owner cancels the previously proposed agent root.
event ProposedAgentRootCancelled(bytes32 proposedRoot);
ProposedAgentRootResolved
Emitted after the contract owner resolves the previously proposed agent root.
event ProposedAgentRootResolved(bytes32 proposedRoot);
StatusUpdated
Emitted whenever a status of the agent is updated.
Only Active/Unstaking/Resting/Slashed flags could be stored in the Agent Merkle Tree. Unknown flag is the default (zero) value and is used to represent agents that never interacted with the BondingManager contract. Fraudulent flag is the value for the agent who has been proven to commit fraud, but their status hasn't been updated to Slashed in the Agent Merkle Tree. This is due to the fact that the update of the status requires a merkle proof of the old status, and happens in a separate transaction because of that.
event StatusUpdated(AgentFlag flag, uint32 indexed domain, address indexed agent);
DestinationEvents
A collection of events emitted by the Destination contract
Events
AgentRootAccepted
event AgentRootAccepted(bytes32 agentRoot);
ExecutionHubEvents
A collection of events emitted by the ExecutionHub contract
Events
Executed
Emitted when message is executed.
event Executed(uint32 indexed remoteDomain, bytes32 indexed messageHash, bool success);
TipsRecorded
Emitted when message tips are recorded.
event TipsRecorded(bytes32 messageHash, uint256 paddedTips);
GasOracleEvents
A collection of events emitted by the GasOracle contract
Events
GasDataUpdated
Emitted when gas data is updated for the domain
event GasDataUpdated(uint32 domain, uint256 paddedGasData);
SummitTipUpdated
Emitted when the value of the summit tip is updated
event SummitTipUpdated(uint256 summitTipWei);
InboxEvents
Events
SnapshotAccepted
Emitted when a snapshot is accepted by the Summit contract.
event SnapshotAccepted(uint32 indexed domain, address indexed agent, bytes snapPayload, bytes snapSignature);
ReceiptAccepted
Emitted when a snapshot is accepted by the Summit contract.
event ReceiptAccepted(uint32 domain, address notary, bytes rcptPayload, bytes rcptSignature);
InvalidAttestation
Emitted when a proof of invalid attestation is submitted.
event InvalidAttestation(bytes attPayload, bytes attSignature);
InvalidAttestationReport
Emitted when a proof of invalid attestation report is submitted.
event InvalidAttestationReport(bytes arPayload, bytes arSignature);
OriginEvents
A collection of events emitted by the Origin contract
Events
Sent
Emitted when a new message is sent.
event Sent(bytes32 indexed messageHash, uint32 indexed nonce, uint32 indexed destination, bytes message);
TipWithdrawalCompleted
Emitted when a tip withdrawal is completed.
event TipWithdrawalCompleted(address actor, uint256 tip);
SnapshotHubEvents
A collection of events emitted by the SnapshotHub contract
Events
AttestationSaved
Emitted when a new Attestation is saved (derived from a Notary snapshot).
event AttestationSaved(bytes attestation);
StateSaved
Emitted when a new Origin State is saved from a Guard snapshot.
event StateSaved(bytes state);
StateHubEvents
A collection of events emitted by the StateHub contract
Events
StateSaved
Emitted when a new Origin State is saved after a message was sent.
event StateSaved(bytes state);
StatementInboxEvents
Events
AttestationAccepted
Emitted when a snapshot is accepted by the Destination contract.
event AttestationAccepted(uint32 domain, address notary, bytes attPayload, bytes attSignature);
InvalidReceipt
Emitted when a proof of invalid receipt statement is submitted.
event InvalidReceipt(bytes rcptPayload, bytes rcptSignature);
InvalidReceiptReport
Emitted when a proof of invalid receipt report is submitted.
event InvalidReceiptReport(bytes rrPayload, bytes rrSignature);
InvalidStateWithAttestation
Emitted when a proof of invalid state in the signed attestation is submitted.
event InvalidStateWithAttestation(uint8 stateIndex, bytes statePayload, bytes attPayload, bytes attSignature);
InvalidStateWithSnapshot
Emitted when a proof of invalid state in the signed snapshot is submitted.
event InvalidStateWithSnapshot(uint8 stateIndex, bytes snapPayload, bytes snapSignature);
InvalidStateReport
Emitted when a proof of invalid state report is submitted.
event InvalidStateReport(bytes srPayload, bytes srSignature);
SummitEvents
A collection of events emitted by the Summit contract
Events
TipAwarded
Emitted when a tip is awarded to the actor, whether they are bonded or unbonded actor.
event TipAwarded(address actor, uint32 origin, uint256 tip);
TipWithdrawalInitiated
Emitted when a tip withdrawal is initiated by the actor.
event TipWithdrawalInitiated(address actor, uint32 origin, uint256 tip);
Contents
ExecutionHub
Inherits: AgentSecured, ReentrancyGuardUpgradeable, ExecutionHubEvents, IExecutionHub
ExecutionHub
is a parent contract for Destination
. It is responsible for the following:
- Executing the messages that are proven against the saved Snapshot Merkle Roots.
- Base messages are forwarded to the specified message recipient, ensuring that the original execution request is fulfilled correctly.
- Manager messages are forwarded to the local
AgentManager
contract. - Keeping track of the saved Snapshot Merkle Roots (which are accepted in
Destination
). - Keeping track of message execution Receipts, as well as verify their validity.
State Variables
_receiptData
(messageHash => status)
Messages coming from different origins will always have a different hash as origin domain is encoded into the formatted message. Thus we can use hash as a key instead of an (origin, hash) tuple.
mapping(bytes32 => ReceiptData) private _receiptData;
_firstExecutor
First executor who made a valid attempt of executing a message. Note: stored only for messages that had Failed status at some point of time
mapping(bytes32 => address) private _firstExecutor;
_roots
All saved snapshot roots
bytes32[] internal _roots;
_rootData
Tracks data for all saved snapshot roots
mapping(bytes32 => SnapRootData) internal _rootData;
__GAP
gap for upgrade safety
uint256[46] private __GAP;
Functions
execute
Attempts to prove inclusion of message into one of Snapshot Merkle Trees, previously submitted to this contract in a form of a signed Attestation. Proven message is immediately executed by passing its contents to the specified recipient.
*Will revert if any of these is true:
- Message is not meant to be executed on this chain
- Message was sent from this chain
- Message payload is not properly formatted.
- Snapshot root (reconstructed from message hash and proofs) is unknown
- Snapshot root is known, but was submitted by an inactive Notary
- Snapshot root is known, but optimistic period for a message hasn't passed
- Provided gas limit is lower than the one requested in the message
- Recipient doesn't implement a
handle
method (refer to IMessageRecipient.sol) - Recipient reverted upon receiving a message Note: refer to libs/memory/State.sol for details about Origin State's sub-leafs.*
function execute(
bytes memory msgPayload,
bytes32[] calldata originProof,
bytes32[] calldata snapProof,
uint8 stateIndex,
uint64 gasLimit
) external nonReentrant;
Parameters
Name | Type | Description |
---|---|---|
msgPayload | bytes | Raw payload with a formatted message to execute |
originProof | bytes32[] | Proof of inclusion of message in the Origin Merkle Tree |
snapProof | bytes32[] | Proof of inclusion of Origin State's Left Leaf into Snapshot Merkle Tree |
stateIndex | uint8 | Index of Origin State in the Snapshot |
gasLimit | uint64 | Gas limit for message execution |
getAttestationNonce
Returns attestation nonce for a given snapshot root.
Will return 0 if the root is unknown.
function getAttestationNonce(bytes32 snapRoot) external view returns (uint32 attNonce);
isValidReceipt
Checks the validity of the unsigned message receipt.
*Will revert if any of these is true:
- Receipt payload is not properly formatted.
- Receipt signer is not an active Notary.
- Receipt destination chain does not refer to this chain.*
function isValidReceipt(bytes memory rcptPayload) external view returns (bool isValid);
Parameters
Name | Type | Description |
---|---|---|
rcptPayload | bytes | Raw payload with Receipt data |
Returns
Name | Type | Description |
---|---|---|
isValid | bool | Whether the requested receipt is valid. |
messageStatus
Returns message execution status: None/Failed/Success.
function messageStatus(bytes32 messageHash) external view returns (MessageStatus status);
Parameters
Name | Type | Description |
---|---|---|
messageHash | bytes32 | Hash of the message payload |
Returns
Name | Type | Description |
---|---|---|
status | MessageStatus | Message execution status |
messageReceipt
Returns a formatted payload with the message receipt.
Notaries could derive the tips, and the tips proof using the message payload, and submit
the signed receipt with the proof of tips to Summit
in order to initiate tips distribution.
function messageReceipt(bytes32 messageHash) external view returns (bytes memory rcptPayload);
Parameters
Name | Type | Description |
---|---|---|
messageHash | bytes32 | Hash of the message payload |
Returns
Name | Type | Description |
---|---|---|
rcptPayload | bytes | data Formatted payload with the message execution receipt |
_executeBaseMessage
Passes message content to recipient that conforms to IMessageRecipient interface.
function _executeBaseMessage(Header header, uint256 proofMaturity, uint64 gasLimit, BaseMessage baseMessage)
internal
returns (bool);
_executeManagerMessage
Uses message body for a call to AgentManager, and checks the returned magic value to ensure that only "remoteX" functions could be called this way.
function _executeManagerMessage(Header header, uint256 proofMaturity, MemView body) internal returns (bool);
_passReceipt
Passes the message receipt to the Inbox contract, if it is deployed on Synapse Chain. This ensures that the message receipts for the messages executed on Synapse Chain are passed to Summit without a Notary having to sign them.
function _passReceipt(
uint32 attNotaryIndex,
uint32 attNonce,
bytes32 messageHash,
uint256 paddedTips,
ReceiptData memory rcptData
) internal returns (bool);
_saveAttestation
Saves a snapshot root with the attestation data provided by a Notary. It is assumed that the Notary signature has been checked outside of this contract.
function _saveAttestation(Attestation att, uint32 notaryIndex, uint256 sigIndex) internal;
_isValidReceipt
Checks if receipt body matches the saved data for the referenced message. Reverts if destination domain doesn't match the local domain.
function _isValidReceipt(Receipt rcpt) internal view returns (bool);
_proveAttestation
Attempts to prove the validity of the cross-chain message. First, the origin Merkle Root is reconstructed using the origin proof. Then the origin state's "left leaf" is reconstructed using the origin domain. After that the snapshot Merkle Root is reconstructed using the snapshot proof. The snapshot root needs to have been submitted by an undisputed Notary.
Reverts if any of the checks fail.
function _proveAttestation(
Header header,
bytes32 msgLeaf,
bytes32[] calldata originProof,
bytes32[] calldata snapProof,
uint8 stateIndex
) internal view returns (SnapRootData memory rootData);
Parameters
Name | Type | Description |
---|---|---|
header | Header | Memory view over the message header |
msgLeaf | bytes32 | Message Leaf that was inserted in the Origin Merkle Tree |
originProof | bytes32[] | Proof of inclusion of Message Leaf in the Origin Merkle Tree |
snapProof | bytes32[] | Proof of inclusion of Origin State Left Leaf into Snapshot Merkle Tree |
stateIndex | uint8 | Index of Origin State in the Snapshot |
Returns
Name | Type | Description |
---|---|---|
rootData | SnapRootData | Data for the derived snapshot root |
_messageReceipt
Formats the message execution receipt payload for the given hash and receipt data.
function _messageReceipt(bytes32 messageHash, ReceiptData memory rcptData)
internal
view
returns (bytes memory rcptPayload);
Structs
SnapRootData
Struct representing stored data for the snapshot root
struct SnapRootData {
uint32 notaryIndex;
uint32 attNonce;
uint40 attBN;
uint40 attTS;
uint32 index;
uint40 submittedAt;
uint256 sigIndex;
}
ReceiptData
Struct representing stored receipt data for the message in Execution Hub.
struct ReceiptData {
uint32 origin;
uint32 rootIndex;
uint8 stateIndex;
address executor;
}
SnapshotHub
Inherits: AgentSecured, SnapshotHubEvents, ISnapshotHub
SnapshotHub
is a parent contract for Summit
. It is responsible for the following:
- Accepting and storing Guard and Notary snapshots to keep track of all the remote
Origin
states. - Generating and storing Attestations derived from Notary snapshots, as well as verifying their validity.
State Variables
_states
All States submitted by any of the Guards
SummitState[] private _states;
_guardSnapshots
All Snapshots submitted by any of the Guards
SummitSnapshot[] private _guardSnapshots;
_notarySnapshots
All Snapshots submitted by any of the Notaries
SummitSnapshot[] private _notarySnapshots;
_attestations
All Attestations created from Notary-submitted Snapshots Invariant: _attestations.length == _notarySnapshots.length
SummitAttestation[] private _attestations;
_leafPtr
Pointer for the given State Leaf of the origin with ZERO as a sentinel value for "state not submitted yet".
mapping(uint32 => mapping(bytes32 => uint256)) private _leafPtr;
_latestStatePtr
Pointer for the latest Agent State of a given origin with ZERO as a sentinel value for "no states submitted yet".
mapping(uint32 => mapping(uint32 => uint256)) private _latestStatePtr;
_latestAttNonce
Latest nonce that a Notary created
mapping(uint32 => uint32) private _latestAttNonce;
__GAP
gap for upgrade safety
uint256[43] private __GAP;
Functions
isValidAttestation
Check that a given attestation is valid: matches the historical attestation derived from an accepted Notary snapshot.
*Will revert if any of these is true:
- Attestation payload is not properly formatted.*
function isValidAttestation(bytes memory attPayload) external view returns (bool isValid);
Parameters
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with attestation data |
Returns
Name | Type | Description |
---|---|---|
isValid | bool | Whether the provided attestation is valid |
getAttestation
Returns saved attestation with the given nonce.
Reverts if attestation with given nonce hasn't been created yet.
function getAttestation(uint32 attNonce)
external
view
returns (bytes memory attPayload, bytes32 agentRoot, uint256[] memory snapGas);
Parameters
Name | Type | Description |
---|---|---|
attNonce | uint32 | Nonce for the attestation |
Returns
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with formatted Attestation data |
agentRoot | bytes32 | Agent root hash used for the attestation |
snapGas | uint256[] | Snapshot gas data used for the attestation |
getLatestAgentState
Returns the state with the highest known nonce submitted by a given Agent.
function getLatestAgentState(uint32 origin, address agent) external view returns (bytes memory stateData);
Parameters
Name | Type | Description |
---|---|---|
origin | uint32 | Domain of origin chain |
agent | address | Agent address |
Returns
Name | Type | Description |
---|---|---|
stateData | bytes | statePayload Raw payload with agent's latest state for origin |
getLatestNotaryAttestation
Returns latest saved attestation for a Notary.
function getLatestNotaryAttestation(address notary)
external
view
returns (bytes memory attPayload, bytes32 agentRoot, uint256[] memory snapGas);
Parameters
Name | Type | Description |
---|---|---|
notary | address | Notary address |
Returns
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with formatted Attestation data |
agentRoot | bytes32 | Agent root hash used for the attestation |
snapGas | uint256[] | Snapshot gas data used for the attestation |
getGuardSnapshot
Returns Guard snapshot from the list of all accepted Guard snapshots.
Reverts if snapshot with given index hasn't been accepted yet.
function getGuardSnapshot(uint256 index) external view returns (bytes memory snapPayload, bytes memory snapSignature);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Snapshot index in the list of all Guard snapshots |
Returns
Name | Type | Description |
---|---|---|
snapPayload | bytes | Raw payload with Guard snapshot |
snapSignature | bytes | Raw payload with Guard signature for snapshot |
getNotarySnapshot
Returns Notary snapshot from the list of all accepted Guard snapshots.
Reverts if snapshot with given index hasn't been accepted yet.
function getNotarySnapshot(uint256 index) public view returns (bytes memory snapPayload, bytes memory snapSignature);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Snapshot index in the list of all Notary snapshots |
Returns
Name | Type | Description |
---|---|---|
snapPayload | bytes | Raw payload with Notary snapshot |
snapSignature | bytes | Raw payload with Notary signature for snapshot |
getNotarySnapshot
Returns Notary snapshot from the list of all accepted Guard snapshots.
Reverts if snapshot with given index hasn't been accepted yet.
function getNotarySnapshot(bytes memory attPayload)
external
view
returns (bytes memory snapPayload, bytes memory snapSignature);
Parameters
Name | Type | Description |
---|---|---|
attPayload | bytes |
Returns
Name | Type | Description |
---|---|---|
snapPayload | bytes | Raw payload with Notary snapshot |
snapSignature | bytes | Raw payload with Notary signature for snapshot |
getSnapshotProof
Returns proof of inclusion of (root, origin) fields of a given snapshot's state into the Snapshot Merkle Tree for a given attestation.
*Reverts if any of these is true:
- Attestation with given nonce hasn't been created yet.
- State index is out of range of snapshot list.*
function getSnapshotProof(uint32 attNonce, uint8 stateIndex) external view returns (bytes32[] memory snapProof);
Parameters
Name | Type | Description |
---|---|---|
attNonce | uint32 | Nonce for the attestation |
stateIndex | uint8 | Index of state in the attestation's snapshot |
Returns
Name | Type | Description |
---|---|---|
snapProof | bytes32[] | The snapshot proof |
_acceptGuardSnapshot
Accepts a Snapshot signed by a Guard. It is assumed that the Guard signature has been checked outside of this contract.
function _acceptGuardSnapshot(Snapshot snapshot, uint32 guardIndex, uint256 sigIndex) internal;
_acceptNotarySnapshot
Accepts a Snapshot signed by a Notary. It is assumed that the Notary signature has been checked outside of this contract. Returns the attestation created from the Notary snapshot.
function _acceptNotarySnapshot(Snapshot snapshot, bytes32 agentRoot, uint32 notaryIndex, uint256 sigIndex)
internal
returns (bytes memory attPayload);
_initializeAttestations
Initializes the saved _attestations list by inserting empty values.
function _initializeAttestations() internal;
_saveGuardSnapshot
Saves the Guard snapshot.
function _saveGuardSnapshot(uint256[] memory statePtrs, uint256 sigIndex) internal;
_saveNotarySnapshot
Saves the Notary snapshot and the attestation created from it. Returns the created attestation.
function _saveNotarySnapshot(
Snapshot snapshot,
uint256[] memory statePtrs,
bytes32 agentRoot,
uint32 notaryIndex,
uint256 sigIndex
) internal returns (bytes memory attPayload);
_saveState
Add a single element to both _attestations
and _notarySnapshots
,
enforcing the (_attestations.length == _notarySnapshots.length) invariant.
Saves the state signed by a Guard.
function _saveState(State state, uint32 guardIndex) internal returns (uint256 statePtr);
_isValidAttestation
Checks if attestation was previously submitted by a Notary (as a signed snapshot).
function _isValidAttestation(Attestation att) internal view returns (bool);
_restoreSnapshot
Restores Snapshot payload from a list of state pointers used for the snapshot.
function _restoreSnapshot(SummitSnapshot memory snapshot)
internal
view
returns (bytes memory snapPayload, bytes memory snapSignature);
_restoreSnapGas
Restores the gas data from the snapshot.
function _restoreSnapGas(SummitSnapshot memory snapshot) internal view returns (uint256[] memory snapGas);
_stateAgents
Returns indexes of agents who provided state data for the Notary snapshot with the given nonce.
function _stateAgents(uint32 nonce, uint8 stateIndex) internal view returns (uint32 guardIndex, uint32 notaryIndex);
_statePtr
Returns the pointer for a matching Guard State, if it exists.
function _statePtr(State state) internal view returns (uint256);
_latestState
Returns the latest state submitted by the Agent for the origin. Will return an empty struct, if the Agent hasn't submitted a single origin State yet.
function _latestState(uint32 origin, uint32 agentIndex) internal view returns (SummitState memory state);
_formatSummitState
Returns a formatted payload for a stored SummitState.
function _formatSummitState(SummitState memory summitState) internal pure returns (bytes memory);
_toSummitState
Returns a SummitState struct to save in the contract.
function _toSummitState(State state, uint32 guardIndex) internal pure returns (SummitState memory summitState);
_formatSummitAttestation
Returns a formatted payload for a stored SummitAttestation.
function _formatSummitAttestation(SummitAttestation memory summitAtt, uint32 nonce)
internal
pure
returns (bytes memory);
_toSummitAttestation
Returns an Attestation struct to save in the Summit contract. Current block number and timestamp are used.
function _toSummitAttestation(bytes32 snapRoot, bytes32 agentRoot, bytes32 snapGasHash)
internal
view
returns (SummitAttestation memory summitAtt);
_areEqual
Checks that an Attestation and its Summit representation are equal.
function _areEqual(Attestation att, SummitAttestation memory summitAtt) internal pure returns (bool);
Structs
SummitState
Struct that represents stored State of Origin contract
struct SummitState {
bytes32 root;
uint32 origin;
uint32 nonce;
uint40 blockNumber;
uint40 timestamp;
GasData gasData;
uint32 guardIndex;
uint32 notaryIndex;
}
SummitSnapshot
struct SummitSnapshot {
uint256[] statePtrs;
uint256 sigIndex;
}
SummitAttestation
struct SummitAttestation {
bytes32 snapRoot;
bytes32 agentRoot;
bytes32 snapGasHash;
uint40 blockNumber;
uint40 timestamp;
}
StateHub
Inherits: AgentSecured, StateHubEvents, IStateHub
StateHub
is a parent contract for Origin
. It is responsible for the following:
- Keeping track of the historical Origin Merkle Tree containing all the message hashes.
- Keeping track of the historical Origin States, as well as verifying their validity.
State Variables
_tree
Historical Merkle Tree Note: Takes two storage slots
HistoricalTree private _tree;
_originStates
All historical contract States
OriginState[] private _originStates;
__GAP
gap for upgrade safety
uint256[47] private __GAP;
Functions
isValidState
Check that a given state is valid: matches the historical state of Origin contract. Note: any Agent including an invalid state in their snapshot will be slashed upon providing the snapshot and agent signature for it to Origin contract.
*Will revert if any of these is true:
- State payload is not properly formatted.*
function isValidState(bytes memory statePayload) external view returns (bool isValid);
Parameters
Name | Type | Description |
---|---|---|
statePayload | bytes | Raw payload with state data |
Returns
Name | Type | Description |
---|---|---|
isValid | bool | Whether the provided state is valid |
statesAmount
Returns the amount of saved states so far.
This includes the initial state of "empty Origin Merkle Tree".
function statesAmount() external view returns (uint256);
suggestLatestState
Suggest the data (state after latest sent message) to sign for an Agent. Note: signing the suggested state data will will never lead to slashing of the actor, assuming they have confirmed that the block, which number is included in the data, is not subject to reorganization (which is different for every observed chain).
function suggestLatestState() external view returns (bytes memory stateData);
Returns
Name | Type | Description |
---|---|---|
stateData | bytes | statePayload Raw payload with the latest state data |
suggestState
Given the historical nonce, suggest the state data to sign for an Agent. Note: signing the suggested state data will will never lead to slashing of the actor, assuming they have confirmed that the block, which number is included in the data, is not subject to reorganization (which is different for every observed chain).
function suggestState(uint32 nonce) public view returns (bytes memory stateData);
Parameters
Name | Type | Description |
---|---|---|
nonce | uint32 | Historical nonce to form a state |
Returns
Name | Type | Description |
---|---|---|
stateData | bytes | statePayload Raw payload with historical state data |
_initializeStates
Initializes the saved states list by inserting a state for an empty Merkle Tree.
function _initializeStates() internal;
_insertAndSave
Inserts leaf into the Merkle Tree and saves the updated origin State.
function _insertAndSave(bytes32 leaf) internal;
_saveState
Saves an updated state of the Origin contract
function _saveState(bytes32 root, OriginState memory state) internal;
_nextNonce
Returns nonce of the next sent message: the amount of saved States so far. This always equals to "total amount of sent messages" plus 1.
function _nextNonce() internal view returns (uint32);
_isValidState
Checks if a state is valid, i.e. if it matches the historical one. Reverts, if state refers to another Origin contract.
function _isValidState(State state) internal view returns (bool);
_formatOriginState
Returns a formatted payload for a stored OriginState.
function _formatOriginState(OriginState memory originState, bytes32 root, uint32 origin, uint32 nonce)
internal
pure
returns (bytes memory);
_fetchGasData
Child contract should implement the logic for getting the current gas data from the gas oracle to be saved as part of the Origin State.
function _fetchGasData() internal view virtual returns (GasData);
_toOriginState
Returns a OriginState struct to save in the contract.
function _toOriginState() internal view returns (OriginState memory originState);
_areEqual
Checks that a state and its Origin representation are equal.
function _areEqual(State state, OriginState memory originState) internal pure returns (bool);
Structs
OriginState
struct OriginState {
uint40 blockNumber;
uint40 timestamp;
GasData gasData;
}
Contents
Inbox
Inherits: StatementInbox, InboxEvents, InterfaceInbox
Inbox
is the child of StatementInbox
contract, that is used on Synapse Chain.
In addition to the functionality of StatementInbox
, it also:
- Accepts Guard and Notary Snapshots and passes them to
Summit
contract. - Accepts Notary-signed Receipts and passes them to
Summit
contract. - Accepts Receipt Reports to initiate a dispute between Guard and Notary.
- Verifies Attestations and Attestation Reports, and slashes the signer if they are invalid.
State Variables
summit
address public summit;
Functions
constructor
constructor(uint32 synapseDomain_) MessagingBase("0.0.3", synapseDomain_);
initialize
Initializes Inbox
contract:
- Sets
msg.sender
as the owner of the contract - Sets
agentManager
,origin
,destination
andsummit
addresses
function initialize(address agentManager_, address origin_, address destination_, address summit_)
external
initializer;
submitSnapshot
Accepts a snapshot signed by a Guard or a Notary and passes it to Summit contract to save.
Snapshot is a list of states for a set of Origin contracts residing on any of the chains.
- Guard-signed snapshots: all the states in the snapshot become available for Notary signing.
- Notary-signed snapshots: Snapshot Merkle Root is saved for valid snapshots, i.e. snapshots which are only using states previously submitted by any of the Guards.
- Notary doesn't have to use states submitted by a single Guard in their snapshot.
- Notary could then proceed to sign the attestation for their submitted snapshot.
Will revert if any of these is true:
- Snapshot payload is not properly formatted.
- Snapshot signer is not an active Agent.
- Agent snapshot contains a state with a nonce smaller or equal then they have previously submitted.
- Notary snapshot contains a state that hasn't been previously submitted by any of the Guards.
- Note: Agent will NOT be slashed for submitting such a snapshot.
Notary will need to provide both agentRoot
and snapGas
when submitting an attestation on
the remote chain (the attestation contains only their merged hash). These are returned by this function,
and could be also obtained by calling getAttestation(nonce)
or getLatestNotaryAttestation(notary)
.
function submitSnapshot(bytes memory snapPayload, bytes memory snapSignature)
external
returns (bytes memory attPayload, bytes32 agentRoot_, uint256[] memory snapGas);
Parameters
Name | Type | Description |
---|---|---|
snapPayload | bytes | Raw payload with snapshot data |
snapSignature | bytes | Agent signature for the snapshot |
Returns
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with data for attestation derived from Notary snapshot. Empty payload, if a Guard snapshot was submitted. |
agentRoot_ | bytes32 | agentRoot Current root of the Agent Merkle Tree (zero, if a Guard snapshot was submitted) |
snapGas | uint256[] | Gas data for each chain in the snapshot Empty list, if a Guard snapshot was submitted. |
submitReceipt
Accepts a receipt signed by a Notary and passes it to Summit contract to save.
Receipt is a statement about message execution status on the remote chain.
- This will distribute the message tips across the off-chain actors once the receipt optimistic period is over.
Will revert if any of these is true:
- Receipt payload is not properly formatted.
- Receipt signer is not an active Notary.
- Receipt signer is in Dispute.
- Receipt's snapshot root is unknown.
- Provided tips could not be proven against the message hash.
function submitReceipt(
bytes memory rcptPayload,
bytes memory rcptSignature,
uint256 paddedTips,
bytes32 headerHash,
bytes32 bodyHash
) external returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
rcptPayload | bytes | Raw payload with receipt data |
rcptSignature | bytes | Notary signature for the receipt |
paddedTips | uint256 | Tips for the message execution |
headerHash | bytes32 | Hash of the message header |
bodyHash | bytes32 | Hash of the message body excluding the tips |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the receipt was accepted |
submitReceiptReport
Accepts a Guard's receipt report signature, as well as Notary signature for the reported Receipt.
ReceiptReport is a Guard statement saying "Reported receipt is invalid".
- This results in an opened Dispute between the Guard and the Notary.
- Note: Guard could (but doesn't have to) form a ReceiptReport and use receipt signature from
verifyReceipt()
successful call that led to Notary being slashed in Summit on Synapse Chain.
Will revert if any of these is true:
- Receipt payload is not properly formatted.
- Receipt Report signer is not an active Guard.
- Receipt signer is not an active Notary.
function submitReceiptReport(bytes memory rcptPayload, bytes memory rcptSignature, bytes memory rrSignature)
external
returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
rcptPayload | bytes | Raw payload with Receipt data that Guard reports as invalid |
rcptSignature | bytes | Notary signature for the reported receipt |
rrSignature | bytes | Guard signature for the report |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Report was accepted (resulting in Dispute between the agents) |
passReceipt
Passes the message execution receipt from Destination to the Summit contract to save.
Will revert if any of these is true:
- Called by anyone other than Destination.
If a receipt is not accepted, any of the Notaries can submit it later using submitReceipt
.
function passReceipt(uint32 attNotaryIndex, uint32 attNonce, uint256 paddedTips, bytes memory rcptPayload)
external
returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
attNotaryIndex | uint32 | Index of the Notary who signed the attestation |
attNonce | uint32 | Nonce of the attestation used for proving the executed message |
paddedTips | uint256 | Tips for the message execution |
rcptPayload | bytes | Raw payload with message execution receipt |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the receipt was accepted |
verifyAttestation
Verifies an attestation signed by a Notary.
- Does nothing, if the attestation is valid (was submitted by this Notary as a snapshot).
- Slashes the Notary, if the attestation is invalid.
Will revert if any of these is true:
- Attestation payload is not properly formatted.
- Attestation signer is not an active Notary.
function verifyAttestation(bytes memory attPayload, bytes memory attSignature)
external
returns (bool isValidAttestation);
Parameters
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the attestation |
Returns
Name | Type | Description |
---|---|---|
isValidAttestation | bool | Whether the provided attestation is valid. Notary is slashed, if return value is FALSE. |
verifyAttestationReport
Verifies a Guard's attestation report signature.
- Does nothing, if the report is valid (if the reported attestation is invalid).
- Slashes the Guard, if the report is invalid (if the reported attestation is valid).
Will revert if any of these is true:
- Attestation payload is not properly formatted.
- Attestation Report signer is not an active Guard.
function verifyAttestationReport(bytes memory attPayload, bytes memory arSignature)
external
returns (bool isValidReport);
Parameters
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with Attestation data that Guard reports as invalid |
arSignature | bytes | Guard signature for the report |
Returns
Name | Type | Description |
---|---|---|
isValidReport | bool | Whether the provided report is valid. Guard is slashed, if return value is FALSE. |
_verifyReceiptTips
Verifies that tips proof matches the message hash.
function _verifyReceiptTips(bytes32 msgHash, uint256 paddedTips, bytes32 headerHash, bytes32 bodyHash) internal pure;
Structs
ReceiptInfo
struct ReceiptInfo {
AgentStatus rcptNotaryStatus;
address notary;
uint32 attNonce;
AgentStatus attNotaryStatus;
}
LightInbox
Inherits: StatementInbox, InterfaceLightInbox
LightInbox
is the child of StatementInbox
contract, that is used chains other than the Synapse Chain.
In addition to the functionality of StatementInbox
, it also:
- Accepts Notary Attestations and passes them to the
Destination
contract. - Accepts Attestation Reports and initiates a dispute between the Notary and the Guard.
Functions
constructor
constructor(uint32 synapseDomain_) MessagingBase("0.0.3", synapseDomain_);
initialize
Initializes LightInbox
contract:
- Sets
msg.sender
as the owner of the contract - Sets
agentManager
,origin
anddestination
addresses
function initialize(address agentManager_, address origin_, address destination_) external initializer;
submitAttestation
Accepts an attestation signed by a Notary and passes it to Destination contract to save.
Attestation is created whenever a Notary-signed snapshot is saved in Summit on Synapse Chain.
- Saved Attestation could be later used to prove the inclusion of message in the Origin Merkle Tree.
- Messages coming from chains included in the Attestation's snapshot could be proven.
- Proof only exists for messages that were sent prior to when the Attestation's snapshot was taken.
Will revert if any of these is true:
- Attestation payload is not properly formatted.
- Attestation signer is not an active Notary for local domain.
- Attestation signer is in Dispute.
- Attestation's snapshot root has been previously submitted.
- Attestation's data hash doesn't match the hash of provided agentRoot and snapshot gas data.
function submitAttestation(
bytes memory attPayload,
bytes memory attSignature,
bytes32 agentRoot_,
uint256[] memory snapGas_
) external returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the attestation |
agentRoot_ | bytes32 | |
snapGas_ | uint256[] |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Attestation was accepted |
submitAttestationReport
Accepts a Guard's attestation report signature, as well as Notary signature for the reported Attestation.
AttestationReport is a Guard statement saying "Reported attestation is invalid".
- This results in an opened Dispute between the Guard and the Notary.
- Note: Guard could (but doesn't have to) form a AttestationReport and use attestation signature from
verifyAttestation()
successful call that led to Notary being slashed in Summit on Synapse Chain.
Will revert if any of these is true:
- Attestation payload is not properly formatted.
- Attestation Report signer is not an active Guard.
- Attestation signer is not an active Notary for local domain.
function submitAttestationReport(bytes memory attPayload, bytes memory arSignature, bytes memory attSignature)
external
returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with Attestation data that Guard reports as invalid |
arSignature | bytes | Guard signature for the report |
attSignature | bytes | Notary signature for the reported attestation |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Report was accepted (resulting in Dispute between the agents) |
StatementInbox
Inherits: MessagingBase, StatementInboxEvents, IStatementInbox
StatementInbox
is the entry point for all agent-signed statements. It verifies the
agent signatures, and passes the unsigned statements to the contract to consume it via acceptX
functions. Is is
also used to verify the agent-signed statements and initiate the agent slashing, should the statement be invalid.
StatementInbox
is responsible for the following:
- Accepting State and Receipt Reports to initiate a dispute between Guard and Notary.
- Storing all the Guard Reports with the Guard signature leading to a dispute.
- Verifying State/State Reports referencing the local chain and slashing the signer if statement is invalid.
- Verifying Receipt/Receipt Reports referencing the local chain and slashing the signer if statement is invalid.
State Variables
agentManager
address public agentManager;
origin
address public origin;
destination
address public destination;
_storedSignatures
bytes[] internal _storedSignatures;
_storedReports
StoredReport[] internal _storedReports;
__GAP
gap for upgrade safety
uint256[45] private __GAP;
Functions
__StatementInbox_init
*Initializes the contract:
- Sets up
msg.sender
as the owner of the contract. - Sets up
agentManager
,origin
, anddestination
.*
function __StatementInbox_init(address agentManager_, address origin_, address destination_)
internal
onlyInitializing;
submitStateReportWithSnapshot
Accepts a Guard's state report signature, a Snapshot containing the reported State, as well as Notary signature for the Snapshot.
StateReport is a Guard statement saying "Reported state is invalid".
- This results in an opened Dispute between the Guard and the Notary.
- Note: Guard could (but doesn't have to) form a StateReport and use other values from
verifyStateWithSnapshot()
successful call that led to Notary being slashed in remote Origin.
Will revert if any of these is true:
- State Report signer is not an active Guard.
- Snapshot payload is not properly formatted.
- Snapshot signer is not an active Notary.
- State index is out of range.
- The Guard or the Notary are already in a Dispute
function submitStateReportWithSnapshot(
uint8 stateIndex,
bytes memory srSignature,
bytes memory snapPayload,
bytes memory snapSignature
) external returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
stateIndex | uint8 | Index of the reported State in the Snapshot |
srSignature | bytes | Guard signature for the report |
snapPayload | bytes | Raw payload with Snapshot data |
snapSignature | bytes | Notary signature for the Snapshot |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Report was accepted (resulting in Dispute between the agents) |
submitStateReportWithAttestation
Accepts a Guard's state report signature, a Snapshot containing the reported State, as well as Notary signature for the Attestation created from this Snapshot.
StateReport is a Guard statement saying "Reported state is invalid".
- This results in an opened Dispute between the Guard and the Notary.
- Note: Guard could (but doesn't have to) form a StateReport and use other values from
verifyStateWithAttestation()
successful call that led to Notary being slashed in remote Origin.
Will revert if any of these is true:
- State Report signer is not an active Guard.
- Snapshot payload is not properly formatted.
- State index is out of range.
- Attestation payload is not properly formatted.
- Attestation signer is not an active Notary.
- Attestation's snapshot root is not equal to Merkle Root derived from the Snapshot.
- The Guard or the Notary are already in a Dispute
function submitStateReportWithAttestation(
uint8 stateIndex,
bytes memory srSignature,
bytes memory snapPayload,
bytes memory attPayload,
bytes memory attSignature
) external returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
stateIndex | uint8 | Index of the reported State in the Snapshot |
srSignature | bytes | Guard signature for the report |
snapPayload | bytes | Raw payload with Snapshot data |
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the Attestation |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Report was accepted (resulting in Dispute between the agents) |
submitStateReportWithSnapshotProof
Accepts a Guard's state report signature, a proof of inclusion of the reported State in an Attestation, as well as Notary signature for the Attestation.
StateReport is a Guard statement saying "Reported state is invalid".
- This results in an opened Dispute between the Guard and the Notary.
- Note: Guard could (but doesn't have to) form a StateReport and use other values from
verifyStateWithSnapshotProof()
successful call that led to Notary being slashed in remote Origin.
Will revert if any of these is true:
- State payload is not properly formatted.
- State Report signer is not an active Guard.
- Attestation payload is not properly formatted.
- Attestation signer is not an active Notary.
- Attestation's snapshot root is not equal to Merkle Root derived from State and Snapshot Proof.
- Snapshot Proof's first element does not match the State metadata.
- Snapshot Proof length exceeds Snapshot Tree Height.
- State index is out of range.
- The Guard or the Notary are already in a Dispute
function submitStateReportWithSnapshotProof(
uint8 stateIndex,
bytes memory statePayload,
bytes memory srSignature,
bytes32[] memory snapProof,
bytes memory attPayload,
bytes memory attSignature
) external returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
stateIndex | uint8 | Index of the reported State in the Snapshot |
statePayload | bytes | Raw payload with State data that Guard reports as invalid |
srSignature | bytes | Guard signature for the report |
snapProof | bytes32[] | Proof of inclusion of reported State's Left Leaf into Snapshot Merkle Tree |
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the Attestation |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Report was accepted (resulting in Dispute between the agents) |
verifyReceipt
Verifies a message receipt signed by the Notary.
- Does nothing, if the receipt is valid (matches the saved receipt data for the referenced message).
- Slashes the Notary, if the receipt is invalid.
Will revert if any of these is true:
- Receipt payload is not properly formatted.
- Receipt signer is not an active Notary.
- Receipt's destination chain does not refer to this chain.
function verifyReceipt(bytes memory rcptPayload, bytes memory rcptSignature) external returns (bool isValidReceipt);
Parameters
Name | Type | Description |
---|---|---|
rcptPayload | bytes | Raw payload with Receipt data |
rcptSignature | bytes | Notary signature for the receipt |
Returns
Name | Type | Description |
---|---|---|
isValidReceipt | bool | Whether the provided receipt is valid. Notary is slashed, if return value is FALSE. |
verifyReceiptReport
Verifies a Guard's receipt report signature.
- Does nothing, if the report is valid (if the reported receipt is invalid).
- Slashes the Guard, if the report is invalid (if the reported receipt is valid).
Will revert if any of these is true:
- Receipt payload is not properly formatted.
- Receipt Report signer is not an active Guard.
- Receipt does not refer to this chain.
function verifyReceiptReport(bytes memory rcptPayload, bytes memory rrSignature)
external
returns (bool isValidReport);
Parameters
Name | Type | Description |
---|---|---|
rcptPayload | bytes | Raw payload with Receipt data that Guard reports as invalid |
rrSignature | bytes | Guard signature for the report |
Returns
Name | Type | Description |
---|---|---|
isValidReport | bool | Whether the provided report is valid. Guard is slashed, if return value is FALSE. |
verifyStateWithAttestation
Verifies a state from the snapshot, that was used for the Notary-signed attestation.
- Does nothing, if the state is valid (matches the historical state of this contract).
- Slashes the Notary, if the state is invalid.
Will revert if any of these is true:
- Attestation payload is not properly formatted.
- Attestation signer is not an active Notary.
- Attestation's snapshot root is not equal to Merkle Root derived from the Snapshot.
- Snapshot payload is not properly formatted.
- State index is out of range.
- State does not refer to this chain.
function verifyStateWithAttestation(
uint8 stateIndex,
bytes memory snapPayload,
bytes memory attPayload,
bytes memory attSignature
) external returns (bool isValidState);
Parameters
Name | Type | Description |
---|---|---|
stateIndex | uint8 | State index to check |
snapPayload | bytes | Raw payload with snapshot data |
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the attestation |
Returns
Name | Type | Description |
---|---|---|
isValidState | bool | Whether the provided state is valid. Notary is slashed, if return value is FALSE. |
verifyStateWithSnapshotProof
Verifies a state from the snapshot, that was used for the Notary-signed attestation.
- Does nothing, if the state is valid (matches the historical state of this contract).
- Slashes the Notary, if the state is invalid.
Will revert if any of these is true:
- Attestation payload is not properly formatted.
- Attestation signer is not an active Notary.
- Attestation's snapshot root is not equal to Merkle Root derived from State and Snapshot Proof.
- Snapshot Proof's first element does not match the State metadata.
- Snapshot Proof length exceeds Snapshot Tree Height.
- State payload is not properly formatted.
- State index is out of range.
- State does not refer to this chain.
function verifyStateWithSnapshotProof(
uint8 stateIndex,
bytes memory statePayload,
bytes32[] memory snapProof,
bytes memory attPayload,
bytes memory attSignature
) external returns (bool isValidState);
Parameters
Name | Type | Description |
---|---|---|
stateIndex | uint8 | Index of state in the snapshot |
statePayload | bytes | Raw payload with State data to check |
snapProof | bytes32[] | Proof of inclusion of provided State's Left Leaf into Snapshot Merkle Tree |
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the attestation |
Returns
Name | Type | Description |
---|---|---|
isValidState | bool | Whether the provided state is valid. Notary is slashed, if return value is FALSE. |
verifyStateWithSnapshot
Verifies a state from the snapshot (a list of states) signed by a Guard or a Notary.
- Does nothing, if the state is valid (matches the historical state of this contract).
- Slashes the Agent, if the state is invalid.
Will revert if any of these is true:
- Snapshot payload is not properly formatted.
- Snapshot signer is not an active Agent.
- State index is out of range.
- State does not refer to this chain.
function verifyStateWithSnapshot(uint8 stateIndex, bytes memory snapPayload, bytes memory snapSignature)
external
returns (bool isValidState);
Parameters
Name | Type | Description |
---|---|---|
stateIndex | uint8 | State index to check |
snapPayload | bytes | Raw payload with snapshot data |
snapSignature | bytes | Agent signature for the snapshot |
Returns
Name | Type | Description |
---|---|---|
isValidState | bool | Whether the provided state is valid. Agent is slashed, if return value is FALSE. |
verifyStateReport
Verifies a Guard's state report signature.
- Does nothing, if the report is valid (if the reported state is invalid).
- Slashes the Guard, if the report is invalid (if the reported state is valid).
Will revert if any of these is true:
- State payload is not properly formatted.
- State Report signer is not an active Guard.
- Reported State does not refer to this chain.
function verifyStateReport(bytes memory statePayload, bytes memory srSignature) external returns (bool isValidReport);
Parameters
Name | Type | Description |
---|---|---|
statePayload | bytes | Raw payload with State data that Guard reports as invalid |
srSignature | bytes | Guard signature for the report |
Returns
Name | Type | Description |
---|---|---|
isValidReport | bool | Whether the provided report is valid. Guard is slashed, if return value is FALSE. |
getReportsAmount
Returns the amount of Guard Reports stored in StatementInbox.
Only reports that led to opening a Dispute are stored.
function getReportsAmount() external view returns (uint256);
getGuardReport
Returns the Guard report with the given index stored in StatementInbox.
Only reports that led to opening a Dispute are stored.
Will revert if report with given index doesn't exist.
function getGuardReport(uint256 index)
external
view
returns (bytes memory statementPayload, bytes memory reportSignature);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Report index |
Returns
Name | Type | Description |
---|---|---|
statementPayload | bytes | Raw payload with statement that Guard reported as invalid |
reportSignature | bytes | Guard signature for the report |
getStoredSignature
Returns the signature with the given index stored in StatementInbox.
Will revert if signature with given index doesn't exist.
function getStoredSignature(uint256 index) external view returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Signature index |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | Raw payload with signature |
_saveReport
Saves the statement reported by Guard as invalid and the Guard Report signature.
function _saveReport(bytes memory statementPayload, bytes memory reportSignature) internal;
_saveSignature
Saves the signature and returns its index.
function _saveSignature(bytes memory signature) internal returns (uint256 sigIndex);
_recoverAgent
Recovers a signer from a hashed message, and a EIP-191 signature for it. Will revert, if the signer is not a known agent.
Agent flag could be any of these: Active/Unstaking/Resting/Fraudulent/Slashed Further checks need to be performed in a caller function.
function _recoverAgent(bytes32 hashedStatement, bytes memory signature)
internal
view
returns (AgentStatus memory status, address agent);
Parameters
Name | Type | Description |
---|---|---|
hashedStatement | bytes32 | Hash of the statement that was signed by an Agent |
signature | bytes | Agent signature for the hashed statement |
Returns
Name | Type | Description |
---|---|---|
status | AgentStatus | Struct representing agent status: - flag Unknown/Active/Unstaking/Resting/Fraudulent/Slashed - domain Domain where agent is/was active - index Index of agent in the Agent Merkle Tree |
agent | address | Agent that signed the statement |
_verifyNotaryDomain
Verifies that Notary signature is active on local domain.
function _verifyNotaryDomain(uint32 notaryDomain) internal view;
_verifyAttestation
*Internal function to verify the signed attestation payload. Reverts if any of these is true:
- Attestation signer is not a known Notary.*
function _verifyAttestation(Attestation att, bytes memory attSignature)
internal
view
returns (AgentStatus memory status, address notary);
Parameters
Name | Type | Description |
---|---|---|
att | Attestation | Typed memory view over attestation payload |
attSignature | bytes | Notary signature for the attestation |
Returns
Name | Type | Description |
---|---|---|
status | AgentStatus | Struct representing agent status, see {_recoverAgent} |
notary | address | Notary that signed the snapshot |
_verifyAttestationReport
*Internal function to verify the signed attestation report payload. Reverts if any of these is true:
- Report signer is not a known Guard.*
function _verifyAttestationReport(Attestation att, bytes memory arSignature)
internal
view
returns (AgentStatus memory status, address guard);
Parameters
Name | Type | Description |
---|---|---|
att | Attestation | Typed memory view over attestation payload that Guard reports as invalid |
arSignature | bytes | Guard signature for the "invalid attestation" report |
Returns
Name | Type | Description |
---|---|---|
status | AgentStatus | Struct representing guard status, see {_recoverAgent} |
guard | address | Guard that signed the report |
_verifyReceipt
*Internal function to verify the signed receipt payload. Reverts if any of these is true:
- Receipt signer is not a known Notary.*
function _verifyReceipt(Receipt rcpt, bytes memory rcptSignature)
internal
view
returns (AgentStatus memory status, address notary);
Parameters
Name | Type | Description |
---|---|---|
rcpt | Receipt | Typed memory view over receipt payload |
rcptSignature | bytes | Notary signature for the receipt |
Returns
Name | Type | Description |
---|---|---|
status | AgentStatus | Struct representing agent status, see {_recoverAgent} |
notary | address | Notary that signed the snapshot |
_verifyReceiptReport
*Internal function to verify the signed receipt report payload. Reverts if any of these is true:
- Report signer is not a known Guard.*
function _verifyReceiptReport(Receipt rcpt, bytes memory rrSignature)
internal
view
returns (AgentStatus memory status, address guard);
Parameters
Name | Type | Description |
---|---|---|
rcpt | Receipt | Typed memory view over receipt payload that Guard reports as invalid |
rrSignature | bytes | Guard signature for the "invalid receipt" report |
Returns
Name | Type | Description |
---|---|---|
status | AgentStatus | Struct representing guard status, see {_recoverAgent} |
guard | address | Guard that signed the report |
_verifyStateReport
*Internal function to verify the signed snapshot report payload. Reverts if any of these is true:
- Report signer is not a known Guard.*
function _verifyStateReport(State state, bytes memory srSignature)
internal
view
returns (AgentStatus memory status, address guard);
Parameters
Name | Type | Description |
---|---|---|
state | State | Typed memory view over state payload that Guard reports as invalid |
srSignature | bytes | Guard signature for the report |
Returns
Name | Type | Description |
---|---|---|
status | AgentStatus | Struct representing guard status, see {_recoverAgent} |
guard | address | Guard that signed the report |
_verifySnapshot
*Internal function to verify the signed snapshot payload. Reverts if any of these is true:
- Snapshot signer is not a known Agent.
- Snapshot signer is not a Notary (if verifyNotary is true).*
function _verifySnapshot(Snapshot snapshot, bytes memory snapSignature, bool verifyNotary)
internal
view
returns (AgentStatus memory status, address agent);
Parameters
Name | Type | Description |
---|---|---|
snapshot | Snapshot | Typed memory view over snapshot payload |
snapSignature | bytes | Agent signature for the snapshot |
verifyNotary | bool | If true, snapshot signer needs to be a Notary, not a Guard |
Returns
Name | Type | Description |
---|---|---|
status | AgentStatus | Struct representing agent status, see {_recoverAgent} |
agent | address | Agent that signed the snapshot |
_verifySnapshotMerkle
*Internal function to verify that snapshot roots match. Reverts if any of these is true:
- Attestation root is not equal to Merkle Root derived from State and Snapshot Proof.
- Snapshot Proof's first element does not match the State metadata.
- Snapshot Proof length exceeds Snapshot tree Height.
- State index is out of range.*
function _verifySnapshotMerkle(Attestation att, uint8 stateIndex, State state, bytes32[] memory snapProof)
internal
pure;
Parameters
Name | Type | Description |
---|---|---|
att | Attestation | Typed memory view over Attestation |
stateIndex | uint8 | Index of state in the snapshot |
state | State | Typed memory view over the provided state payload |
snapProof | bytes32[] | Raw payload with snapshot data |
Structs
StoredReport
struct StoredReport {
uint256 sigIndex;
bytes statementPayload;
}
Contents
- IAgentManager
- IAgentSecured
- IExecutionHub
- IMessageRecipient
- ISnapshotHub
- IStateHub
- IStatementInbox
- InterfaceBondingManager
- InterfaceDestination
- InterfaceGasOracle
- InterfaceInbox
- InterfaceLightInbox
- InterfaceLightManager
- InterfaceOrigin
- InterfaceSummit
IAgentManager
Functions
openDispute
Allows Inbox to open a Dispute between a Guard and a Notary, if they are both not in Dispute already.
Will revert if any of these is true:
- Caller is not Inbox.
- Guard or Notary is already in Dispute.
function openDispute(uint32 guardIndex, uint32 notaryIndex) external;
Parameters
Name | Type | Description |
---|---|---|
guardIndex | uint32 | Index of the Guard in the Agent Merkle Tree |
notaryIndex | uint32 | Index of the Notary in the Agent Merkle Tree |
slashAgent
Allows Inbox to slash an agent, if their fraud was proven.
Will revert if any of these is true:
- Caller is not Inbox.
- Domain doesn't match the saved agent domain.
function slashAgent(uint32 domain, address agent, address prover) external;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain where the Agent is active |
agent | address | Address of the Agent |
prover | address | Address that initially provided fraud proof |
agentRoot
Returns the latest known root of the Agent Merkle Tree.
function agentRoot() external view returns (bytes32);
agentStatus
Returns (flag, domain, index) for a given agent. See Structures.sol for details.
Will return AgentFlag.Fraudulent for agents that have been proven to commit fraud, but their status is not updated to Slashed yet.
function agentStatus(address agent) external view returns (AgentStatus memory);
Parameters
Name | Type | Description |
---|---|---|
agent | address | Agent address |
Returns
Name | Type | Description |
---|---|---|
<none> | AgentStatus | Status for the given agent: (flag, domain, index). |
getAgent
Returns agent address and their current status for a given agent index.
Will return empty values if agent with given index doesn't exist.
function getAgent(uint256 index) external view returns (address agent, AgentStatus memory status);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Agent index in the Agent Merkle Tree |
Returns
Name | Type | Description |
---|---|---|
agent | address | Agent address |
status | AgentStatus | Status for the given agent: (flag, domain, index) |
getDisputesAmount
Returns the number of opened Disputes.
This includes the Disputes that have been resolved already.
function getDisputesAmount() external view returns (uint256);
getDispute
Returns information about the dispute with the given index.
Will revert if dispute with given index hasn't been opened yet.
function getDispute(uint256 index)
external
view
returns (
address guard,
address notary,
address slashedAgent,
address fraudProver,
bytes memory reportPayload,
bytes memory reportSignature
);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Dispute index |
Returns
Name | Type | Description |
---|---|---|
guard | address | Address of the Guard in the Dispute |
notary | address | Address of the Notary in the Dispute |
slashedAgent | address | Address of the Agent who was slashed when Dispute was resolved |
fraudProver | address | Address who provided fraud proof to resolve the Dispute |
reportPayload | bytes | Raw payload with report data that led to the Dispute |
reportSignature | bytes | Guard signature for the report payload |
disputeStatus
Returns the current Dispute status of a given agent. See Structures.sol for details.
Every returned value will be set to zero if agent was not slashed and is not in Dispute.
rival
and disputePtr
will be set to zero if the agent was slashed without being in Dispute.
function disputeStatus(address agent)
external
view
returns (DisputeFlag flag, address rival, address fraudProver, uint256 disputePtr);
Parameters
Name | Type | Description |
---|---|---|
agent | address | Agent address |
Returns
Name | Type | Description |
---|---|---|
flag | DisputeFlag | Flag describing the current Dispute status for the agent: None/Pending/Slashed |
rival | address | Address of the rival agent in the Dispute |
fraudProver | address | Address who provided fraud proof to resolve the Dispute |
disputePtr | uint256 | Index of the opened Dispute PLUS ONE. Zero if agent is not in Dispute. |
IAgentSecured
Functions
openDispute
Local AgentManager should call this function to indicate that a dispute between a Guard and a Notary has been opened.
function openDispute(uint32 guardIndex, uint32 notaryIndex) external;
Parameters
Name | Type | Description |
---|---|---|
guardIndex | uint32 | Index of the Guard in the Agent Merkle Tree |
notaryIndex | uint32 | Index of the Notary in the Agent Merkle Tree |
resolveDispute
Local AgentManager should call this function to indicate that a dispute has been resolved due to one of the agents being slashed.
rivalIndex
will be ZERO, if the slashed agent was not in the Dispute.
function resolveDispute(uint32 slashedIndex, uint32 rivalIndex) external;
Parameters
Name | Type | Description |
---|---|---|
slashedIndex | uint32 | Index of the slashed agent in the Agent Merkle Tree |
rivalIndex | uint32 | Index of the their Dispute Rival in the Agent Merkle Tree |
agentManager
Returns the address of the local AgentManager contract, which is treated as the "source of truth" for agent statuses.
function agentManager() external view returns (address);
inbox
Returns the address of the local Inbox contract, which is treated as the "source of truth" for agent-signed statements.
Inbox passes verified agent statements to IAgentSecured
contract.
function inbox() external view returns (address);
agentStatus
Returns (flag, domain, index) for a given agent. See Structures.sol for details.
Will return AgentFlag.Fraudulent for agents that have been proven to commit fraud, but their status is not updated to Slashed yet.
function agentStatus(address agent) external view returns (AgentStatus memory);
Parameters
Name | Type | Description |
---|---|---|
agent | address | Agent address |
Returns
Name | Type | Description |
---|---|---|
<none> | AgentStatus | Status for the given agent: (flag, domain, index). |
getAgent
Returns agent address and their current status for a given agent index.
Will return empty values if agent with given index doesn't exist.
function getAgent(uint256 index) external view returns (address agent, AgentStatus memory status);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Agent index in the Agent Merkle Tree |
Returns
Name | Type | Description |
---|---|---|
agent | address | Agent address |
status | AgentStatus | Status for the given agent: (flag, domain, index) |
latestDisputeStatus
Returns (flag, openedAt, resolvedAt) that describes the latest status of the latest dispute for an agent with a given index.
Will return empty values if agent with given index doesn't exist.
function latestDisputeStatus(uint32 agentIndex) external view returns (DisputeStatus memory);
Parameters
Name | Type | Description |
---|---|---|
agentIndex | uint32 | Agent index in the Agent Merkle Tree |
Returns
Name | Type | Description |
---|---|---|
<none> | DisputeStatus | Latest dispute status for the given agent: (flag, openedAt, resolvedAt) |
IExecutionHub
Functions
execute
Attempts to prove inclusion of message into one of Snapshot Merkle Trees, previously submitted to this contract in a form of a signed Attestation. Proven message is immediately executed by passing its contents to the specified recipient.
*Will revert if any of these is true:
- Message is not meant to be executed on this chain
- Message was sent from this chain
- Message payload is not properly formatted.
- Snapshot root (reconstructed from message hash and proofs) is unknown
- Snapshot root is known, but was submitted by an inactive Notary
- Snapshot root is known, but optimistic period for a message hasn't passed
- Provided gas limit is lower than the one requested in the message
- Recipient doesn't implement a
handle
method (refer to IMessageRecipient.sol) - Recipient reverted upon receiving a message Note: refer to libs/memory/State.sol for details about Origin State's sub-leafs.*
function execute(
bytes memory msgPayload,
bytes32[] calldata originProof,
bytes32[] calldata snapProof,
uint8 stateIndex,
uint64 gasLimit
) external;
Parameters
Name | Type | Description |
---|---|---|
msgPayload | bytes | Raw payload with a formatted message to execute |
originProof | bytes32[] | Proof of inclusion of message in the Origin Merkle Tree |
snapProof | bytes32[] | Proof of inclusion of Origin State's Left Leaf into Snapshot Merkle Tree |
stateIndex | uint8 | Index of Origin State in the Snapshot |
gasLimit | uint64 | Gas limit for message execution |
getAttestationNonce
Returns attestation nonce for a given snapshot root.
Will return 0 if the root is unknown.
function getAttestationNonce(bytes32 snapRoot) external view returns (uint32 attNonce);
isValidReceipt
Checks the validity of the unsigned message receipt.
*Will revert if any of these is true:
- Receipt payload is not properly formatted.
- Receipt signer is not an active Notary.
- Receipt destination chain does not refer to this chain.*
function isValidReceipt(bytes memory rcptPayload) external view returns (bool isValid);
Parameters
Name | Type | Description |
---|---|---|
rcptPayload | bytes | Raw payload with Receipt data |
Returns
Name | Type | Description |
---|---|---|
isValid | bool | Whether the requested receipt is valid. |
messageStatus
Returns message execution status: None/Failed/Success.
function messageStatus(bytes32 messageHash) external view returns (MessageStatus status);
Parameters
Name | Type | Description |
---|---|---|
messageHash | bytes32 | Hash of the message payload |
Returns
Name | Type | Description |
---|---|---|
status | MessageStatus | Message execution status |
messageReceipt
Returns a formatted payload with the message receipt.
Notaries could derive the tips, and the tips proof using the message payload, and submit
the signed receipt with the proof of tips to Summit
in order to initiate tips distribution.
function messageReceipt(bytes32 messageHash) external view returns (bytes memory data);
Parameters
Name | Type | Description |
---|---|---|
messageHash | bytes32 | Hash of the message payload |
Returns
Name | Type | Description |
---|---|---|
data | bytes | Formatted payload with the message execution receipt |
IMessageRecipient
Functions
receiveBaseMessage
Message recipient needs to implement this function in order to receive cross-chain messages.
Message recipient needs to ensure that merkle proof for the message is at least as old as the optimistic period that the recipient is using. Note: as this point it is checked that the "message optimistic period" has passed, however the period value itself could be anything, and thus could differ from the one that the recipient would like to enforce.
function receiveBaseMessage(
uint32 origin,
uint32 nonce,
bytes32 sender,
uint256 proofMaturity,
uint32 version,
bytes memory content
) external payable;
Parameters
Name | Type | Description |
---|---|---|
origin | uint32 | Domain where message originated |
nonce | uint32 | Message nonce on the origin domain |
sender | bytes32 | Sender address on origin chain |
proofMaturity | uint256 | Message's merkle proof age in seconds |
version | uint32 | Message version specified by sender |
content | bytes | Raw bytes content of message |
ISnapshotHub
Functions
isValidAttestation
Check that a given attestation is valid: matches the historical attestation derived from an accepted Notary snapshot.
*Will revert if any of these is true:
- Attestation payload is not properly formatted.*
function isValidAttestation(bytes memory attPayload) external view returns (bool isValid);
Parameters
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with attestation data |
Returns
Name | Type | Description |
---|---|---|
isValid | bool | Whether the provided attestation is valid |
getAttestation
Returns saved attestation with the given nonce.
Reverts if attestation with given nonce hasn't been created yet.
function getAttestation(uint32 attNonce)
external
view
returns (bytes memory attPayload, bytes32 agentRoot, uint256[] memory snapGas);
Parameters
Name | Type | Description |
---|---|---|
attNonce | uint32 | Nonce for the attestation |
Returns
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with formatted Attestation data |
agentRoot | bytes32 | Agent root hash used for the attestation |
snapGas | uint256[] | Snapshot gas data used for the attestation |
getLatestAgentState
Returns the state with the highest known nonce submitted by a given Agent.
function getLatestAgentState(uint32 origin, address agent) external view returns (bytes memory statePayload);
Parameters
Name | Type | Description |
---|---|---|
origin | uint32 | Domain of origin chain |
agent | address | Agent address |
Returns
Name | Type | Description |
---|---|---|
statePayload | bytes | Raw payload with agent's latest state for origin |
getLatestNotaryAttestation
Returns latest saved attestation for a Notary.
function getLatestNotaryAttestation(address notary)
external
view
returns (bytes memory attPayload, bytes32 agentRoot, uint256[] memory snapGas);
Parameters
Name | Type | Description |
---|---|---|
notary | address | Notary address |
Returns
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with formatted Attestation data |
agentRoot | bytes32 | Agent root hash used for the attestation |
snapGas | uint256[] | Snapshot gas data used for the attestation |
getGuardSnapshot
Returns Guard snapshot from the list of all accepted Guard snapshots.
Reverts if snapshot with given index hasn't been accepted yet.
function getGuardSnapshot(uint256 index) external view returns (bytes memory snapPayload, bytes memory snapSignature);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Snapshot index in the list of all Guard snapshots |
Returns
Name | Type | Description |
---|---|---|
snapPayload | bytes | Raw payload with Guard snapshot |
snapSignature | bytes | Raw payload with Guard signature for snapshot |
getNotarySnapshot
Returns Notary snapshot from the list of all accepted Guard snapshots.
Reverts if snapshot with given index hasn't been accepted yet.
function getNotarySnapshot(uint256 index)
external
view
returns (bytes memory snapPayload, bytes memory snapSignature);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Snapshot index in the list of all Notary snapshots |
Returns
Name | Type | Description |
---|---|---|
snapPayload | bytes | Raw payload with Notary snapshot |
snapSignature | bytes | Raw payload with Notary signature for snapshot |
getNotarySnapshot
Returns Notary snapshot that was used for creating a given attestation.
*Reverts if any of these is true:
- Attestation payload is not properly formatted.
- Attestation is invalid (doesn't have a matching Notary snapshot).*
function getNotarySnapshot(bytes memory attPayload)
external
view
returns (bytes memory snapPayload, bytes memory snapSignature);
Parameters
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with attestation data |
Returns
Name | Type | Description |
---|---|---|
snapPayload | bytes | Raw payload with Notary snapshot |
snapSignature | bytes | Raw payload with Notary signature for snapshot |
getSnapshotProof
Returns proof of inclusion of (root, origin) fields of a given snapshot's state into the Snapshot Merkle Tree for a given attestation.
*Reverts if any of these is true:
- Attestation with given nonce hasn't been created yet.
- State index is out of range of snapshot list.*
function getSnapshotProof(uint32 attNonce, uint8 stateIndex) external view returns (bytes32[] memory snapProof);
Parameters
Name | Type | Description |
---|---|---|
attNonce | uint32 | Nonce for the attestation |
stateIndex | uint8 | Index of state in the attestation's snapshot |
Returns
Name | Type | Description |
---|---|---|
snapProof | bytes32[] | The snapshot proof |
IStateHub
Functions
isValidState
Check that a given state is valid: matches the historical state of Origin contract. Note: any Agent including an invalid state in their snapshot will be slashed upon providing the snapshot and agent signature for it to Origin contract.
*Will revert if any of these is true:
- State payload is not properly formatted.*
function isValidState(bytes memory statePayload) external view returns (bool isValid);
Parameters
Name | Type | Description |
---|---|---|
statePayload | bytes | Raw payload with state data |
Returns
Name | Type | Description |
---|---|---|
isValid | bool | Whether the provided state is valid |
statesAmount
Returns the amount of saved states so far.
This includes the initial state of "empty Origin Merkle Tree".
function statesAmount() external view returns (uint256);
suggestLatestState
Suggest the data (state after latest sent message) to sign for an Agent. Note: signing the suggested state data will will never lead to slashing of the actor, assuming they have confirmed that the block, which number is included in the data, is not subject to reorganization (which is different for every observed chain).
function suggestLatestState() external view returns (bytes memory statePayload);
Returns
Name | Type | Description |
---|---|---|
statePayload | bytes | Raw payload with the latest state data |
suggestState
Given the historical nonce, suggest the state data to sign for an Agent. Note: signing the suggested state data will will never lead to slashing of the actor, assuming they have confirmed that the block, which number is included in the data, is not subject to reorganization (which is different for every observed chain).
function suggestState(uint32 nonce) external view returns (bytes memory statePayload);
Parameters
Name | Type | Description |
---|---|---|
nonce | uint32 | Historical nonce to form a state |
Returns
Name | Type | Description |
---|---|---|
statePayload | bytes | Raw payload with historical state data |
IStatementInbox
Functions
submitStateReportWithSnapshot
Accepts a Guard's state report signature, a Snapshot containing the reported State, as well as Notary signature for the Snapshot.
StateReport is a Guard statement saying "Reported state is invalid".
- This results in an opened Dispute between the Guard and the Notary.
- Note: Guard could (but doesn't have to) form a StateReport and use other values from
verifyStateWithSnapshot()
successful call that led to Notary being slashed in remote Origin.
Will revert if any of these is true:
- State Report signer is not an active Guard.
- Snapshot payload is not properly formatted.
- Snapshot signer is not an active Notary.
- State index is out of range.
- The Guard or the Notary are already in a Dispute
function submitStateReportWithSnapshot(
uint8 stateIndex,
bytes memory srSignature,
bytes memory snapPayload,
bytes memory snapSignature
) external returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
stateIndex | uint8 | Index of the reported State in the Snapshot |
srSignature | bytes | Guard signature for the report |
snapPayload | bytes | Raw payload with Snapshot data |
snapSignature | bytes | Notary signature for the Snapshot |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Report was accepted (resulting in Dispute between the agents) |
submitStateReportWithAttestation
Accepts a Guard's state report signature, a Snapshot containing the reported State, as well as Notary signature for the Attestation created from this Snapshot.
StateReport is a Guard statement saying "Reported state is invalid".
- This results in an opened Dispute between the Guard and the Notary.
- Note: Guard could (but doesn't have to) form a StateReport and use other values from
verifyStateWithAttestation()
successful call that led to Notary being slashed in remote Origin.
Will revert if any of these is true:
- State Report signer is not an active Guard.
- Snapshot payload is not properly formatted.
- State index is out of range.
- Attestation payload is not properly formatted.
- Attestation signer is not an active Notary.
- Attestation's snapshot root is not equal to Merkle Root derived from the Snapshot.
- The Guard or the Notary are already in a Dispute
function submitStateReportWithAttestation(
uint8 stateIndex,
bytes memory srSignature,
bytes memory snapPayload,
bytes memory attPayload,
bytes memory attSignature
) external returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
stateIndex | uint8 | Index of the reported State in the Snapshot |
srSignature | bytes | Guard signature for the report |
snapPayload | bytes | Raw payload with Snapshot data |
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the Attestation |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Report was accepted (resulting in Dispute between the agents) |
submitStateReportWithSnapshotProof
Accepts a Guard's state report signature, a proof of inclusion of the reported State in an Attestation, as well as Notary signature for the Attestation.
StateReport is a Guard statement saying "Reported state is invalid".
- This results in an opened Dispute between the Guard and the Notary.
- Note: Guard could (but doesn't have to) form a StateReport and use other values from
verifyStateWithSnapshotProof()
successful call that led to Notary being slashed in remote Origin.
Will revert if any of these is true:
- State payload is not properly formatted.
- State Report signer is not an active Guard.
- Attestation payload is not properly formatted.
- Attestation signer is not an active Notary.
- Attestation's snapshot root is not equal to Merkle Root derived from State and Snapshot Proof.
- Snapshot Proof's first element does not match the State metadata.
- Snapshot Proof length exceeds Snapshot Tree Height.
- State index is out of range.
- The Guard or the Notary are already in a Dispute
function submitStateReportWithSnapshotProof(
uint8 stateIndex,
bytes memory statePayload,
bytes memory srSignature,
bytes32[] memory snapProof,
bytes memory attPayload,
bytes memory attSignature
) external returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
stateIndex | uint8 | Index of the reported State in the Snapshot |
statePayload | bytes | Raw payload with State data that Guard reports as invalid |
srSignature | bytes | Guard signature for the report |
snapProof | bytes32[] | Proof of inclusion of reported State's Left Leaf into Snapshot Merkle Tree |
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the Attestation |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Report was accepted (resulting in Dispute between the agents) |
verifyReceipt
Verifies a message receipt signed by the Notary.
- Does nothing, if the receipt is valid (matches the saved receipt data for the referenced message).
- Slashes the Notary, if the receipt is invalid.
Will revert if any of these is true:
- Receipt payload is not properly formatted.
- Receipt signer is not an active Notary.
- Receipt's destination chain does not refer to this chain.
function verifyReceipt(bytes memory rcptPayload, bytes memory rcptSignature) external returns (bool isValidReceipt);
Parameters
Name | Type | Description |
---|---|---|
rcptPayload | bytes | Raw payload with Receipt data |
rcptSignature | bytes | Notary signature for the receipt |
Returns
Name | Type | Description |
---|---|---|
isValidReceipt | bool | Whether the provided receipt is valid. Notary is slashed, if return value is FALSE. |
verifyReceiptReport
Verifies a Guard's receipt report signature.
- Does nothing, if the report is valid (if the reported receipt is invalid).
- Slashes the Guard, if the report is invalid (if the reported receipt is valid).
Will revert if any of these is true:
- Receipt payload is not properly formatted.
- Receipt Report signer is not an active Guard.
- Receipt does not refer to this chain.
function verifyReceiptReport(bytes memory rcptPayload, bytes memory rrSignature)
external
returns (bool isValidReport);
Parameters
Name | Type | Description |
---|---|---|
rcptPayload | bytes | Raw payload with Receipt data that Guard reports as invalid |
rrSignature | bytes | Guard signature for the report |
Returns
Name | Type | Description |
---|---|---|
isValidReport | bool | Whether the provided report is valid. Guard is slashed, if return value is FALSE. |
verifyStateWithAttestation
Verifies a state from the snapshot, that was used for the Notary-signed attestation.
- Does nothing, if the state is valid (matches the historical state of this contract).
- Slashes the Notary, if the state is invalid.
Will revert if any of these is true:
- Attestation payload is not properly formatted.
- Attestation signer is not an active Notary.
- Attestation's snapshot root is not equal to Merkle Root derived from the Snapshot.
- Snapshot payload is not properly formatted.
- State index is out of range.
- State does not refer to this chain.
function verifyStateWithAttestation(
uint8 stateIndex,
bytes memory snapPayload,
bytes memory attPayload,
bytes memory attSignature
) external returns (bool isValidState);
Parameters
Name | Type | Description |
---|---|---|
stateIndex | uint8 | State index to check |
snapPayload | bytes | Raw payload with snapshot data |
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the attestation |
Returns
Name | Type | Description |
---|---|---|
isValidState | bool | Whether the provided state is valid. Notary is slashed, if return value is FALSE. |
verifyStateWithSnapshotProof
Verifies a state from the snapshot, that was used for the Notary-signed attestation.
- Does nothing, if the state is valid (matches the historical state of this contract).
- Slashes the Notary, if the state is invalid.
Will revert if any of these is true:
- Attestation payload is not properly formatted.
- Attestation signer is not an active Notary.
- Attestation's snapshot root is not equal to Merkle Root derived from State and Snapshot Proof.
- Snapshot Proof's first element does not match the State metadata.
- Snapshot Proof length exceeds Snapshot Tree Height.
- State payload is not properly formatted.
- State index is out of range.
- State does not refer to this chain.
function verifyStateWithSnapshotProof(
uint8 stateIndex,
bytes memory statePayload,
bytes32[] memory snapProof,
bytes memory attPayload,
bytes memory attSignature
) external returns (bool isValidState);
Parameters
Name | Type | Description |
---|---|---|
stateIndex | uint8 | Index of state in the snapshot |
statePayload | bytes | Raw payload with State data to check |
snapProof | bytes32[] | Proof of inclusion of provided State's Left Leaf into Snapshot Merkle Tree |
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the attestation |
Returns
Name | Type | Description |
---|---|---|
isValidState | bool | Whether the provided state is valid. Notary is slashed, if return value is FALSE. |
verifyStateWithSnapshot
Verifies a state from the snapshot (a list of states) signed by a Guard or a Notary.
- Does nothing, if the state is valid (matches the historical state of this contract).
- Slashes the Agent, if the state is invalid.
Will revert if any of these is true:
- Snapshot payload is not properly formatted.
- Snapshot signer is not an active Agent.
- State index is out of range.
- State does not refer to this chain.
function verifyStateWithSnapshot(uint8 stateIndex, bytes memory snapPayload, bytes memory snapSignature)
external
returns (bool isValidState);
Parameters
Name | Type | Description |
---|---|---|
stateIndex | uint8 | State index to check |
snapPayload | bytes | Raw payload with snapshot data |
snapSignature | bytes | Agent signature for the snapshot |
Returns
Name | Type | Description |
---|---|---|
isValidState | bool | Whether the provided state is valid. Agent is slashed, if return value is FALSE. |
verifyStateReport
Verifies a Guard's state report signature.
- Does nothing, if the report is valid (if the reported state is invalid).
- Slashes the Guard, if the report is invalid (if the reported state is valid).
Will revert if any of these is true:
- State payload is not properly formatted.
- State Report signer is not an active Guard.
- Reported State does not refer to this chain.
function verifyStateReport(bytes memory statePayload, bytes memory srSignature) external returns (bool isValidReport);
Parameters
Name | Type | Description |
---|---|---|
statePayload | bytes | Raw payload with State data that Guard reports as invalid |
srSignature | bytes | Guard signature for the report |
Returns
Name | Type | Description |
---|---|---|
isValidReport | bool | Whether the provided report is valid. Guard is slashed, if return value is FALSE. |
getReportsAmount
Returns the amount of Guard Reports stored in StatementInbox.
Only reports that led to opening a Dispute are stored.
function getReportsAmount() external view returns (uint256);
getGuardReport
Returns the Guard report with the given index stored in StatementInbox.
Only reports that led to opening a Dispute are stored.
Will revert if report with given index doesn't exist.
function getGuardReport(uint256 index)
external
view
returns (bytes memory statementPayload, bytes memory reportSignature);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Report index |
Returns
Name | Type | Description |
---|---|---|
statementPayload | bytes | Raw payload with statement that Guard reported as invalid |
reportSignature | bytes | Guard signature for the report |
getStoredSignature
Returns the signature with the given index stored in StatementInbox.
Will revert if signature with given index doesn't exist.
function getStoredSignature(uint256 index) external view returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Signature index |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | Raw payload with signature |
InterfaceBondingManager
Functions
addAgent
Adds a new agent for the domain. This is either a fresh address (Inactive), or an agent who used to be active on the same domain before (Resting).
Inactive: proof
should be the proof of inclusion of an empty leaf
having index following the last added agent in the tree.
Resting: proof
should be the proof of inclusion of the agent leaf
with Resting flag having index previously assigned to the agent.
function addAgent(uint32 domain, address agent, bytes32[] memory proof) external;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain where the Agent will be active |
agent | address | Address of the Agent |
proof | bytes32[] | Merkle proof of the Inactive/Resting status for the agent |
initiateUnstaking
Initiates the unstaking of the agent bond. Agent signature is immediately no longer considered valid on Synapse Chain, and will be invalid on other chains once the Light Manager updates their agent merkle root on these chains.
proof
should be the proof of inclusion of the agent leaf
with Active flag having index previously assigned to the agent.
function initiateUnstaking(uint32 domain, address agent, bytes32[] memory proof) external;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain where the Agent is active |
agent | address | Address of the Agent |
proof | bytes32[] | Merkle proof of the Active status for the agent |
completeUnstaking
Completes the unstaking of the agent bond. Agent signature is no longer considered valid on any of the chains.
proof
should be the proof of inclusion of the agent leaf
with Unstaking flag having index previously assigned to the agent.
function completeUnstaking(uint32 domain, address agent, bytes32[] memory proof) external;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain where the Agent was active |
agent | address | Address of the Agent |
proof | bytes32[] | Merkle proof of the unstaking status for the agent |
completeSlashing
Completes the slashing of the agent bond. Agent signature is no longer considered valid under the updated Agent Merkle Root.
proof
should be the proof of inclusion of the agent leaf
with Active/Unstaking flag having index previously assigned to the agent.
function completeSlashing(uint32 domain, address agent, bytes32[] memory proof) external;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain where the Agent was active |
agent | address | Address of the Agent |
proof | bytes32[] | Merkle proof of the active/unstaking status for the agent |
remoteSlashAgent
Remote AgentManager should call this function to indicate that the agent has been proven to commit fraud on the origin chain.
This initiates the process of agent slashing. It could be immediately
completed by anyone calling completeSlashing() providing a correct merkle proof
for the OLD agent status.
Note: as an extra security check this function returns its own selector, so that
Destination could verify that a "remote" function was called when executing a manager message.
Will revert if msgOrigin
is equal to contract's local domain.
function remoteSlashAgent(uint32 msgOrigin, uint256 proofMaturity, uint32 domain, address agent, address prover)
external
returns (bytes4 magicValue);
Parameters
Name | Type | Description |
---|---|---|
msgOrigin | uint32 | |
proofMaturity | uint256 | |
domain | uint32 | Domain where the slashed agent was active |
agent | address | Address of the slashed Agent |
prover | address | Address that initially provided fraud proof to remote AgentManager |
Returns
Name | Type | Description |
---|---|---|
magicValue | bytes4 | Selector of this function |
withdrawTips
Withdraws locked base message tips from requested domain Origin to the recipient. Issues a call to a local Origin contract, or sends a manager message to the remote chain.
Could only be called by the Summit contract.
function withdrawTips(address recipient, uint32 origin, uint256 amount) external;
Parameters
Name | Type | Description |
---|---|---|
recipient | address | Address to withdraw tips to |
origin | uint32 | Domain where tips need to be withdrawn |
amount | uint256 | Tips value to withdraw |
resolveDisputeWhenStuck
Allows contract owner to resolve a stuck Dispute. This could only be called if no fresh data has been submitted by the Notaries to the Inbox, which is required for the Dispute to be resolved naturally.
Will revert if any of these is true:
- Caller is not contract owner.
- Domain doesn't match the saved agent domain.
slashedAgent
is not in Dispute.- Less than
FRESH_DATA_TIMEOUT
has passed since the last Notary submission to the Inbox.
function resolveDisputeWhenStuck(uint32 domain, address slashedAgent) external;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | |
slashedAgent | address | Agent that is being slashed |
getActiveAgents
Returns all active agents for a given domain.
function getActiveAgents(uint32 domain) external view returns (address[] memory agents);
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain to get agents from (ZERO for Guards) |
agentLeaf
Returns a leaf representing the current status of agent in the Agent Merkle Tree.
Will return an empty leaf, if agent is not added to the tree yet.
function agentLeaf(address agent) external view returns (bytes32 leaf);
Parameters
Name | Type | Description |
---|---|---|
agent | address | Agent address |
Returns
Name | Type | Description |
---|---|---|
leaf | bytes32 | Agent leaf in the Agent Merkle Tree |
leafsAmount
Returns a total amount of leafs representing known agents.
This includes active, unstaking, resting and slashed agents. This also includes an empty leaf as the very first entry.
function leafsAmount() external view returns (uint256 amount);
allLeafs
Returns a full list of leafs from the Agent Merkle Tree.
This might consume a lot of gas, do not use this on-chain.
function allLeafs() external view returns (bytes32[] memory leafs);
getLeafs
Returns a list of leafs from the Agent Merkle Tree with indexes [indexFrom .. indexFrom + amount).
This might consume a lot of gas, do not use this on-chain.
Will return less than amount
entries, if indexFrom + amount > leafsAmount
function getLeafs(uint256 indexFrom, uint256 amount) external view returns (bytes32[] memory leafs);
getProof
Returns a proof of inclusion of the agent in the Agent Merkle Tree.
Will return a proof for an empty leaf, if agent is not added to the tree yet. This proof could be used by ANY next new agent that calls {addAgent}.
This WILL consume a lot of gas, do not use this on-chain.
The alternative way to create a proof is to fetch the full list of leafs using either {allLeafs} or {getLeafs}, and create a merkle proof from that.
function getProof(address agent) external view returns (bytes32[] memory proof);
Parameters
Name | Type | Description |
---|---|---|
agent | address | Agent address |
Returns
Name | Type | Description |
---|---|---|
proof | bytes32[] | Merkle proof for the agent |
InterfaceDestination
Functions
passAgentRoot
Attempts to pass a quarantined Agent Merkle Root to a local Light Manager.
Will do nothing, if root optimistic period is not over.
function passAgentRoot() external returns (bool rootPending);
Returns
Name | Type | Description |
---|---|---|
rootPending | bool | Whether there is a pending agent merkle root left |
acceptAttestation
Accepts an attestation, which local AgentManager
verified to have been signed
by an active Notary for this chain.
Attestation is created whenever a Notary-signed snapshot is saved in Summit on Synapse Chain.
- Saved Attestation could be later used to prove the inclusion of message in the Origin Merkle Tree.
- Messages coming from chains included in the Attestation's snapshot could be proven.
- Proof only exists for messages that were sent prior to when the Attestation's snapshot was taken.
Will revert if any of these is true:
- Called by anyone other than local
AgentManager
.- Attestation payload is not properly formatted.
- Attestation signer is in Dispute.
- Attestation's snapshot root has been previously submitted. Note: agentRoot and snapGas have been verified by the local
AgentManager
.
function acceptAttestation(
uint32 notaryIndex,
uint256 sigIndex,
bytes memory attPayload,
bytes32 agentRoot,
ChainGas[] memory snapGas
) external returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
notaryIndex | uint32 | Index of Attestation Notary in Agent Merkle Tree |
sigIndex | uint256 | Index of stored Notary signature |
attPayload | bytes | Raw payload with Attestation data |
agentRoot | bytes32 | Agent Merkle Root from the Attestation |
snapGas | ChainGas[] | Gas data for each chain in the Attestation's snapshot |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Attestation was accepted |
attestationsAmount
Returns the total amount of Notaries attestations that have been accepted.
function attestationsAmount() external view returns (uint256);
getAttestation
Returns a Notary-signed attestation with a given index.
Index refers to the list of all attestations accepted by this contract.
Attestations are created on Synapse Chain whenever a Notary-signed snapshot is accepted by Summit. Will return an empty signature if this contract is deployed on Synapse Chain.
function getAttestation(uint256 index) external view returns (bytes memory attPayload, bytes memory attSignature);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Attestation index |
Returns
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the reported attestation |
getGasData
Returns the gas data for a given chain from the latest accepted attestation with that chain.
Will return empty values if there is no data for the domain, or if the notary who provided the data is in dispute.
function getGasData(uint32 domain) external view returns (GasData gasData, uint256 dataMaturity);
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain for the chain |
Returns
Name | Type | Description |
---|---|---|
gasData | GasData | Gas data for the chain |
dataMaturity | uint256 | Gas data age in seconds |
destStatus
Returns status of Destination contract as far as snapshot/agent roots are concerned
function destStatus() external view returns (uint40 snapRootTime, uint40 agentRootTime, uint32 notaryIndex);
Returns
Name | Type | Description |
---|---|---|
snapRootTime | uint40 | Timestamp when latest snapshot root was accepted |
agentRootTime | uint40 | Timestamp when latest agent root was accepted |
notaryIndex | uint32 | Index of Notary who signed the latest agent root |
nextAgentRoot
Returns Agent Merkle Root to be passed to LightManager once its optimistic period is over.
function nextAgentRoot() external view returns (bytes32);
lastAttestationNonce
Returns the nonce of the last attestation submitted by a Notary with a given agent index.
Will return zero if the Notary hasn't submitted any attestations yet.
function lastAttestationNonce(uint32 notaryIndex) external view returns (uint32);
InterfaceGasOracle
Functions
updateGasData
Fetches the latest gas data for the chain from Destination
contract,
and uses it to update the oracle values for the requested chain.
function updateGasData(uint32 domain) external;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain to update the gas data for |
getGasData
Returns the gas data for the local chain.
function getGasData() external view returns (uint256 paddedGasData);
getDecodedGasData
Returns the gas data for the given domain, in the decoded format.
function getDecodedGasData(uint32 domain)
external
view
returns (
uint256 gasPrice,
uint256 dataPrice,
uint256 execBuffer,
uint256 amortAttCost,
uint256 etherPrice,
uint256 markup
);
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain of chain to get gas data for |
Returns
Name | Type | Description |
---|---|---|
gasPrice | uint256 | Gas price for the chain (in Wei per gas unit) |
dataPrice | uint256 | Calldata price (in Wei per byte of content) |
execBuffer | uint256 | Tx fee safety buffer for message execution (in Wei) |
amortAttCost | uint256 | Amortized cost for attestation submission (in Wei) |
etherPrice | uint256 | Ratio of Chain's Ether Price / Mainnet Ether Price (in BWAD) |
markup | uint256 | Markup for the message execution (in BWAD) |
getMinimumTips
Returns the minimum tips for sending a message to a given destination.
function getMinimumTips(uint32 destination, uint256 paddedRequest, uint256 contentLength)
external
view
returns (uint256 paddedTips);
Parameters
Name | Type | Description |
---|---|---|
destination | uint32 | Domain of destination chain |
paddedRequest | uint256 | Padded encoded message execution request on destination chain |
contentLength | uint256 | The length of the message content |
Returns
Name | Type | Description |
---|---|---|
paddedTips | uint256 | Padded encoded minimum tips information |
InterfaceInbox
Functions
submitSnapshot
Accepts a snapshot signed by a Guard or a Notary and passes it to Summit contract to save.
Snapshot is a list of states for a set of Origin contracts residing on any of the chains.
- Guard-signed snapshots: all the states in the snapshot become available for Notary signing.
- Notary-signed snapshots: Snapshot Merkle Root is saved for valid snapshots, i.e. snapshots which are only using states previously submitted by any of the Guards.
- Notary doesn't have to use states submitted by a single Guard in their snapshot.
- Notary could then proceed to sign the attestation for their submitted snapshot.
Will revert if any of these is true:
- Snapshot payload is not properly formatted.
- Snapshot signer is not an active Agent.
- Agent snapshot contains a state with a nonce smaller or equal then they have previously submitted.
- Notary snapshot contains a state that hasn't been previously submitted by any of the Guards.
- Note: Agent will NOT be slashed for submitting such a snapshot.
Notary will need to provide both agentRoot
and snapGas
when submitting an attestation on
the remote chain (the attestation contains only their merged hash). These are returned by this function,
and could be also obtained by calling getAttestation(nonce)
or getLatestNotaryAttestation(notary)
.
function submitSnapshot(bytes memory snapPayload, bytes memory snapSignature)
external
returns (bytes memory attPayload, bytes32 agentRoot, uint256[] memory snapGas);
Parameters
Name | Type | Description |
---|---|---|
snapPayload | bytes | Raw payload with snapshot data |
snapSignature | bytes | Agent signature for the snapshot |
Returns
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with data for attestation derived from Notary snapshot. Empty payload, if a Guard snapshot was submitted. |
agentRoot | bytes32 | Current root of the Agent Merkle Tree (zero, if a Guard snapshot was submitted) |
snapGas | uint256[] | Gas data for each chain in the snapshot Empty list, if a Guard snapshot was submitted. |
submitReceipt
Accepts a receipt signed by a Notary and passes it to Summit contract to save.
Receipt is a statement about message execution status on the remote chain.
- This will distribute the message tips across the off-chain actors once the receipt optimistic period is over.
Will revert if any of these is true:
- Receipt payload is not properly formatted.
- Receipt signer is not an active Notary.
- Receipt signer is in Dispute.
- Receipt's snapshot root is unknown.
- Provided tips could not be proven against the message hash.
function submitReceipt(
bytes memory rcptPayload,
bytes memory rcptSignature,
uint256 paddedTips,
bytes32 headerHash,
bytes32 bodyHash
) external returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
rcptPayload | bytes | Raw payload with receipt data |
rcptSignature | bytes | Notary signature for the receipt |
paddedTips | uint256 | Tips for the message execution |
headerHash | bytes32 | Hash of the message header |
bodyHash | bytes32 | Hash of the message body excluding the tips |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the receipt was accepted |
submitReceiptReport
Accepts a Guard's receipt report signature, as well as Notary signature for the reported Receipt.
ReceiptReport is a Guard statement saying "Reported receipt is invalid".
- This results in an opened Dispute between the Guard and the Notary.
- Note: Guard could (but doesn't have to) form a ReceiptReport and use receipt signature from
verifyReceipt()
successful call that led to Notary being slashed in Summit on Synapse Chain.
Will revert if any of these is true:
- Receipt payload is not properly formatted.
- Receipt Report signer is not an active Guard.
- Receipt signer is not an active Notary.
function submitReceiptReport(bytes memory rcptPayload, bytes memory rcptSignature, bytes memory rrSignature)
external
returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
rcptPayload | bytes | Raw payload with Receipt data that Guard reports as invalid |
rcptSignature | bytes | Notary signature for the reported receipt |
rrSignature | bytes | Guard signature for the report |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Report was accepted (resulting in Dispute between the agents) |
passReceipt
Passes the message execution receipt from Destination to the Summit contract to save.
Will revert if any of these is true:
- Called by anyone other than Destination.
If a receipt is not accepted, any of the Notaries can submit it later using submitReceipt
.
function passReceipt(uint32 attNotaryIndex, uint32 attNonce, uint256 paddedTips, bytes memory rcptPayload)
external
returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
attNotaryIndex | uint32 | Index of the Notary who signed the attestation |
attNonce | uint32 | Nonce of the attestation used for proving the executed message |
paddedTips | uint256 | Tips for the message execution |
rcptPayload | bytes | Raw payload with message execution receipt |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the receipt was accepted |
verifyAttestation
Verifies an attestation signed by a Notary.
- Does nothing, if the attestation is valid (was submitted by this Notary as a snapshot).
- Slashes the Notary, if the attestation is invalid.
Will revert if any of these is true:
- Attestation payload is not properly formatted.
- Attestation signer is not an active Notary.
function verifyAttestation(bytes memory attPayload, bytes memory attSignature)
external
returns (bool isValidAttestation);
Parameters
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the attestation |
Returns
Name | Type | Description |
---|---|---|
isValidAttestation | bool | Whether the provided attestation is valid. Notary is slashed, if return value is FALSE. |
verifyAttestationReport
Verifies a Guard's attestation report signature.
- Does nothing, if the report is valid (if the reported attestation is invalid).
- Slashes the Guard, if the report is invalid (if the reported attestation is valid).
Will revert if any of these is true:
- Attestation payload is not properly formatted.
- Attestation Report signer is not an active Guard.
function verifyAttestationReport(bytes memory attPayload, bytes memory arSignature)
external
returns (bool isValidReport);
Parameters
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with Attestation data that Guard reports as invalid |
arSignature | bytes | Guard signature for the report |
Returns
Name | Type | Description |
---|---|---|
isValidReport | bool | Whether the provided report is valid. Guard is slashed, if return value is FALSE. |
InterfaceLightInbox
Functions
submitAttestation
Accepts an attestation signed by a Notary and passes it to Destination contract to save.
Attestation is created whenever a Notary-signed snapshot is saved in Summit on Synapse Chain.
- Saved Attestation could be later used to prove the inclusion of message in the Origin Merkle Tree.
- Messages coming from chains included in the Attestation's snapshot could be proven.
- Proof only exists for messages that were sent prior to when the Attestation's snapshot was taken.
Will revert if any of these is true:
- Attestation payload is not properly formatted.
- Attestation signer is not an active Notary for local domain.
- Attestation signer is in Dispute.
- Attestation's snapshot root has been previously submitted.
- Attestation's data hash doesn't match the hash of provided agentRoot and snapshot gas data.
function submitAttestation(
bytes memory attPayload,
bytes memory attSignature,
bytes32 agentRoot,
uint256[] memory snapGas
) external returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the attestation |
agentRoot | bytes32 | Agent Merkle Root from the Attestation |
snapGas | uint256[] | Gas data for each chain in the snapshot |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Attestation was accepted |
submitAttestationReport
Accepts a Guard's attestation report signature, as well as Notary signature for the reported Attestation.
AttestationReport is a Guard statement saying "Reported attestation is invalid".
- This results in an opened Dispute between the Guard and the Notary.
- Note: Guard could (but doesn't have to) form a AttestationReport and use attestation signature from
verifyAttestation()
successful call that led to Notary being slashed in Summit on Synapse Chain.
Will revert if any of these is true:
- Attestation payload is not properly formatted.
- Attestation Report signer is not an active Guard.
- Attestation signer is not an active Notary for local domain.
function submitAttestationReport(bytes memory attPayload, bytes memory arSignature, bytes memory attSignature)
external
returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with Attestation data that Guard reports as invalid |
arSignature | bytes | Guard signature for the report |
attSignature | bytes | Notary signature for the reported attestation |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Report was accepted (resulting in Dispute between the agents) |
InterfaceLightManager
Functions
updateAgentStatus
Updates agent status, using a proof against the latest known Agent Merkle Root.
Will revert if the provided proof doesn't match the latest merkle root.
function updateAgentStatus(address agent, AgentStatus memory status, bytes32[] memory proof) external;
Parameters
Name | Type | Description |
---|---|---|
agent | address | Agent address |
status | AgentStatus | Structure specifying agent status: (flag, domain, index) |
proof | bytes32[] | Merkle proof of Active status for the agent |
setAgentRoot
Updates the root of Agent Merkle Tree that the Light Manager is tracking. Could be only called by a local Destination contract, which is supposed to verify the attested Agent Merkle Roots.
function setAgentRoot(bytes32 agentRoot_) external;
Parameters
Name | Type | Description |
---|---|---|
agentRoot_ | bytes32 | New Agent Merkle Root |
proposeAgentRootWhenStuck
Allows contract owner to set the agent root to resolve the "stuck" chain by proposing the new agent root. The contract owner will be able to resolve the proposed agent root after a certain period of time. Note: this function could be called multiple times, each time the timer will be reset. This could only be called if no fresh data has been submitted by the Notaries to the Inbox, indicating that the chain is stuck for one of the reasons:
- All active Notaries are in Dispute.
- No active Notaries exist under the current agent root.
*Will revert if any of the following conditions is met:
- Caller is not the contract owner.
- Agent root is empty.
- The chain is not in a stuck state (has recently received a fresh data from the Notaries).*
function proposeAgentRootWhenStuck(bytes32 agentRoot_) external;
Parameters
Name | Type | Description |
---|---|---|
agentRoot_ | bytes32 | New Agent Merkle Root that is proposed to be set |
cancelProposedAgentRoot
Allows contract owner to cancel the previously proposed agent root.
*Will revert if any of the following conditions is met:
- Caller is not the contract owner.
- No agent root was proposed.*
function cancelProposedAgentRoot() external;
resolveProposedAgentRoot
Allows contract owner to resolve the previously proposed agent root. This will update the agent root, allowing the agents to update their status, effectively resolving the "stuck" chain.
*Will revert if any of the following conditions is met:
- Caller is not the contract owner.
- No agent root was proposed.
- Not enough time has passed since the agent root was proposed.*
function resolveProposedAgentRoot() external;
remoteWithdrawTips
Withdraws locked base message tips from local Origin to the recipient.
Could only be remote-called by BondingManager contract on Synapse Chain. Note: as an extra security check this function returns its own selector, so that Destination could verify that a "remote" function was called when executing a manager message.
function remoteWithdrawTips(uint32 msgOrigin, uint256 proofMaturity, address recipient, uint256 amount)
external
returns (bytes4 magicValue);
Parameters
Name | Type | Description |
---|---|---|
msgOrigin | uint32 | |
proofMaturity | uint256 | |
recipient | address | Address to withdraw tips to |
amount | uint256 | Tips value to withdraw |
proposedAgentRootData
Returns the latest proposed agent root and the timestamp when it was proposed.
Will return zero values if no agent root was proposed, or if the proposed agent root was already resolved.
function proposedAgentRootData() external view returns (bytes32 agentRoot_, uint256 proposedAt_);
InterfaceOrigin
Functions
sendBaseMessage
Send a message to the recipient located on destination domain.
*Recipient has to conform to IMessageRecipient interface, otherwise message won't be delivered. Will revert if any of these is true:
destination
is equal to contract's local domaincontent
length is greater thanMAX_CONTENT_BYTES
msg.value
is lower than value of minimum tips for the given message*
function sendBaseMessage(
uint32 destination,
bytes32 recipient,
uint32 optimisticPeriod,
uint256 paddedRequest,
bytes memory content
) external payable returns (uint32 messageNonce, bytes32 messageHash);
Parameters
Name | Type | Description |
---|---|---|
destination | uint32 | Domain of destination chain |
recipient | bytes32 | Address of recipient on destination chain as bytes32 |
optimisticPeriod | uint32 | Optimistic period for message execution on destination chain |
paddedRequest | uint256 | Padded encoded message execution request on destination chain |
content | bytes | Raw bytes content of message |
Returns
Name | Type | Description |
---|---|---|
messageNonce | uint32 | Nonce of the sent message |
messageHash | bytes32 | Hash of the sent message |
sendManagerMessage
Send a manager message to the destination domain.
This could only be called by AgentManager, which takes care of encoding the calldata payload.
Note: (msgOrigin, proofMaturity) security args will be added to payload on the destination chain
so that the AgentManager could verify where the Manager Message came from and how mature is the proof.
Note: function is not payable, as no tips are required for sending a manager message.
Will revert if destination
is equal to contract's local domain.
function sendManagerMessage(uint32 destination, uint32 optimisticPeriod, bytes memory payload)
external
returns (uint32 messageNonce, bytes32 messageHash);
Parameters
Name | Type | Description |
---|---|---|
destination | uint32 | Domain of destination chain |
optimisticPeriod | uint32 | Optimistic period for message execution on destination chain |
payload | bytes | Payload for calling AgentManager on destination chain (with extra security args) |
withdrawTips
Withdraws locked base message tips to the recipient.
Could only be called by a local AgentManager.
function withdrawTips(address recipient, uint256 amount) external;
Parameters
Name | Type | Description |
---|---|---|
recipient | address | Address to withdraw tips to |
amount | uint256 | Tips value to withdraw |
getMinimumTipsValue
Returns the minimum tips value for sending a message to a given destination.
Using at least tipsValue
as msg.value
for sendBaseMessage()
will guarantee that the message will be accepted.
function getMinimumTipsValue(uint32 destination, uint256 paddedRequest, uint256 contentLength)
external
view
returns (uint256 tipsValue);
Parameters
Name | Type | Description |
---|---|---|
destination | uint32 | Domain of destination chain |
paddedRequest | uint256 | Padded encoded message execution request on destination chain |
contentLength | uint256 | The length of the message content |
Returns
Name | Type | Description |
---|---|---|
tipsValue | uint256 | Minimum tips value for a message to be accepted |
InterfaceSummit
Functions
acceptReceipt
Accepts a receipt, which local AgentManager
verified to have been signed by an active Notary.
Receipt is a statement about message execution status on the remote chain.
- This will distribute the message tips across the off-chain actors once the receipt optimistic period is over.
- Notary who signed the receipt is referenced as the "Receipt Notary".
- Notary who signed the attestation on destination chain is referenced as the "Attestation Notary".
Will revert if any of these is true:
- Called by anyone other than local
AgentManager
.- Receipt body payload is not properly formatted.
- Receipt signer is in Dispute.
- Receipt's snapshot root is unknown.
function acceptReceipt(
uint32 rcptNotaryIndex,
uint32 attNotaryIndex,
uint256 sigIndex,
uint32 attNonce,
uint256 paddedTips,
bytes memory rcptPayload
) external returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
rcptNotaryIndex | uint32 | Index of Receipt Notary in Agent Merkle Tree |
attNotaryIndex | uint32 | Index of Attestation Notary in Agent Merkle Tree |
sigIndex | uint256 | Index of stored Notary signature |
attNonce | uint32 | Nonce of the attestation used for proving the executed message |
paddedTips | uint256 | Padded encoded paid tips information |
rcptPayload | bytes | Raw payload with message execution receipt |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the receipt was accepted |
acceptGuardSnapshot
Accepts a snapshot, which local AgentManager
verified to have been signed by an active Guard.
Snapshot is a list of states for a set of Origin contracts residing on any of the chains. All the states in the Guard-signed snapshot become available for Notary signing. Will revert if any of these is true:
- Called by anyone other than local
AgentManager
.- Snapshot payload is not properly formatted.
- Snapshot contains a state older then the Guard has previously submitted.
function acceptGuardSnapshot(uint32 guardIndex, uint256 sigIndex, bytes memory snapPayload) external;
Parameters
Name | Type | Description |
---|---|---|
guardIndex | uint32 | Index of Guard in Agent Merkle Tree |
sigIndex | uint256 | Index of stored Agent signature |
snapPayload | bytes | Raw payload with snapshot data |
acceptNotarySnapshot
Accepts a snapshot, which local AgentManager
verified to have been signed by an active Notary.
Snapshot is a list of states for a set of Origin contracts residing on any of the chains. Snapshot Merkle Root is calculated and saved for valid snapshots, i.e. snapshots which are only using states previously submitted by any of the Guards.
- Notary could use states singed by the same of different Guards in their snapshot.
- Notary could then proceed to sign the attestation for their submitted snapshot.
Will revert if any of these is true:
- Called by anyone other than local
AgentManager
.- Snapshot payload is not properly formatted.
- Snapshot contains a state older then the Notary has previously submitted.
- Snapshot contains a state that no Guard has previously submitted.
function acceptNotarySnapshot(uint32 notaryIndex, uint256 sigIndex, bytes32 agentRoot, bytes memory snapPayload)
external
returns (bytes memory attPayload);
Parameters
Name | Type | Description |
---|---|---|
notaryIndex | uint32 | Index of Notary in Agent Merkle Tree |
sigIndex | uint256 | Index of stored Agent signature |
agentRoot | bytes32 | Current root of the Agent Merkle Tree |
snapPayload | bytes | Raw payload with snapshot data |
Returns
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with data for attestation derived from Notary snapshot. |
distributeTips
Distributes tips using the first Receipt from the "receipt quarantine queue". Possible scenarios:
- Receipt queue is empty => does nothing
- Receipt optimistic period is not over => does nothing
- Either of Notaries present in Receipt was slashed => receipt is deleted from the queue
- Either of Notaries present in Receipt in Dispute => receipt is moved to the end of queue
- None of the above => receipt tips are distributed
Returned value makes it possible to do the following: while (distributeTips()) {}
function distributeTips() external returns (bool queuePopped);
Returns
Name | Type | Description |
---|---|---|
queuePopped | bool | Whether the first element was popped from the queue |
withdrawTips
Withdraws locked base message tips from requested domain Origin to the recipient. This is done by a call to a local Origin contract, or by a manager message to the remote chain.
This will revert, if the pending balance of origin tips (earned-claimed) is lower than requested.
function withdrawTips(uint32 origin, uint256 amount) external;
Parameters
Name | Type | Description |
---|---|---|
origin | uint32 | Domain of chain to withdraw tips on |
amount | uint256 | Amount of tips to withdraw |
actorTips
Returns earned and claimed tips for the actor. Note: Tips for address(0) belong to the Treasury.
function actorTips(address actor, uint32 origin) external view returns (uint128 earned, uint128 claimed);
Parameters
Name | Type | Description |
---|---|---|
actor | address | Address of the actor |
origin | uint32 | Domain where the tips were initially paid |
Returns
Name | Type | Description |
---|---|---|
earned | uint128 | Total amount of origin tips the actor has earned so far |
claimed | uint128 | Total amount of origin tips the actor has claimed so far |
receiptQueueLength
Returns the amount of receipts in the "Receipt Quarantine Queue".
function receiptQueueLength() external view returns (uint256);
getLatestState
Returns the state with the highest known nonce submitted by any of the currently active Guards.
function getLatestState(uint32 origin) external view returns (bytes memory statePayload);
Parameters
Name | Type | Description |
---|---|---|
origin | uint32 | Domain of origin chain |
Returns
Name | Type | Description |
---|---|---|
statePayload | bytes | Raw payload with latest active Guard state for origin |
Contents
- memory
- merkle
- stack
- ChainContext
- Constants
- CallerNotAgentManager
- CallerNotDestination
- CallerNotInbox
- CallerNotSummit
- IncorrectAttestation
- IncorrectAgentDomain
- IncorrectAgentIndex
- IncorrectAgentProof
- IncorrectAgentRoot
- IncorrectDataHash
- IncorrectDestinationDomain
- IncorrectOriginDomain
- IncorrectSnapshotProof
- IncorrectSnapshotRoot
- IncorrectState
- IncorrectStatesAmount
- IncorrectTipsProof
- IncorrectVersionLength
- IncorrectNonce
- IncorrectSender
- IncorrectRecipient
- FlagOutOfRange
- IndexOutOfRange
- NonceOutOfRange
- OutdatedNonce
- UnformattedAttestation
- UnformattedAttestationReport
- UnformattedBaseMessage
- UnformattedCallData
- UnformattedCallDataPrefix
- UnformattedMessage
- UnformattedReceipt
- UnformattedReceiptReport
- UnformattedSignature
- UnformattedSnapshot
- UnformattedState
- UnformattedStateReport
- LeafNotProven
- MerkleTreeFull
- NotEnoughLeafs
- TreeHeightTooLow
- BaseClientOptimisticPeriod
- MessageOptimisticPeriod
- SlashAgentOptimisticPeriod
- WithdrawTipsOptimisticPeriod
- ZeroProofMaturity
- AgentNotGuard
- AgentNotNotary
- AgentCantBeAdded
- AgentNotActive
- AgentNotActiveNorUnstaking
- AgentNotFraudulent
- AgentNotUnstaking
- AgentUnknown
- AgentRootNotProposed
- AgentRootTimeoutNotOver
- NotStuck
- DisputeAlreadyResolved
- DisputeNotOpened
- DisputeTimeoutNotOver
- GuardInDispute
- NotaryInDispute
- MustBeSynapseDomain
- SynapseDomainForbidden
- AlreadyExecuted
- AlreadyFailed
- DuplicatedSnapshotRoot
- IncorrectMagicValue
- GasLimitTooLow
- GasSuppliedTooLow
- ContentLengthTooBig
- EthTransferFailed
- InsufficientEthBalance
- LocalGasDataNotSet
- RemoteGasDataNotSet
- SummitTipTooHigh
- TipsClaimMoreThanEarned
- TipsClaimZero
- TipsOverflow
- TipsValueTooLow
- IndexedTooMuch
- ViewOverrun
- OccupiedMemory
- UnallocatedMemory
- PrecompileOutOfGas
- MulticallFailed
- SafeCall
- AgentFlag
- AgentStatus
- DisputeFlag
- DisputeStatus
- DestinationStatus
- MessageStatus
- StructureUtils
- TypeCasts
Contents
- Attestation
- AttestationLib
- BaseMessage
- BaseMessageLib
- CallData
- Signature
- ByteString
- MemView
- MemViewLib
- Message
- MessageLib
- Receipt
- ReceiptLib
- Snapshot
- SnapshotLib
- State
- StateLib
Attestation
Attestation is a memory view over a formatted attestation payload.
type Attestation is uint256;
AttestationLib
Attestation
Attestation structure represents the "Snapshot Merkle Tree" created from every Notary snapshot accepted by the Summit contract. Attestation includes" the root of the "Snapshot Merkle Tree", as well as additional metadata.
Steps for creation of "Snapshot Merkle Tree":
- The list of hashes is composed for states in the Notary snapshot.
- The list is padded with zero values until its length is 2**SNAPSHOT_TREE_HEIGHT.
- Values from the list are used as leafs and the merkle tree is constructed.
Differences between a State and Attestation
Similar to Origin, every derived Notary's "Snapshot Merkle Root" is saved in Summit contract. The main difference is that Origin contract itself is keeping track of an incremental merkle tree, by inserting the hash of the sent message and calculating the new "Origin Merkle Root". While Summit relies on Guards and Notaries to provide snapshot data, which is used to calculate the "Snapshot Merkle Root".
- Origin's State is "state of Origin Merkle Tree after N-th message was sent".
- Summit's Attestation is "data for the N-th accepted Notary Snapshot" + "agent merkle root at the time snapshot was submitted" + "attestation metadata".
Attestation validity
- Attestation is considered "valid" in Summit contract, if it matches the N-th (nonce) snapshot submitted by Notaries, as well as the historical agent merkle root.
- Attestation is considered "valid" in Origin contract, if its underlying Snapshot is "valid".
- This means that a snapshot could be "valid" in Summit contract and "invalid" in Origin, if the underlying snapshot is invalid (i.e. one of the states in the list is invalid).
- The opposite could also be true. If a perfectly valid snapshot was never submitted to Summit, its attestation would be valid in Origin, but invalid in Summit (it was never accepted, so the metadata would be incorrect).
- Attestation is considered "globally valid", if it is valid in the Summit and all the Origin contracts.
Memory layout of Attestation fields
Position | Field | Type | Bytes | Description |
---|---|---|---|---|
[000..032) | snapRoot | bytes32 | 32 | Root for "Snapshot Merkle Tree" created from a Notary snapshot |
[032..064) | dataHash | bytes32 | 32 | Agent Root and SnapGasHash combined into a single hash |
[064..068) | nonce | uint32 | 4 | Total amount of all accepted Notary snapshots |
[068..073) | blockNumber | uint40 | 5 | Block when this Notary snapshot was accepted in Summit |
[073..078) | timestamp | uint40 | 5 | Time when this Notary snapshot was accepted in Summit |
Attestation could be signed by a Notary and submitted to Destination
in order to use if for proving
messages coming from origin chains that the initial snapshot refers to.
State Variables
OFFSET_SNAP_ROOT
The variables below are not supposed to be used outside of the library directly.
uint256 private constant OFFSET_SNAP_ROOT = 0;
OFFSET_DATA_HASH
uint256 private constant OFFSET_DATA_HASH = 32;
OFFSET_NONCE
uint256 private constant OFFSET_NONCE = 64;
OFFSET_BLOCK_NUMBER
uint256 private constant OFFSET_BLOCK_NUMBER = 68;
OFFSET_TIMESTAMP
uint256 private constant OFFSET_TIMESTAMP = 73;
Functions
formatAttestation
Returns a formatted Attestation payload with provided fields.
function formatAttestation(bytes32 snapRoot_, bytes32 dataHash_, uint32 nonce_, uint40 blockNumber_, uint40 timestamp_)
internal
pure
returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
snapRoot_ | bytes32 | Snapshot merkle tree's root |
dataHash_ | bytes32 | Agent Root and SnapGasHash combined into a single hash |
nonce_ | uint32 | Attestation Nonce |
blockNumber_ | uint40 | Block number when attestation was created in Summit |
timestamp_ | uint40 | Block timestamp when attestation was created in Summit |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | Formatted attestation |
castToAttestation
Returns an Attestation view over the given payload.
Will revert if the payload is not an attestation.
function castToAttestation(bytes memory payload) internal pure returns (Attestation);
castToAttestation
Casts a memory view to an Attestation view.
Will revert if the memory view is not over an attestation.
function castToAttestation(MemView memView) internal pure returns (Attestation);
isAttestation
Checks that a payload is a formatted Attestation.
function isAttestation(MemView memView) internal pure returns (bool);
hashValid
Returns the hash of an Attestation, that could be later signed by a Notary to signal that the attestation is valid.
function hashValid(Attestation att) internal pure returns (bytes32);
hashInvalid
Returns the hash of an Attestation, that could be later signed by a Guard to signal that the attestation is invalid.
function hashInvalid(Attestation att) internal pure returns (bytes32);
unwrap
Convenience shortcut for unwrapping a view.
function unwrap(Attestation att) internal pure returns (MemView);
snapRoot
Returns root of the Snapshot merkle tree created in the Summit contract.
function snapRoot(Attestation att) internal pure returns (bytes32);
dataHash
Returns hash of the Agent Root and SnapGasHash combined into a single hash.
function dataHash(Attestation att) internal pure returns (bytes32);
dataHash
Returns hash of the Agent Root and SnapGasHash combined into a single hash.
function dataHash(bytes32 agentRoot_, bytes32 snapGasHash_) internal pure returns (bytes32);
nonce
Returns nonce of Summit contract at the time, when attestation was created.
function nonce(Attestation att) internal pure returns (uint32);
blockNumber
Returns a block number when attestation was created in Summit.
function blockNumber(Attestation att) internal pure returns (uint40);
timestamp
Returns a block timestamp when attestation was created in Summit.
This is the timestamp according to the Synapse Chain.
function timestamp(Attestation att) internal pure returns (uint40);
BaseMessage
BaseMessage is a memory view over the base message supported by Origin-Destination
type BaseMessage is uint256;
BaseMessageLib
BaseMessage structure represents a base message sent via the Origin-Destination contracts.
- It only contains data relevant to the base message, the rest of data is encoded in the message header.
sender
andrecipient
for EVM chains are EVM addresses casted to bytes32, while preserving left-alignment.tips
andrequest
parameters are specified by a message sender
Origin will calculate minimum tips for given request and content length, and will reject messages with tips lower than that.
Memory layout of BaseMessage fields
Position | Field | Type | Bytes | Description |
---|---|---|---|---|
[000..032) | tips | uint256 | 32 | Encoded tips paid on origin chain |
[032..064) | sender | bytes32 | 32 | Sender address on origin chain |
[064..096) | recipient | bytes32 | 32 | Recipient address on destination chain |
[096..116) | request | uint160 | 20 | Encoded request for message execution |
[104..AAA) | content | bytes | ?? | Content to be passed to recipient |
State Variables
OFFSET_TIPS
The variables below are not supposed to be used outside of the library directly.
uint256 private constant OFFSET_TIPS = 0;
OFFSET_SENDER
uint256 private constant OFFSET_SENDER = 32;
OFFSET_RECIPIENT
uint256 private constant OFFSET_RECIPIENT = 64;
OFFSET_REQUEST
uint256 private constant OFFSET_REQUEST = OFFSET_RECIPIENT + TIPS_LENGTH;
OFFSET_CONTENT
uint256 private constant OFFSET_CONTENT = OFFSET_REQUEST + REQUEST_LENGTH;
Functions
formatBaseMessage
Returns a formatted BaseMessage payload with provided fields.
function formatBaseMessage(Tips tips_, bytes32 sender_, bytes32 recipient_, Request request_, bytes memory content_)
internal
pure
returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
tips_ | Tips | Encoded tips information |
sender_ | bytes32 | Sender address on origin chain |
recipient_ | bytes32 | Recipient address on destination chain |
request_ | Request | Encoded request for message execution |
content_ | bytes | Raw content to be passed to recipient on destination chain |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | Formatted base message |
castToBaseMessage
Returns a BaseMessage view over the given payload.
Will revert if the payload is not a base message.
function castToBaseMessage(bytes memory payload) internal pure returns (BaseMessage);
castToBaseMessage
Casts a memory view to a BaseMessage view.
Will revert if the memory view is not over a base message payload.
function castToBaseMessage(MemView memView) internal pure returns (BaseMessage);
isBaseMessage
Checks that a payload is a formatted BaseMessage.
function isBaseMessage(MemView memView) internal pure returns (bool);
unwrap
Convenience shortcut for unwrapping a view.
function unwrap(BaseMessage baseMessage) internal pure returns (MemView);
leaf
Returns baseMessage's hash: a leaf to be inserted in the "Message mini-Merkle tree".
function leaf(BaseMessage baseMessage) internal pure returns (bytes32);
bodyLeaf
Returns hash for the "everything but tips" part of the base message.
function bodyLeaf(BaseMessage baseMessage) internal pure returns (bytes32);
tips
Returns encoded tips paid on origin chain.
function tips(BaseMessage baseMessage) internal pure returns (Tips);
sender
Returns sender address on origin chain.
function sender(BaseMessage baseMessage) internal pure returns (bytes32);
recipient
Returns recipient address on destination chain.
function recipient(BaseMessage baseMessage) internal pure returns (bytes32);
request
Returns an encoded request for message execution on destination chain.
function request(BaseMessage baseMessage) internal pure returns (Request);
content
Returns an untyped memory view over the content to be passed to recipient.
function content(BaseMessage baseMessage) internal pure returns (MemView);
CallData
*CallData is a memory view over the payload to be used for an external call, i.e. recipient.call(callData). Its length is always (4 + 32 * N) bytes:
- First 4 bytes represent the function selector.
- 32 * N bytes represent N words that function arguments occupy.*
type CallData is uint256;
Signature
Attach library functions to CallData
Signature is a memory view over a "65 bytes" array representing a ECDSA signature.
type Signature is uint256;
ByteString
Attach library functions to Signature
State Variables
SIGNATURE_LENGTH
non-compact ECDSA signatures are enforced as of OZ 4.7.3 Signature payload memory layout [000 .. 032) r bytes32 32 bytes [032 .. 064) s bytes32 32 bytes [064 .. 065) v uint8 1 byte
uint256 internal constant SIGNATURE_LENGTH = 65;
OFFSET_R
uint256 private constant OFFSET_R = 0;
OFFSET_S
uint256 private constant OFFSET_S = 32;
OFFSET_V
uint256 private constant OFFSET_V = 64;
SELECTOR_LENGTH
Calldata memory layout [000 .. 004) selector bytes4 4 bytes Optional: N function arguments [004 .. 036) arg1 bytes32 32 bytes .. [AAA .. END) argN bytes32 32 bytes
uint256 internal constant SELECTOR_LENGTH = 4;
OFFSET_SELECTOR
uint256 private constant OFFSET_SELECTOR = 0;
OFFSET_ARGUMENTS
uint256 private constant OFFSET_ARGUMENTS = SELECTOR_LENGTH;
Functions
formatSignature
Constructs the signature payload from the given values.
Using ByteString.formatSignature({r: r, s: s, v: v}) will make sure that params are given in the right order.
function formatSignature(bytes32 r, bytes32 s, uint8 v) internal pure returns (bytes memory);
castToSignature
Returns a Signature view over for the given payload.
Will revert if the payload is not a signature.
function castToSignature(bytes memory payload) internal pure returns (Signature);
castToSignature
Casts a memory view to a Signature view.
Will revert if the memory view is not over a signature.
function castToSignature(MemView memView) internal pure returns (Signature);
isSignature
Checks that a byte string is a signature
function isSignature(MemView memView) internal pure returns (bool);
unwrap
Convenience shortcut for unwrapping a view.
function unwrap(Signature signature) internal pure returns (MemView);
toRSV
Unpacks signature payload into (r, s, v) parameters.
Make sure to verify signature length with isSignature() beforehand.
function toRSV(Signature signature) internal pure returns (bytes32 r, bytes32 s, uint8 v);
addPrefix
Constructs the calldata with the modified arguments: the existing arguments are prepended with the arguments from the prefix.
*Given:
calldata = abi.encodeWithSelector(foo.selector, d, e);
prefix = abi.encode(a, b, c);
a
,b
,c
are arguments of static type (i.e. not dynamically sized ones) Then:- Function will return abi.encodeWithSelector(foo.selector, a, c, c, d, e)
- Returned calldata will trigger
foo(a, b, c, d, e)
when used for a contract call. Note: for clarification as to what types are considered static, see https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding*
function addPrefix(CallData callData, bytes memory prefix) internal view returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
callData | CallData | Calldata that needs to be modified |
prefix | bytes | ABI-encoded arguments to use as the first arguments in the new calldata |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | Modified calldata having prefix as the first arguments. |
castToCallData
Returns a CallData view over for the given payload.
Will revert if the memory view is not over a calldata.
function castToCallData(bytes memory payload) internal pure returns (CallData);
castToCallData
Casts a memory view to a CallData view.
Will revert if the memory view is not over a calldata.
function castToCallData(MemView memView) internal pure returns (CallData);
isCallData
Checks that a byte string is a valid calldata, i.e. a function selector, followed by arbitrary amount of arguments.
function isCallData(MemView memView) internal pure returns (bool);
unwrap
Convenience shortcut for unwrapping a view.
function unwrap(CallData callData) internal pure returns (MemView);
leaf
Returns callData's hash: a leaf to be inserted in the "Message mini-Merkle tree".
function leaf(CallData callData) internal pure returns (bytes32);
argumentWords
Returns amount of memory words (32 byte chunks) the function arguments occupy in the calldata.
This might differ from amount of arguments supplied, if any of the arguments
occupies more than one memory slot. It is true, however, that argument part of the payload
occupies exactly N words, even for dynamic types like bytes
function argumentWords(CallData callData) internal pure returns (uint256);
callSelector
Returns selector for the provided calldata.
function callSelector(CallData callData) internal pure returns (bytes4);
arguments
Returns abi encoded arguments for the provided calldata.
function arguments(CallData callData) internal pure returns (MemView);
_fullWords
Checks if length is full amount of memory words (32 bytes).
function _fullWords(uint256 length) internal pure returns (bool);
MemView
MemView is an untyped view over a portion of memory to be used instead of bytes memory
type MemView is uint256;
MemViewLib
Library for operations with the memory views. Forked from https://github.com/summa-tx/memview-sol with several breaking changes:
- The codebase is ported to Solidity 0.8
- Custom errors are added
- The runtime type checking is replaced with compile-time check provided by User-Defined Value Types https://docs.soliditylang.org/en/latest/types.html#user-defined-value-types
- uint256 is used as the underlying type for the "memory view" instead of bytes29. It is wrapped into MemView custom type in order not to be confused with actual integers.
- Therefore the "type" field is discarded, allowing to allocate 16 bytes for both view location and length
- The documentation is expanded
- Library functions unused by the rest of the codebase are removed
Attach library functions to MemView
Functions
build
Stack layout for uint256 (from highest bits to lowest) (32 .. 16] loc 16 bytes Memory address of underlying bytes (16 .. 00] len 16 bytes Length of underlying bytes
Instantiate a new untyped memory view. This should generally not be called directly.
Prefer ref
wherever possible.
function build(uint256 loc_, uint256 len_) internal pure returns (MemView);
Parameters
Name | Type | Description |
---|---|---|
loc_ | uint256 | The memory address |
len_ | uint256 | The length |
Returns
Name | Type | Description |
---|---|---|
<none> | MemView | The new view with the specified location and length |
ref
Instantiate a memory view from a byte array.
Note that due to Solidity memory representation, it is not possible to
implement a deref, as the bytes
type stores its len in memory.
function ref(bytes memory arr) internal pure returns (MemView);
Parameters
Name | Type | Description |
---|---|---|
arr | bytes | The byte array |
Returns
Name | Type | Description |
---|---|---|
<none> | MemView | The memory view over the provided byte array |
clone
Copies the referenced memory to a new loc in memory, returning a bytes
pointing to the new memory.
function clone(MemView memView) internal view returns (bytes memory arr);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
Returns
Name | Type | Description |
---|---|---|
arr | bytes | The cloned byte array |
join
Copies all views, joins them into a new bytearray.
function join(MemView[] memory memViews) internal view returns (bytes memory arr);
Parameters
Name | Type | Description |
---|---|---|
memViews | MemView[] | The memory views |
Returns
Name | Type | Description |
---|---|---|
arr | bytes | The new byte array with joined data behind the given views |
loc
Returns the memory address of the underlying bytes.
function loc(MemView memView) internal pure returns (uint256 loc_);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
Returns
Name | Type | Description |
---|---|---|
loc_ | uint256 | The memory address |
len
Returns the number of bytes of the view.
function len(MemView memView) internal pure returns (uint256 len_);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
Returns
Name | Type | Description |
---|---|---|
len_ | uint256 | The length of the view |
end
Returns the endpoint of memView
.
function end(MemView memView) internal pure returns (uint256 end_);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
Returns
Name | Type | Description |
---|---|---|
end_ | uint256 | The endpoint of memView |
words
Returns the number of memory words this memory view occupies, rounded up.
function words(MemView memView) internal pure returns (uint256 words_);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
Returns
Name | Type | Description |
---|---|---|
words_ | uint256 | The number of memory words |
footprint
Returns the in-memory footprint of a fresh copy of the view.
function footprint(MemView memView) internal pure returns (uint256 footprint_);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
Returns
Name | Type | Description |
---|---|---|
footprint_ | uint256 | The in-memory footprint of a fresh copy of the view. |
keccak
Returns the keccak256 hash of the underlying memory
function keccak(MemView memView) internal pure returns (bytes32 digest);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
Returns
Name | Type | Description |
---|---|---|
digest | bytes32 | The keccak256 hash of the underlying memory |
keccakSalted
Adds a salt to the keccak256 hash of the underlying data and returns the keccak256 hash of the resulting data.
function keccakSalted(MemView memView, bytes32 salt) internal pure returns (bytes32 digestSalted);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
salt | bytes32 |
Returns
Name | Type | Description |
---|---|---|
digestSalted | bytes32 | keccak256(salt, keccak256(memView)) |
slice
Safe slicing without memory modification.
function slice(MemView memView, uint256 index_, uint256 len_) internal pure returns (MemView);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
index_ | uint256 | The start index |
len_ | uint256 | The length |
Returns
Name | Type | Description |
---|---|---|
<none> | MemView | The new view for the slice of the given length starting from the given index |
sliceFrom
Shortcut to slice
. Gets a view representing bytes from index
to end(memView).
function sliceFrom(MemView memView, uint256 index_) internal pure returns (MemView);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
index_ | uint256 | The start index |
Returns
Name | Type | Description |
---|---|---|
<none> | MemView | The new view for the slice starting from the given index until the initial view endpoint |
prefix
Shortcut to slice
. Gets a view representing the first len
bytes.
function prefix(MemView memView, uint256 len_) internal pure returns (MemView);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
len_ | uint256 | The length |
Returns
Name | Type | Description |
---|---|---|
<none> | MemView | The new view for the slice of the given length starting from the initial view beginning |
postfix
Shortcut to slice
. Gets a view representing the last len
byte.
function postfix(MemView memView, uint256 len_) internal pure returns (MemView);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
len_ | uint256 | The length |
Returns
Name | Type | Description |
---|---|---|
<none> | MemView | The new view for the slice of the given length until the initial view endpoint |
index
Load up to 32 bytes from the view onto the stack.
Returns a bytes32 with only the bytes_
HIGHEST bytes set.
This can be immediately cast to a smaller fixed-length byte array.
To automatically cast to an integer, use indexUint
.
function index(MemView memView, uint256 index_, uint256 bytes_) internal pure returns (bytes32 result);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
index_ | uint256 | The index |
bytes_ | uint256 | The amount of bytes to load onto the stack |
Returns
Name | Type | Description |
---|---|---|
result | bytes32 | The 32 byte result having only bytes_ highest bytes set |
indexUint
Parse an unsigned integer from the view at index
.
Requires that the view have >= bytes_
bytes following that index.
function indexUint(MemView memView, uint256 index_, uint256 bytes_) internal pure returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
index_ | uint256 | The index |
bytes_ | uint256 | The amount of bytes to load onto the stack |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The unsigned integer |
indexAddress
Parse an address from the view at index
.
Requires that the view have >= 20 bytes following that index.
function indexAddress(MemView memView, uint256 index_) internal pure returns (address);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
index_ | uint256 | The index |
Returns
Name | Type | Description |
---|---|---|
<none> | address | The address |
_unsafeBuildUnchecked
Returns a memory view over the specified memory location without checking if it points to unallocated memory.
function _unsafeBuildUnchecked(uint256 loc_, uint256 len_) private pure returns (MemView);
_unsafeCopyTo
Copy the view to a location, return an unsafe memory reference
Super Dangerous direct memory access. This reference can be overwritten if anything else modifies memory (!!!). As such it MUST be consumed IMMEDIATELY. Update the free memory pointer to ensure the copied data is not overwritten. This function is private to prevent unsafe usage by callers.
function _unsafeCopyTo(MemView memView, uint256 newLoc) private view returns (MemView);
Parameters
Name | Type | Description |
---|---|---|
memView | MemView | The memory view |
newLoc | uint256 | The new location to copy the underlying view data |
Returns
Name | Type | Description |
---|---|---|
<none> | MemView | The memory view over the unsafe memory with the copied underlying data |
_unsafeJoin
Join the views in memory, return an unsafe reference to the memory.
Super Dangerous direct memory access. This reference can be overwritten if anything else modifies memory (!!!). As such it MUST be consumed IMMEDIATELY. Update the free memory pointer to ensure the copied data is not overwritten. This function is private to prevent unsafe usage by callers.
function _unsafeJoin(MemView[] memory memViews, uint256 location) private view returns (MemView);
Parameters
Name | Type | Description |
---|---|---|
memViews | MemView[] | The memory views |
location | uint256 |
Returns
Name | Type | Description |
---|---|---|
<none> | MemView | The conjoined view pointing to the new memory |
Message
Message is a memory over over a formatted message payload.
type Message is uint256;
MessageLib
Library for formatting the various messages supported by Origin and Destination.
Message memory layout
Position | Field | Type | Bytes | Description |
---|---|---|---|---|
[000..017) | header | uint136 | 17 | Encoded general routing information for the message |
[017..AAA) | body | bytes | ?? | Formatted payload (according to flag) with message body |
State Variables
OFFSET_HEADER
The variables below are not supposed to be used outside of the library directly.
uint256 private constant OFFSET_HEADER = 0;
OFFSET_BODY
uint256 private constant OFFSET_BODY = OFFSET_HEADER + HEADER_LENGTH;
Functions
formatMessage
Returns formatted message with provided fields.
function formatMessage(Header header_, bytes memory body_) internal pure returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
header_ | Header | Encoded general routing information for the message |
body_ | bytes | Formatted payload (according to flag) with message body |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | Formatted message |
castToMessage
Returns a Message view over for the given payload.
Will revert if the payload is not a message payload.
function castToMessage(bytes memory payload) internal pure returns (Message);
castToMessage
Casts a memory view to a Message view.
Will revert if the memory view is not over a message payload.
function castToMessage(MemView memView) internal pure returns (Message);
isMessage
Checks that a payload is a formatted Message.
function isMessage(MemView memView) internal pure returns (bool);
unwrap
Convenience shortcut for unwrapping a view.
function unwrap(Message message) internal pure returns (MemView);
leaf
Returns message's hash: a leaf to be inserted in the Merkle tree.
function leaf(Message message) internal pure returns (bytes32);
header
Returns message's encoded header field.
function header(Message message) internal pure returns (Header);
body
Returns message's body field as an untyped memory view.
function body(Message message) internal pure returns (MemView);
_header
Returns message's padded header without checking that it is a valid header.
function _header(MemView memView) private pure returns (uint256);
_body
Returns an untyped memory view over the body field without checking if the whole payload or the body are properly formatted.
function _body(MemView memView) private pure returns (MemView);
Receipt
Receipt is a memory view over a formatted "full receipt" payload.
type Receipt is uint256;
ReceiptLib
Receipt structure represents a Notary statement that a certain message has been executed in ExecutionHub
.
- It is possible to prove the correctness of the tips payload using the message hash, therefore tips are not included in the receipt.
- Receipt is signed by a Notary and submitted to
Summit
in order to initiate the tips distribution for an executed message. - If a message execution fails the first time, the
finalExecutor
field will be set to zero address. In this case, when the message is finally executed successfully, thefinalExecutor
field will be updated. Both receipts will be considered valid.
Memory layout of Receipt fields
Position | Field | Type | Bytes | Description |
---|---|---|---|---|
[000..004) | origin | uint32 | 4 | Domain where message originated |
[004..008) | destination | uint32 | 4 | Domain where message was executed |
[008..040) | messageHash | bytes32 | 32 | Hash of the message |
[040..072) | snapshotRoot | bytes32 | 32 | Snapshot root used for proving the message |
[072..073) | stateIndex | uint8 | 1 | Index of state used for the snapshot proof |
[073..093) | attNotary | address | 20 | Notary who posted attestation with snapshot root |
[093..113) | firstExecutor | address | 20 | Executor who performed first valid execution |
[113..133) | finalExecutor | address | 20 | Executor who successfully executed the message |
State Variables
OFFSET_ORIGIN
The variables below are not supposed to be used outside of the library directly.
uint256 private constant OFFSET_ORIGIN = 0;
OFFSET_DESTINATION
uint256 private constant OFFSET_DESTINATION = 4;
OFFSET_MESSAGE_HASH
uint256 private constant OFFSET_MESSAGE_HASH = 8;
OFFSET_SNAPSHOT_ROOT
uint256 private constant OFFSET_SNAPSHOT_ROOT = 40;
OFFSET_STATE_INDEX
uint256 private constant OFFSET_STATE_INDEX = 72;
OFFSET_ATT_NOTARY
uint256 private constant OFFSET_ATT_NOTARY = 73;
OFFSET_FIRST_EXECUTOR
uint256 private constant OFFSET_FIRST_EXECUTOR = 93;
OFFSET_FINAL_EXECUTOR
uint256 private constant OFFSET_FINAL_EXECUTOR = 113;
Functions
formatReceipt
Returns a formatted Receipt payload with provided fields.
function formatReceipt(
uint32 origin_,
uint32 destination_,
bytes32 messageHash_,
bytes32 snapshotRoot_,
uint8 stateIndex_,
address attNotary_,
address firstExecutor_,
address finalExecutor_
) internal pure returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
origin_ | uint32 | Domain where message originated |
destination_ | uint32 | Domain where message was executed |
messageHash_ | bytes32 | Hash of the message |
snapshotRoot_ | bytes32 | Snapshot root used for proving the message |
stateIndex_ | uint8 | Index of state used for the snapshot proof |
attNotary_ | address | Notary who posted attestation with snapshot root |
firstExecutor_ | address | Executor who performed first valid execution attempt |
finalExecutor_ | address | Executor who successfully executed the message |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | Formatted receipt |
castToReceipt
Returns a Receipt view over the given payload.
Will revert if the payload is not a receipt.
function castToReceipt(bytes memory payload) internal pure returns (Receipt);
castToReceipt
Casts a memory view to a Receipt view.
Will revert if the memory view is not over a receipt.
function castToReceipt(MemView memView) internal pure returns (Receipt);
isReceipt
Checks that a payload is a formatted Receipt.
function isReceipt(MemView memView) internal pure returns (bool);
hashValid
Returns the hash of an Receipt, that could be later signed by a Notary to signal that the receipt is valid.
function hashValid(Receipt receipt) internal pure returns (bytes32);
hashInvalid
Returns the hash of a Receipt, that could be later signed by a Guard to signal that the receipt is invalid.
function hashInvalid(Receipt receipt) internal pure returns (bytes32);
unwrap
Convenience shortcut for unwrapping a view.
function unwrap(Receipt receipt) internal pure returns (MemView);
equals
Compares two Receipt structures.
function equals(Receipt a, Receipt b) internal pure returns (bool);
origin
Returns receipt's origin field
function origin(Receipt receipt) internal pure returns (uint32);
destination
Returns receipt's destination field
function destination(Receipt receipt) internal pure returns (uint32);
messageHash
Returns receipt's "message hash" field
function messageHash(Receipt receipt) internal pure returns (bytes32);
snapshotRoot
Returns receipt's "snapshot root" field
function snapshotRoot(Receipt receipt) internal pure returns (bytes32);
stateIndex
Returns receipt's "state index" field
function stateIndex(Receipt receipt) internal pure returns (uint8);
attNotary
Returns receipt's "attestation notary" field
function attNotary(Receipt receipt) internal pure returns (address);
firstExecutor
Returns receipt's "first executor" field
function firstExecutor(Receipt receipt) internal pure returns (address);
finalExecutor
Returns receipt's "final executor" field
function finalExecutor(Receipt receipt) internal pure returns (address);
Snapshot
Snapshot is a memory view over a formatted snapshot payload: a list of states.
type Snapshot is uint256;
SnapshotLib
Snapshot
Snapshot structure represents the state of multiple Origin contracts deployed on multiple chains. In short, snapshot is a list of "State" structs. See State.sol for details about the "State" structs.
Snapshot usage
- Both Guards and Notaries are supposed to form snapshots and sign
snapshot.hash()
to verify its validity. - Each Guard should be monitoring a set of Origin contracts chosen as they see fit.
- They are expected to form snapshots with Origin states for this set of chains, sign and submit them to Summit contract.
- Notaries are expected to monitor the Summit contract for new snapshots submitted by the Guards.
- They should be forming their own snapshots using states from snapshots of any of the Guards.
- The states for the Notary snapshots don't have to come from the same Guard snapshot, or don't even have to be submitted by the same Guard.
- With their signature, Notary effectively "notarizes" the work that some Guards have done in Summit contract.
- Notary signature on a snapshot doesn't only verify the validity of the Origins, but also serves as a proof of liveliness for Guards monitoring these Origins.
Snapshot validity
- Snapshot is considered "valid" in Origin, if every state referring to that Origin is valid there.
- Snapshot is considered "globally valid", if it is "valid" in every Origin contract.
Snapshot memory layout
Position | Field | Type | Bytes | Description |
---|---|---|---|---|
[000..050) | states[0] | bytes | 50 | Origin State with index==0 |
[050..100) | states[1] | bytes | 50 | Origin State with index==1 |
... | ... | ... | 50 | ... |
[AAA..BBB) | states[N-1] | bytes | 50 | Origin State with index==N-1 |
Snapshot could be signed by both Guards and Notaries and submitted to Summit
in order to produce Attestations
that could be used in ExecutionHub for proving the messages coming from origin chains that the snapshot refers to.
Functions
formatSnapshot
Returns a formatted Snapshot payload using a list of States.
function formatSnapshot(State[] memory states) internal view returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
states | State[] | Arrays of State-typed memory views over Origin states |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | Formatted snapshot |
castToSnapshot
Returns a Snapshot view over for the given payload.
Will revert if the payload is not a snapshot payload.
function castToSnapshot(bytes memory payload) internal pure returns (Snapshot);
castToSnapshot
Casts a memory view to a Snapshot view.
Will revert if the memory view is not over a snapshot payload.
function castToSnapshot(MemView memView) internal pure returns (Snapshot);
isSnapshot
Checks that a payload is a formatted Snapshot.
function isSnapshot(MemView memView) internal pure returns (bool);
hashValid
Returns the hash of a Snapshot, that could be later signed by an Agent to signal that the snapshot is valid.
function hashValid(Snapshot snapshot) internal pure returns (bytes32 hashedSnapshot);
unwrap
Convenience shortcut for unwrapping a view.
function unwrap(Snapshot snapshot) internal pure returns (MemView);
state
Returns a state with a given index from the snapshot.
function state(Snapshot snapshot, uint256 stateIndex) internal pure returns (State);
statesAmount
Returns the amount of states in the snapshot.
function statesAmount(Snapshot snapshot) internal pure returns (uint256);
snapGas
Extracts the list of ChainGas structs from the snapshot.
function snapGas(Snapshot snapshot) internal pure returns (ChainGas[] memory snapGas_);
calculateRoot
Returns the root for the "Snapshot Merkle Tree" composed of state leafs from the snapshot.
function calculateRoot(Snapshot snapshot) internal pure returns (bytes32);
proofSnapRoot
Reconstructs Snapshot merkle Root from State Merkle Data (root + origin domain) and proof of inclusion of State Merkle Data (aka State "left sub-leaf") in Snapshot Merkle Tree.
Reverts if any of these is true:
- State index is out of range.
- Snapshot Proof length exceeds Snapshot tree Height.
function proofSnapRoot(bytes32 originRoot, uint32 domain, bytes32[] memory snapProof, uint8 stateIndex)
internal
pure
returns (bytes32);
Parameters
Name | Type | Description |
---|---|---|
originRoot | bytes32 | Root of Origin Merkle Tree |
domain | uint32 | Domain of Origin chain |
snapProof | bytes32[] | Proof of inclusion of State Merkle Data into Snapshot Merkle Tree |
stateIndex | uint8 | Index of Origin State in the Snapshot |
_isValidAmount
Checks if snapshot's states amount is valid.
function _isValidAmount(uint256 statesAmount_) internal pure returns (bool);
State
State is a memory view over a formatted state payload.
type State is uint256;
StateLib
State
State structure represents the state of Origin contract at some point of time.
- State is structured in a way to track the updates of the Origin Merkle Tree.
- State includes root of the Origin Merkle Tree, origin domain and some additional metadata.
Origin Merkle Tree
Hash of every sent message is inserted in the Origin Merkle Tree, which changes the value of Origin Merkle Root (which is the root for the mentioned tree).
- Origin has a single Merkle Tree for all messages, regardless of their destination domain.
- This leads to Origin state being updated if and only if a message was sent in a block.
- Origin contract is a "source of truth" for states: a state is considered "valid" in its Origin, if it matches the state of the Origin contract after the N-th (nonce) message was sent.
Memory layout of State fields
Position | Field | Type | Bytes | Description |
---|---|---|---|---|
[000..032) | root | bytes32 | 32 | Root of the Origin Merkle Tree |
[032..036) | origin | uint32 | 4 | Domain where Origin is located |
[036..040) | nonce | uint32 | 4 | Amount of sent messages |
[040..045) | blockNumber | uint40 | 5 | Block of last sent message |
[045..050) | timestamp | uint40 | 5 | Time of last sent message |
[050..062) | gasData | uint96 | 12 | Gas data for the chain |
State could be used to form a Snapshot to be signed by a Guard or a Notary.
State Variables
OFFSET_ROOT
The variables below are not supposed to be used outside of the library directly.
uint256 private constant OFFSET_ROOT = 0;
OFFSET_ORIGIN
uint256 private constant OFFSET_ORIGIN = 32;
OFFSET_NONCE
uint256 private constant OFFSET_NONCE = 36;
OFFSET_BLOCK_NUMBER
uint256 private constant OFFSET_BLOCK_NUMBER = 40;
OFFSET_TIMESTAMP
uint256 private constant OFFSET_TIMESTAMP = 45;
OFFSET_GAS_DATA
uint256 private constant OFFSET_GAS_DATA = 50;
Functions
formatState
Returns a formatted State payload with provided fields
function formatState(
bytes32 root_,
uint32 origin_,
uint32 nonce_,
uint40 blockNumber_,
uint40 timestamp_,
GasData gasData_
) internal pure returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
root_ | bytes32 | New merkle root |
origin_ | uint32 | Domain of Origin's chain |
nonce_ | uint32 | Nonce of the merkle root |
blockNumber_ | uint40 | Block number when root was saved in Origin |
timestamp_ | uint40 | Block timestamp when root was saved in Origin |
gasData_ | GasData | Gas data for the chain |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | Formatted state |
castToState
Returns a State view over the given payload.
Will revert if the payload is not a state.
function castToState(bytes memory payload) internal pure returns (State);
castToState
Casts a memory view to a State view.
Will revert if the memory view is not over a state.
function castToState(MemView memView) internal pure returns (State);
isState
Checks that a payload is a formatted State.
function isState(MemView memView) internal pure returns (bool);
hashInvalid
Returns the hash of a State, that could be later signed by a Guard to signal that the state is invalid.
function hashInvalid(State state) internal pure returns (bytes32);
unwrap
Convenience shortcut for unwrapping a view.
function unwrap(State state) internal pure returns (MemView);
equals
Compares two State structures.
function equals(State a, State b) internal pure returns (bool);
leaf
Returns the hash of the State.
We are using the Merkle Root of a tree with two leafs (see below) as state hash.
function leaf(State state) internal pure returns (bytes32);
subLeafs
Returns "sub-leafs" of the State. Hash of these "sub leafs" is going to be used
as a "state leaf" in the "Snapshot Merkle Tree".
This enables proving that leftLeaf = (root, origin) was a part of the "Snapshot Merkle Tree",
by combining rightLeaf
with the remainder of the "Snapshot Merkle Proof".
function subLeafs(State state) internal pure returns (bytes32 leftLeaf_, bytes32 rightLeaf_);
leftLeaf
Returns the left "sub-leaf" of the State.
function leftLeaf(bytes32 root_, uint32 origin_) internal pure returns (bytes32);
rightLeaf
Returns the right "sub-leaf" of the State.
function rightLeaf(uint32 nonce_, uint40 blockNumber_, uint40 timestamp_, GasData gasData_)
internal
pure
returns (bytes32);
root
Returns a historical Merkle root from the Origin contract.
function root(State state) internal pure returns (bytes32);
origin
Returns domain of chain where the Origin contract is deployed.
function origin(State state) internal pure returns (uint32);
nonce
Returns nonce of Origin contract at the time, when root
was the Merkle root.
function nonce(State state) internal pure returns (uint32);
blockNumber
Returns a block number when root
was saved in Origin.
function blockNumber(State state) internal pure returns (uint40);
timestamp
Returns a block timestamp when root
was saved in Origin.
This is the timestamp according to the origin chain.
function timestamp(State state) internal pure returns (uint40);
gasData
Returns gas data for the chain.
function gasData(State state) internal pure returns (GasData);
Contents
MerkleMath
Functions
proofRoot
Calculates the merkle root for the given leaf and merkle proof.
Will revert if proof length exceeds the tree height.
function proofRoot(uint256 index, bytes32 leaf, bytes32[] memory proof, uint256 height)
internal
pure
returns (bytes32 root_);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Index of leaf in tree |
leaf | bytes32 | Leaf of the merkle tree |
proof | bytes32[] | Proof of inclusion of leaf in the tree |
height | uint256 | Height of the merkle tree |
Returns
Name | Type | Description |
---|---|---|
root_ | bytes32 | Calculated Merkle Root |
getParent
Calculates the parent of a node on the path from one of the leafs to root.
Apply unchecked to all ++h operations
function getParent(bytes32 node, bytes32 sibling, uint256 leafIndex, uint256 nodeHeight)
internal
pure
returns (bytes32 parent);
Parameters
Name | Type | Description |
---|---|---|
node | bytes32 | Node on a path from tree leaf to root |
sibling | bytes32 | Sibling for a given node |
leafIndex | uint256 | Index of the tree leaf |
nodeHeight | uint256 | "Level height" for node (ZERO for leafs, ORIGIN_TREE_HEIGHT for root) |
getParent
Calculates the parent of tow nodes in the merkle tree.
We use implementation with H(0,0) = 0 This makes EVERY empty node in the tree equal to ZERO, saving us from storing H(0,0), H(H(0,0), H(0, 0)), and so on
function getParent(bytes32 leftChild, bytes32 rightChild) internal pure returns (bytes32 parent);
Parameters
Name | Type | Description |
---|---|---|
leftChild | bytes32 | Left child of the calculated node |
rightChild | bytes32 | Right child of the calculated node |
Returns
Name | Type | Description |
---|---|---|
parent | bytes32 | Value for the node having above mentioned children |
calculateRoot
Calculates merkle root for a list of given leafs.
Merkle Tree is constructed by padding the list with ZERO values for leafs until list length is 2**height
.
Merkle Root is calculated for the constructed tree, and then saved in leafs[0]
.
Note:
leafs
values are overwritten in the process to avoid excessive memory allocations.- Caller is expected not to reuse
hashes
list after the call, and only useleafs[0]
value, which is guaranteed to contain the calculated merkle root.- root is calculated using the
H(0,0) = 0
Merkle Tree implementation. See MerkleTree.sol for details.
Amount of leaves should be at most 2**height
function calculateRoot(bytes32[] memory hashes, uint256 height) internal pure;
Parameters
Name | Type | Description |
---|---|---|
hashes | bytes32[] | List of leafs for the merkle tree (to be overwritten) |
height | uint256 | Height of the Merkle Tree to construct |
calculateProof
Generates a proof of inclusion of a leaf in the list. If the requested index is outside of the list range, generates a proof of inclusion for an empty leaf (proof of non-inclusion). The Merkle Tree is constructed by padding the list with ZERO values until list length is a power of two AND index is in the extended list range. For example:
hashes.length == 6
and0 <= index <= 7
will "extend" the list to 8 entries.hashes.length == 6
and7 < index <= 15
will "extend" the list to 16 entries.
Note:
leafs
values are overwritten in the process to avoid excessive memory allocations. Caller is expected not to reusehashes
list after the call.
h, leftIndex, rightIndex and levelLength never overflow
function calculateProof(bytes32[] memory hashes, uint256 index) internal pure returns (bytes32[] memory proof);
Parameters
Name | Type | Description |
---|---|---|
hashes | bytes32[] | List of leafs for the merkle tree (to be overwritten) |
index | uint256 | Leaf index to generate the proof for |
Returns
Name | Type | Description |
---|---|---|
proof | bytes32[] | Generated merkle proof |
getHeight
Returns the height of the tree having a given amount of leafs.
h, leftIndex, rightIndex and levelLength never overflow
function getHeight(uint256 leafs) internal pure returns (uint256 height);
BaseTree
BaseTree
is a struct representing incremental merkle tree.
- Contains only the current branch.
- The number of inserted leaves is stored externally, and is later supplied for tree operations.
- Has a fixed height of
ORIGIN_TREE_HEIGHT
. - Can store up to
2 ** ORIGIN_TREE_HEIGHT - 1
leaves.
Note: the hash function for the tree
H(x, y)
is defined as:
H(0,0) = 0
H(x,y) = keccak256(x, y), when (x != 0 || y != 0)
Invariant for leafs
- The leftmost empty leaf has
index == count
, wherecount
is the amount of the inserted leafs so far. - Value for any empty leaf or node is bytes32(0).
Invariant for current branch
branch[i]
is always the value of a node on the i-th level.
Levels are numbered from leafs to root: 0 .. ORIGIN_TREE_HEIGHT
.
branch[i]
stores the value for the node, such that:
- The node must have two non-empty children.
- Out of all level's "left child" nodes with "non-empty children",
the one with the biggest index (the rightmost one) is stored as
branch[i]
.
branch
could be used to form a proof of inclusion for the first empty leaf (index == count
). Here is how:
- Let's walk along the path from the "first empty leaf" to the root.
- i-th bit of the "first empty leaf" index (which is equal to
count
) determines if the path's node for this i-th level is a "left child" or a "right child". - i-th bit in
count
is 0 → we are the left child on this level → sibling is the right child that does not exist yet →proof[i] = bytes32(0)
. - i-th bit in
count
is 1 → we are the right child on this level → sibling is the left child sibling is the rightmost "left child" node on the level →proof[i] = branch[i]
.
Therefore
proof[i] = (count & (1 << i)) == 0 ? bytes32(0) : branch[i])
struct BaseTree {
bytes32[ORIGIN_TREE_HEIGHT] branch;
}
HistoricalTree
HistoricalTree
is an incremental merkle tree keeping track of its historical merkle roots.
roots[N]
is the root of the tree afterN
leafs were insertedroots[0] == bytes32(0)
struct HistoricalTree {
BaseTree tree;
bytes32[] roots;
}
DynamicTree
DynamicTree
is a struct representing a Merkle Tree with 2**AGENT_TREE_HEIGHT
leaves.
- A single operation is available: update value for leaf with an arbitrary index (which might be a non-empty leaf).
- This is done by requesting the proof of inclusion for the old value, which is used to both verify the old value, and calculate the new root.
Based on Original idea from ER forum post.
struct DynamicTree {
bytes32 root;
}
MerkleTree
MerkleTree is work based on Nomad's Merkle.sol, which is used under MIT OR Apache-2.0 link. With the following changes:
- Adapted for Solidity 0.8.x.
- Amount of tree leaves stored externally.
- Added thorough documentation.
H(0,0) = 0
optimization from ER forum post.
Nomad's Merkle.sol is work based on eth2 deposit contract, which is used under CC0-1.0 link. With the following changes:
- Implemented in Solidity 0.7.6 (eth2 deposit contract implemented in Vyper).
H() = keccak256()
is used as the hashing function instead ofsha256()
.
State Variables
MAX_LEAVES
For root calculation we need at least one empty leaf, thus the minus one in the formula.
uint256 internal constant MAX_LEAVES = 2 ** ORIGIN_TREE_HEIGHT - 1;
Functions
insertBase
Inserts node
into merkle tree
Reverts if tree is full
function insertBase(BaseTree storage tree, uint256 newCount, bytes32 node) internal;
Parameters
Name | Type | Description |
---|---|---|
tree | BaseTree | |
newCount | uint256 | Amount of inserted leaves in the tree after the insertion (i.e. current + 1) |
node | bytes32 | Element to insert into tree |
rootBase
Calculates and returns current root of the merkle tree.
function rootBase(BaseTree storage tree, uint256 count) internal view returns (bytes32 current);
Parameters
Name | Type | Description |
---|---|---|
tree | BaseTree | |
count | uint256 | Current amount of inserted leaves in the tree |
Returns
Name | Type | Description |
---|---|---|
current | bytes32 | Calculated root of tree |
initializeRoots
Initializes the historical roots for the tree by inserting an empty root.
function initializeRoots(HistoricalTree storage tree) internal returns (bytes32 savedRoot);
insert
Inserts a new leaf into the merkle tree.
Reverts if tree is full.
function insert(HistoricalTree storage tree, bytes32 node) internal returns (bytes32 newRoot);
Parameters
Name | Type | Description |
---|---|---|
tree | HistoricalTree | |
node | bytes32 | Element to insert into tree |
Returns
Name | Type | Description |
---|---|---|
newRoot | bytes32 | Merkle root after the leaf was inserted |
root
Returns the historical root of the merkle tree.
Reverts if not enough leafs have been inserted.
function root(HistoricalTree storage tree, uint256 count) internal view returns (bytes32 historicalRoot);
Parameters
Name | Type | Description |
---|---|---|
tree | HistoricalTree | |
count | uint256 | Amount of leafs in the tree at some point of time |
Returns
Name | Type | Description |
---|---|---|
historicalRoot | bytes32 | Merkle root after count leafs were inserted |
update
Updates the value for the leaf with the given index in the Dynamic Merkle Tree.
Will revert if incorrect proof of inclusion for old value is supplied.
function update(DynamicTree storage tree, uint256 index, bytes32 oldValue, bytes32[] memory branch, bytes32 newValue)
internal
returns (bytes32 newRoot);
Parameters
Name | Type | Description |
---|---|---|
tree | DynamicTree | Dynamic merkle tree |
index | uint256 | Index of the leaf to update |
oldValue | bytes32 | Previous value of the leaf |
branch | bytes32[] | Proof of inclusion of previous value into the tree |
newValue | bytes32 | New leaf value to assign |
Returns
Name | Type | Description |
---|---|---|
newRoot | bytes32 | New value for the Merkle Root after the leaf is updated |
Contents
- GasData
- ChainGas
- GasDataLib
- Header
- MessageFlag
- HeaderLib
- Number
- NumberLib
- Request
- RequestLib
- Tips
- TipsLib
GasData
GasData in encoded data with "basic information about gas prices" for some chain.
type GasData is uint96;
ChainGas
ChainGas is encoded data with given chain's "basic information about gas prices".
type ChainGas is uint128;
GasDataLib
Library for encoding and decoding GasData and ChainGas structs.
GasData
GasData
is a struct to store the "basic information about gas prices", that could
be later used to approximate the cost of a message execution, and thus derive the
minimal tip values for sending a message to the chain.
GasData
is supposed to be cached byGasOracle
contract, allowing to store the approximates instead of the exact values, and thus save on storage costs.- For instance, if
GasOracle
only updates the values on +- 10% change, having an 0.4% error on the approximates would be acceptable.GasData
is supposed to be included in the Origin's state, which are synced across chains using Agent-signed snapshots and attestations.
GasData stack layout (from highest bits to lowest)
Position | Field | Type | Bytes | Description |
---|---|---|---|---|
(012..010] | gasPrice | uint16 | 2 | Gas price for the chain (in Wei per gas unit) |
(010..008] | dataPrice | uint16 | 2 | Calldata price (in Wei per byte of content) |
(008..006] | execBuffer | uint16 | 2 | Tx fee safety buffer for message execution (in Wei) |
(006..004] | amortAttCost | uint16 | 2 | Amortized cost for attestation submission (in Wei) |
(004..002] | etherPrice | uint16 | 2 | Chain's Ether Price / Mainnet Ether Price (in BWAD) |
(002..000] | markup | uint16 | 2 | Markup for the message execution (in BWAD) |
See Number.sol for more details on
Number
type and BWAD (binary WAD) math.
ChainGas stack layout (from highest bits to lowest)
Position | Field | Type | Bytes | Description |
---|---|---|---|---|
(016..004] | gasData | uint96 | 12 | Chain's gas data |
(004..000] | domain | uint32 | 4 | Chain's domain |
State Variables
SHIFT_GAS_PRICE
Amount of bits to shift to gasPrice field
uint96 private constant SHIFT_GAS_PRICE = 10 * 8;
SHIFT_DATA_PRICE
Amount of bits to shift to dataPrice field
uint96 private constant SHIFT_DATA_PRICE = 8 * 8;
SHIFT_EXEC_BUFFER
Amount of bits to shift to execBuffer field
uint96 private constant SHIFT_EXEC_BUFFER = 6 * 8;
SHIFT_AMORT_ATT_COST
Amount of bits to shift to amortAttCost field
uint96 private constant SHIFT_AMORT_ATT_COST = 4 * 8;
SHIFT_ETHER_PRICE
Amount of bits to shift to etherPrice field
uint96 private constant SHIFT_ETHER_PRICE = 2 * 8;
SHIFT_GAS_DATA
Amount of bits to shift to gasData field
uint128 private constant SHIFT_GAS_DATA = 4 * 8;
Functions
encodeGasData
Returns an encoded GasData struct with the given fields.
function encodeGasData(
Number gasPrice_,
Number dataPrice_,
Number execBuffer_,
Number amortAttCost_,
Number etherPrice_,
Number markup_
) internal pure returns (GasData);
Parameters
Name | Type | Description |
---|---|---|
gasPrice_ | Number | Gas price for the chain (in Wei per gas unit) |
dataPrice_ | Number | Calldata price (in Wei per byte of content) |
execBuffer_ | Number | Tx fee safety buffer for message execution (in Wei) |
amortAttCost_ | Number | Amortized cost for attestation submission (in Wei) |
etherPrice_ | Number | Ratio of Chain's Ether Price / Mainnet Ether Price (in BWAD) |
markup_ | Number | Markup for the message execution (in BWAD) |
wrapGasData
Wraps padded uint256 value into GasData struct.
function wrapGasData(uint256 paddedGasData) internal pure returns (GasData);
gasPrice
Returns the gas price, in Wei per gas unit.
function gasPrice(GasData data) internal pure returns (Number);
dataPrice
Returns the calldata price, in Wei per byte of content.
function dataPrice(GasData data) internal pure returns (Number);
execBuffer
Returns the tx fee safety buffer for message execution, in Wei.
function execBuffer(GasData data) internal pure returns (Number);
amortAttCost
Returns the amortized cost for attestation submission, in Wei.
function amortAttCost(GasData data) internal pure returns (Number);
etherPrice
Returns the ratio of Chain's Ether Price / Mainnet Ether Price, in BWAD math.
function etherPrice(GasData data) internal pure returns (Number);
markup
Returns the markup for the message execution, in BWAD math.
function markup(GasData data) internal pure returns (Number);
encodeChainGas
Returns an encoded ChainGas struct with the given fields.
function encodeChainGas(GasData gasData_, uint32 domain_) internal pure returns (ChainGas);
Parameters
Name | Type | Description |
---|---|---|
gasData_ | GasData | Chain's gas data |
domain_ | uint32 | Chain's domain |
wrapChainGas
Wraps padded uint256 value into ChainGas struct.
function wrapChainGas(uint256 paddedChainGas) internal pure returns (ChainGas);
gasData
Returns the chain's gas data.
function gasData(ChainGas data) internal pure returns (GasData);
domain
Returns the chain's domain.
function domain(ChainGas data) internal pure returns (uint32);
snapGasHash
Returns the hash for the list of ChainGas structs.
function snapGasHash(ChainGas[] memory snapGas) internal pure returns (bytes32 snapGasHash_);
Header
Header is encoded data with "general routing information".
type Header is uint136;
MessageFlag
Types of messages supported by Origin-Destination
- Base: message sent by protocol user, contains tips
- Manager: message sent between AgentManager contracts located on different chains, no tips
enum MessageFlag {
Base,
Manager
}
HeaderLib
Library for formatting the header part of the messages used by Origin and Destination.
- Header represents general information for routing a Message for Origin and Destination.
- Header occupies a single storage word, and thus is stored on stack instead of being stored in memory.
Header stack layout (from highest bits to lowest)
Position | Field | Type | Bytes | Description |
---|---|---|---|---|
(017..016] | flag | uint8 | 1 | Flag specifying the type of message |
(016..012] | origin | uint32 | 4 | Domain where message originated |
(012..008] | nonce | uint32 | 4 | Message nonce on the origin domain |
(008..004] | destination | uint32 | 4 | Domain where message will be executed |
(004..000] | optimisticPeriod | uint32 | 4 | Optimistic period that will be enforced |
State Variables
SHIFT_FLAG
Amount of bits to shift to flag field
uint136 private constant SHIFT_FLAG = 16 * 8;
SHIFT_ORIGIN
Amount of bits to shift to origin field
uint136 private constant SHIFT_ORIGIN = 12 * 8;
SHIFT_NONCE
Amount of bits to shift to nonce field
uint136 private constant SHIFT_NONCE = 8 * 8;
SHIFT_DESTINATION
Amount of bits to shift to destination field
uint136 private constant SHIFT_DESTINATION = 4 * 8;
Functions
encodeHeader
Returns an encoded header with provided fields
function encodeHeader(MessageFlag flag_, uint32 origin_, uint32 nonce_, uint32 destination_, uint32 optimisticPeriod_)
internal
pure
returns (Header);
Parameters
Name | Type | Description |
---|---|---|
flag_ | MessageFlag | |
origin_ | uint32 | Domain of origin chain |
nonce_ | uint32 | Message nonce on origin chain |
destination_ | uint32 | Domain of destination chain |
optimisticPeriod_ | uint32 | Optimistic period for message execution |
isHeader
Checks that the header is a valid encoded header.
function isHeader(uint256 paddedHeader) internal pure returns (bool);
wrapPadded
Wraps the padded encoded request into a Header-typed value.
The "padded" header is simply an encoded header casted to uint256 (highest bits are set to zero). Casting to uint256 is done automatically in Solidity, so no extra actions from consumers are needed. The highest bits are discarded, so that the contracts dealing with encoded headers don't need to be updated, if a new field is added.
function wrapPadded(uint256 paddedHeader) internal pure returns (Header);
leaf
Returns header's hash: a leaf to be inserted in the "Message mini-Merkle tree".
function leaf(Header header) internal pure returns (bytes32 hashedHeader);
flag
Returns header's flag field
function flag(Header header) internal pure returns (MessageFlag);
origin
Returns header's origin field
function origin(Header header) internal pure returns (uint32);
nonce
Returns header's nonce field
function nonce(Header header) internal pure returns (uint32);
destination
Returns header's destination field
function destination(Header header) internal pure returns (uint32);
optimisticPeriod
Returns header's optimistic seconds field
function optimisticPeriod(Header header) internal pure returns (uint32);
_flag
Returns header's flag field without casting to MessageFlag
function _flag(uint256 paddedHeader) private pure returns (uint8);
Number
Number is a compact representation of uint256, that is fit into 16 bits with the maximum relative error under 0.4%.
type Number is uint16;
NumberLib
Number
Library for compact representation of uint256 numbers.
- Number is stored using mantissa and exponent, each occupying 8 bits.
- Numbers under 2**8 are stored as
mantissa
withexponent = 0xFF
. - Numbers at least 2**8 are approximated as
(256 + mantissa) << exponent
0 <= mantissa < 256
0 <= exponent <= 247
(256 * 2**248
doesn't fit into uint256)
Number stack layout (from highest bits to lowest)
Position | Field | Type | Bytes |
---|---|---|---|
(002..001] | mantissa | uint8 | 1 |
(001..000] | exponent | uint8 | 1 |
State Variables
SHIFT_MANTISSA
Amount of bits to shift to mantissa field
uint16 private constant SHIFT_MANTISSA = 8;
BWAD_SHIFT
For bwad math (binary wad) we use 2**64 as "wad" unit.
We are using not using 10**18 as wad, because it is not stored precisely in NumberLib.
uint256 internal constant BWAD_SHIFT = 64;
BWAD
uint256 internal constant BWAD = 1 << BWAD_SHIFT;
PER_MILLE_SHIFT
~0.1% in bwad units.
uint256 internal constant PER_MILLE_SHIFT = BWAD_SHIFT - 10;
PER_MILLE
uint256 internal constant PER_MILLE = 1 << PER_MILLE_SHIFT;
Functions
compress
Compresses uint256 number into 16 bits.
function compress(uint256 value) internal pure returns (Number);
decompress
Decompresses 16 bits number into uint256.
The outcome is an approximation of the original number: (value - value / 256) < number <= value
.
function decompress(Number number) internal pure returns (uint256 value);
mostSignificantBit
Returns the most significant bit of x
https://solidity-by-example.org/bitwise/
function mostSignificantBit(uint256 x) internal pure returns (uint256 msb);
_encode
Wraps (mantissa, exponent) pair into Number.
function _encode(uint8 mantissa, uint8 exponent) private pure returns (Number);
Request
Request is encoded data with "message execution request".
type Request is uint192;
RequestLib
Library for formatting the request part of the base messages.
- Request represents a message sender requirements for the message execution on the destination chain.
- Request occupies a single storage word, and thus is stored on stack instead of being stored in memory.
gasDrop field is included for future compatibility and is ignored at the moment.
Request stack layout (from highest bits to lowest)
Position | Field | Type | Bytes | Description |
---|---|---|---|---|
(024..012] | gasDrop | uint96 | 12 | Minimum amount of gas token to drop to the recipient |
(012..004] | gasLimit | uint64 | 8 | Minimum amount of gas units to supply for execution |
(004..000] | version | uint32 | 4 | Base message version to pass to the recipient |
State Variables
SHIFT_GAS_DROP
Amount of bits to shift to gasDrop field
uint192 private constant SHIFT_GAS_DROP = 12 * 8;
SHIFT_GAS_LIMIT
Amount of bits to shift to gasLimit field
uint192 private constant SHIFT_GAS_LIMIT = 4 * 8;
Functions
encodeRequest
Returns an encoded request with the given fields
function encodeRequest(uint96 gasDrop_, uint64 gasLimit_, uint32 version_) internal pure returns (Request);
Parameters
Name | Type | Description |
---|---|---|
gasDrop_ | uint96 | Minimum amount of gas token to drop to the recipient (ignored at the moment) |
gasLimit_ | uint64 | Minimum amount of gas units to supply for execution |
version_ | uint32 | Base message version to pass to the recipient |
wrapPadded
Wraps the padded encoded request into a Request-typed value.
The "padded" request is simply an encoded request casted to uint256 (highest bits are set to zero). Casting to uint256 is done automatically in Solidity, so no extra actions from consumers are needed. The highest bits are discarded, so that the contracts dealing with encoded requests don't need to be updated, if a new field is added.
function wrapPadded(uint256 paddedRequest) internal pure returns (Request);
gasDrop
Returns the requested of gas token to drop to the recipient.
function gasDrop(Request request) internal pure returns (uint96);
gasLimit
Returns the requested minimum amount of gas units to supply for execution.
function gasLimit(Request request) internal pure returns (uint64);
version
Returns the requested base message version to pass to the recipient.
function version(Request request) internal pure returns (uint32);
Tips
Tips is encoded data with "tips paid for sending a base message". Note: even though uint256 is also an underlying type for MemView, Tips is stored ON STACK.
type Tips is uint256;
TipsLib
Tips
Library for formatting the tips part of the base messages.
How the tips are awarded
Tips are paid for sending a base message, and are split across all the agents that made the message execution on destination chain possible.
Summit tips
Split between:
- Guard posting a snapshot with state ST_G for the origin chain.
- Notary posting a snapshot SN_N using ST_G. This creates attestation A.
- Notary posting a message receipt after it is executed on destination chain.
Attestation tips
Paid to:
- Notary posting attestation A to destination chain.
Execution tips
Paid to:
- First executor performing a valid execution attempt (correct proofs, optimistic period over), using attestation A to prove message inclusion on origin chain, whether the recipient reverted or not.
Delivery tips.
Paid to:
- Executor who successfully executed the message on destination chain.
Tips encoding
- Tips occupy a single storage word, and thus are stored on stack instead of being stored in memory.
- The actual tip values should be determined by multiplying stored values by divided by TIPS_MULTIPLIER=2**32.
- Tips are packed into a single word of storage, while allowing real values up to ~8*10**28 for every tip category.
The only downside is that the "real tip values" are now multiplies of ~4*10**9, which should be fine even for the chains with the most expensive gas currency.
Tips stack layout (from highest bits to lowest)
Position | Field | Type | Bytes | Description |
---|---|---|---|---|
(032..024] | summitTip | uint64 | 8 | Tip for agents interacting with Summit contract |
(024..016] | attestationTip | uint64 | 8 | Tip for Notary posting attestation to Destination contract |
(016..008] | executionTip | uint64 | 8 | Tip for valid execution attempt on destination chain |
(008..000] | deliveryTip | uint64 | 8 | Tip for successful message delivery on destination chain |
State Variables
SHIFT_SUMMIT_TIP
Amount of bits to shift to summitTip field
uint256 private constant SHIFT_SUMMIT_TIP = 24 * 8;
SHIFT_ATTESTATION_TIP
Amount of bits to shift to attestationTip field
uint256 private constant SHIFT_ATTESTATION_TIP = 16 * 8;
SHIFT_EXECUTION_TIP
Amount of bits to shift to executionTip field
uint256 private constant SHIFT_EXECUTION_TIP = 8 * 8;
Functions
encodeTips
Returns encoded tips with the given fields
function encodeTips(uint64 summitTip_, uint64 attestationTip_, uint64 executionTip_, uint64 deliveryTip_)
internal
pure
returns (Tips);
Parameters
Name | Type | Description |
---|---|---|
summitTip_ | uint64 | Tip for agents interacting with Summit contract, divided by TIPS_MULTIPLIER |
attestationTip_ | uint64 | Tip for Notary posting attestation to Destination contract, divided by TIPS_MULTIPLIER |
executionTip_ | uint64 | Tip for valid execution attempt on destination chain, divided by TIPS_MULTIPLIER |
deliveryTip_ | uint64 | Tip for successful message delivery on destination chain, divided by TIPS_MULTIPLIER |
encodeTips256
Convenience function to encode tips with uint256 values.
function encodeTips256(uint256 summitTip_, uint256 attestationTip_, uint256 executionTip_, uint256 deliveryTip_)
internal
pure
returns (Tips);
wrapPadded
Wraps the padded encoded tips into a Tips-typed value.
There is no actual padding here, as the underlying type is already uint256, but we include this function for consistency and to be future-proof, if tips will eventually use anything smaller than uint256.
function wrapPadded(uint256 paddedTips) internal pure returns (Tips);
emptyTips
Returns a formatted Tips payload specifying empty tips.
function emptyTips() internal pure returns (Tips);
Returns
Name | Type | Description |
---|---|---|
<none> | Tips | Formatted tips |
leaf
Returns tips's hash: a leaf to be inserted in the "Message mini-Merkle tree".
function leaf(Tips tips) internal pure returns (bytes32 hashedTips);
summitTip
Returns summitTip field
function summitTip(Tips tips) internal pure returns (uint64);
attestationTip
Returns attestationTip field
function attestationTip(Tips tips) internal pure returns (uint64);
executionTip
Returns executionTip field
function executionTip(Tips tips) internal pure returns (uint64);
deliveryTip
Returns deliveryTip field
function deliveryTip(Tips tips) internal pure returns (uint64);
value
Returns total value of the tips payload. This is the sum of the encoded values, scaled up by TIPS_MULTIPLIER
function value(Tips tips) internal pure returns (uint256 value_);
matchValue
Increases the delivery tip to match the new value.
function matchValue(Tips tips, uint256 newValue) internal pure returns (Tips newTips);
ChainContext
Library for accessing chain context variables as tightly packed integers. Messaging contracts should rely on this library for accessing chain context variables instead of doing the casting themselves.
Functions
blockNumber
Returns the current block number as uint40.
Reverts if block number is greater than 40 bits, which is not supposed to happen until the block.timestamp overflows (assuming block time is at least 1 second).
function blockNumber() internal view returns (uint40);
blockTimestamp
Returns the current block timestamp as uint40.
Reverts if block timestamp is greater than 40 bits, which is supposed to happen approximately in year 36835.
function blockTimestamp() internal view returns (uint40);
chainId
Returns the chain id as uint32.
Reverts if chain id is greater than 32 bits, which is not supposed to happen in production.
function chainId() internal view returns (uint32);
Constants
AGENT_TREE_HEIGHT
Height of the Agent Merkle Tree
uint256 constant AGENT_TREE_HEIGHT = 32;
ORIGIN_TREE_HEIGHT
Height of the Origin Merkle Tree
uint256 constant ORIGIN_TREE_HEIGHT = 32;
SNAPSHOT_TREE_HEIGHT
Height of the Snapshot Merkle Tree. Allows up to 64 leafs, e.g. up to 32 states
uint256 constant SNAPSHOT_TREE_HEIGHT = 6;
ATTESTATION_LENGTH
See Attestation.sol: (bytes32,bytes32,uint32,uint40,uint40): 32+32+4+5+5
uint256 constant ATTESTATION_LENGTH = 78;
GAS_DATA_LENGTH
See GasData.sol: (uint16,uint16,uint16,uint16,uint16,uint16): 2+2+2+2+2+2
uint256 constant GAS_DATA_LENGTH = 12;
RECEIPT_LENGTH
See Receipt.sol: (uint32,uint32,bytes32,bytes32,uint8,address,address,address): 4+4+32+32+1+20+20+20
uint256 constant RECEIPT_LENGTH = 133;
STATE_LENGTH
See State.sol: (bytes32,uint32,uint32,uint40,uint40,GasData): 32+4+4+5+5+len(GasData)
uint256 constant STATE_LENGTH = 50 + GAS_DATA_LENGTH;
SNAPSHOT_MAX_STATES
Maximum amount of states in a single snapshot. Each state produces two leafs in the tree
uint256 constant SNAPSHOT_MAX_STATES = 1 << (SNAPSHOT_TREE_HEIGHT - 1);
HEADER_LENGTH
See Header.sol: (uint8,uint32,uint32,uint32,uint32): 1+4+4+4+4
uint256 constant HEADER_LENGTH = 17;
REQUEST_LENGTH
See Request.sol: (uint96,uint64,uint32): 12+8+4
uint256 constant REQUEST_LENGTH = 24;
TIPS_LENGTH
See Tips.sol: (uint64,uint64,uint64,uint64): 8+8+8+8
uint256 constant TIPS_LENGTH = 32;
TIPS_GRANULARITY
The amount of discarded last bits when encoding tip values
uint256 constant TIPS_GRANULARITY = 32;
TIPS_MULTIPLIER
Tip values could be only the multiples of TIPS_MULTIPLIER
uint256 constant TIPS_MULTIPLIER = 1 << TIPS_GRANULARITY;
ATTESTATION_VALID_SALT
Salts for signing various statements
bytes32 constant ATTESTATION_VALID_SALT = keccak256("ATTESTATION_VALID_SALT");
ATTESTATION_INVALID_SALT
bytes32 constant ATTESTATION_INVALID_SALT = keccak256("ATTESTATION_INVALID_SALT");
RECEIPT_VALID_SALT
bytes32 constant RECEIPT_VALID_SALT = keccak256("RECEIPT_VALID_SALT");
RECEIPT_INVALID_SALT
bytes32 constant RECEIPT_INVALID_SALT = keccak256("RECEIPT_INVALID_SALT");
SNAPSHOT_VALID_SALT
bytes32 constant SNAPSHOT_VALID_SALT = keccak256("SNAPSHOT_VALID_SALT");
STATE_INVALID_SALT
bytes32 constant STATE_INVALID_SALT = keccak256("STATE_INVALID_SALT");
AGENT_ROOT_OPTIMISTIC_PERIOD
Optimistic period for new agent roots in LightManager
uint32 constant AGENT_ROOT_OPTIMISTIC_PERIOD = 1 days;
AGENT_ROOT_PROPOSAL_TIMEOUT
Timeout between the agent root could be proposed and resolved in LightManager
uint32 constant AGENT_ROOT_PROPOSAL_TIMEOUT = 12 hours;
BONDING_OPTIMISTIC_PERIOD
uint32 constant BONDING_OPTIMISTIC_PERIOD = 1 days;
DISPUTE_TIMEOUT_NOTARY
Amount of time that the Notary will not be considered active after they won a dispute
uint32 constant DISPUTE_TIMEOUT_NOTARY = 12 hours;
FRESH_DATA_TIMEOUT
Amount of time without fresh data from Notaries before contract owner can resolve stuck disputes manually
uint256 constant FRESH_DATA_TIMEOUT = 4 hours;
MAX_CONTENT_BYTES
Maximum bytes per message = 2 KiB (somewhat arbitrarily set to begin)
uint256 constant MAX_CONTENT_BYTES = 2 * 2 ** 10;
MAX_SUMMIT_TIP
Maximum value for the summit tip that could be set in GasOracle
uint256 constant MAX_SUMMIT_TIP = 0.01 ether;
CallerNotAgentManager
error CallerNotAgentManager();
CallerNotDestination
error CallerNotDestination();
CallerNotInbox
error CallerNotInbox();
CallerNotSummit
error CallerNotSummit();
IncorrectAttestation
error IncorrectAttestation();
IncorrectAgentDomain
error IncorrectAgentDomain();
IncorrectAgentIndex
error IncorrectAgentIndex();
IncorrectAgentProof
error IncorrectAgentProof();
IncorrectAgentRoot
error IncorrectAgentRoot();
IncorrectDataHash
error IncorrectDataHash();
IncorrectDestinationDomain
error IncorrectDestinationDomain();
IncorrectOriginDomain
error IncorrectOriginDomain();
IncorrectSnapshotProof
error IncorrectSnapshotProof();
IncorrectSnapshotRoot
error IncorrectSnapshotRoot();
IncorrectState
error IncorrectState();
IncorrectStatesAmount
error IncorrectStatesAmount();
IncorrectTipsProof
error IncorrectTipsProof();
IncorrectVersionLength
error IncorrectVersionLength();
IncorrectNonce
error IncorrectNonce();
IncorrectSender
error IncorrectSender();
IncorrectRecipient
error IncorrectRecipient();
FlagOutOfRange
error FlagOutOfRange();
IndexOutOfRange
error IndexOutOfRange();
NonceOutOfRange
error NonceOutOfRange();
OutdatedNonce
error OutdatedNonce();
UnformattedAttestation
error UnformattedAttestation();
UnformattedAttestationReport
error UnformattedAttestationReport();
UnformattedBaseMessage
error UnformattedBaseMessage();
UnformattedCallData
error UnformattedCallData();
UnformattedCallDataPrefix
error UnformattedCallDataPrefix();
UnformattedMessage
error UnformattedMessage();
UnformattedReceipt
error UnformattedReceipt();
UnformattedReceiptReport
error UnformattedReceiptReport();
UnformattedSignature
error UnformattedSignature();
UnformattedSnapshot
error UnformattedSnapshot();
UnformattedState
error UnformattedState();
UnformattedStateReport
error UnformattedStateReport();
LeafNotProven
error LeafNotProven();
MerkleTreeFull
error MerkleTreeFull();
NotEnoughLeafs
error NotEnoughLeafs();
TreeHeightTooLow
error TreeHeightTooLow();
BaseClientOptimisticPeriod
error BaseClientOptimisticPeriod();
MessageOptimisticPeriod
error MessageOptimisticPeriod();
SlashAgentOptimisticPeriod
error SlashAgentOptimisticPeriod();
WithdrawTipsOptimisticPeriod
error WithdrawTipsOptimisticPeriod();
ZeroProofMaturity
error ZeroProofMaturity();
AgentNotGuard
error AgentNotGuard();
AgentNotNotary
error AgentNotNotary();
AgentCantBeAdded
error AgentCantBeAdded();
AgentNotActive
error AgentNotActive();
AgentNotActiveNorUnstaking
error AgentNotActiveNorUnstaking();
AgentNotFraudulent
error AgentNotFraudulent();
AgentNotUnstaking
error AgentNotUnstaking();
AgentUnknown
error AgentUnknown();
AgentRootNotProposed
error AgentRootNotProposed();
AgentRootTimeoutNotOver
error AgentRootTimeoutNotOver();
NotStuck
error NotStuck();
DisputeAlreadyResolved
error DisputeAlreadyResolved();
DisputeNotOpened
error DisputeNotOpened();
DisputeTimeoutNotOver
error DisputeTimeoutNotOver();
GuardInDispute
error GuardInDispute();
NotaryInDispute
error NotaryInDispute();
MustBeSynapseDomain
error MustBeSynapseDomain();
SynapseDomainForbidden
error SynapseDomainForbidden();
AlreadyExecuted
error AlreadyExecuted();
AlreadyFailed
error AlreadyFailed();
DuplicatedSnapshotRoot
error DuplicatedSnapshotRoot();
IncorrectMagicValue
error IncorrectMagicValue();
GasLimitTooLow
error GasLimitTooLow();
GasSuppliedTooLow
error GasSuppliedTooLow();
ContentLengthTooBig
error ContentLengthTooBig();
EthTransferFailed
error EthTransferFailed();
InsufficientEthBalance
error InsufficientEthBalance();
LocalGasDataNotSet
error LocalGasDataNotSet();
RemoteGasDataNotSet
error RemoteGasDataNotSet();
SummitTipTooHigh
error SummitTipTooHigh();
TipsClaimMoreThanEarned
error TipsClaimMoreThanEarned();
TipsClaimZero
error TipsClaimZero();
TipsOverflow
error TipsOverflow();
TipsValueTooLow
error TipsValueTooLow();
IndexedTooMuch
error IndexedTooMuch();
ViewOverrun
error ViewOverrun();
OccupiedMemory
error OccupiedMemory();
UnallocatedMemory
error UnallocatedMemory();
PrecompileOutOfGas
error PrecompileOutOfGas();
MulticallFailed
error MulticallFailed();
SafeCall
Library for performing safe calls to the recipients. Inspired by https://github.com/nomad-xyz/ExcessivelySafeCall
Functions
safeCall
Performs a call to the recipient using the provided gas limit, msg.value and payload in a safe way:
- If the recipient is not a contract, false is returned instead of reverting.
- If the recipient call reverts for any reason, false is returned instead of reverting.
- If the recipient call succeeds, true is returned, and any returned data is ignored.
function safeCall(address recipient, uint256 gasLimit, uint256 msgValue, bytes memory payload)
internal
returns (bool success);
Parameters
Name | Type | Description |
---|---|---|
recipient | address | The recipient of the call |
gasLimit | uint256 | The gas limit to use for the call |
msgValue | uint256 | The msg.value to use for the call |
payload | bytes | The payload to use for the call |
Returns
Name | Type | Description |
---|---|---|
success | bool | True if the call succeeded, false otherwise |
AgentFlag
*Potential statuses for the off-chain bonded agent:
- Unknown: never provided a bond => signature not valid
- Active: has a bond in BondingManager => signature valid
- Unstaking: has a bond in BondingManager, initiated the unstaking => signature not valid
- Resting: used to have a bond in BondingManager, successfully unstaked => signature not valid
- Fraudulent: proven to commit fraud, value in Merkle Tree not updated => signature not valid
- Slashed: proven to commit fraud, value in Merkle Tree was updated => signature not valid Unstaked agent could later be added back to THE SAME domain by staking a bond again. Honest agent: Unknown -> Active -> unstaking -> Resting -> Active ... Malicious agent: Unknown -> Active -> Fraudulent -> Slashed Malicious agent: Unknown -> Active -> Unstaking -> Fraudulent -> Slashed*
enum AgentFlag {
Unknown,
Active,
Unstaking,
Resting,
Fraudulent,
Slashed
}
AgentStatus
Struct for storing an agent in the BondingManager contract.
struct AgentStatus {
AgentFlag flag;
uint32 domain;
uint32 index;
}
DisputeFlag
Potential statuses of an agent in terms of being in dispute
- None: agent is not in dispute
- Pending: agent is in unresolved dispute
- Slashed: agent was in dispute that lead to agent being slashed Note: agent who won the dispute has their status reset to None
enum DisputeFlag {
None,
Pending,
Slashed
}
DisputeStatus
Struct for storing dispute status of an agent.
struct DisputeStatus {
DisputeFlag flag;
uint40 openedAt;
uint40 resolvedAt;
}
DestinationStatus
Struct representing the status of Destination contract.
struct DestinationStatus {
uint40 snapRootTime;
uint40 agentRootTime;
uint32 notaryIndex;
}
MessageStatus
Potential statuses of the message in Execution Hub.
- None: there hasn't been a valid attempt to execute the message yet
- Failed: there was a valid attempt to execute the message, but recipient reverted
- Success: there was a valid attempt to execute the message, and recipient did not revert Note: message can be executed until its status is Success
enum MessageStatus {
None,
Failed,
Success
}
StructureUtils
Functions
verifyActive
Checks that Agent is Active
function verifyActive(AgentStatus memory status) internal pure;
verifyUnstaking
Checks that Agent is Unstaking
function verifyUnstaking(AgentStatus memory status) internal pure;
verifyActiveUnstaking
Checks that Agent is Active or Unstaking
function verifyActiveUnstaking(AgentStatus memory status) internal pure;
verifyFraudulent
Checks that Agent is Fraudulent
function verifyFraudulent(AgentStatus memory status) internal pure;
verifyKnown
Checks that Agent is not Unknown
function verifyKnown(AgentStatus memory status) internal pure;
TypeCasts
Functions
addressToBytes32
function addressToBytes32(address addr) internal pure returns (bytes32);
bytes32ToAddress
function bytes32ToAddress(bytes32 buf) internal pure returns (address);
Contents
AgentManager
Inherits: MessagingBase, AgentManagerEvents, IAgentManager
AgentManager
is used to keep track of all the bonded agents and their statuses.
The exact logic of how the agent statuses are stored and updated is implemented in child contracts,
and depends on whether the contract is used on Synapse Chain or on other chains.
AgentManager
is responsible for the following:
- Keeping track of all the bonded agents and their statuses.
- Keeping track of all the disputes between agents.
- Notifying
AgentSecured
contracts about the opened and resolved disputes. - Notifying
AgentSecured
contracts about the slashed agents.
State Variables
origin
address public origin;
destination
address public destination;
inbox
address public inbox;
_agentDispute
mapping(uint256 => AgentDispute) internal _agentDispute;
_disputes
OpenedDispute[] internal _disputes;
__GAP
gap for upgrade safety
uint256[45] private __GAP;
Functions
onlyInbox
modifier onlyInbox();
onlyWhenStuck
modifier onlyWhenStuck();
__AgentManager_init
function __AgentManager_init(address origin_, address destination_, address inbox_) internal onlyInitializing;
openDispute
Allows Inbox to open a Dispute between a Guard and a Notary, if they are both not in Dispute already.
Will revert if any of these is true:
- Caller is not Inbox.
- Guard or Notary is already in Dispute.
function openDispute(uint32 guardIndex, uint32 notaryIndex) external onlyInbox;
Parameters
Name | Type | Description |
---|---|---|
guardIndex | uint32 | Index of the Guard in the Agent Merkle Tree |
notaryIndex | uint32 | Index of the Notary in the Agent Merkle Tree |
slashAgent
Allows Inbox to slash an agent, if their fraud was proven.
Will revert if any of these is true:
- Caller is not Inbox.
- Domain doesn't match the saved agent domain.
function slashAgent(uint32 domain, address agent, address prover) external onlyInbox;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain where the Agent is active |
agent | address | Address of the Agent |
prover | address | Address that initially provided fraud proof |
getAgent
Returns agent address and their current status for a given agent index.
Will return empty values if agent with given index doesn't exist.
function getAgent(uint256 index) external view returns (address agent, AgentStatus memory status);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Agent index in the Agent Merkle Tree |
Returns
Name | Type | Description |
---|---|---|
agent | address | Agent address |
status | AgentStatus | Status for the given agent: (flag, domain, index) |
agentStatus
Returns (flag, domain, index) for a given agent. See Structures.sol for details.
Will return AgentFlag.Fraudulent for agents that have been proven to commit fraud, but their status is not updated to Slashed yet.
function agentStatus(address agent) public view returns (AgentStatus memory status);
Parameters
Name | Type | Description |
---|---|---|
agent | address | Agent address |
Returns
Name | Type | Description |
---|---|---|
status | AgentStatus | Status for the given agent: (flag, domain, index). |
getDisputesAmount
Returns the number of opened Disputes.
This includes the Disputes that have been resolved already.
function getDisputesAmount() external view returns (uint256);
getDispute
Returns information about the dispute with the given index.
Will revert if dispute with given index hasn't been opened yet.
function getDispute(uint256 index)
external
view
returns (
address guard,
address notary,
address slashedAgent,
address fraudProver,
bytes memory reportPayload,
bytes memory reportSignature
);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Dispute index |
Returns
Name | Type | Description |
---|---|---|
guard | address | Address of the Guard in the Dispute |
notary | address | Address of the Notary in the Dispute |
slashedAgent | address | Address of the Agent who was slashed when Dispute was resolved |
fraudProver | address | Address who provided fraud proof to resolve the Dispute |
reportPayload | bytes | Raw payload with report data that led to the Dispute |
reportSignature | bytes | Guard signature for the report payload |
disputeStatus
Returns the current Dispute status of a given agent. See Structures.sol for details.
Every returned value will be set to zero if agent was not slashed and is not in Dispute.
rival
and disputePtr
will be set to zero if the agent was slashed without being in Dispute.
function disputeStatus(address agent)
external
view
returns (DisputeFlag flag, address rival, address fraudProver, uint256 disputePtr);
Parameters
Name | Type | Description |
---|---|---|
agent | address | Agent address |
Returns
Name | Type | Description |
---|---|---|
flag | DisputeFlag | Flag describing the current Dispute status for the agent: None/Pending/Slashed |
rival | address | Address of the rival agent in the Dispute |
fraudProver | address | Address who provided fraud proof to resolve the Dispute |
disputePtr | uint256 | Index of the opened Dispute PLUS ONE. Zero if agent is not in Dispute. |
_afterAgentSlashed
Hook that is called after agent was slashed in AgentManager and AgentSecured contracts were notified.
function _afterAgentSlashed(uint32 domain, address agent, address prover) internal virtual;
_notifyDisputeOpened
Child contract should implement the logic for notifying AgentSecured contracts about the opened dispute.
function _notifyDisputeOpened(uint32 guardIndex, uint32 notaryIndex) internal virtual;
_notifyDisputeResolved
Child contract should implement the logic for notifying AgentSecured contracts about the resolved dispute.
function _notifyDisputeResolved(uint32 slashedIndex, uint32 rivalIndex) internal virtual;
_slashAgent
Slashes the Agent and notifies the local Destination and Origin contracts about the slashed agent. Should be called when the agent fraud was confirmed.
function _slashAgent(uint32 domain, address agent, address prover) internal;
_resolveDispute
Resolves a Dispute between a slashed Agent and their Rival (if there was one).
function _resolveDispute(uint32 slashedIndex, address prover) internal;
_agentLeaf
Generates leaf to be saved in the Agent Merkle Tree
function _agentLeaf(AgentFlag flag, uint32 domain, address agent) internal pure returns (bytes32);
_storedAgentStatus
Returns the last known status for the agent from the Agent Merkle Tree.
Note: the actual agent status (returned by agentStatus()
) may differ, if agent fraud was proven.
function _storedAgentStatus(address agent) internal view virtual returns (AgentStatus memory);
_getAgent
Returns agent address for the given index. Returns zero for non existing indexes.
function _getAgent(uint256 index) internal view virtual returns (address);
_getIndex
Returns the index of the agent in the Agent Merkle Tree. Returns zero for non existing agents.
function _getIndex(address agent) internal view virtual returns (uint256);
Structs
AgentDispute
struct AgentDispute {
DisputeFlag flag;
uint88 disputePtr;
address fraudProver;
}
OpenedDispute
struct OpenedDispute {
uint32 guardIndex;
uint32 notaryIndex;
uint32 slashedIndex;
}
BondingManager
Inherits: AgentManager, InterfaceBondingManager
BondingManager keeps track of all existing agents on the Synapse Chain.
It utilizes a dynamic Merkle Tree to store the agent information. This enables passing only the
latest merkle root of this tree (referenced as the Agent Merkle Root) to the remote chains,
so that the agents could "register" themselves by proving their current status against this root.
BondingManager
is responsible for the following:
- Keeping track of all existing agents, as well as their statuses. In the MVP version there is no token staking, which will be added in the future. Nonetheless, the agent statuses are still stored in the Merkle Tree, and the agent slashing is still possible, though with no reward/penalty for the reporter/reported.
- Marking agents as "ready to be slashed" once their fraud is proven on the local or remote chain. Anyone could complete the slashing by providing the proof of the current agent status against the current Agent Merkle Root.
- Sending Manager Message to remote
LightManager
to withdraw collected tips from the remote chain. - Accepting Manager Message from remote
LightManager
to slash agents on the Synapse Chain, when their fraud is proven on the remote chain.
State Variables
summit
address public summit;
_agentMap
mapping(address => AgentStatus) private _agentMap;
_domainAgents
mapping(uint32 => address[]) private _domainAgents;
_agents
address[] private _agents;
_agentTree
DynamicTree private _agentTree;
Functions
constructor
constructor(uint32 synapseDomain_) MessagingBase("0.0.3", synapseDomain_);
initialize
function initialize(address origin_, address destination_, address inbox_, address summit_) external initializer;
addAgent
Adds a new agent for the domain. This is either a fresh address (Inactive), or an agent who used to be active on the same domain before (Resting).
Inactive: proof
should be the proof of inclusion of an empty leaf
having index following the last added agent in the tree.
function addAgent(uint32 domain, address agent, bytes32[] memory proof) external onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain where the Agent will be active |
agent | address | Address of the Agent |
proof | bytes32[] | Merkle proof of the Inactive/Resting status for the agent |
initiateUnstaking
Initiates the unstaking of the agent bond. Agent signature is immediately no longer considered valid on Synapse Chain, and will be invalid on other chains once the Light Manager updates their agent merkle root on these chains.
proof
should be the proof of inclusion of the agent leaf
with Active flag having index previously assigned to the agent.
function initiateUnstaking(uint32 domain, address agent, bytes32[] memory proof) external onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain where the Agent is active |
agent | address | Address of the Agent |
proof | bytes32[] | Merkle proof of the Active status for the agent |
completeUnstaking
Completes the unstaking of the agent bond. Agent signature is no longer considered valid on any of the chains.
proof
should be the proof of inclusion of the agent leaf
with Unstaking flag having index previously assigned to the agent.
function completeUnstaking(uint32 domain, address agent, bytes32[] memory proof) external onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain where the Agent was active |
agent | address | Address of the Agent |
proof | bytes32[] | Merkle proof of the unstaking status for the agent |
resolveDisputeWhenStuck
Allows contract owner to resolve a stuck Dispute. This could only be called if no fresh data has been submitted by the Notaries to the Inbox, which is required for the Dispute to be resolved naturally.
Will revert if any of these is true:
- Caller is not contract owner.
- Domain doesn't match the saved agent domain.
slashedAgent
is not in Dispute.- Less than
FRESH_DATA_TIMEOUT
has passed since the last Notary submission to the Inbox.
function resolveDisputeWhenStuck(uint32 domain, address slashedAgent) external onlyOwner onlyWhenStuck;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | |
slashedAgent | address | Agent that is being slashed |
completeSlashing
Completes the slashing of the agent bond. Agent signature is no longer considered valid under the updated Agent Merkle Root.
proof
should be the proof of inclusion of the agent leaf
with Active/Unstaking flag having index previously assigned to the agent.
function completeSlashing(uint32 domain, address agent, bytes32[] memory proof) external;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain where the Agent was active |
agent | address | Address of the Agent |
proof | bytes32[] | Merkle proof of the active/unstaking status for the agent |
remoteSlashAgent
Remote AgentManager should call this function to indicate that the agent has been proven to commit fraud on the origin chain.
This initiates the process of agent slashing. It could be immediately
completed by anyone calling completeSlashing() providing a correct merkle proof
for the OLD agent status.
Note: as an extra security check this function returns its own selector, so that
Destination could verify that a "remote" function was called when executing a manager message.
Will revert if msgOrigin
is equal to contract's local domain.
function remoteSlashAgent(uint32 msgOrigin, uint256 proofMaturity, uint32 domain, address agent, address prover)
external
returns (bytes4 magicValue);
Parameters
Name | Type | Description |
---|---|---|
msgOrigin | uint32 | |
proofMaturity | uint256 | |
domain | uint32 | Domain where the slashed agent was active |
agent | address | Address of the slashed Agent |
prover | address | Address that initially provided fraud proof to remote AgentManager |
Returns
Name | Type | Description |
---|---|---|
magicValue | bytes4 | Selector of this function |
withdrawTips
Withdraws locked base message tips from requested domain Origin to the recipient. Issues a call to a local Origin contract, or sends a manager message to the remote chain.
Could only be called by the Summit contract.
function withdrawTips(address recipient, uint32 origin_, uint256 amount) external;
Parameters
Name | Type | Description |
---|---|---|
recipient | address | Address to withdraw tips to |
origin_ | uint32 | |
amount | uint256 | Tips value to withdraw |
agentRoot
Returns the latest known root of the Agent Merkle Tree.
function agentRoot() external view override returns (bytes32);
getActiveAgents
Returns all active agents for a given domain.
function getActiveAgents(uint32 domain) external view returns (address[] memory agents);
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain to get agents from (ZERO for Guards) |
agentLeaf
Returns a leaf representing the current status of agent in the Agent Merkle Tree.
Will return an empty leaf, if agent is not added to the tree yet.
function agentLeaf(address agent) external view returns (bytes32 leaf);
Parameters
Name | Type | Description |
---|---|---|
agent | address | Agent address |
Returns
Name | Type | Description |
---|---|---|
leaf | bytes32 | Agent leaf in the Agent Merkle Tree |
leafsAmount
Returns a total amount of leafs representing known agents.
This includes active, unstaking, resting and slashed agents. This also includes an empty leaf as the very first entry.
function leafsAmount() external view returns (uint256 amount);
getProof
Returns a proof of inclusion of the agent in the Agent Merkle Tree.
Will return a proof for an empty leaf, if agent is not added to the tree yet. This proof could be used by ANY next new agent that calls {addAgent}.
function getProof(address agent) external view returns (bytes32[] memory proof);
Parameters
Name | Type | Description |
---|---|---|
agent | address | Agent address |
Returns
Name | Type | Description |
---|---|---|
proof | bytes32[] | Merkle proof for the agent |
allLeafs
Returns a full list of leafs from the Agent Merkle Tree.
This might consume a lot of gas, do not use this on-chain.
function allLeafs() public view returns (bytes32[] memory leafs);
getLeafs
Returns a list of leafs from the Agent Merkle Tree with indexes [indexFrom .. indexFrom + amount).
This might consume a lot of gas, do not use this on-chain.
function getLeafs(uint256 indexFrom, uint256 amount) public view returns (bytes32[] memory leafs);
_updateLeaf
Updates value in the Agent Merkle Tree to reflect the newStatus
.
Will revert, if supplied proof for the old value is incorrect.
function _updateLeaf(bytes32 oldValue, bytes32[] memory proof, AgentStatus memory newStatus, address agent) internal;
_notifyDisputeOpened
Notify local AgentSecured contracts about the opened dispute.
function _notifyDisputeOpened(uint32 guardIndex, uint32 notaryIndex) internal override;
_notifyDisputeResolved
Notify local AgentSecured contracts about the resolved dispute.
function _notifyDisputeResolved(uint32 slashedIndex, uint32 rivalIndex) internal override;
_storedAgentStatus
Returns the status of the agent.
function _storedAgentStatus(address agent) internal view override returns (AgentStatus memory);
_getAgent
Returns agent address for the given index. Returns zero for non existing indexes.
function _getAgent(uint256 index) internal view override returns (address agent);
_getIndex
Returns the index of the agent in the Agent Merkle Tree. Returns zero for non existing agents.
function _getIndex(address agent) internal view override returns (uint256 index);
_getLeaf
Returns the current leaf representing agent in the Agent Merkle Tree.
function _getLeaf(address agent) internal view returns (bytes32 leaf);
_getLeaf
Returns a leaf from the Agent Merkle Tree with a given index.
function _getLeaf(uint256 index) internal view returns (bytes32 leaf);
LightManager
Inherits: AgentManager, InterfaceLightManager
LightManager keeps track of all agents on chains other than Synapse Chain.
Is uses the Agent Merkle Roots from the Notary-signed attestations to stay in sync with the BondingManager
.
LightManager
is responsible for the following:
- Accepting the Agent Merkle Roots (passing the optimistic period check) from the
Destination
contract. - Using these roots to enable agents to register themselves by proving their status.
- Accepting Manager Message from
BondingManager
on Synapse Chain to withdraw tips. - Sending Manager Messages to
BondingManager
on Synapse Chain to slash agents, when their fraud is proven.
State Variables
agentRoot
Returns the latest known root of the Agent Merkle Tree.
bytes32 public agentRoot;
_proposedAgentRoot
Pending Agent Merkle Root that was proposed by the contract owner.
bytes32 internal _proposedAgentRoot;
_agentRootProposedAt
Timestamp when the Agent Merkle Root was proposed by the contract owner.
uint256 internal _agentRootProposedAt;
_agentMap
mapping(bytes32 => mapping(address => AgentStatus)) private _agentMap;
_agents
mapping(uint256 => address) private _agents;
_agentIndexes
mapping(address => uint256) private _agentIndexes;
Functions
constructor
constructor(uint32 synapseDomain_) MessagingBase("0.0.3", synapseDomain_);
initialize
function initialize(address origin_, address destination_, address inbox_) external initializer;
proposeAgentRootWhenStuck
Allows contract owner to set the agent root to resolve the "stuck" chain by proposing the new agent root. The contract owner will be able to resolve the proposed agent root after a certain period of time. Note: this function could be called multiple times, each time the timer will be reset. This could only be called if no fresh data has been submitted by the Notaries to the Inbox, indicating that the chain is stuck for one of the reasons:
- All active Notaries are in Dispute.
- No active Notaries exist under the current agent root.
*Will revert if any of the following conditions is met:
- Caller is not the contract owner.
- Agent root is empty.
- The chain is not in a stuck state (has recently received a fresh data from the Notaries).*
function proposeAgentRootWhenStuck(bytes32 agentRoot_) external onlyOwner onlyWhenStuck;
Parameters
Name | Type | Description |
---|---|---|
agentRoot_ | bytes32 | New Agent Merkle Root that is proposed to be set |
cancelProposedAgentRoot
Allows contract owner to cancel the previously proposed agent root.
*Will revert if any of the following conditions is met:
- Caller is not the contract owner.
- No agent root was proposed.*
function cancelProposedAgentRoot() external onlyOwner;
resolveProposedAgentRoot
Allows contract owner to resolve the previously proposed agent root. This will update the agent root, allowing the agents to update their status, effectively resolving the "stuck" chain.
Should proceed with the proposed root, even if new Notary data is available.
This is done to prevent rogue Notaries from going offline and then
indefinitely blocking the agent root resolution, thus onlyWhenStuck
modifier is not used here.
function resolveProposedAgentRoot() external onlyOwner;
updateAgentStatus
Updates agent status, using a proof against the latest known Agent Merkle Root.
Will revert if the provided proof doesn't match the latest merkle root.
function updateAgentStatus(address agent, AgentStatus memory status, bytes32[] memory proof) external;
Parameters
Name | Type | Description |
---|---|---|
agent | address | Agent address |
status | AgentStatus | Structure specifying agent status: (flag, domain, index) |
proof | bytes32[] | Merkle proof of Active status for the agent |
setAgentRoot
Updates the root of Agent Merkle Tree that the Light Manager is tracking. Could be only called by a local Destination contract, which is supposed to verify the attested Agent Merkle Roots.
function setAgentRoot(bytes32 agentRoot_) external;
Parameters
Name | Type | Description |
---|---|---|
agentRoot_ | bytes32 | New Agent Merkle Root |
remoteWithdrawTips
Withdraws locked base message tips from local Origin to the recipient.
Could only be remote-called by BondingManager contract on Synapse Chain. Note: as an extra security check this function returns its own selector, so that Destination could verify that a "remote" function was called when executing a manager message.
function remoteWithdrawTips(uint32 msgOrigin, uint256 proofMaturity, address recipient, uint256 amount)
external
returns (bytes4 magicValue);
Parameters
Name | Type | Description |
---|---|---|
msgOrigin | uint32 | |
proofMaturity | uint256 | |
recipient | address | Address to withdraw tips to |
amount | uint256 | Tips value to withdraw |
proposedAgentRootData
Returns the latest proposed agent root and the timestamp when it was proposed.
Will return zero values if no agent root was proposed, or if the proposed agent root was already resolved.
function proposedAgentRootData() external view returns (bytes32 agentRoot_, uint256 proposedAt_);
_afterAgentSlashed
function _afterAgentSlashed(uint32 domain, address agent, address prover) internal virtual override;
_notifyDisputeOpened
Notify local AgentSecured contracts about the opened dispute.
function _notifyDisputeOpened(uint32 guardIndex, uint32 notaryIndex) internal override;
_notifyDisputeResolved
Notify local AgentSecured contracts about the resolved dispute.
function _notifyDisputeResolved(uint32 slashedIndex, uint32 rivalIndex) internal override;
_setAgentRoot
Updates the Agent Merkle Root that Light Manager is tracking.
function _setAgentRoot(bytes32 _agentRoot) internal;
_storedAgentStatus
Returns the stored status for the agent: whether or not they have been added using latest Agent merkle Root.
function _storedAgentStatus(address agent) internal view override returns (AgentStatus memory);
_getAgent
Returns agent address for the given index. Returns zero for non existing indexes, or for indexes of the agents that have not been added to Light Manager yet.
function _getAgent(uint256 index) internal view override returns (address agent);
_getIndex
Returns the index of the agent in the Agent Merkle Tree. Returns zero for non existing agents, or for agents that have not been added to Light Manager yet.
function _getIndex(address agent) internal view override returns (uint256 index);
Destination
Inherits: ExecutionHub, DestinationEvents, InterfaceDestination
Destination
contract is used for receiving messages from other chains. It relies on
Notary-signed statements to get the truthful states of the remote chains. These states are then
used to verify the validity of the messages sent from the remote chains.
Destination
is responsible for the following:
- Accepting the Attestations from the local Inbox contract.
- Using these Attestations to execute the messages (see parent
ExecutionHub
). - Passing the Agent Merkle Roots from the Attestations to the local LightManager contract, if deployed on a non-Synapse chain.
- Keeping track of the remote domains GasData submitted by Notaries, that could be later consumed
by the local
GasOracle
contract.
State Variables
_nextAgentRoot
Invariant: this is either current LightManager root, or the pending root to be passed to LightManager once its optimistic period is over.
bytes32 internal _nextAgentRoot;
destStatus
Returns status of Destination contract as far as snapshot/agent roots are concerned
DestinationStatus public destStatus;
lastAttestationNonce
Returns the nonce of the last attestation submitted by a Notary with a given agent index.
Will return zero if the Notary hasn't submitted any attestations yet.
mapping(uint32 => uint32) public lastAttestationNonce;
_storedAttestations
Stored lookup data for all accepted Notary Attestations
StoredAttData[] internal _storedAttestations;
_storedGasData
Remote domains GasData submitted by Notaries
mapping(uint32 => StoredGasData) internal _storedGasData;
Functions
constructor
constructor(uint32 synapseDomain_, address agentManager_, address inbox_)
AgentSecured("0.0.3", synapseDomain_, agentManager_, inbox_);
initialize
Initializes Destination contract:
- msg.sender is set as contract owner
function initialize(bytes32 agentRoot) external initializer;
acceptAttestation
Accepts an attestation, which local AgentManager
verified to have been signed
by an active Notary for this chain.
Attestation is created whenever a Notary-signed snapshot is saved in Summit on Synapse Chain.
- Saved Attestation could be later used to prove the inclusion of message in the Origin Merkle Tree.
- Messages coming from chains included in the Attestation's snapshot could be proven.
- Proof only exists for messages that were sent prior to when the Attestation's snapshot was taken.
Will revert if any of these is true:
- Called by anyone other than local
AgentManager
.- Attestation payload is not properly formatted.
- Attestation signer is in Dispute.
- Attestation's snapshot root has been previously submitted. Note: agentRoot and snapGas have been verified by the local
AgentManager
.
function acceptAttestation(
uint32 notaryIndex,
uint256 sigIndex,
bytes memory attPayload,
bytes32 agentRoot,
ChainGas[] memory snapGas
) external onlyInbox returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
notaryIndex | uint32 | Index of Attestation Notary in Agent Merkle Tree |
sigIndex | uint256 | Index of stored Notary signature |
attPayload | bytes | Raw payload with Attestation data |
agentRoot | bytes32 | Agent Merkle Root from the Attestation |
snapGas | ChainGas[] | Gas data for each chain in the Attestation's snapshot |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the Attestation was accepted |
passAgentRoot
Attempts to pass a quarantined Agent Merkle Root to a local Light Manager.
Will do nothing, if root optimistic period is not over.
function passAgentRoot() public returns (bool rootPending);
Returns
Name | Type | Description |
---|---|---|
rootPending | bool | Whether there is a pending agent merkle root left |
attestationsAmount
Returns the total amount of Notaries attestations that have been accepted.
function attestationsAmount() external view returns (uint256);
getAttestation
Returns a Notary-signed attestation with a given index.
Index refers to the list of all attestations accepted by this contract.
Attestations are created on Synapse Chain whenever a Notary-signed snapshot is accepted by Summit. Will return an empty signature if this contract is deployed on Synapse Chain.
function getAttestation(uint256 index) external view returns (bytes memory attPayload, bytes memory attSignature);
Parameters
Name | Type | Description |
---|---|---|
index | uint256 | Attestation index |
Returns
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with Attestation data |
attSignature | bytes | Notary signature for the reported attestation |
getGasData
Returns the gas data for a given chain from the latest accepted attestation with that chain.
Will return empty values if there is no data for the domain, or if the notary who provided the data is in dispute.
function getGasData(uint32 domain) external view returns (GasData gasData, uint256 dataMaturity);
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain for the chain |
Returns
Name | Type | Description |
---|---|---|
gasData | GasData | Gas data for the chain |
dataMaturity | uint256 | Gas data age in seconds |
nextAgentRoot
Returns Agent Merkle Root to be passed to LightManager once its optimistic period is over.
function nextAgentRoot() external view returns (bytes32);
_saveAgentRoot
Saves Agent Merkle Root from the accepted attestation, if there is no pending root to be passed to LightManager. Returns the updated "last snapshot root / last agent root" status struct.
function _saveAgentRoot(bool rootPending, bytes32 agentRoot, uint32 notaryIndex)
internal
returns (DestinationStatus memory status);
_saveGasData
Saves updated values from the snapshot's gas data list.
function _saveGasData(ChainGas[] memory snapGas, uint32 notaryIndex) internal;
Structs
StoredAttData
struct StoredAttData {
bytes32 agentRoot;
bytes32 dataHash;
}
StoredGasData
struct StoredGasData {
GasData gasData;
uint32 notaryIndex;
uint40 submittedAt;
}
GasOracle
Inherits: MessagingBase, GasOracleEvents, InterfaceGasOracle
GasOracle
contract is responsible for tracking the gas data for both local and remote chains.
Local gas data tracking
GasOracle
is using the available tools such astx.gasprice
to track the time-averaged values for different "gas statistics" (to be implemented in the future).- These values are cached, so that the reported values are only changed when a big enough change is detected.
- In the MVP version the gas data is set manually by the owner of the contract.
- The reported values are included in Origin's State, whenever a new message is sent.
This leads to cached "chain gas data" being included in the Guard and Notary snapshots.
Remote gas data tracking
- To track gas data for the remote chains, GasOracle relies on the Notaries to pass the gas data alongside their attestations.
- As the gas data is cached, this leads to a storage write only when the gas data for the remote chain changes significantly.
- GasOracle is in charge of enforcing the optimistic periods for the gas data it gets from
Destination
. - The optimistic period is smaller when the "gas statistics" are increasing, and bigger when they are decreasing.
Reason for that is that the decrease of the gas price leads to lower execution/delivery tips, and we want the Executors to be protected against that.
State Variables
destination
address public immutable destination;
GAS_DATA_INCREASED_OPTIMISTIC_PERIOD
uint256 public constant GAS_DATA_INCREASED_OPTIMISTIC_PERIOD = 5 minutes;
GAS_DATA_DECREASED_OPTIMISTIC_PERIOD
uint256 public constant GAS_DATA_DECREASED_OPTIMISTIC_PERIOD = 1 hours;
_gasData
mapping(uint32 => GasData) internal _gasData;
summitTipWei
uint256 public summitTipWei;
Functions
constructor
constructor(uint32 synapseDomain_, address destination_) MessagingBase("0.0.3", synapseDomain_);
initialize
Initializes GasOracle contract:
- msg.sender is set as contract owner
function initialize() external initializer;
setGasData
MVP function to set the gas data for the given domain.
function setGasData(
uint32 domain,
uint256 gasPrice,
uint256 dataPrice,
uint256 execBuffer,
uint256 amortAttCost,
uint256 etherPrice,
uint256 markup
) external onlyOwner;
setSummitTip
MVP function to set the summit tip.
function setSummitTip(uint256 summitTipWei_) external onlyOwner;
updateGasData
Fetches the latest gas data for the chain from Destination
contract,
and uses it to update the oracle values for the requested chain.
function updateGasData(uint32 domain) external;
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain to update the gas data for |
getDecodedGasData
Returns the gas data for the given domain, in the decoded format.
function getDecodedGasData(uint32 domain)
external
view
returns (
uint256 gasPrice,
uint256 dataPrice,
uint256 execBuffer,
uint256 amortAttCost,
uint256 etherPrice,
uint256 markup
);
Parameters
Name | Type | Description |
---|---|---|
domain | uint32 | Domain of chain to get gas data for |
Returns
Name | Type | Description |
---|---|---|
gasPrice | uint256 | Gas price for the chain (in Wei per gas unit) |
dataPrice | uint256 | Calldata price (in Wei per byte of content) |
execBuffer | uint256 | Tx fee safety buffer for message execution (in Wei) |
amortAttCost | uint256 | Amortized cost for attestation submission (in Wei) |
etherPrice | uint256 | Ratio of Chain's Ether Price / Mainnet Ether Price (in BWAD) |
markup | uint256 | Markup for the message execution (in BWAD) |
getGasData
Returns the gas data for the local chain.
function getGasData() external view returns (uint256 paddedGasData);
getMinimumTips
Returns the minimum tips for sending a message to a given destination.
function getMinimumTips(uint32 destination_, uint256 paddedRequest, uint256 contentLength)
external
view
returns (uint256 paddedTips);
Parameters
Name | Type | Description |
---|---|---|
destination_ | uint32 | |
paddedRequest | uint256 | Padded encoded message execution request on destination chain |
contentLength | uint256 | The length of the message content |
Returns
Name | Type | Description |
---|---|---|
paddedTips | uint256 | Padded encoded minimum tips information |
_setGasData
Sets the gas data for the given domain, and emits a corresponding event.
function _setGasData(uint32 domain, GasData updatedGasData) internal;
_fetchGasData
Returns the updated gas data for the given domain by
optimistically consuming the data from the Destination
contract.
function _fetchGasData(uint32 domain) internal view returns (bool wasUpdated, GasData updatedGasData);
_updateGasParameter
Returns the updated value for the gas parameter, given the maturity of the incoming data.
function _updateGasParameter(Number current, Number incoming, uint256 dataMaturity)
internal
pure
returns (Number updatedParameter);
Origin
Inherits: StateHub, OriginEvents, InterfaceOrigin
Origin
contract is used for sending messages to remote chains. It is done
by inserting the message hashes into the Origin Merkle, which makes it possible to
prove that message was sent using the Merkle proof against the Origin Merkle Root. This essentially
compresses the list of messages into a single 32-byte value that needs to be stored on the destination chain.
Origin
is responsible for the following:
- Formatting the sent message payloads, and inserting their hashes into the Origin Merkle Tree.
- Keeping track of its own historical states (see parent contract
StateHub
). - Enforcing minimum tip values for sent base messages based on the provided execution requests.
- Distributing the collected tips upon request from a local
AgentManager
contract.
State Variables
gasOracle
address public immutable gasOracle;
Functions
onlyRemoteDestination
modifier onlyRemoteDestination(uint32 destination);
constructor
constructor(uint32 synapseDomain_, address agentManager_, address inbox_, address gasOracle_)
AgentSecured("0.0.3", synapseDomain_, agentManager_, inbox_);
initialize
Initializes Origin contract:
- msg.sender is set as contract owner
- State of "empty merkle tree" is saved
function initialize() external initializer;
sendBaseMessage
Send a message to the recipient located on destination domain.
*Recipient has to conform to IMessageRecipient interface, otherwise message won't be delivered. Will revert if any of these is true:
destination
is equal to contract's local domaincontent
length is greater thanMAX_CONTENT_BYTES
msg.value
is lower than value of minimum tips for the given message*
function sendBaseMessage(
uint32 destination,
bytes32 recipient,
uint32 optimisticPeriod,
uint256 paddedRequest,
bytes memory content
) external payable onlyRemoteDestination(destination) returns (uint32 messageNonce, bytes32 messageHash);
Parameters
Name | Type | Description |
---|---|---|
destination | uint32 | Domain of destination chain |
recipient | bytes32 | Address of recipient on destination chain as bytes32 |
optimisticPeriod | uint32 | Optimistic period for message execution on destination chain |
paddedRequest | uint256 | Padded encoded message execution request on destination chain |
content | bytes | Raw bytes content of message |
Returns
Name | Type | Description |
---|---|---|
messageNonce | uint32 | Nonce of the sent message |
messageHash | bytes32 | Hash of the sent message |
sendManagerMessage
Send a manager message to the destination domain.
This could only be called by AgentManager, which takes care of encoding the calldata payload.
Note: (msgOrigin, proofMaturity) security args will be added to payload on the destination chain
so that the AgentManager could verify where the Manager Message came from and how mature is the proof.
Note: function is not payable, as no tips are required for sending a manager message.
Will revert if destination
is equal to contract's local domain.
function sendManagerMessage(uint32 destination, uint32 optimisticPeriod, bytes memory payload)
external
onlyAgentManager
onlyRemoteDestination(destination)
returns (uint32 messageNonce, bytes32 messageHash);
Parameters
Name | Type | Description |
---|---|---|
destination | uint32 | Domain of destination chain |
optimisticPeriod | uint32 | Optimistic period for message execution on destination chain |
payload | bytes | Payload for calling AgentManager on destination chain (with extra security args) |
withdrawTips
Withdraws locked base message tips to the recipient.
Could only be called by a local AgentManager.
function withdrawTips(address recipient, uint256 amount) external onlyAgentManager;
Parameters
Name | Type | Description |
---|---|---|
recipient | address | Address to withdraw tips to |
amount | uint256 | Tips value to withdraw |
getMinimumTipsValue
Returns the minimum tips value for sending a message to a given destination.
Using at least tipsValue
as msg.value
for sendBaseMessage()
will guarantee that the message will be accepted.
function getMinimumTipsValue(uint32 destination, uint256 paddedRequest, uint256 contentLength)
external
view
returns (uint256 tipsValue);
Parameters
Name | Type | Description |
---|---|---|
destination | uint32 | Domain of destination chain |
paddedRequest | uint256 | Padded encoded message execution request on destination chain |
contentLength | uint256 | The length of the message content |
Returns
Name | Type | Description |
---|---|---|
tipsValue | uint256 | Minimum tips value for a message to be accepted |
_sendMessage
Sends the given message to the specified destination. Message hash is inserted into the Origin Merkle Tree, which will enable message execution on destination chain.
function _sendMessage(uint32 destination, uint32 optimisticPeriod, MessageFlag flag, bytes memory body)
internal
returns (uint32 messageNonce, bytes32 messageHash);
_getMinimumTips
Returns the minimum tips for sending a message to the given destination with the given request and content.
function _getMinimumTips(uint32 destination, uint256 paddedRequest, uint256 contentLength)
internal
view
returns (Tips);
_fetchGasData
Gets the current gas data from the gas oracle to be saved as part of the Origin State.
function _fetchGasData() internal view override returns (GasData);
Summit
Inherits: SnapshotHub, SummitEvents, InterfaceSummit
Summit
contract is the cornerstone of the Synapse messaging protocol. This is where the
states of all the remote chains (provided collectively by the Guards and Notaries) are stored. This is
also the place where the tips are distributed among the off-chain actors.
Summit
is responsible for the following:
- Accepting Guard and Notary snapshots from the local
Inbox
contract, and storing the states from these snapshots (see parent contractSnapshotHub
). - Accepting Notary Receipts from the local
Inbox
contract, and using them to distribute tips among the off-chain actors that participated in the message lifecycle.
State Variables
_receipts
mapping(bytes32 => SummitReceipt) private _receipts;
_receiptStatus
mapping(bytes32 => ReceiptStatus) private _receiptStatus;
_receiptTips
mapping(bytes32 => ReceiptTips) private _receiptTips;
_receiptQueue
DoubleEndedQueue.Bytes32Deque private _receiptQueue;
actorTips
Returns earned and claimed tips for the actor. Note: Tips for address(0) belong to the Treasury.
mapping(address => mapping(uint32 => ActorTips)) public actorTips;
Functions
constructor
constructor(uint32 synapseDomain_, address agentManager_, address inbox_)
AgentSecured("0.0.3", synapseDomain_, agentManager_, inbox_);
initialize
function initialize() external initializer;
acceptReceipt
Accepts a receipt, which local AgentManager
verified to have been signed by an active Notary.
Receipt is a statement about message execution status on the remote chain.
- This will distribute the message tips across the off-chain actors once the receipt optimistic period is over.
- Notary who signed the receipt is referenced as the "Receipt Notary".
- Notary who signed the attestation on destination chain is referenced as the "Attestation Notary".
Will revert if any of these is true:
- Called by anyone other than local
AgentManager
.- Receipt body payload is not properly formatted.
- Receipt signer is in Dispute.
- Receipt's snapshot root is unknown.
function acceptReceipt(
uint32 rcptNotaryIndex,
uint32 attNotaryIndex,
uint256 sigIndex,
uint32 attNonce,
uint256 paddedTips,
bytes memory rcptPayload
) external onlyInbox returns (bool wasAccepted);
Parameters
Name | Type | Description |
---|---|---|
rcptNotaryIndex | uint32 | Index of Receipt Notary in Agent Merkle Tree |
attNotaryIndex | uint32 | Index of Attestation Notary in Agent Merkle Tree |
sigIndex | uint256 | Index of stored Notary signature |
attNonce | uint32 | Nonce of the attestation used for proving the executed message |
paddedTips | uint256 | Padded encoded paid tips information |
rcptPayload | bytes | Raw payload with message execution receipt |
Returns
Name | Type | Description |
---|---|---|
wasAccepted | bool | Whether the receipt was accepted |
acceptGuardSnapshot
Accepts a snapshot, which local AgentManager
verified to have been signed by an active Guard.
Snapshot is a list of states for a set of Origin contracts residing on any of the chains. All the states in the Guard-signed snapshot become available for Notary signing. Will revert if any of these is true:
- Called by anyone other than local
AgentManager
.- Snapshot payload is not properly formatted.
- Snapshot contains a state older then the Guard has previously submitted.
function acceptGuardSnapshot(uint32 guardIndex, uint256 sigIndex, bytes memory snapPayload) external onlyInbox;
Parameters
Name | Type | Description |
---|---|---|
guardIndex | uint32 | Index of Guard in Agent Merkle Tree |
sigIndex | uint256 | Index of stored Agent signature |
snapPayload | bytes | Raw payload with snapshot data |
acceptNotarySnapshot
Accepts a snapshot, which local AgentManager
verified to have been signed by an active Notary.
Snapshot is a list of states for a set of Origin contracts residing on any of the chains. Snapshot Merkle Root is calculated and saved for valid snapshots, i.e. snapshots which are only using states previously submitted by any of the Guards.
- Notary could use states singed by the same of different Guards in their snapshot.
- Notary could then proceed to sign the attestation for their submitted snapshot.
Will revert if any of these is true:
- Called by anyone other than local
AgentManager
.- Snapshot payload is not properly formatted.
- Snapshot contains a state older then the Notary has previously submitted.
- Snapshot contains a state that no Guard has previously submitted.
function acceptNotarySnapshot(uint32 notaryIndex, uint256 sigIndex, bytes32 agentRoot, bytes memory snapPayload)
external
onlyInbox
returns (bytes memory attPayload);
Parameters
Name | Type | Description |
---|---|---|
notaryIndex | uint32 | Index of Notary in Agent Merkle Tree |
sigIndex | uint256 | Index of stored Agent signature |
agentRoot | bytes32 | Current root of the Agent Merkle Tree |
snapPayload | bytes | Raw payload with snapshot data |
Returns
Name | Type | Description |
---|---|---|
attPayload | bytes | Raw payload with data for attestation derived from Notary snapshot. |
distributeTips
Distributes tips using the first Receipt from the "receipt quarantine queue". Possible scenarios:
- Receipt queue is empty => does nothing
- Receipt optimistic period is not over => does nothing
- Either of Notaries present in Receipt was slashed => receipt is deleted from the queue
- Either of Notaries present in Receipt in Dispute => receipt is moved to the end of queue
- None of the above => receipt tips are distributed
Returned value makes it possible to do the following: while (distributeTips()) {}
function distributeTips() public returns (bool queuePopped);
Returns
Name | Type | Description |
---|---|---|
queuePopped | bool | Whether the first element was popped from the queue |
withdrawTips
Withdraws locked base message tips from requested domain Origin to the recipient. This is done by a call to a local Origin contract, or by a manager message to the remote chain.
This will revert, if the pending balance of origin tips (earned-claimed) is lower than requested.
function withdrawTips(uint32 origin, uint256 amount) external;
Parameters
Name | Type | Description |
---|---|---|
origin | uint32 | Domain of chain to withdraw tips on |
amount | uint256 | Amount of tips to withdraw |
receiptQueueLength
Returns the amount of receipts in the "Receipt Quarantine Queue".
function receiptQueueLength() external view returns (uint256);
getLatestState
Returns the state with the highest known nonce submitted by any of the currently active Guards.
function getLatestState(uint32 origin) external view returns (bytes memory statePayload);
Parameters
Name | Type | Description |
---|---|---|
origin | uint32 | Domain of origin chain |
Returns
Name | Type | Description |
---|---|---|
statePayload | bytes | Raw payload with latest active Guard state for origin |
_checkNotaryDisputed
*Checks if the given Notary has been disputed.
- Notary was slashed => receipt is invalided and deleted
- Notary is in Dispute => receipt handling is postponed*
function _checkNotaryDisputed(bytes32 messageHash, uint32 notaryIndex) internal returns (bool queuePopped);
_deleteFromQueue
Deletes all stored receipt data and removes it from the queue.
function _deleteFromQueue(bytes32 messageHash) internal;
_moveToBack
Moves the front element of the queue to its back.
function _moveToBack() internal;
_saveReceipt
Saves the message from the receipt into the "quarantine queue". Once message leaves the queue, tips associated with the message are distributed across off-chain actors.
function _saveReceipt(
Receipt rcpt,
Tips tips,
uint32 rcptNotaryIndex,
uint32 attNotaryIndex,
uint256 sigIndex,
uint32 attNonce
) internal returns (bool);
_awardTips
Awards tips to the agent/actors that participated in message lifecycle
function _awardTips(
uint32 rcptNotaryIndex,
uint32 attNotaryIndex,
bytes32 messageHash,
SummitReceipt memory summitRcpt,
ReceiptStatus memory rcptStatus
) internal;
_awardAgentTip
Award tip to the bonded agent
function _awardAgentTip(uint32 agentIndex, uint32 origin, uint64 tip) internal;
_awardActorTip
Award tip to any actor whether bonded or unbonded
function _awardActorTip(address actor, uint32 origin, uint64 tip) internal;
_awardReceiptTip
Award tip for posting Receipt to Summit contract.
function _awardReceiptTip(uint32 rcptNotaryIndex, bool awardFirst, bool awardFinal, uint32 origin, uint64 summitTip)
internal;
_awardSnapshotTip
Award tip for posting Snapshot to Summit contract.
function _awardSnapshotTip(uint32 attNonce, uint8 stateIndex, uint32 origin, uint64 summitTip) internal;
_snapshotTip
Returns "snapshot part" of the summit tip.
function _snapshotTip(uint64 summitTip) internal pure returns (uint64);
_receiptTip
Returns "receipt part" of the summit tip.
function _receiptTip(uint64 summitTip) internal pure returns (uint64);
Structs
SummitReceipt
struct SummitReceipt {
uint32 origin;
uint32 destination;
uint32 attNonce;
uint8 stateIndex;
uint32 attNotaryIndex;
address firstExecutor;
address finalExecutor;
}
ReceiptStatus
struct ReceiptStatus {
MessageStatus status;
bool pending;
bool tipsAwarded;
uint32 receiptNotaryIndex;
uint40 submittedAt;
}
ReceiptTips
struct ReceiptTips {
uint64 summitTip;
uint64 attestationTip;
uint64 executionTip;
uint64 deliveryTip;
}
ActorTips
Struct for storing the actor tips for a given origin domain.
struct ActorTips {
uint128 earned;
uint128 claimed;
}