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
Transfer
events 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
,lastBlock
are 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
contractAddress
andchainId
to 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 + amount
is assigned to the wrong variableuserLastMintedBlock_
. ReplaceuserLastMintedBlock_[msg.sender]
withuserMint
.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]
touserMint
.
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 functionToken.updateOracle()
, which requires the caller to berngOracle_
itself and immediately sets therngOracle_
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 operationsToken.batchReward()
andToken.manualReward()
, which sets the winners and reward amounts.As the oracle
rngOracle_
, it can set oracle to a new address by calling functionToken.updateOracle()
. The function requires the function call to be made fromrngOracle_
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()
andToken.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 validation
Severity Medium Source contracts/ethereum/contracts/Token.sol#L111; Commit 3578295; Status Acknowledged. Description
Function
Token.updateOracle()
lacks of zero-value check onnewOracle
. 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 parameternewOracle
. 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 recovery
Severity Medium Source contracts/ethereum/contracts/Token.sol#L257; Commit 3578295; Status Resolved in commit cac3886; Description
Lack of check on
s
range before feeding it toecrecover(hash, v, r, s)
function. This results in potential failure in claim reward viamanualReward
due 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
s
value is within range (0, secp256k1n ÷ 2 + 1) needs to be added to prevent signature recovery failure.
Exploit Scenario
The input
s
is greater than secp256k1n/2 results in the failure of signature recovery and calls tomanualReward
fails.
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 rewards
Severity Medium Source contracts/ethereum/contracts/Token.sol; Commit 3578295; Status Acknowledged. Description
Insufficient check for
firstBlock
andlastBlock
inbatchReward()
andmanualReward()
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 forfirstBlock
and no check forlastBlock
.winAmount
can be added tomanualRewards_[winner]
and rewards will be distributed to users more than one time. This can result inmanualRewards_[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.manualReward
is called withfirstBlock
10 andlastBlock
20 for winner Alice. Rewards are distributed to Alice.Then
manualReward
was called withfirstBlock
10 andlastBlock
20 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 function
Severity Medium File contracts/ethereum/contracts/WorkerConfig.sol contracts/ethereum/contracts/Token.sol Commit 26e9450; Status Acknowledged; Description
operator_
andemergencyCouncil_
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_
andemergencyCouncil_
.
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 functionToken.updateOperator()
, which requires the caller to beoperator_
itself and immediately sets theoperator_
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 operationsToken.enableEmergencyMode()
suspends the protocol, andToken.batchReward()
andToken.manualReward()
, which sets the winners and reward amounts.As the operator
operator_
, he/she can set the operator to a new address by calling functionToken.updateOperator()
. The function requires the function call to be made fromoperator_
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()
andToken.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 functionerc20Out()
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 operations
Severity Low Source contracts/ethereum/contracts/Token.sol#L111; Commit 3578295; Status Resolved in commit e8d0a51. Description
critical function
updateOracle
lacks 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 functionupdateOracle()
.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 functionupdateOracle()
.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
, andenableMintLimits
lack 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 version
Severity 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.11
and<0.9.0
can 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 unspecified
Severity 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 ofToken.sol
,private
or 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 style
Severity 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, theinternal
functionrewardFromPool
andrecover
do 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
rewardFromPool
to_rewardFromPool
.
Results
Acknowledged.
- Redundant assertions for arithmetic operations in Solidity ≥ 0.8
Severity 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 declarations
Severity Informational Source microservice-ethereum-worker-server/main.go#L145-L145; Commit 3578295; Status Acknowledged. Description
The two environment variables for
ethFluxAddress_
andtokenFluxAddress_
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 numbers
Severity Informational Source contracts/ethereum/contracts/Token.sol#L200; Commit 3578295; Status Resolved in commit 2600ff8. Description
Magic number
1
is used to flag the first block of the last reward inbatchReward()
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 issues
Severity Informational Source contracts/ethereum/contracts/Token.sol#L10-12; Commit 3578295; Status Resolved in commit 0553932. Description
Distinguishing
FIRST_REWARDED_BLOCK
andLAST_REWARDED_BLOCK
in terms of value and name is redundant since the code logic defined inmanualReward()
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]
andmanualRewardedBlocks_[winner][lastBlock]
are flagged withFIRST_REWARDED_BLOCK
andLAST_REWARDED_BLOCK
respectively to prevent rewards from being distributed twice.FIRST_REWARDED_BLOCK
andLAST_REWARDED_BLOCK
functions 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
initializer
modifier 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
Token
contract,AaveLiquidityProvider
contract andCompoundLiquidityProvider
contract will be upgradable contracts deployed with beacon proxy. Theinitializer
modifier can be added to the initialize functioninit()
to protect it.
Exploit Scenario
N/A.
Recommendations
Use the Openzeppelin’s
initializer
from theinitializable
contract to protect theinit()
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 dependency
Severity 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
erc20In
anderc20Out
that interacted.
Exploit Scenario
N/A
Recommendations
ReentrancyGaurd
can be added toerc20In
anderc20Out
that 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 ofblockedRewards_
and never uses it to mint rewards.
Exploit Scenario
N/A.
Recommendations
N/A.
Results
Reply from Fluidity team:
“
blockedRewards_
gets used in theunblockReward
function, 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()
anddisableEmergencyMode()
- 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
Transfer
events 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.