# Telepathy Validator Documentation
## Introduction
The [Telepathy Protocol](https://www.telepathy.xyz/) has been [launched](https://twitter.com/SuccinctLabs/status/1636429568172228609), which removes the need to trust centralized actors or permissioned multisigs when passing information between chains.
For developers wishing to use Telepathy for cross-chain messaging, the standard path is to plug into the [Telepathy Router](https://docs.telepathy.xyz/protocol/contracts#router) by using the send function:
```Solidity
send(uint32 destinationChainId, bytes32 destinationAddress, bytes calldata data)
```
For *existing* contracts that are cannot be modified to make this external call, Telepathy provides a different system: **On-Chain PubSub for events**. Since the [TokenBridge contracts](https://github.com/omni/tokenbridge-contracts) fall into the category, we will demonstrate how this system is used to create a Validator secured by the [Telepathy Light Client](https://docs.telepathy.xyz/protocol/contracts#light-client):
![gnosis-validator](https://i.imgur.com/Be6IAg7.png)
For additional information on the protocol, please refer to the official [Telepathy docs](https://docs.telepathy.xyz/). This specific document will focus on the PubSub system and the Validator.
Telepathy PubSub Technical Walkthrough
---
To listen to any arbitrary event that was emitted on-chain, a contract must first [subscribe](https://github.com/succinctlabs/telepathy-contracts/blob/9ed099dc2eed7a000b2b3d5309da8ccf813a896d/src/pubsub/interfaces/IPubSub.sol#L45-L52) to it:
```Solidity
function subscribe(
uint32 sourceChainId,
address sourceAddress,
address callbackAddress,
bytes32 eventSig,
uint64 startSlot,
uint64 endSlot
) external returns (bytes32 subscriptionId)
```
Then, the subscribed contract specified by `callbackAddress` will receive updates from the [publisher](https://github.com/succinctlabs/telepathy-contracts/blob/9ed099dc2eed7a000b2b3d5309da8ccf813a896d/src/pubsub/TelepathyPublisher.sol#L16) whenever a new event is emitted for that `sourceChainId` + `sourceAddress` + `eventSig`. All events that are published are verified with the Light Client and event proof in [publishEvent()](https://github.com/succinctlabs/telepathy-contracts/blob/9ed099dc2eed7a000b2b3d5309da8ccf813a896d/src/pubsub/TelepathyPublisher.sol#L26).
The subscribed contract *must* implement [ISubscriptionReceiver](https://github.com/succinctlabs/telepathy-contracts/blob/9ed099dc2eed7a000b2b3d5309da8ccf813a896d/src/pubsub/interfaces/ISubscriptionReceiver.sol#L3). We also provide an abstract contract, [SubscriptionReceiver](https://github.com/succinctlabs/telepathy-contracts/blob/9ed099dc2eed7a000b2b3d5309da8ccf813a896d/src/pubsub/interfaces/SubscriptionReceiver.sol#L6), for ensuring that all the checks for handling this event are met. This means that all that needs to be done is implementing this function:
```Solidity
function handlePublishImpl(
bytes32 _subscriptionId,
uint32 _sourceChainId,
address _sourceAddress,
uint64 _slot,
bytes32[] memory _eventTopics,
bytes memory _eventdata
) internal virtual;
```
Gnosis Validator Technical Walkthrough
---
To create a trustless ETH->Gnosis Validator on top of this system, we simply subscribe to the [UserRequestForAffirmation](https://github.com/succinctlabs/tokenbridge-contracts/blob/908a48107919d4ab127f9af07d44d47eac91547e/contracts/upgradeable_contracts/arbitrary_message/ForeignAMB.sol#L6) event emitted by the [ForeignAMB](https://github.com/succinctlabs/tokenbridge-contracts/blob/908a48107919d4ab127f9af07d44d47eac91547e/contracts/upgradeable_contracts/arbitrary_message/ForeignAMB.sol#L5):
```Solidity
event UserRequestForAffirmation(bytes32 indexed messageId, bytes encodedData);
```
In the [Telepathy Validator](https://github.com/succinctlabs/telepathy-contracts/blob/9ed099dc2eed7a000b2b3d5309da8ccf813a896d/examples/pubsub/gnosis/TelepathyValidator.sol#L11) contract deployed on Gnosis, we specify the Ethereum ForeignAMB and the event via its signature:
```Solidity
bytes32 constant AFFIRMATION_EVENT_SIG = keccak256("UserRequestForAffirmation(bytes32,bytes)");
function subscribeToAMBAffirmationEvent() external onlyOwner returns (bytes32) {
ambAffirmationSubscriptionId = telepathyPubSub.subscribe(
SOURCE_CHAIN_ID,
AMB_AFFIRMATION_SOURCE_ADDRESS,
address(this),
AMB_AFFIRMATION_EVENT_SIG,
START_SLOT,
END_SLOT
);
return ambAffirmationSubscriptionId;
}
```
The contract now receives updates whenever this event is emitted. It handles these in the [handlePublishImpl](https://github.com/succinctlabs/telepathy-contracts/blob/9ed099dc2eed7a000b2b3d5309da8ccf813a896d/examples/pubsub/gnosis/TelepathyValidator.sol#L67) function, where additional validation is done:
```Solidity
/// @notice Handle the published AMBAffirmation or BridgeAffirmation event by executing the
/// affirmation in the HomeAMB or HomeBridge.
function handlePublishImpl(
bytes32 _subscriptionId,
uint32 _sourceChainId,
address _sourceAddress,
uint64 _slot,
bytes32 _publishKey,
bytes32[] memory _eventTopics,
bytes memory _eventData
) internal override {
if (_sourceChainId != SOURCE_CHAIN_ID) {
revert InvalidSourceChain(_sourceChainId);
}
if (
_sourceAddress != AMB_AFFIRMATION_SOURCE_ADDRESS
&& _sourceAddress != BRIDGE_AFFIRMATION_SOURCE_ADDRESS
) {
revert InvalidSourceAddress(_sourceAddress);
}
if (
_subscriptionId != ambAffirmationSubscriptionId
&& _subscriptionId != bridgeAffirmationSubscriptionId
) {
revert InvalidSubscriptionId(_subscriptionId);
}
if (_slot < START_SLOT || (END_SLOT != 0 && _slot > END_SLOT)) {
revert InvalidSlot(_slot);
}
bytes32 eventSig = _eventTopics[0];
if (eventSig == AMB_AFFIRMATION_EVENT_SIG) {
bytes32 messageId = _eventTopics[1];
if (executeAffirmationsEnabled) {
// abi.decode strips away the added offset+length prefix, which is added
// by Solidity for all dynamic types.
bytes memory eventData = abi.decode(_eventData, (bytes));
HOME_AMB.executeAffirmation(eventData);
}
emit AMBAffirmationHandled(_publishKey, messageId, _eventData);
} else if (eventSig == BRIDGE_AFFIRMATION_EVENT_SIG) {
(address recipient, uint256 value) = abi.decode(_eventData, (address, uint256));
bytes32 affirmationKey = keccak256(abi.encode(recipient, value));
if (bridgeAffirmationStatuses[affirmationKey] != ExecutionStatus.NONE) {
revert AffirmationNotNew(recipient, value);
}
bridgeAffirmationStatuses[affirmationKey] = ExecutionStatus.PENDING;
emit BridgeAffirmationHandled(_publishKey, recipient, value);
}
}
```
When this contract is added as a Validator, `executeAffirmationsEnabled` can be set to true and the HomeAMB's [executeAffirmation()](https://github.com/succinctlabs/tokenbridge-contracts/blob/908a48107919d4ab127f9af07d44d47eac91547e/contracts/upgradeable_contracts/arbitrary_message/BasicHomeAMB.sol#L20) function.
For now, we emit `AffirmationHandled` with the event data.
Results (AffirmationHandled Subscription)
---
The Telepathy Validator contract is deployed, and the source code can be viewed on GnosisScan [here](https://gnosisscan.io/address/0xbfe15ccbf28c504ddcebcef60753abfff731a675#code). As shown in the [events](https://gnosisscan.io/address/0xbfe15ccbf28c504ddcebcef60753abfff731a675#events) tab, we can see these results successfully handled:
![https://gnosisscan.io/address/0xbfe15ccbf28c504ddcebcef60753abfff731a675#events](https://i.imgur.com/TrTsoPw.png)
You can also find this and the PubSub system in our [contracts repository](https://github.com/succinctlabs/telepathy-contracts) on GitHub.
Results (Succesfull Token Transfer)
---
Token Transfer Tx: https://gnosisscan.io/tx/0x8bc4bdf3db73b5a563e7181451daaf3ec4b4b4579e85a17c9b33767842c1be5f
![](https://i.imgur.com/fQ7KFoB.jpg)
Contracts
---
The working testnet validator is deployed at: [0x8982285539cdd25981e27a84E049aa6390Ab01eD](https://gnosisscan.io/address/0x8982285539cdd25981e27a84e049aa6390ab01ed.).
All the smart contracts related to the Telepathy Validator are available in our [open-source repo](https://github.com/succinctlabs/telepathy-contracts). The main components consist of the:
- [Light Client](https://github.com/succinctlabs/telepathy-contracts/blob/main/src/lightclient/LightClient.sol): A contract which uses our [sync committee zkSNARK](https://github.com/succinctlabs/telepathy-circuits) to keep Gnosis Chain updated with Ethereum headers.
- [Protocol Explanation](https://docs.telepathy.xyz/protocol/overview)
- [Telepathy PubSub](https://github.com/succinctlabs/telepathy-contracts/blob/main/src/pubsub/TelepathyPubSub.sol): A contract which allows one to "subscribe" to events emitted on Ethereum on other chains.
- Refer to the diagram above for an explanation.
- [Telepathy Validator](https://github.com/succinctlabs/telepathy-contracts/blob/main/external/integrations/gnosis/TelepathyValidator.sol): A contract which uses the "PubSub" contract to be notified about affirmation requests and calls back to the Omnibrdige with `executeAffirmation`.
- Refer to the diagram above for an explanation.
For more details on how both of these systems works, refer to the code and comments.
Relayer
---
We have not yet open-sourced the relayer as it is interconnected with our monorepo. Given that we are running the relayer, please let us know if it is necessary to open-source it in the short-term. We plan to add the following:
- Replicas
- Metrics & logging with [Datadog](https://www.datadoghq.com/)
- 24/7 on-call with [Pagerduty](https://www.pagerduty.com/)
Please let us know if there is anything else Gnosis DevOps advises us to add.
Audits
---
- [Light Client](https://github.com/succinctlabs/telepathy-contracts/blob/main/src/lightclient/LightClient.sol): **This contract does need an audit.** It was audited by Trail of Bits, Veridise, and Zellic in early 2023.
- [Telepathy PubSub](https://github.com/succinctlabs/telepathy-contracts/blob/main/src/pubsub/TelepathyPubSub.sol): **This contract needs an audit.** However, the grand majority of the complexity are betwen lines [L35-L65](https://github.com/succinctlabs/telepathy-contracts/blob/main/src/pubsub/TelepathyPublisher.sol#L35-L64) which dispatches to our libraries which are all audited.
- In particular, the following libraries are audited.
- `src/libraries/SimpleSerialize.sol`
- `src/libraries/Typecast.sol`
- Extra Notes:
- `src/pubsub/EventProof.sol`: This library is not directly audited, but it is heavily based on [StateProofHelper.sol](https://github.com/succinctlabs/telepathy-contracts/blob/main/src/libraries/StateProofHelper.sol#L36-L101) which was audited by Trail of Bits and Zellic. We needed to make changes to this file as we also needed the contents of the event, not just the hash.
- [Telepathy Validator](https://github.com/succinctlabs/telepathy-contracts/blob/main/external/integrations/gnosis/TelepathyValidator.sol): **This contract needs an audit.**
In aggregate, we suggest auditing the following folders:
- [src/pubsub](https://github.com/succinctlabs/telepathy-contracts/tree/main/src/pubsub)
- [external/integrations/gnosis](https://github.com/succinctlabs/telepathy-contracts/tree/main/external/integrations/gnosis)
Unit tests are available for all contracts using foundry:
- [test/pubsub](https://github.com/succinctlabs/telepathy-contracts/tree/main/test/pubsub)
- [external/integrations/gnosis/TelepathyValidator.t.sol](https://github.com/succinctlabs/telepathy-contracts/blob/main/external/integrations/gnosis/TelepathyValidator.t.sol)
Testing Contracts
---
To build and test the contracts, follow the following commands
```
curl -L https://foundry.paradigm.xyz | bash
source ~/.bashrc
foundryup
forge build
forge test
```
All tests should pass.