TLDR: Vault depositors are eligible to receive a share of the fees operators earn in exchange for the due diligence they perform. The precise mechanism of distributing the fees downstream to depositors is left to the vaults, though a few mechanisms are provided out of the box to assist vault operators.
Oyster-based bridging
In this mechanism, pro rata share of fees for every depositor on Ethereum (based on their deposits at the point when the job was created) is calculated within an enclave and submitted on-chain so that depositors can withdraw fees on Arbitrum. This data can be posted in full on Arbitrum or a merkle root of the data can be posted and the merkle tree can be made available either on a server or pushed to IPFS/Swarm.
The data can be divided and submitted in multiple transactions to avoid gas limit issues. Block information is to be submitted as well to ensure that data is always submitted in order and no information is left out. Although anyone can run the enclave, vault operators can take the responsibility of bridging this data and enabling their depositors to claim their share of fees. If vault operators fail to do so, depositors are anyway incentivized to do this themselves.
The flow is as follows:
-
Enclave image for bridging fee allocation data is prebuilt, available publicly and the image’s PCRs are added to the staking contract.
-
The vault owner or any user can deploy the enclave with the specified image in a permissionless way which starts a server that accepts requests for creating signed messages that can be used to transmit relevant information.
-
Enclave deployer verifies the signing key for the enclave on Arbitrum.
-
Enclave deployer then sends a request to the enclave server with the following inputs:
- API keys for RPCs necessary for both Ethereum and Arbitrum
- Number of entries per signed message to enable splitting into multiple transaction
- Block number from which data has to be queried for fee calculations
- (optional) Block number till which data has to be queried for fee calculations. If not specified, the latest block number is used.
-
When a request is received by the server, it pulls the total fee information along with the job data for these fees from the point of last update on Arbitrum. It then calculates the fee per depositor based on their delegation as per the captureTimestamp at which job was created. Fee info from all the jobs during the time period for which fees are being updated are aggregated.
-
Depending on the enclave image, a merkle root or the fee data for all depositors is produced as response.
-
Format for merkle root based response
{ entriesPerTx: 1, startBlock: <integer>, endBlock: <integer>, feeData: [ { data: <merkle root> signature: <Signature on merkle root, txIndex, entriesPerTx, startBlock, endBlock> }, …… ] }
-
Format for fee data for all stakers as response
{ entriesPerTx: <integer>, startBlock: <integer>, endBlock: <integer>, feeData: [ { data: <RLP encoded list of address, fee amount> signature: <Signature on data, txIndex, entriesPerTx, startBlock, endBlock> }, …… ] }
-
-
The enclave deployer can then submit this information to
submitFeeSnapshot
function of the symbioticFeeDistributor contract deployed for the vault. The definition ofsubmitFeeSnapshot
is below:function submitFeeSnapshot( uint256 txIndex, uint256 entriesPerTx, uint256 startBlock, uint256 endBlock, bytes data, bytes signature )
-
submitFeeSnapshot
will make the following checks for accepting a fee snapshot- accepts only if txIndex is not already submitted for the start and end blocks
- entriesPerTx aren’t more than a limit hard coded within the contract. This ensures that someone can’t set a very high entriesPerTx such that transactions never get included.
- startBlock and endBlock should match one of the existing submissions or startBlock should be
last submitted block + 1
. - endBlock > startBlock && endBlock < block.number
- Signature should match signed information as mentioned in signature creation
-
This ensures that data can be submitted by anyone and even if partial data is submitted, there is a way for someone to rebuild the same data from the enclave and resubmit as startBlock, endBlock and entriesPerTx are already specified.
-
Claim flow will be as follows depending on the data submitted on symbioticFeeDistributor
-
Merkle tree based
- Merkle tree data should be stored on a persistent storage platform of choice by the vault operator for easy access to merkle proofs by stakers.
- In case a vault operator either maliciously or due to non availability, doesn’t provide access to merkle tree data to create proofs, users should be able to run the merkle proof generation script based on the data provided in contract and generate the merkle tree data. Hence forced withdrawals are always possible.
-
Fee data for all stakers
- Since all data will be available on chain, stakers can withdraw tokens based on the data by sending tx directly to the
symbioticFeeDistributor
contract
- Since all data will be available on chain, stakers can withdraw tokens based on the data by sending tx directly to the
-