Fluidity Audit Report
Copyright © 2022 by Verilog Solutions. All rights reserved.Oct 26, 2022
by Verilog Solutions

This report presents our engineering engagement with the Fluidity team on their yield generating protocol – Fluidity Protocol.
| Project Name | Fluidity Protocol | 
|---|---|
| Repository Link | https://github.com/fluidity-money/fluidity-app/tree/develop-verilog | 
| Commit Hash | First: 3578295; Final: 26e9450; | 
| Language | Go, Solidity | 
| Chain | Ethereum | 
About Verilog Solutions
About Verilog Solutions
Founded by a group of cryptography researchers and smart contract engineers in North America, Verilog Solutions elevates the security standard for Web3 ecosystems by being a full-stack Web3 security firm covering smart contract security, consensus security, and operational security for Web3 projects.
Verilog Solutions team works closely with major ecosystems and Web3 projects and applies a quality above quantity approach with a continuous security model. Verilog Solutions onboards the best and most innovative projects and provides the best-in-class advisory service on security needs, including on-chain and off-chain components.
Table of Contents
Table of Contents
Service Scope
Service Scope
Service Stages 
Service Stages
Methodology
Methodology
- Code Assessment- We evaluate the overall quality of the code and comments as well as the architecture of the repository.
 - We help the project dev team improve the overall quality of the repository by providing suggestions on refactorization to follow the best practice of Web3 software engineering.
 
- Code Logic Analysis- We dive into the data structures and algorithms in the repository and provide suggestions to improve the data structures and algorithms for the lower time and space complexities.
 - We analyze the hierarchy among multiple modules and the relations among the source code files in the repository and provide suggestions to improve the code architecture with better readability, reusability, and extensibility.
 
- Business Logic Analysis- We study the technical whitepaper and other documents of the project and compare its specification with the functionality implemented in the code for any potential mismatch between them.
 - We analyze the risks and potential vulnerabilities in the business logic and make suggestions to improve the robustness of the project.
 
- Access Control Analysis- We perform a comprehensive assessment of the special roles of the project, including their authorities and privileges.
 - We provide suggestions regarding the best practice of privilege role management according to the standard operating procedures (SOP).
 
- Off-Chain Components Analysis- We analyze the off-chain modules that are interacting with the on-chain functionalities and provide suggestions according to the SOP.
 - We conduct a comprehensive investigation for potential risks and hacks that may happen on the off-chain components and provide suggestions for patches.
 
Audit Scope
Audit Scope
Project Summary
Project Summary
Fluidity is a yield-generating protocol that rewards people for using their cryptocurrencies. Fluidity Money tokens (Fluid Assets) are a 1-to-1 wrapped asset that exposes holders to randomly paid rewards when they use their cryptocurrencies. Rewards are paid out according to a drawing mechanism held on each transaction of their Fluid Assets. These rewards are generated by the cumulative yield generated by the underlying asset, which is deposited and lent on money markets.
Fluidity contains two parts, on-chain, and off-chain components. Below are some major on-chain and off-chain components

- On-chain Components- Fluidity token: it’s a 1-to-1 wrapped asset. User can wrap their principals and receive the same amount of fluidity tokens. Deposited Principals are transferred back to users when they unwrap through the fluidity token contract.
 - Liquidity provider: liquidity provider is the intermediate interface that connects assets with yield-bearing protocols like AAVE / Compound. The assets wrapped through fluidity tokens are transferred to liquidity tokens and then deposited into yield-generating protocols to generate yields. When users unwrap their fluidity token, the liquidity provider will withdraw assets back to users from the yield-bearing protocol.
 - WorkerConfig: it works like a register that registers the Oracle of the fluidity token contract. And it can also enable or disable the emergency mode of the entire protocol.
 
- Off-chain components- block-fluid-transfers-amqp: It collects blocks with Transferevents and sends messages to worker-server.
 - worker-server: the worker on the server-side receives the blocks and transaction data from the block-fluid-transfers-amqp. It filters out transactions unrelated to fluid tokens. Those data are used to randomly draw winners and calculate winners’ payout amounts based on the hypergeometric distribution. It sends out messages containing winners’ info to worker-client.
 - worker-client: the worker on the client-side decodes the winner messages sent from the worker-server. It decodes the winner message and checks the winning status. It will check winning info and filter out invalid winner info. It then sends out winner announcement messages to the transaction-spooler.
 - transaction-spooler: the worker receives messages containing winner announcements from worker-client and scales the winning amount based on token decimals. It then appends rewards info to batched rewards queue if the scaled amount exceeds the rewards threshold.
 - transaction-sender: the worker receives the batched rewards queue sent from the transaction-spooler. It calls FluidToken.batchReward()function to mint rewards to winners.
 
- block-fluid-transfers-amqp: It collects blocks with 
Findings & Improvement Suggestions
Findings & Improvement Suggestions
| Severity | Total | Acknowledged | Resolved | 
| High | 3 | 3 | 3 | 
| Medium | 7 | 7 | 2 | 
| Low | 2 | 2 | 2 | 
| Informational | 9 | 8 | 5 | 
| Undetermined | 1 | 1 | 0 | 
High
High
- Potential signature replay attack and vulnerability.Severity High Source contracts/ethereum/contracts/Token.sol#L257; Commit 3578295; Status Resolved in commit b325a91. - Description- The signature lacks fields for validation (e.g., nonce, timestamp, and token address). This leads to potential signature replay attacks. - When constructing signatures, only fields - winner,- winAmount,- firstBlock,- lastBlockare used. Fluid token supports multiple principle tokens and multiple platforms. It does not specify which fluid token contract it can only be used on. Thus, one signature can be replayed on different fluid token contracts.
 - Exploit Scenario- Mallory uses the signature that is designed to claim manualReward()of USDC to claimmanualReward()for USDT;
 - Mallory uses the signature that is designed to claim manualReward()of USDC to claimmanualReward()for a second time.
 
- Mallory uses the signature that is designed to claim 
 - Recommendations- We suggest constructing signatures according to EIP-712. Fields like chain-id and contract address should be included in messages to prevent signature replay on different fluid tokens. Besides, it can also increase signature readability since most wallets support decoding messages that follow the EIP-712 standard. 
 - Results- Resolved in commit b325a91. The fluidity team added - contractAddressand- chainIdto construct the signatures.
 
- Updating the wrong variable.Severity High File contracts/ethereum/contracts/Token.sol#L292; Commit 26e9450; Status Resolved in commit 5d88bec. - Description- The value - amount/- userAmountMinted + amountis assigned to the wrong variable- userLastMintedBlock_. Replace- userLastMintedBlock_[msg.sender]with- userMint.- if (userHasMinted) { userMint = amount; } else { userMint = userAmountMinted_[msg.sender] + amount; } require(userMint <= userMintLimit_, "mint amount exceeds user limit!");
 - Exploit Scenario- N/A 
 - Recommendations- Change - userLastMintedBlock_[msg.sender]to- userMint.
 - Results- Resolved in commit 5d88bec. 
 
- Lack of function to disable emergency mode Severity High File contracts/ethereum/contracts/WorkerConfig.sol; contracts/ethereum/contracts/Token.sol; Commit 26e9450; Status Resolved in commit 6d8b5ab and e181cef; - Description- The entire protocol will be suspended when it is in emergency mode. However, there is no function to disable the emergency mode and resume working again. 
 - Exploit Scenario- N/A 
 - Recommendations- Add a function to disable the emergency mode. 
 
Medium
Medium
- Lack of two-step process for critical operations Severity Medium Source contracts/ethereum/contracts/Token.sol#L111; Commit 3578295; Status Resolved in commit f56127a. - Description- The critical state variable - rngOracle_can be changed by calling function- Token.updateOracle(), which requires the caller to be- rngOracle_itself and immediately sets the- rngOracle_to a new address. Value change of the critical state variable in a single step is error-prone and can lead to irrevocable mistakes.- rngOracle_is a critical state variable related to critical operations- Token.batchReward()and- Token.manualReward(), which sets the winners and reward amounts.- As the oracle - rngOracle_, it can set oracle to a new address by calling function- Token.updateOracle(). The function requires the function call to be made from- rngOracle_and set the oracle to a new address directly. Once the oracle is set to a new address, only the new oracle address has the authority to update the oracle address. This process is single-step and irrevocable. The new oracle has the right to set the winners and rewards amounts. And if the oracle is set to a zero address, the normal operations of the protocol are halted directly.
 - Exploit Scenario- As the oracle contract, it accidentally set the oracle address of contract Token.sol to a random address. The owner of the new oracle address can call function - Token.batchReward()and- Token.manualReward()to set any award amounts to any users.
 - Recommendations- Implement a two-step process for updating the oracle address. The oracle proposes a new address and the oracle is only updated after the proposed new oracle address executes a call to confirm the change. 
 - Results- Resolved in commit f56127a. A set and claim two-step process was implemented to update the oracle address 
 
- Lack of input data validationSeverity Medium Source contracts/ethereum/contracts/Token.sol#L111; Commit 3578295; Status Acknowledged. - Description- Function - Token.updateOracle()lacks of zero-value check on- newOracle. The protocol's normal operations can be halted if the oracle is set to zero address.- Function - Token.updateOracle()sets critical state variable in single step and lack of zero-value check on parameter- newOracle. Once the oracle is set to the zero address. The contracts can no longer set winners and reward amounts since these states can only be updated by oracle. In this situation, it directly halts the normal operation of the protocol.
 - Exploit Scenario- When the oracle account sets the oracle to the zero address, winners and reward amounts can no longer be set. 
 - Recommendations- Add input validations such as the zero-value check. 
 - Results- Acknowledged. 
 
- Lack of checking in signature recoverySeverity Medium Source contracts/ethereum/contracts/Token.sol#L257; Commit 3578295; Status Resolved in commit cac3886; - Description- Lack of check on - srange before feeding it to- ecrecover(hash, v, r, s)function. This results in potential failure in claim reward via- manualRewarddue to signature recovery failure.- According to EIP-2, all transaction signatures whose s-value is greater than secp256k1n/2 are now considered invalid. A check to make sure - svalue is within range (0, secp256k1n ÷ 2 + 1) needs to be added to prevent signature recovery failure.
 - Exploit Scenario- The input - sis greater than secp256k1n/2 results in the failure of signature recovery and calls to- manualRewardfails.
 - Recommendations- We recommend using OpenZepplin’s cryptography library. 
 - Results- Resolved in commit cac3886. fluidity team modified it based on openzeppelin's ECDSA library. 
 
- Insufficient check for the block range when distributing rewardsSeverity Medium Source contracts/ethereum/contracts/Token.sol; Commit 3578295; Status Acknowledged. - Description- Insufficient check for - firstBlockand- lastBlockin- batchReward()and- manualReward()could result in the rewards being distributed more than one time in a block range.- For function - batchReward(), there is no check against the block range of rewarded blocks. Rewards can be distributed to the same block range with the same winners again if workers in the server with oracle signing rights distribute rewards incorrectly.- For function - manualReward(), there is only one check for- firstBlockand no check for- lastBlock.- winAmountcan be added to- manualRewards_[winner]and rewards will be distributed to users more than one time. This can result in- manualRewards_[winner]being bigger than it should be and users get more rewards than they should.- Checks should be enforced on the smart contract side as workers in the server can work incorrectly or be exploited. 
 - Exploit Scenario- lastRewardedBlock_is 9.- manualRewardis called with- firstBlock10 and- lastBlock20 for winner Alice. Rewards are distributed to Alice.- Then - manualRewardwas called with- firstBlock10 and- lastBlock20 for winner Alice. Rewards are distributed to Alice again.- Alice gets more rewards than she should. 
 - Recommendations- Enforce checks for block range on the smart contract side. 
 - Results- Acknowledged. - Reply from Fluidity team: - “We think manualReward is safe given the spooler implementation.” 
 
- Lack of important variables update functionSeverity Medium File contracts/ethereum/contracts/WorkerConfig.sol contracts/ethereum/contracts/Token.sol Commit 26e9450; Status Acknowledged; - Description- operator_and- emergencyCouncil_are two main privileged roles, these two variables are set when initializing the smart contract. But these two variables can not be changed after initializing. In some cases, the smart contract owner may want to update it.
 - Exploit Scenario- N/A 
 - Recommendations- Add a two-step process to change - operator_and- emergencyCouncil_.
 - Results- Acknowledged. - Reply from Fluidity team: - “We don’t intend to change the operator or emergency council in production as they are both multisigs with stringent requirements.” 
 
- Lack of a two-step process for critical operations. Severity Medium File contracts/ethereum/contracts/Token.sol; Commit 26e9450; Status Acknowledged; - Description- The critical state variable - operator_can be changed by calling function- Token.updateOperator(), which requires the caller to be- operator_itself and immediately sets the- operator_to a new address. Value change of the critical state variable in a single step is error-prone and can lead to irrevocable mistakes.- operator_is a critical state variable related to critical operations- Token.enableEmergencyMode()suspends the protocol, and- Token.batchReward()and- Token.manualReward(), which sets the winners and reward amounts.- As the operator - operator_, he/she can set the operator to a new address by calling function- Token.updateOperator(). The function requires the function call to be made from- operator_and set the operator to a new address directly. Once the operator is set to a new address, only the new operator address has the authority to update the operator address. This process is single-step and irrevocable. The new operator has the right to set the winners and rewards amounts. And if the operator is set to a zero address, the normal operations of the protocol are halted directly.
 - Exploit Scenario- As the operator contract, it accidentally set the operator address of contract Token.sol to a random address. The owner of the new operator address can call function - Token.batchReward()and- Token.manualReward()to set any award amounts to any users.
 - Recommendations- Implement a two-step process for updating the operator address. The operator proposes a new address and the operator is only updated after the proposed new operator address executes a call to confirm the change. 
 - Results- Acknowledged. - Reply from Fluidity team: - “We felt that the nature of the operator/emergency council (being multisigs) would prevent manual error from cropping up in practice along these lines. We will implement a process with the members of the multisig to manually verify the call by shifting the generated input to the safe to an ABI-decorated call and add some extra logging.” 
 
- Lack of emergency mode check for critical operations.Severity Medium File contracts/ethereum/contracts/Token.sol; Commit 26e9450; Status Acknowledged. - Description- The protocol is supposed to be paused after activating the emergency mode. However, critical operation - rc20Out()is not protected by the emergency mode. Attackers are still able to execute the functions and get tokens from the pool by executing the function- erc20Out()in the emergency mode of the protocol.
 - Exploit Scenario- N/A. 
 - Recommendations- Add emergency control for function and - erc20Out().
 - Results- Acknowledged. - Reply from Fluidity team: - We wanted our users to be able to withdraw their funds but not deposit them in an emergency situation, so we didn’t disable - erc20Out.
 
Low
Low
- Lack of event emission for critical operationsSeverity Low Source contracts/ethereum/contracts/Token.sol#L111; Commit 3578295; Status Resolved in commit e8d0a51. - Description- critical function - updateOraclelacks event emission. Event emissions are important for monitoring contracts and detecting suspicious behaviour.- There is no event emission upon the value change of critical state variable - rngOracle_in function- updateOracle().- Operations that transfer value or perform critical operations should trigger events so that users and off-chain monitoring tools can account for important state changes. Events are important for monitoring contracts and detecting suspicious behavior. 
 - Exploit Scenario- N/A 
 - Recommendations- Emit event when updating critical state variable - rngOracle_in function- updateOracle().- event UpdateOracle(address indexed oldOracle, address indexed newOracle); /// @notice updates the trusted oracle to a new address function updateOracle(address newOracle) public { require(msg.sender == rngOracle_, "only the oracle account can use this"); emit UpdateOracle(rngOracle_, newOracle); rngOracle_ = newOracle; }
 - Results- Resolved in commit e8d0a51. 
 
- Lack of event emission for critical operations.Severity Low File contracts/ethereum/contracts/Token.sol; Commit 26e9450; Status Resolved in commit 6d8b5ab; - Description- Critical functions - setRestrictions,- updateWorkerConfig,- updateRewardQuarantineThreshold,- updateMintLimits, and- enableMintLimitslack event emission. Event emissions are important for monitoring contracts and detecting suspicious behavior. Operations that transfer value or perform critical operations should trigger events so that users and off-chain monitoring tools can account for important state changes. Events are important for monitoring contracts and detecting suspicious behavior.
 - Exploit Scenario- N/A. 
 - Recommendations- Add events for these critical functions. 
 - Results- Resolved in commit 6d8b5ab. Events are added for critical operations. 
 
Informational
Informational
- Floating solidity pragma versionSeverity Informational Source contracts/ethereum/contracts/Token.sol; Commit 3578295; Status Resolved in commit fa89c3e. - Description- Current smart contracts use - ^0.8.11. And compilers within versions- ≥ 0.8.11and- <0.9.0can be used to compile those contracts. Therefore, the contract may be deployed with a newer or latest compiler version which generally has higher risks of undiscovered bugs.- It is a good practice to fix the solidity pragma version if the contract is not designed as a package or library that will be used by other projects or developers. - Reference: SWC-103. 
 - Exploit Scenario- N/A 
 - Recommendations- Use the fixed solidity pragma version. 
 - Results- Resolved in commit fa89c3e. 
 
- State variable visibility unspecifiedSeverity Informational Source contracts/ethereum/contracts/Token.sol; Commit 3578295; Status Resolved in commit fa89c3e. - Description- Some state variables’ visibilities are not specified. Labelling the visibility explicitly makes it easier to catch incorrect assumptions about who can access the variable. - Visibility unspecified state variables: - initialized_
 - pool_
 - rngOracle_
 - rewardedBlocks_
 - lastRewardedBlock_
 - The above state variables’ visibilities will be the default visibility - internal. According to the naming style of- Token.sol,- privateor non-public variable is named as variableName_, a name with an underscore suffix.- All private state variables have public getter functions and some of those Visibility-unspecified variables do not have public getter functions. It would not be easy to obtain those variables’ values if they were meant to be publicly accessible. - Specifying variables’ visibility can improve code readability and makes it easier to catch incorrect assumptions about the visibility of those variable. 
 - Exploit Scenario- N/A 
 - Recommendations- Explicitly specify all the state variable’s visibility. 
 - Results- Resolved in commit fa89c3e. 
 
- Inconsistent naming styleSeverity Informational Source contracts/ethereum/contracts/Token.sol#L183; Commit 3578295; Status Acknowledged. - Description- Function naming style is inconsistent in contract - Token.sol. A consistent naming style can improve code readability and make it easier to catch incorrect assumptions about the visibility of the function.- In contract - Token.sol, most of the functions with non-public visibilities are named as _functionName, function name with an underscore prefix. However, the- internalfunction- rewardFromPooland- recoverdo not follow this naming style.- Inconsistent naming style damages the code readability and can easily make people have false visibility assumptions of the function. 
 - Exploit Scenario- N/A 
 - Recommendations- Change function name from - rewardFromPoolto- _rewardFromPool.
 - Results- Acknowledged. 
 
- Redundant assertions for arithmetic operations in Solidity ≥ 0.8Severity Informational Source contracts/ethereum/contracts/Token.sol#L135; Commit 3578295; Status Resolved in commit b4eb458. - Description- The overflow check require statement is unnecessary. Arithmetic operations revert on underflow and overflow since pragma version - 0.8.0.- Inside the function - Token.erc20In(), it has a require statement that checks if the arithmetic operation will overflow.- However, this require statement is unnecessary. Arithmetic operations revert on underflow and overflow since pragma version - 0.8.0. No need for an extra arithmetic overflow check, which also costs extra gas consumption.
 - Exploit Scenario- N/A 
 - Recommendations- Remove the unnecessary arithmetic overflow check for better gas optimization. 
 - Results- Resolved in commit b4eb458. 
 
- Shadowed variable declarationsSeverity Informational Source microservice-ethereum-worker-server/main.go#L145-L145; Commit 3578295; Status Acknowledged. - Description- The two environment variables for - ethFluxAddress_and- tokenFluxAddress_are the same. Need to remind Fluidity to double-check.- ethFluxAddress_ = os.Getenv(EnvAuroraTokenFluxAddress) tokenFluxAddress_ = os.Getenv(EnvAuroraTokenFluxAddress)
 - Exploit Scenario- N/A 
 - Recommendations- Double-check to confirm.
 - Add a comment in the code saying that the two environment variables are purposely the same.
 
 - Results- Acknowledged. 
 
- Magic numbersSeverity Informational Source contracts/ethereum/contracts/Token.sol#L200; Commit 3578295; Status Resolved in commit 2600ff8. - Description- Magic number - 1is used to flag the first block of the last reward in- batchReward()with no comments. This may lead to difficulty in future maintenance.- function batchReward(...){ ... rewardedBlocks_[firstBlock] = 1; ... }
 - Exploit Scenario- N/A 
 - Recommendations- Use a constant variable to represent the magic number. 
 - Results- Resolved in commit 2600ff8. 
 
- Naming issuesSeverity Informational Source contracts/ethereum/contracts/Token.sol#L10-12; Commit 3578295; Status Resolved in commit 0553932. - Description- Distinguishing - FIRST_REWARDED_BLOCKand- LAST_REWARDED_BLOCKin terms of value and name is redundant since the code logic defined in- manualReward()does not check their specific value. They are only used to flag blocks and can be replaced with a single constant variable.- /// @dev sentinel to mark the start of a range iin rewardedBlocks uint constant FIRST_REWARDED_BLOCK = 1; /// @dev sentinel to mark the end of a range iin rewardedBlocks uint constant LAST_REWARDED_BLOCK = 2;- In - manualReward()function,- manualRewardedBlocks_[winner][firstBlock]and- manualRewardedBlocks_[winner][lastBlock]are flagged with- FIRST_REWARDED_BLOCKand- LAST_REWARDED_BLOCKrespectively to prevent rewards from being distributed twice.- FIRST_REWARDED_BLOCKand- LAST_REWARDED_BLOCKfunctions the same. They are just used to flag blocks. A single non-zero variable can be used to replace these two constant variables.
 - Exploit Scenario- N/A 
 - Recommendations- These two constant variables can be replaced with a single variable to flag the block. 
 - Results- Resolved in commit 0553932. 
 
- Use initializermodifier to protect the initialize functionSeverity Informational File contracts/ethereum/contracts/Token.sol; contracts/ethereum/contracts/AaveLiquidityProvider.sol; contracts/ethereum/contracts/CompoundLiquidityProvider.sol; Commit 26e9450; Status Acknowledged. - Description- Tokencontract,- AaveLiquidityProvidercontract and- CompoundLiquidityProvidercontract will be upgradable contracts deployed with beacon proxy. The- initializermodifier can be added to the initialize function- init()to protect it.
 - Exploit Scenario- N/A. 
 - Recommendations- Use the Openzeppelin’s - initializerfrom the- initializablecontract to protect the- init()function.
 - Results- Acknowledged. - Reply from Fluidity team: - we use a version count now for dealing with migrations and the like, so the OZ initializer library isn’t really applicable now 
 
- Lack of Re-entrancy Guard for critical function with external dependencySeverity Informational Source contracts/ethereum/contracts/Token.sol; Commit 26e9450; Status Pending - Description- The snippets are following a proper check-effects-interaction pattern. However, attention should be paid to the external - erc20Inand- erc20Outthat interacted.
 - Exploit Scenario- N/A 
 - Recommendations- ReentrancyGaurdcan be added to- erc20Inand- erc20Outthat contain interactions with the external token transfer.
 - Results- Pending 
 
Undetermined
Undetermined
- Unclear usage of blockedRewards_Severity Undetermined File contracts/ethereum/contracts/Token.sol#L107; Commit 26e9450; Status Acknowledged. - Description- The - blockedRewards_is used to store users’ quarantine rewards. However, the protocol only updates the value of- blockedRewards_and never uses it to mint rewards.
 - Exploit Scenario- N/A. 
 - Recommendations- N/A. 
 - Results- Reply from Fluidity team: - “ - blockedRewards_gets used in the- unblockRewardfunction, which allows the operator to unblock and mint a reward after external verification.”
 
Access Control Analysis
Access Control Analysis
Token contract
Token contract
There are three major privileged roles for the token contract:
- operator_:- A multi-sig wallet controlled by the Fluidity dev team that can call below functions. - setRestrictions()- update maxUncheckedReward_, mintLimitsEnabled_, remainingGlobalMint_, userMintLimit_ and userMintResetBlock_ variables.
 
 - updateOperator()- update Operator multi-sig wallet.
 
 - enableEmergencyMode()- enable emergency mode.
 
 - disableEmergencyMode()- disable emergency mode.
 
 - updateWorkerConfig()- update worker configure which works as a register for the protocol.
 
 - updateRewardQuarantineThreshold()- update RewardQuarantineThreshold.
 
 - enableMintLimits()- enables or disables mint limits.
 
 - unblockReward()- unblocks a reward that was quarantined for being too large.
 
 
- emergencyCouncil_:- A multi-sig wallet controlled by the Fluidity dev team that can trigger the emergency mode.
 
- oracle:-  Distribute rewards by calling function batchReward()or signing reward messages off-chain (signature verified and rewards distributed by functionmanualReward()).
 
-  Distribute rewards by calling function 
WorkerConfig contract
WorkerConfig contract
- operator_:- A multi-sig wallet controlled by the Fluidity dev team. - updateOracles()- update token contract oracles
 
 - enableEmergencyMode()and- disableEmergencyMode()- enable or disable Emergency Mode.
 
 
- emergencyCouncil_:- A multi-sig wallet controlled by the Fluidity dev team that can trigger the emergency mode.
 
Off-Chain OpSec 
Off-Chain OpSec
- block-fluid-transfers-amqp: It collects blocks with Transferevents and sends messages to worker-server.
- worker-server: the worker on the server-side receives the blocks and transaction data from the block-fluid-transfers-amqp. It filters out transactions unrelated to fluid tokens. Those data are used to randomly draw winners and calculate winners’ payout amounts based on the hypergeometric distribution. It sends out messages containing winners’ info to worker-client.
- worker-client: the worker on the client-side decodes the winner messages sent from the worker-server. It decodes the winner message and checks the winning status. It will check winning info and filter out invalid winner info. It then sends out winner announcement messages to the transaction-spooler.
- transaction-spooler: the worker receives messages containing winner announcements from worker-client and scales the winning amount based on token decimals. It then appends rewards info to batched rewards queue if the scaled amount exceeds the rewards threshold.
- transaction-sender: the worker receives the batched rewards queue sent from the transaction-spooler. It calls FluidToken.batchReward()function to mint rewards to winners.
For the oracle address which has permission to distribute rewards, it is rotated with a serverless function and a trail uploaded to GitHub operating entirely trustless. And the governor (operator) address is a multi-sig account held by key members of the team and community (including trusted advisors) - this address must sign off on disproportionately large payouts and key rotation of the worker key.
Appendix I: Severity Categories
Appendix I: Severity Categories
| Severity | Description | 
|---|---|
| High | Issues that are highly exploitable security vulnerabilities. It may cause direct loss of funds / permanent freezing of funds. All high severity issues should be resolved. | 
| Medium | Issues that are only exploitable under some conditions or with some privileged access to the system. Users’ yields/rewards/information is at risk. All medium severity issues should be resolved unless there is a clear reason not to. | 
| Low | Issues that are low risk. Not fixing those issues will not result in the failure of the system. A fix on low severity issues is recommended but subject to the clients’ decisions. | 
| Informational | Issues that pose no risk to the system and are related to the security best practices. Not fixing those issues will not result in the failure of the system. A fix on informational issues or adoption of those security best practices-related suggestions is recommended but subject to clients’ decision. | 
Appendix II: Status Categories
Appendix II: Status Categories
| Status | Description | 
|---|---|
| Unresolved | The issue is not acknowledged and not resolved. | 
| Partially Resolved | The issue has been partially resolved. | 
| Acknowledged | The Finding / Suggestion is acknowledged but not fixed / not implemented. | 
| Resolved | The issue has been sufficiently resolved. | 
Disclaimer
Disclaimer
Verilog Solutions receives compensation from one or more clients for performing the smart contract and auditing analysis contained in these reports. The report created is solely for Clients and published with their consent. As such, the scope of our audit is limited to a review of code, and only the code we note as being within the scope of our audit is detailed in this report. It is important to note that the Solidity code itself presents unique and unquantifiable risks since the Solidity language itself remains under current development and is subject to unknown risks and flaws. Our sole goal is to help reduce the attack vectors and the high level of variance associated with utilizing new and consistently changing technologies. Thus, Verilog Solutions in no way claims any guarantee of security or functionality of the technology we agree to analyze.
In addition, Verilog Solutions reports do not provide any indication of the technology proprietors, business, business model, or legal compliance. As such, reports do not provide investment advice and should not be used to make decisions about investment or involvement with any particular project. Verilog Solutions has the right to distribute the Report through other means, including via Verilog Solutions publications and other distributions. Verilog Solutions makes the reports available to parties other than the Clients (i.e., “third parties”) – on its website in hopes that it can help the blockchain ecosystem develop technical best practices in this rapidly evolving area of innovation.